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