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