xref: /trunk/main/sw/source/filter/ww8/wrtww8gr.cxx (revision 870262e3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
28 
29 #if OSL_DEBUG_LEVEL > 0
30 #   include <cstdio>
31 #endif
32 
33 #include <com/sun/star/embed/XEmbedPersist.hpp>
34 #include <com/sun/star/embed/Aspects.hpp>
35 #include <rtl/math.hxx>
36 #include <svtools/filter.hxx>
37 #include <svl/itemiter.hxx>
38 #include "svl/urihelper.hxx"
39 
40 #include <svtools/embedhlp.hxx>
41 
42 #include <vcl/virdev.hxx>
43 #include <vcl/svapp.hxx>
44 
45 #include <hintids.hxx>
46 #include <editeng/boxitem.hxx>
47 #include <editeng/shaditem.hxx>
48 #include <editeng/shaditem.hxx>
49 #include <filter/msfilter/msoleexp.hxx>
50 #include <editeng/lrspitem.hxx> // SvxLRSpaceItem
51 #include <editeng/ulspitem.hxx>
52 #include <editeng/fhgtitem.hxx>
53 #include <svx/svdoole2.hxx>
54 
55 #include <unotools/ucbstreamhelper.hxx>
56 #include <fmtanchr.hxx>
57 #include <ndgrf.hxx>
58 #include <frmfmt.hxx>       // class SwFlyFrmFmt
59 #include <grfatr.hxx>       // class SwCropGrf
60 #include <ndole.hxx>
61 #include <ndtxt.hxx>
62 #include <fmtfsize.hxx>
63 #include <fmtornt.hxx>
64 
65 #include <writerfilter/doctok/sprmids.hxx>
66 
67 #include <doc.hxx>
68 #include "writerhelper.hxx"
69 #include "writerwordglue.hxx"
70 #include "ww8struc.hxx"
71 #include "wrtww8.hxx"
72 #include "ww8par.hxx"
73 #include "escher.hxx"
74 //Added for i120568
75 #include "ww8attributeoutput.hxx"
76 #include "fmturl.hxx"
77 //End
78 #include "docsh.hxx"
79 #include <cstdio>
80 
81 #include <stdio.h>
82 
83 using namespace ::com::sun::star;
84 using namespace nsFieldFlags;
85 
86 // Damit KA debuggen kann, ohne sich den ganzen Writer zu holen, ist
87 // temporaer dieses Debug gesetzt. Ist ausserdem noch das passende IniFlag
88 // gesetzt, dann werden in d:\ Hilfsdateien erzeugt.
89 // !! sollte demnaechst wieder entfernt werden !!
90 // #define DEBUG_KA
91 
92 
93 // ToDo:
94 // 5. Die MapModes, die Win nicht kann, umrechnen
95 
96 // OutGrf() wird fuer jeden GrafNode im Doc gerufen. Es wird ein PicLocFc-Sprm
97 // eingefuegt, der statt Adresse ein Magic sal_uLong enthaelt. Ausserdem wird
98 // in der Graf-Klasse der GrfNode-Ptr gemerkt ( fuers spaetere Ausgeben der
99 // Grafiken und Patchen der PicLocFc-Attribute )
100 
OutputGrfNode(const SwGrfNode &)101 void WW8Export::OutputGrfNode( const SwGrfNode& /*rNode*/ )
102 {
103     OSL_TRACE("WW8Export::OutputGrfNode( const SwGrfNode& )\n" );
104     ASSERT( mpParentFrame, "frame not set!" );
105     if ( mpParentFrame )
106     {
107         OutGrf( *mpParentFrame );
108         pFib->fHasPic = 1;
109     }
110 }
111 
TestOleNeedsGraphic(const SwAttrSet & rSet,SvStorageRef xOleStg,SvStorageRef xObjStg,String & rStorageName,SwOLENode * pOLENd)112 bool WW8Export::TestOleNeedsGraphic(const SwAttrSet& rSet,
113     SvStorageRef xOleStg, SvStorageRef xObjStg, String &rStorageName,
114     SwOLENode *pOLENd)
115 {
116 #ifdef NO_OLE_SIZE_OPTIMIZE
117     return true;
118 #else
119     bool bGraphicNeeded = false;
120     SfxItemIter aIter( rSet );
121     const SfxPoolItem* pItem = aIter.GetCurItem();
122 
123     do {
124         switch (pItem->Which())
125         {
126             /*
127             For an inline object these properties are irrelevant because they
128             will be the same as the defaults that msword applies in their
129             absence, so if that is all that there is for these inline objects
130             then if there turns out to be enough information in the object
131             itself to regenerate the correct size and preview of the object
132             then we will not need to provide an additional graphics preview in
133             the data stream, which can save a lot of disk space.
134             */
135             case RES_FRM_SIZE:
136             case RES_CNTNT:
137             case RES_VERT_ORIENT:
138             case RES_ANCHOR:
139                 break;
140             default:
141                 bGraphicNeeded = true;
142         }
143     } while( !bGraphicNeeded && !aIter.IsAtEnd() &&
144         0 != ( pItem = aIter.NextItem() ) );
145 
146     /*
147     Now we must see if the object contains a preview itself which is equal to
148     the preview that we are currently using. If the graphics are equal then we
149     dont need to store another preview
150     */
151     GDIMetaFile aWMF;
152     long nX=0,nY=0;
153     if (!bGraphicNeeded && SwWW8ImplReader::ImportOleWMF(xOleStg,aWMF,nX,nY))
154     {
155         // bGraphicNeeded set to true is right / fixes #i51670#.
156         bGraphicNeeded = true;
157         Point aTmpPoint;
158         Rectangle aRect( aTmpPoint, Size( nX, nY ) );
159         Graphic aGraph(aWMF);
160 
161         ErrCode nErr = ERRCODE_NONE;
162 		Rectangle aVisArea;
163         sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
164         if ( pOLENd )
165             nAspect = pOLENd->GetAspect();
166         SdrOle2Obj *pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
167             rStorageName,xObjStg,pDoc->GetDocStorage(),aGraph,aRect,aVisArea,0,nErr,0,nAspect);
168 
169         if (pRet)
170         {
171             uno::Reference< embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
172             if ( xObj.is() )
173             {
174                 SvStream* pGraphicStream = NULL;
175                 comphelper::EmbeddedObjectContainer aCnt( pDoc->GetDocStorage() );
176 			    try
177 			    {
178                     uno::Reference< embed::XEmbedPersist > xPersist(
179                             xObj,
180                             uno::UNO_QUERY_THROW );
181 
182                     // it makes no sence to search the object in the container by reference since the object was created
183                     // outside of the container and was not inserted there, only the name makes sence
184 				    pGraphicStream =
185                             ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) );
186                 }
187                 catch( uno::Exception& )
188                 {}
189 
190                 DBG_ASSERT( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
191                 if ( pGraphicStream && !pGraphicStream->GetError() )
192                 {
193                     Graphic aGr1;
194                     GraphicFilter* pGF = GraphicFilter::GetGraphicFilter();
195                     if( pGF->ImportGraphic( aGr1, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
196                     {
197                         Graphic aGr2;
198                         delete pGraphicStream;
199                         pGraphicStream =
200                                 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
201                         if( pGF->ImportGraphic( aGr2, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
202                         {
203                             if ( aGr1 == aGr2 )
204                                 bGraphicNeeded = false;
205                         }
206                     }
207                 }
208                 else
209                     delete pGraphicStream;
210             }
211 
212             delete pRet;
213         }
214     }
215     else
216         bGraphicNeeded = true;
217     return bGraphicNeeded;
218 #endif
219 }
220 
OutputOLENode(const SwOLENode & rOLENode)221 void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
222 {
223     OSL_TRACE("WW8Export::OutputOLENode( const SwOLENode& rOLENode )\n" );
224     sal_uInt8 *pSpecOLE;
225     sal_uInt8 *pDataAdr;
226     short nSize;
227     static sal_uInt8 aSpecOLE_WW8[] = {
228             0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
229             0x0a, 0x08, 1,          // sprmCFOLE2
230             0x56, 0x08, 1           // sprmCFObj
231         };
232     static sal_uInt8 aSpecOLE_WW6[] = {
233             68, 4, 0, 0, 0, 0,      // sprmCPicLocation (len is 4)
234             75, 1,                  // sprmCFOLE2
235             118, 1                  // sprmCFObj
236         };
237 
238     if ( bWrtWW8 )
239     {
240         pSpecOLE = aSpecOLE_WW8;
241         nSize = sizeof( aSpecOLE_WW8 );
242     }
243     else
244     {
245         pSpecOLE = aSpecOLE_WW6;
246         nSize = sizeof( aSpecOLE_WW6 );
247     }
248     pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
249 
250     SvStorageRef xObjStg = GetWriter().GetStorage().OpenSotStorage(
251         CREATE_CONST_ASC(SL::aObjectPool), STREAM_READWRITE |
252         STREAM_SHARE_DENYALL );
253 
254     if( xObjStg.Is()  )
255     {
256         uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
257         if( xObj.is() )
258         {
259             embed::XEmbeddedObject *pObj = xObj.get();
260             sal_uInt32 nPictureId = (sal_uInt32)(sal_uIntPtr)pObj;
261             Set_UInt32(pDataAdr, nPictureId);
262 
263             WW8OleMap *pMap = new WW8OleMap(nPictureId);
264             bool bDuplicate = false;
265             WW8OleMaps &rOleMap = GetOLEMap();
266             sal_uInt16 nPos;
267             if ( rOleMap.Seek_Entry(pMap, &nPos) )
268             {
269                 bDuplicate = true;
270                 delete pMap;
271             }
272             else if( 0 == rOleMap.Insert( pMap) )
273                 delete pMap;
274 
275             String sStorageName( '_' );
276             sStorageName += String::CreateFromInt32( nPictureId );
277             SvStorageRef xOleStg = xObjStg->OpenSotStorage( sStorageName,
278                                 STREAM_READWRITE| STREAM_SHARE_DENYALL );
279             if( xOleStg.Is() )
280             {
281                 /*
282                 If this object storage has been written already don't
283                 waste time rewriting it
284                 */
285                 if (!bDuplicate)
286                 {
287 		            sal_Int64 nAspect = rOLENode.GetAspect();
288 					svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
289                     GetOLEExp().ExportOLEObject( aObjRef, *xOleStg );
290                     if ( nAspect == embed::Aspects::MSOLE_ICON )
291                     {
292                         ::rtl::OUString aObjInfo( RTL_CONSTASCII_USTRINGPARAM( "\3ObjInfo" ) );
293                         if ( !xOleStg->IsStream( aObjInfo ) )
294                         {
295                             const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
296                             SvStorageStreamRef rObjInfoStream = xOleStg->OpenSotStream( aObjInfo );
297                             if ( rObjInfoStream.Is() && !rObjInfoStream->GetError() )
298                             {
299                                 rObjInfoStream->Write( pObjInfoData, sizeof( pObjInfoData ) );
300                                 xOleStg->Commit();
301                             }
302                         }
303                     }
304                 }
305 
306                 // write as embedded field - the other things will be done
307                 // in the escher export
308                 String sServer(FieldString(ww::eEMBED));
309                 sServer += xOleStg->GetUserName();
310                 sServer += ' ';
311 
312                 OutputField(0, ww::eEMBED, sServer, WRITEFIELD_START |
313                     WRITEFIELD_CMD_START | WRITEFIELD_CMD_END);
314 
315                 pChpPlc->AppendFkpEntry( Strm().Tell(),
316                         nSize, pSpecOLE );
317 
318                 bool bEndCR = true;
319                 /*
320                 In the word filter we only need a preview image for
321                 floating images, and then only (the usual case) if the
322                 object doesn't contain enough information to reconstruct
323                 what we need.
324 
325                 We don't need a graphic for inline objects, so we don't
326                 even need the overhead of a graphic in that case.
327                 */
328                 bool bGraphicNeeded = false;
329 
330                 if (mpParentFrame)
331                 {
332                     bGraphicNeeded = true;
333 
334                     if (mpParentFrame->IsInline())
335                     {
336                         const SwAttrSet& rSet =
337                             mpParentFrame->GetFrmFmt().GetAttrSet();
338                         bEndCR = false;
339                         bGraphicNeeded = TestOleNeedsGraphic(rSet,
340                             xOleStg, xObjStg, sStorageName, const_cast<SwOLENode*>(&rOLENode));
341                     }
342                 }
343 
344                 if (!bGraphicNeeded)
345                     WriteChar(0x1);
346                 else
347                 {
348                     /*
349                     ##897##
350                     We need to insert the graphic representation of
351                     this object for the inline case, otherwise word
352                     has no place to find the dimensions of the ole
353                     object, and will not be able to draw it
354                     */
355                     OutGrf(*mpParentFrame);
356                 }
357 
358                 OutputField(0, ww::eEMBED, aEmptyStr,
359                     WRITEFIELD_END | WRITEFIELD_CLOSE);
360 
361                 if (bEndCR) //No newline in inline case
362                     WriteCR();
363             }
364         }
365     }
366 }
367 
OutGrf(const sw::Frame & rFrame)368 void WW8Export::OutGrf(const sw::Frame &rFrame)
369 {
370 	//Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
371 	//will be exported to ensure the fidelity
372     const SwFmtURL& rURL = rFrame.GetFrmFmt().GetAttrSet().GetURL();
373     bool bURLStarted = false;
374     if( rURL.GetURL().Len() && rFrame.GetWriterType() == sw::Frame::eGraphic)
375     {
376         bURLStarted = true;
377         m_pAttrOutput->StartURL( rURL.GetURL(), rURL.GetTargetFrameName() );
378     }
379     //End
380 
381     // GrfNode fuer spaeteres rausschreiben der Grafik merken
382     pGrf->Insert(rFrame);
383 
384     pChpPlc->AppendFkpEntry( Strm().Tell(), pO->Count(), pO->GetData() );
385     pO->Remove( 0, pO->Count() );                   // leeren
386 
387     // --> OD 2007-06-06 #i29408#
388     // linked, as-character anchored graphics have to be exported as fields.
389     const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
390                               ? rFrame.GetContent()->GetGrfNode() : 0;
391     if ( pGrfNd && pGrfNd->IsLinkedFile() )
392     {
393         String sStr( FieldString(ww::eINCLUDEPICTURE) );
394         sStr.APPEND_CONST_ASC(" \"");
395         {
396             if ( pGrfNd )
397             {
398                 String aFileURL;
399                 pGrfNd->GetFileFilterNms( &aFileURL, 0 );
400                 sStr += aFileURL;
401             }
402         }
403         sStr.APPEND_CONST_ASC("\" \\d");
404 
405         OutputField( 0, ww::eINCLUDEPICTURE, sStr,
406                    WRITEFIELD_START | WRITEFIELD_CMD_START | WRITEFIELD_CMD_END );
407     }
408     // <--
409 
410     WriteChar( (char)1 );   // Grafik-Sonderzeichen in Haupttext einfuegen
411 
412     sal_uInt8 aArr[ 18 ];
413     sal_uInt8* pArr = aArr;
414 
415     const SwFrmFmt &rFlyFmt = rFrame.GetFrmFmt();
416     const RndStdIds eAn = rFlyFmt.GetAttrSet().GetAnchor(false).GetAnchorId();
417     if (eAn == FLY_AS_CHAR)
418     {
419         sal_Int16 eVert = rFlyFmt.GetVertOrient().GetVertOrient();
420         if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
421         {
422             bool bVert = false;
423             //The default for word in vertical text mode is to center,
424             //otherwise a sub/super script hack is employed
425             if (pOutFmtNode && pOutFmtNode->ISA(SwCntntNode) )
426             {
427                 const SwTxtNode* pTxtNd = (const SwTxtNode*)pOutFmtNode;
428                 SwPosition aPos(*pTxtNd);
429                 bVert = pDoc->IsInVerticalText(aPos) ? true : false;
430             }
431             if (!bVert)
432             {
433                 SwTwips nHeight = rFlyFmt.GetFrmSize().GetHeight();
434                 nHeight/=20; //nHeight was in twips, want it in half points, but
435                              //then half of total height.
436                 long nFontHeight = ((const SvxFontHeightItem&)
437                     GetItem(RES_CHRATR_FONTSIZE)).GetHeight();
438                 nHeight-=nFontHeight/20;
439 
440                 if (bWrtWW8)
441                     Set_UInt16( pArr, NS_sprm::LN_CHpsPos );
442                 else
443                     Set_UInt8( pArr, 101 );
444                 Set_UInt16( pArr, -((sal_Int16)nHeight));
445             }
446         }
447     }
448 
449     // sprmCFSpec
450     if( bWrtWW8 )
451         Set_UInt16( pArr, 0x855 );
452     else
453         Set_UInt8( pArr, 117 );
454     Set_UInt8( pArr, 1 );
455 
456     // sprmCPicLocation
457     if( bWrtWW8 )
458         Set_UInt16( pArr, NS_sprm::LN_CPicLocation );
459     else
460     {
461         Set_UInt8( pArr, 68 );
462         Set_UInt8( pArr, 4 );
463     }
464     Set_UInt32( pArr, GRF_MAGIC_321 );
465 
466     // Magic variieren, damit verschiedene Grafik-Attribute nicht
467     // gemerged werden
468     static sal_uInt8 nAttrMagicIdx = 0;
469     --pArr;
470     Set_UInt8( pArr, nAttrMagicIdx++ );
471     pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
472 
473     // --> OD 2007-04-23 #i75464#
474     // Check, if graphic isn't exported as-character anchored.
475     // Otherwise, an additional paragraph is exported for a graphic, which is
476     // forced to be treated as inline, because it's anchored inside another frame.
477     if ( !rFrame.IsInline() &&
478          ( ((eAn == FLY_AT_PARA) && ( bWrtWW8 || !IsInTable() )) ||
479            (eAn == FLY_AT_PAGE)) )
480     // <--
481     {
482         WriteChar( (char)0x0d ); // umgebenden Rahmen mit CR abschliessen
483 
484         static sal_uInt8 __READONLY_DATA nSty[2] = { 0, 0 };
485         pO->Insert( nSty, 2, pO->Count() );     // Style #0
486         bool bOldGrf = bOutGrf;
487         bOutGrf = true;
488 
489         OutputFormat( rFrame.GetFrmFmt(), false, false, true ); // Fly-Attrs
490 
491         bOutGrf = bOldGrf;
492         pPapPlc->AppendFkpEntry( Strm().Tell(), pO->Count(), pO->GetData() );
493         pO->Remove( 0, pO->Count() );                   // leeren
494     }
495     // --> OD 2007-06-06 #i29408#
496     // linked, as-character anchored graphics have to be exported as fields.
497     else if ( pGrfNd && pGrfNd->IsLinkedFile() )
498     {
499         OutputField( 0, ww::eINCLUDEPICTURE, String(), WRITEFIELD_CLOSE );
500     }
501     // <--
502 	//Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
503 	//will be exported to ensure the fidelity
504     if( bURLStarted )
505         m_pAttrOutput->EndURL();
506         //End
507 }
508 
operator =(const GraphicDetails & rOther)509 GraphicDetails& GraphicDetails::operator=(const GraphicDetails &rOther)
510 {
511     maFly = rOther.maFly;
512     mnPos = rOther.mnPos;
513     mnWid = rOther.mnWid;
514     mnHei = rOther.mnHei;
515     return *this;
516 }
517 
Insert(const sw::Frame & rFly)518 void SwWW8WrGrf::Insert(const sw::Frame &rFly)
519 {
520     const Size aSize( rFly.GetLayoutSize() );
521     const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
522     const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
523     maDetails.push_back(GraphicDetails(rFly, nWidth, nHeight));
524 }
525 
WritePICFHeader(SvStream & rStrm,const sw::Frame & rFly,sal_uInt16 mm,sal_uInt16 nWidth,sal_uInt16 nHeight,const SwAttrSet * pAttrSet)526 void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const sw::Frame &rFly,
527     sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
528 {
529     sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
530     sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
531 
532             // Crop-AttributInhalt in Header schreiben ( falls vorhanden )
533     const SfxPoolItem* pItem;
534     if (pAttrSet && (SFX_ITEM_ON
535         == pAttrSet->GetItemState(RES_GRFATR_CROPGRF, false, &pItem)))
536     {
537         const SwCropGrf& rCr = *(SwCropGrf*)pItem;
538         nCropL = (sal_Int16)rCr.GetLeft();
539         nCropR = (sal_Int16)rCr.GetRight();
540         nCropT = (sal_Int16)rCr.GetTop();
541         nCropB = (sal_Int16)rCr.GetBottom();
542         nXSizeAdd = nXSizeAdd - (sal_Int16)( rCr.GetLeft() + rCr.GetRight() );
543         nYSizeAdd = nYSizeAdd - (sal_Int16)( rCr.GetTop() + rCr.GetBottom() );
544     }
545 
546     Size aGrTwipSz(rFly.GetSize());
547     bool bWrtWW8 = rWrt.bWrtWW8;
548     sal_uInt16 nHdrLen = bWrtWW8 ? 0x44 : 0x3A;
549 
550     sal_uInt8 aArr[ 0x44 ] = { 0 };
551 
552     sal_uInt8* pArr = aArr + 0x2E;  //Do borders first
553 
554     const SwAttrSet& rAttrSet = rFly.GetFrmFmt().GetAttrSet();
555     if (SFX_ITEM_ON == rAttrSet.GetItemState(RES_BOX, false, &pItem))
556     {
557         const SvxBoxItem* pBox = (const SvxBoxItem*)pItem;
558         if( pBox )
559         {
560             bool bShadow = false;               // Shadow ?
561             const SvxShadowItem* pSI =
562                 sw::util::HasItem<SvxShadowItem>(rAttrSet, RES_SHADOW);
563             if (pSI)
564             {
565                 bShadow = (pSI->GetLocation() != SVX_SHADOW_NONE) &&
566                     (pSI->GetWidth() != 0);
567             }
568 
569             sal_uInt8 aLnArr[4] = { BOX_LINE_TOP, BOX_LINE_LEFT,
570                                 BOX_LINE_BOTTOM, BOX_LINE_RIGHT };
571             for( sal_uInt8 i = 0; i < 4; ++i )
572             {
573                 const SvxBorderLine* pLn = pBox->GetLine( aLnArr[ i ] );
574                 WW8_BRC aBrc;
575                 if (pLn)
576                 {
577                     aBrc = rWrt.TranslateBorderLine( *pLn,
578                         pBox->GetDistance( aLnArr[ i ] ), bShadow );
579                 }
580 
581                 //use importer logic to determine how large the exported
582                 //border will really be in word and adjust accordingly
583                 short nSpacing;
584                 short nThick = aBrc.DetermineBorderProperties(!bWrtWW8,
585                     &nSpacing);
586                 switch (aLnArr[ i ])
587                 {
588                     case BOX_LINE_TOP:
589                     case BOX_LINE_BOTTOM:
590                         nHeight -= bShadow ? nThick*2 : nThick;
591                         nHeight = nHeight - nSpacing;
592                         break;
593                     case BOX_LINE_LEFT:
594                     case BOX_LINE_RIGHT:
595                     default:
596                         nWidth -= bShadow ? nThick*2 : nThick;
597                         nWidth = nWidth - nSpacing;
598                         break;
599                 }
600                 memcpy( pArr, &aBrc.aBits1, 2);
601                 pArr+=2;
602 
603                 if( bWrtWW8 )
604                 {
605                     memcpy( pArr, &aBrc.aBits2, 2);
606                     pArr+=2;
607                 }
608             }
609         }
610     }
611 
612     pArr = aArr + 4;                                //skip lcb
613     Set_UInt16( pArr, nHdrLen );                    // set cbHeader
614 
615     Set_UInt16( pArr, mm );                         // set mm
616 
617     /*
618     #92494#
619     Just in case our original size is too big to fit inside a ushort we can
620     substitute the final size and loose on retaining the scaling factor but
621     still keep the correct display size anyway.
622     */
623     const bool bIsSubstitutedSize = (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) ||
624                                     (aGrTwipSz.Width() < 0 ) || (aGrTwipSz.Height() < 0);
625     if ( bIsSubstitutedSize )
626     {
627         aGrTwipSz.Width() = nWidth;
628         aGrTwipSz.Height() = nHeight;
629     }
630     using namespace sw::types;
631     // set xExt & yExt
632     Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width() * 254L / 144));
633     Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height() * 254L / 144));
634     pArr += 16;
635     // skip hMF & rcWinMF
636     // set dxaGoal & dyaGoal
637     Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
638     Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
639 
640     if ( aGrTwipSz.Width() + nXSizeAdd )             // set mx
641     {
642         if ( !bIsSubstitutedSize )
643         {
644             const double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd );
645             Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
646         }
647         else
648         {
649             Set_UInt16( pArr, 1000 );
650         }
651     }
652     else
653     {
654         pArr += 2;
655     }
656 
657     if ( aGrTwipSz.Height() + nYSizeAdd )            // set my
658     {
659         if ( !bIsSubstitutedSize )
660         {
661             const double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
662             Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
663         }
664         else
665         {
666             Set_UInt16( pArr, 1000 );
667         }
668     }
669     else
670     {
671         pArr += 2;
672     }
673 
674     if ( !bIsSubstitutedSize )
675     {
676         Set_UInt16( pArr, nCropL );                     // set dxaCropLeft
677         Set_UInt16( pArr, nCropT );                     // set dyaCropTop
678         Set_UInt16( pArr, nCropR );                     // set dxaCropRight
679         Set_UInt16( pArr, nCropB );                     // set dyaCropBottom
680     }
681     else
682     {
683         pArr += 8;
684     }
685 
686     rStrm.Write( aArr, nHdrLen );
687 }
688 
WriteGrfFromGrfNode(SvStream & rStrm,const SwGrfNode & rGrfNd,const sw::Frame & rFly,sal_uInt16 nWidth,sal_uInt16 nHeight)689 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd,
690     const sw::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
691 {
692     if (rGrfNd.IsLinkedFile())     // Linked File
693     {
694         String aFileN;
695         rGrfNd.GetFileFilterNms( &aFileN, 0 );
696 
697         // --> OD 2007-06-06 #i29408# - take the file URL as it is.
698 //        aFileN = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(),
699 //                                          aFileN);
700 //        INetURLObject aUrl( aFileN );
701 //        if( aUrl.GetProtocol() == INET_PROT_FILE )
702 //            aFileN = aUrl.PathToFileName();
703         // <--
704 
705 //JP 05.12.98: nach einigen tests hat sich gezeigt, das WW mit 99 nicht
706 //              klarkommt. Sie selbst schreiben aber bei Verknuepfunfen,
707 //              egal um welchen Type es sich handelt, immer den Wert 94.
708 //              Bug 59859
709 //      if ( COMPARE_EQUAL == aFiltN.ICompare( "TIF", 3 ) )
710 //          mm = 99;                    // 99 = TIFF
711 //      else
712             sal_uInt16 mm = 94;                    // 94 = BMP, GIF
713 
714         WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
715             rGrfNd.GetpSwAttrSet());
716         rStrm << (sal_uInt8)aFileN.Len();    // Pascal-String schreiben
717         SwWW8Writer::WriteString8(rStrm, aFileN, false,
718             RTL_TEXTENCODING_MS_1252);
719     }
720     else                                // Embedded File oder DDE oder so was
721     {
722         if (rWrt.bWrtWW8)
723         {
724             WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
725                 rGrfNd.GetpSwAttrSet());
726             SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
727             aInlineEscher.WriteGrfFlyFrame(rFly.GetFrmFmt(), 0x401);
728             aInlineEscher.WritePictures();
729         }
730         else
731         {
732             Graphic& rGrf = const_cast<Graphic&>(rGrfNd.GetGrf());
733             bool bSwapped = rGrf.IsSwapOut() ? true : false;
734             // immer ueber den Node einswappen!
735             const_cast<SwGrfNode&>(rGrfNd).SwapIn();
736 
737             GDIMetaFile aMeta;
738             switch (rGrf.GetType())
739             {
740                 case GRAPHIC_BITMAP:        // Bitmap -> in Metafile abspielen
741                     {
742                         VirtualDevice aVirt;
743                         aMeta.Record(&aVirt);
744                         aVirt.DrawBitmap( Point( 0,0 ), rGrf.GetBitmap() );
745                         aMeta.Stop();
746                         aMeta.WindStart();
747                         aMeta.SetPrefMapMode( rGrf.GetPrefMapMode());
748                         aMeta.SetPrefSize( rGrf.GetPrefSize());
749                     }
750                     break;
751                 case GRAPHIC_GDIMETAFILE :      // GDI ( =SV ) Metafile
752                     aMeta = rGrf.GetGDIMetaFile();
753                     break;
754                 default:
755                     return;
756             }
757 
758             WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
759                 rGrfNd.GetpSwAttrSet());
760             WriteWindowMetafileBits(rStrm, aMeta);
761 
762             if (bSwapped)
763                 rGrf.SwapOut();
764         }
765     }
766 }
767 //For i120928,export graphic info of bullet
WritePICBulletFHeader(SvStream & rStrm,const Graphic & rGrf,sal_uInt16 mm,sal_uInt16 nWidth,sal_uInt16 nHeight)768 void SwWW8WrGrf::WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf,
769             sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
770 {
771 	sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
772 	sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
773 
774 	Size aGrTwipSz(rGrf.GetPrefSize());
775 	bool bWrtWW8 = rWrt.bWrtWW8;
776 	sal_uInt16 nHdrLen = bWrtWW8 ? 0x44 : 0x3A;
777 
778 	sal_uInt8 aArr[ 0x44 ] = { 0 };
779 
780 	sal_uInt8* pArr = aArr + 0x2E;  //Do borders first
781 
782 	sal_uInt8 aLnArr[4] = { BOX_LINE_TOP, BOX_LINE_LEFT,
783 	BOX_LINE_BOTTOM, BOX_LINE_RIGHT };
784 	for( sal_uInt8 i = 0; i < 4; ++i )
785 	{
786 		WW8_BRC aBrc;
787 
788 		short nSpacing;
789 		short nThick = aBrc.DetermineBorderProperties(!bWrtWW8,
790 		&nSpacing);
791 		switch (aLnArr[ i ])
792 		{
793 			case BOX_LINE_TOP:
794 			case BOX_LINE_BOTTOM:
795 			nHeight -= nThick;
796 			nHeight = nHeight - nSpacing;
797 			break;
798 			case BOX_LINE_LEFT:
799 			case BOX_LINE_RIGHT:
800 			default:
801 			nWidth -= nThick;
802 			nWidth = nWidth - nSpacing;
803 			break;
804 		}
805 		memcpy( pArr, &aBrc.aBits1, 2);
806 		pArr+=2;
807 
808 		if( bWrtWW8 )
809 		{
810 			memcpy( pArr, &aBrc.aBits2, 2);
811 			pArr+=2;
812 		}
813 	}
814 
815 	pArr = aArr + 4;                                //skip lcb
816 	Set_UInt16( pArr, nHdrLen );                    // set cbHeader
817 
818 	Set_UInt16( pArr, mm );                         // set mm
819 
820 	if ( (aGrTwipSz.Width() * 254L / 144 > USHRT_MAX) || (aGrTwipSz.Height()  * 254L / 144 > USHRT_MAX)
821 		|| (aGrTwipSz.Width() < 0 ) || (aGrTwipSz.Height() < 0) )
822 	{
823 		aGrTwipSz.Width() = nWidth;
824 		aGrTwipSz.Height() = nHeight;
825 	}
826 	using namespace sw::types;
827 	// set xExt & yExt
828 	Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width() * 254L / 144));
829 	Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height() * 254L / 144));
830 	pArr += 16;
831 	// skip hMF & rcWinMF
832 	// set dxaGoal & dyaGoal
833 	Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
834 	Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
835 
836 	if( aGrTwipSz.Width() + nXSizeAdd )             // set mx
837 	{
838 		double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
839 		Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
840 	}
841 	else
842 		pArr += 2;
843 
844 	if( aGrTwipSz.Height() + nYSizeAdd )            // set my
845 	{
846 		double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
847 		Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
848 	}
849 	else
850 	pArr += 2;
851 
852 	Set_UInt16( pArr, nCropL );                     // set dxaCropLeft
853 	Set_UInt16( pArr, nCropT );                     // set dyaCropTop
854 	Set_UInt16( pArr, nCropR );                     // set dxaCropRight
855 	Set_UInt16( pArr, nCropB );                     // set dyaCropBottom
856 
857 	rStrm.Write( aArr, nHdrLen );
858 }
WriteGrfForBullet(SvStream & rStrm,const Graphic & rGrf,sal_uInt16 nWidth,sal_uInt16 nHeight)859 void SwWW8WrGrf::WriteGrfForBullet(SvStream& rStrm,  const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
860 {
861 	if (rWrt.bWrtWW8)
862 	{
863 		WritePICBulletFHeader(rStrm,rGrf, 0x64,nWidth,nHeight);
864 		SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
865 		aInlineEscher.WriteGrfBullet(rGrf);
866 		aInlineEscher.WritePictures();
867 	}
868 	else
869 	{
870 		/* bool bSwapped = rGrf.IsSwapOut() ? true : false; */
871 
872 		GDIMetaFile aMeta;
873 		switch (rGrf.GetType())
874 		{
875 			case GRAPHIC_BITMAP:        // Bitmap -> in Metafile abspielen
876 			{
877 				VirtualDevice aVirt;
878 				aMeta.Record(&aVirt);
879 				aVirt.DrawBitmap( Point( 0,0 ), rGrf.GetBitmap() );
880 				aMeta.Stop();
881 				aMeta.WindStart();
882 				aMeta.SetPrefMapMode( rGrf.GetPrefMapMode());
883 				aMeta.SetPrefSize( rGrf.GetPrefSize());
884 			}
885 			break;
886 			case GRAPHIC_GDIMETAFILE :      // GDI ( =SV ) Metafile
887 				aMeta = rGrf.GetGDIMetaFile();
888 			break;
889 			default:
890 				return;
891 		}
892 		WritePICBulletFHeader(rStrm, rGrf, 8, nWidth, nHeight);
893 		WriteWindowMetafileBits(rStrm, aMeta);
894 	}
895 }
896 
WriteGraphicNode(SvStream & rStrm,const GraphicDetails & rItem)897 void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem)
898 {
899     sal_uInt16 nWidth = rItem.mnWid;
900     sal_uInt16 nHeight = rItem.mnHei;
901     sal_uInt32 nPos = rStrm.Tell();         // Grafik-Anfang merken
902 
903     const sw::Frame &rFly = rItem.maFly;
904     switch (rFly.GetWriterType())
905     {
906         case sw::Frame::eGraphic:
907         {
908             const SwNode *pNode = rItem.maFly.GetContent();
909             const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : 0;
910             ASSERT(pNd, "Impossible");
911             if (pNd)
912                 WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
913         }
914         break;
915         //For i120928,add branch to export graphic of bullet
916         case sw::Frame::eBulletGrf:
917         {
918 		if (rItem.maFly.HasGraphic())
919 		{
920 			const Graphic& rGrf = rItem.maFly.GetGraphic();
921 			WriteGrfForBullet(rStrm, rGrf, nWidth, nHeight);
922 		}
923         }
924         break;
925 
926         case sw::Frame::eOle:
927         {
928 #ifdef OLE_PREVIEW_AS_EMF
929             const SwNode *pNode = rItem.maFly.GetContent();
930             const SwOLENode *pNd = pNode ? pNode->GetOLENode() : 0;
931             ASSERT(pNd, "Impossible");
932             if (!rWrt.bWrtWW8)
933             {
934                 SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
935                 ASSERT( pOleNd, " Wer hat den OleNode versteckt ?" );
936                 SwOLEObj&                   rSObj= pOleNd->GetOLEObj();
937                 uno::Reference < embed::XEmbeddedObject > rObj(  rSObj.GetOleRef() );
938 
939                 comphelper::EmbeddedObjectContainer aCnt( pOleNd->GetDoc()->GetDocStorage() );
940 
941                 SvStream* pGraphicStream = ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( rObj ) );
942                 DBG_ASSERT( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
943                 if ( pGraphicStream && !pGraphicStream->GetError() )
944                 {
945                     Graphic aGr;
946                     GraphicFilter* pGF = GraphicFilter::GetGraphicFilter();
947                     if( pGF->ImportGraphic( aGr, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
948                     {
949                         //TODO/LATER: do we really want to use GDIMetafile?!
950                         GDIMetaFile aMtf;
951                         aMtf = aGr.GetGDIMetaFile();
952                         aMtf.WindStart();
953                         aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
954                             Size(2880, 2880));
955                         WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
956                             pNd->GetpSwAttrSet());
957                         WriteWindowMetafileBits(rStrm, aMtf);
958                     }
959                 }
960                 else
961                     delete pGraphicStream;
962             }
963             else
964             {
965                 //Convert this ole2 preview in ww8+ to an EMF for better unicode
966                 //support (note that at this moment this breaks StarSymbol
967                 //using graphics because I need to embed starsymbol in exported
968                 //documents.
969                 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
970                     pNd->GetpSwAttrSet());
971                 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
972                 aInlineEscher.WriteOLEFlyFrame(rFly.GetFrmFmt(), 0x401);
973                 aInlineEscher.WritePictures();
974             }
975 #else
976             // cast away const
977             SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
978             ASSERT( pOleNd, " Wer hat den OleNode versteckt ?" );
979             SwOLEObj&                   rSObj= pOleNd->GetOLEObj();
980 
981             // TODO/LATER: do we need to load object?
982             Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
983 
984             //TODO/LATER: do we really want to use GDIMetafile?!
985             GDIMetaFile aMtf;
986             if ( pGr )
987                 aMtf = pGr->GetGDIMetaFile();
988 
989             Size aS(aMtf.GetPrefSize());
990             aMtf.WindStart();
991             aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
992                 Size(2880, 2880));
993 
994             WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
995                 pNd->GetpSwAttrSet());
996             WriteWindowMetafileBits(rStrm, aMtf);
997             delete pGr;
998 #endif
999         }
1000         break;
1001         case sw::Frame::eDrawing:
1002         case sw::Frame::eTxtBox:
1003         case sw::Frame::eFormControl:
1004             ASSERT(rWrt.bWrtWW8,
1005                 "You can't try and export these in WW8 format, a filter bug");
1006             /*
1007             #i3958# We only export an empty dummy picture frame here, this is
1008             what word does the escher export should contain an anchored to
1009             character element which is drawn over this dummy and the whole
1010             shebang surrounded with a SHAPE field. This isn't *my* hack :-),
1011             its what word does.
1012             */
1013             if (rWrt.bWrtWW8)
1014             {
1015                 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
1016                 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
1017                 aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrmFmt(), 0x401);
1018             }
1019             break;
1020         default:
1021             ASSERT(sal_False,
1022            "Some inline export not implemented, remind cmc before we ship :-)");
1023             break;
1024     }
1025 
1026     sal_uInt32 nPos2 = rStrm.Tell();                    // Ende merken
1027     rStrm.Seek( nPos );
1028     SVBT32 nLen;
1029     UInt32ToSVBT32( nPos2 - nPos, nLen );             // Grafik-Laenge ausrechnen
1030     rStrm.Write( nLen, 4 );                         // im Header einpatchen
1031     rStrm.Seek( nPos2 );                            // Pos wiederherstellen
1032 }
1033 
1034 // SwWW8WrGrf::Write() wird nach dem Text gerufen. Es schreibt die alle
1035 // Grafiken raus und merkt sich die File-Positionen der Grafiken, damit
1036 // beim Schreiben der Attribute die Positionen in die PicLocFc-Sprms
1037 // eingepatcht werden koennen.
1038 // Das Suchen in den Attributen nach dem Magic sal_uLong und das Patchen
1039 // passiert beim Schreiben der Attribute. Die SwWW8WrGrf-Klasse liefert
1040 // hierfuer nur mit GetFPos() sequentiell die Positionen.
Write()1041 void SwWW8WrGrf::Write()
1042 {
1043     SvStream& rStrm = *rWrt.pDataStrm;
1044     myiter aEnd = maDetails.end();
1045     for (myiter aIter = maDetails.begin(); aIter != aEnd; ++aIter)
1046     {
1047         sal_uInt32 nPos = rStrm.Tell();                 // auf 4 Bytes alignen
1048         if( nPos & 0x3 )
1049             SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
1050 
1051         bool bDuplicated = false;
1052         for (myiter aIter2 = maDetails.begin(); aIter2 != aIter; ++aIter2)
1053         {
1054             if (*aIter2 == *aIter)
1055             {
1056                 aIter->mnPos = aIter2->mnPos;
1057                 bDuplicated = true;
1058                 break;
1059             }
1060         }
1061 
1062         if (!bDuplicated)
1063         {
1064             aIter->mnPos = rStrm.Tell();
1065             WriteGraphicNode(rStrm, *aIter);
1066         }
1067     }
1068 }
1069 
1070 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
1071