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