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