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