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 <svtools/filter.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> // SvxLRSpaceItem
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> // class SwFlyFrmFmt
47 : #include <grfatr.hxx> // class SwCropGrf
48 : #include <ndole.hxx>
49 : #include <ndtxt.hxx>
50 : #include <fmtfsize.hxx>
51 : #include <fmtornt.hxx>
52 :
53 : #include <writerfilter/doctok/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 :
63 : #include "docsh.hxx"
64 : #include <cstdio>
65 :
66 : #if OSL_DEBUG_LEVEL > 1
67 : #include <stdio.h>
68 : #endif
69 :
70 : using namespace ::com::sun::star;
71 : using namespace nsFieldFlags;
72 :
73 : // ToDo:
74 : // 5. Die MapModes, die Win nicht kann, umrechnen
75 :
76 : // OutGrf() wird fuer jeden GrafNode im Doc gerufen. Es wird ein PicLocFc-Sprm
77 : // eingefuegt, der statt Adresse ein Magic sal_uLong enthaelt. Ausserdem wird
78 : // in der Graf-Klasse der GrfNode-Ptr gemerkt ( fuers spaetere Ausgeben der
79 : // Grafiken und Patchen der PicLocFc-Attribute )
80 :
81 0 : void WW8Export::OutputGrfNode( const SwGrfNode& /*rNode*/ )
82 : {
83 : OSL_TRACE("WW8Export::OutputGrfNode( const SwGrfNode& )" );
84 : OSL_ENSURE( mpParentFrame, "frame not set!" );
85 0 : if ( mpParentFrame )
86 : {
87 0 : OutGrf( *mpParentFrame );
88 0 : pFib->fHasPic = 1;
89 : }
90 0 : }
91 :
92 0 : bool WW8Export::TestOleNeedsGraphic(const SwAttrSet& rSet,
93 : SvStorageRef xOleStg, SvStorageRef xObjStg, String &rStorageName,
94 : SwOLENode *pOLENd)
95 : {
96 0 : bool bGraphicNeeded = false;
97 0 : SfxItemIter aIter( rSet );
98 0 : const SfxPoolItem* pItem = aIter.GetCurItem();
99 :
100 0 : do {
101 0 : switch (pItem->Which())
102 : {
103 : /*
104 : For an inline object these properties are irrelevent because they
105 : will be the same as the defaults that msword applies in their
106 : absence, so if that is all that there is for these inline objects
107 : then if there turns out to be enough information in the object
108 : itself to regenerate the correct size and preview of the object
109 : then we will not need to provide an additional graphics preview in
110 : the data stream, which can save a lot of disk space.
111 : */
112 : case RES_FRM_SIZE:
113 : case RES_CNTNT:
114 : case RES_VERT_ORIENT:
115 : case RES_ANCHOR:
116 0 : break;
117 : default:
118 0 : bGraphicNeeded = true;
119 : }
120 0 : } while( !bGraphicNeeded && !aIter.IsAtEnd() &&
121 : 0 != ( pItem = aIter.NextItem() ) );
122 :
123 : /*
124 : Now we must see if the object contains a preview itself which is equal to
125 : the preview that we are currently using. If the graphics are equal then we
126 : dont need to store another preview
127 : */
128 0 : GDIMetaFile aWMF;
129 0 : long nX=0,nY=0;
130 0 : if (!bGraphicNeeded && SwWW8ImplReader::ImportOleWMF(xOleStg,aWMF,nX,nY))
131 : {
132 : // bGraphicNeeded set to true is right / fixes #i51670#.
133 0 : bGraphicNeeded = true;
134 0 : Point aTmpPoint;
135 0 : Rectangle aRect( aTmpPoint, Size( nX, nY ) );
136 0 : Graphic aGraph(aWMF);
137 :
138 0 : ErrCode nErr = ERRCODE_NONE;
139 0 : Rectangle aVisArea;
140 0 : sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
141 0 : if ( pOLENd )
142 0 : nAspect = pOLENd->GetAspect();
143 : SdrOle2Obj *pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
144 0 : rStorageName,xObjStg,pDoc->GetDocStorage(),aGraph,aRect,aVisArea,0,nErr,0,nAspect);
145 :
146 0 : if (pRet)
147 : {
148 0 : uno::Reference< embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
149 0 : if ( xObj.is() )
150 : {
151 0 : SvStream* pGraphicStream = NULL;
152 0 : comphelper::EmbeddedObjectContainer aCnt( pDoc->GetDocStorage() );
153 : try
154 : {
155 : uno::Reference< embed::XEmbedPersist > xPersist(
156 : xObj,
157 0 : uno::UNO_QUERY_THROW );
158 :
159 : // it makes no sence to search the object in the container by reference since the object was created
160 : // outside of the container and was not inserted there, only the name makes sence
161 : pGraphicStream =
162 0 : ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) );
163 : }
164 0 : catch( const uno::Exception& )
165 : {}
166 :
167 : OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
168 0 : if ( pGraphicStream && !pGraphicStream->GetError() )
169 : {
170 0 : Graphic aGr1;
171 0 : GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
172 0 : if( rGF.ImportGraphic( aGr1, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
173 : {
174 0 : Graphic aGr2;
175 0 : delete pGraphicStream;
176 : pGraphicStream =
177 0 : ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
178 0 : if( rGF.ImportGraphic( aGr2, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
179 : {
180 0 : if ( aGr1 == aGr2 )
181 0 : bGraphicNeeded = false;
182 0 : }
183 0 : }
184 : }
185 : else
186 0 : delete pGraphicStream;
187 : }
188 :
189 0 : delete pRet;
190 0 : }
191 : }
192 : else
193 0 : bGraphicNeeded = true;
194 0 : return bGraphicNeeded;
195 : }
196 :
197 0 : void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
198 : {
199 : OSL_TRACE("WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
200 : sal_uInt8 *pSpecOLE;
201 : sal_uInt8 *pDataAdr;
202 : short nSize;
203 : static sal_uInt8 aSpecOLE_WW8[] = {
204 : 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
205 : 0x0a, 0x08, 1, // sprmCFOLE2
206 : 0x56, 0x08, 1 // sprmCFObj
207 : };
208 : static sal_uInt8 aSpecOLE_WW6[] = {
209 : 68, 4, 0, 0, 0, 0, // sprmCPicLocation (len is 4)
210 : 75, 1, // sprmCFOLE2
211 : 118, 1 // sprmCFObj
212 : };
213 :
214 0 : if ( bWrtWW8 )
215 : {
216 0 : pSpecOLE = aSpecOLE_WW8;
217 0 : nSize = sizeof( aSpecOLE_WW8 );
218 : }
219 : else
220 : {
221 0 : pSpecOLE = aSpecOLE_WW6;
222 0 : nSize = sizeof( aSpecOLE_WW6 );
223 : }
224 0 : pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
225 :
226 0 : SvStorageRef xObjStg = GetWriter().GetStorage().OpenSotStorage(
227 : rtl::OUString(SL::aObjectPool), STREAM_READWRITE |
228 0 : STREAM_SHARE_DENYALL );
229 :
230 0 : if( xObjStg.Is() )
231 : {
232 0 : uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
233 0 : if( xObj.is() )
234 : {
235 0 : const embed::XEmbeddedObject *pObj = xObj.get();
236 0 : WW8OleMap& rPointerToObjId = GetOLEMap();
237 : //Don't want to use pointer ids, as is traditional, because we need
238 : //to put this into a 32bit value, and on 64bit the bottom bits
239 : //might collide and two unrelated ole objects end up considered the
240 : //same. Don't want to simply start at 0 which is a special value
241 0 : sal_Int32 nPictureId = SAL_MAX_INT32 - rPointerToObjId.size();
242 0 : WW8OleMap::value_type entry = std::make_pair(pObj, nPictureId);
243 0 : std::pair<WW8OleMap::iterator, bool> aRes = rPointerToObjId.insert(entry);
244 0 : bool bIsNotDuplicate = aRes.second; //.second is false when element already existed
245 0 : nPictureId = aRes.first->second;
246 0 : Set_UInt32(pDataAdr, nPictureId);
247 0 : String sStorageName = rtl::OUString('_');
248 0 : sStorageName += String::CreateFromInt32( nPictureId );
249 : SvStorageRef xOleStg = xObjStg->OpenSotStorage( sStorageName,
250 0 : STREAM_READWRITE| STREAM_SHARE_DENYALL );
251 0 : if( xOleStg.Is() )
252 : {
253 : /*
254 : If this object storage has been written already don't
255 : waste time rewriting it
256 : */
257 0 : if (bIsNotDuplicate)
258 : {
259 0 : sal_Int64 nAspect = rOLENode.GetAspect();
260 0 : svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
261 0 : GetOLEExp().ExportOLEObject( aObjRef, *xOleStg );
262 0 : if ( nAspect == embed::Aspects::MSOLE_ICON )
263 : {
264 0 : ::rtl::OUString aObjInfo( "\3ObjInfo" );
265 0 : if ( !xOleStg->IsStream( aObjInfo ) )
266 : {
267 0 : const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
268 0 : SvStorageStreamRef rObjInfoStream = xOleStg->OpenSotStream( aObjInfo );
269 0 : if ( rObjInfoStream.Is() && !rObjInfoStream->GetError() )
270 : {
271 0 : rObjInfoStream->Write( pObjInfoData, sizeof( pObjInfoData ) );
272 0 : xOleStg->Commit();
273 0 : }
274 0 : }
275 0 : }
276 : }
277 :
278 : // write as embedded field - the other things will be done
279 : // in the escher export
280 0 : String sServer(FieldString(ww::eEMBED));
281 0 : sServer += xOleStg->GetUserName();
282 0 : sServer += ' ';
283 :
284 : OutputField(0, ww::eEMBED, sServer, WRITEFIELD_START |
285 0 : WRITEFIELD_CMD_START | WRITEFIELD_CMD_END);
286 :
287 0 : pChpPlc->AppendFkpEntry( Strm().Tell(),
288 0 : nSize, pSpecOLE );
289 :
290 0 : bool bEndCR = true;
291 : /*
292 : In the word filter we only need a preview image for
293 : floating images, and then only (the usual case) if the
294 : object doesn't contain enough information to reconstruct
295 : what we need.
296 :
297 : We don't need a graphic for inline objects, so we don't
298 : even need the overhead of a graphic in that case.
299 : */
300 0 : bool bGraphicNeeded = false;
301 :
302 0 : if (mpParentFrame)
303 : {
304 0 : bGraphicNeeded = true;
305 :
306 0 : if (mpParentFrame->IsInline())
307 : {
308 : const SwAttrSet& rSet =
309 0 : mpParentFrame->GetFrmFmt().GetAttrSet();
310 0 : bEndCR = false;
311 : bGraphicNeeded = TestOleNeedsGraphic(rSet,
312 0 : xOleStg, xObjStg, sStorageName, const_cast<SwOLENode*>(&rOLENode));
313 : }
314 : }
315 :
316 0 : if (!bGraphicNeeded)
317 0 : WriteChar(0x1);
318 : else
319 : {
320 : /*
321 : ##897##
322 : We need to insert the graphic representation of
323 : this object for the inline case, otherwise word
324 : has no place to find the dimensions of the ole
325 : object, and will not be able to draw it
326 : */
327 0 : OutGrf(*mpParentFrame);
328 : }
329 :
330 : OutputField(0, ww::eEMBED, aEmptyStr,
331 0 : WRITEFIELD_END | WRITEFIELD_CLOSE);
332 :
333 0 : if (bEndCR) //No newline in inline case
334 0 : WriteCR();
335 0 : }
336 0 : }
337 0 : }
338 0 : }
339 :
340 0 : void WW8Export::OutputLinkedOLE( const rtl::OUString& rOleId )
341 : {
342 0 : uno::Reference< embed::XStorage > xDocStg = pDoc->GetDocStorage();
343 0 : uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( "OLELinks", embed::ElementModes::READ );
344 0 : SotStorageRef xObjSrc = SotStorage::OpenOLEStorage( xOleStg, rOleId, STREAM_READ );
345 :
346 0 : SotStorageRef xObjStg = GetWriter().GetStorage().OpenSotStorage(
347 : rtl::OUString(SL::aObjectPool), STREAM_READWRITE |
348 0 : STREAM_SHARE_DENYALL );
349 :
350 0 : if( xObjStg.Is() && xObjSrc.Is() )
351 : {
352 : SotStorageRef xOleDst = xObjStg->OpenSotStorage( rOleId,
353 0 : STREAM_READWRITE | STREAM_SHARE_DENYALL );
354 0 : if ( xOleDst.Is() )
355 0 : xObjSrc->CopyTo( xOleDst );
356 :
357 0 : if ( !xOleDst->GetError( ) )
358 : {
359 0 : xOleDst->Commit();
360 :
361 : // Ouput the cPicLocation attribute
362 0 : ww::bytes* pBuf = new ww::bytes();
363 0 : GetWriter().InsUInt16( *pBuf, NS_sprm::LN_CPicLocation );
364 0 : GetWriter().InsUInt32( *pBuf, rOleId.copy( 1 ).toInt32() );
365 :
366 0 : GetWriter().InsUInt16( *pBuf, NS_sprm::LN_CFOle2 );
367 0 : pBuf->push_back( 1 );
368 :
369 0 : GetWriter().InsUInt16( *pBuf, NS_sprm::LN_CFSpec );
370 0 : pBuf->push_back( 1 );
371 :
372 0 : GetWriter().InsUInt16( *pBuf, NS_sprm::LN_CFObj );
373 0 : pBuf->push_back( 1 );
374 :
375 0 : pChpPlc->AppendFkpEntry( Strm().Tell(), pBuf->size(), pBuf->data() );
376 0 : delete pBuf;
377 0 : }
378 0 : }
379 0 : }
380 :
381 0 : void WW8Export::OutGrf(const sw::Frame &rFrame)
382 : {
383 : // GrfNode fuer spaeteres rausschreiben der Grafik merken
384 0 : pGrf->Insert(rFrame);
385 :
386 0 : pChpPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
387 0 : pO->clear();
388 :
389 : // #i29408#
390 : // linked, as-character anchored graphics have to be exported as fields.
391 0 : const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
392 0 : ? rFrame.GetContent()->GetGrfNode() : 0;
393 0 : if ( pGrfNd && pGrfNd->IsLinkedFile() )
394 : {
395 0 : String sStr( FieldString(ww::eINCLUDEPICTURE) );
396 0 : sStr.AppendAscii(" \"");
397 : {
398 0 : if ( pGrfNd )
399 : {
400 0 : String aFileURL;
401 0 : pGrfNd->GetFileFilterNms( &aFileURL, 0 );
402 0 : sStr += aFileURL;
403 : }
404 : }
405 0 : sStr.AppendAscii("\" \\d");
406 :
407 : OutputField( 0, ww::eINCLUDEPICTURE, sStr,
408 0 : WRITEFIELD_START | WRITEFIELD_CMD_START | WRITEFIELD_CMD_END );
409 : }
410 :
411 0 : WriteChar( (char)1 ); // Grafik-Sonderzeichen in Haupttext einfuegen
412 :
413 : sal_uInt8 aArr[ 18 ];
414 0 : sal_uInt8* pArr = aArr;
415 :
416 0 : const SwFrmFmt &rFlyFmt = rFrame.GetFrmFmt();
417 0 : const RndStdIds eAn = rFlyFmt.GetAttrSet().GetAnchor(false).GetAnchorId();
418 0 : if (eAn == FLY_AS_CHAR)
419 : {
420 0 : sal_Int16 eVert = rFlyFmt.GetVertOrient().GetVertOrient();
421 0 : if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
422 : {
423 0 : bool bVert = false;
424 : //The default for word in vertical text mode is to center,
425 : //otherwise a sub/super script hack is employed
426 0 : if (pOutFmtNode && pOutFmtNode->ISA(SwCntntNode) )
427 : {
428 0 : const SwTxtNode* pTxtNd = (const SwTxtNode*)pOutFmtNode;
429 0 : SwPosition aPos(*pTxtNd);
430 0 : bVert = pDoc->IsInVerticalText(aPos);
431 : }
432 0 : if (!bVert)
433 : {
434 0 : SwTwips nHeight = rFlyFmt.GetFrmSize().GetHeight();
435 0 : nHeight/=20; //nHeight was in twips, want it in half points, but
436 : //then half of total height.
437 : long nFontHeight = ((const SvxFontHeightItem&)
438 0 : GetItem(RES_CHRATR_FONTSIZE)).GetHeight();
439 0 : nHeight-=nFontHeight/20;
440 :
441 0 : if (bWrtWW8)
442 0 : Set_UInt16( pArr, NS_sprm::LN_CHpsPos );
443 : else
444 0 : Set_UInt8( pArr, 101 );
445 0 : Set_UInt16( pArr, -((sal_Int16)nHeight));
446 : }
447 : }
448 : }
449 :
450 : // sprmCFSpec
451 0 : if( bWrtWW8 )
452 0 : Set_UInt16( pArr, 0x855 );
453 : else
454 0 : Set_UInt8( pArr, 117 );
455 0 : Set_UInt8( pArr, 1 );
456 :
457 : // sprmCPicLocation
458 0 : if( bWrtWW8 )
459 0 : Set_UInt16( pArr, NS_sprm::LN_CPicLocation );
460 : else
461 : {
462 0 : Set_UInt8( pArr, 68 );
463 0 : Set_UInt8( pArr, 4 );
464 : }
465 0 : Set_UInt32( pArr, GRF_MAGIC_321 );
466 :
467 : // Magic variieren, damit verschiedene Grafik-Attribute nicht
468 : // gemerged werden
469 : static sal_uInt8 nAttrMagicIdx = 0;
470 0 : --pArr;
471 0 : Set_UInt8( pArr, nAttrMagicIdx++ );
472 0 : pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
473 :
474 : // #i75464#
475 : // Check, if graphic isn't exported as-character anchored.
476 : // Otherwise, an additional paragraph is exported for a graphic, which is
477 : // forced to be treated as inline, because it's anchored inside another frame.
478 0 : if ( !rFrame.IsInline() &&
479 0 : ( ((eAn == FLY_AT_PARA) && ( bWrtWW8 || !IsInTable() )) ||
480 : (eAn == FLY_AT_PAGE)) )
481 : {
482 0 : WriteChar( (char)0x0d ); // umgebenden Rahmen mit CR abschliessen
483 :
484 : static sal_uInt8 nSty[2] = { 0, 0 };
485 0 : pO->insert( pO->end(), nSty, nSty+2 ); // Style #0
486 0 : bool bOldGrf = bOutGrf;
487 0 : bOutGrf = true;
488 :
489 0 : OutputFormat( rFrame.GetFrmFmt(), false, false, true ); // Fly-Attrs
490 :
491 0 : bOutGrf = bOldGrf;
492 0 : pPapPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
493 0 : pO->clear();
494 : }
495 : // #i29408#
496 : // linked, as-character anchored graphics have to be exported as fields.
497 0 : else if ( pGrfNd && pGrfNd->IsLinkedFile() )
498 : {
499 0 : OutputField( 0, ww::eINCLUDEPICTURE, String(), WRITEFIELD_CLOSE );
500 : }
501 0 : }
502 :
503 0 : GraphicDetails& GraphicDetails::operator=(const GraphicDetails &rOther)
504 : {
505 0 : maFly = rOther.maFly;
506 0 : mnPos = rOther.mnPos;
507 0 : mnWid = rOther.mnWid;
508 0 : mnHei = rOther.mnHei;
509 0 : return *this;
510 : }
511 :
512 0 : void SwWW8WrGrf::Insert(const sw::Frame &rFly)
513 : {
514 0 : const Size aSize( rFly.GetLayoutSize() );
515 0 : const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
516 0 : const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
517 0 : maDetails.push_back(GraphicDetails(rFly, nWidth, nHeight));
518 0 : }
519 :
520 0 : void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const sw::Frame &rFly,
521 : sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
522 : {
523 0 : sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
524 0 : sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
525 :
526 : // Crop-AttributInhalt in Header schreiben ( falls vorhanden )
527 : const SfxPoolItem* pItem;
528 0 : if (pAttrSet && (SFX_ITEM_ON
529 0 : == pAttrSet->GetItemState(RES_GRFATR_CROPGRF, false, &pItem)))
530 : {
531 0 : const SwCropGrf& rCr = *(SwCropGrf*)pItem;
532 0 : nCropL = (sal_Int16)rCr.GetLeft();
533 0 : nCropR = (sal_Int16)rCr.GetRight();
534 0 : nCropT = (sal_Int16)rCr.GetTop();
535 0 : nCropB = (sal_Int16)rCr.GetBottom();
536 0 : nXSizeAdd = nXSizeAdd - (sal_Int16)( rCr.GetLeft() + rCr.GetRight() );
537 0 : nYSizeAdd = nYSizeAdd - (sal_Int16)( rCr.GetTop() + rCr.GetBottom() );
538 : }
539 :
540 0 : Size aGrTwipSz(rFly.GetSize());
541 0 : bool bWrtWW8 = rWrt.bWrtWW8;
542 0 : sal_uInt16 nHdrLen = bWrtWW8 ? 0x44 : 0x3A;
543 :
544 0 : sal_uInt8 aArr[ 0x44 ] = { 0 };
545 :
546 0 : sal_uInt8* pArr = aArr + 0x2E; //Do borders first
547 :
548 0 : const SwAttrSet& rAttrSet = rFly.GetFrmFmt().GetAttrSet();
549 0 : if (SFX_ITEM_ON == rAttrSet.GetItemState(RES_BOX, false, &pItem))
550 : {
551 0 : const SvxBoxItem* pBox = (const SvxBoxItem*)pItem;
552 0 : if( pBox )
553 : {
554 0 : bool bShadow = false; // Shadow ?
555 : const SvxShadowItem* pSI =
556 0 : sw::util::HasItem<SvxShadowItem>(rAttrSet, RES_SHADOW);
557 0 : if (pSI)
558 : {
559 0 : bShadow = (pSI->GetLocation() != SVX_SHADOW_NONE) &&
560 0 : (pSI->GetWidth() != 0);
561 : }
562 :
563 : sal_uInt8 aLnArr[4] = { BOX_LINE_TOP, BOX_LINE_LEFT,
564 0 : BOX_LINE_BOTTOM, BOX_LINE_RIGHT };
565 0 : for( sal_uInt8 i = 0; i < 4; ++i )
566 : {
567 0 : const ::editeng::SvxBorderLine* pLn = pBox->GetLine( aLnArr[ i ] );
568 0 : WW8_BRC aBrc;
569 0 : if (pLn)
570 : {
571 : aBrc = rWrt.TranslateBorderLine( *pLn,
572 0 : pBox->GetDistance( aLnArr[ i ] ), bShadow );
573 : }
574 :
575 : //use importer logic to determine how large the exported
576 : //border will really be in word and adjust accordingly
577 : short nSpacing;
578 0 : short nThick = aBrc.DetermineBorderProperties(!bWrtWW8,
579 0 : &nSpacing);
580 0 : switch (aLnArr[ i ])
581 : {
582 : case BOX_LINE_TOP:
583 : case BOX_LINE_BOTTOM:
584 0 : nHeight -= bShadow ? nThick*2 : nThick;
585 0 : nHeight = nHeight - nSpacing;
586 0 : break;
587 : case BOX_LINE_LEFT:
588 : case BOX_LINE_RIGHT:
589 : default:
590 0 : nWidth -= bShadow ? nThick*2 : nThick;
591 0 : nWidth = nWidth - nSpacing;
592 0 : break;
593 : }
594 0 : memcpy( pArr, &aBrc.aBits1, 2);
595 0 : pArr+=2;
596 :
597 0 : if( bWrtWW8 )
598 : {
599 0 : memcpy( pArr, &aBrc.aBits2, 2);
600 0 : pArr+=2;
601 : }
602 : }
603 : }
604 : }
605 :
606 0 : pArr = aArr + 4; //skip lcb
607 0 : Set_UInt16( pArr, nHdrLen ); // set cbHeader
608 :
609 0 : Set_UInt16( pArr, mm ); // set mm
610 :
611 : /*
612 : Just in case our original size is too big to fit inside a ushort we can
613 : substitute the final size and loose on retaining the scaling factor but
614 : still keep the correct display size anyway.
615 : */
616 0 : if ( (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX)
617 0 : || (aGrTwipSz.Width() < 0 ) || (aGrTwipSz.Height() < 0) )
618 : {
619 0 : aGrTwipSz.Width() = nWidth;
620 0 : aGrTwipSz.Height() = nHeight;
621 : }
622 : using namespace sw::types;
623 : // set xExt & yExt
624 0 : Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width() * 254L / 144));
625 0 : Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height() * 254L / 144));
626 0 : pArr += 16;
627 : // skip hMF & rcWinMF
628 : // set dxaGoal & dyaGoal
629 0 : Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
630 0 : Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
631 :
632 0 : if( aGrTwipSz.Width() + nXSizeAdd ) // set mx
633 : {
634 0 : double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
635 0 : Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
636 : }
637 : else
638 0 : pArr += 2;
639 :
640 0 : if( aGrTwipSz.Height() + nYSizeAdd ) // set my
641 : {
642 0 : double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
643 0 : Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
644 : }
645 : else
646 0 : pArr += 2;
647 :
648 0 : Set_UInt16( pArr, nCropL ); // set dxaCropLeft
649 0 : Set_UInt16( pArr, nCropT ); // set dyaCropTop
650 0 : Set_UInt16( pArr, nCropR ); // set dxaCropRight
651 0 : Set_UInt16( pArr, nCropB ); // set dyaCropBottom
652 :
653 0 : rStrm.Write( aArr, nHdrLen );
654 0 : }
655 :
656 0 : void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd,
657 : const sw::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
658 : {
659 0 : if (rGrfNd.IsLinkedFile()) // Linked File
660 : {
661 0 : String aFileN;
662 0 : rGrfNd.GetFileFilterNms( &aFileN, 0 );
663 :
664 0 : sal_uInt16 mm = 94; // 94 = BMP, GIF
665 :
666 : WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
667 0 : rGrfNd.GetpSwAttrSet());
668 0 : rStrm << (sal_uInt8)aFileN.Len(); // Pascal-String schreiben
669 : SwWW8Writer::WriteString8(rStrm, aFileN, false,
670 0 : RTL_TEXTENCODING_MS_1252);
671 : }
672 : else // Embedded File oder DDE oder so was
673 : {
674 0 : if (rWrt.bWrtWW8)
675 : {
676 : WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
677 0 : rGrfNd.GetpSwAttrSet());
678 0 : SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
679 0 : aInlineEscher.WriteGrfFlyFrame(rFly.GetFrmFmt(), 0x401);
680 0 : aInlineEscher.WritePictures();
681 : }
682 : else
683 : {
684 0 : Graphic& rGrf = const_cast<Graphic&>(rGrfNd.GetGrf());
685 0 : bool bSwapped = rGrf.IsSwapOut() ? true : false;
686 : // immer ueber den Node einswappen!
687 0 : const_cast<SwGrfNode&>(rGrfNd).SwapIn();
688 :
689 0 : GDIMetaFile aMeta;
690 0 : switch (rGrf.GetType())
691 : {
692 : case GRAPHIC_BITMAP: // Bitmap -> in Metafile abspielen
693 : {
694 0 : VirtualDevice aVirt;
695 0 : aMeta.Record(&aVirt);
696 0 : aVirt.DrawBitmap( Point( 0,0 ), rGrf.GetBitmap() );
697 0 : aMeta.Stop();
698 0 : aMeta.WindStart();
699 0 : aMeta.SetPrefMapMode( rGrf.GetPrefMapMode());
700 0 : aMeta.SetPrefSize( rGrf.GetPrefSize());
701 : }
702 0 : break;
703 : case GRAPHIC_GDIMETAFILE : // GDI ( =SV ) Metafile
704 0 : aMeta = rGrf.GetGDIMetaFile();
705 0 : break;
706 : default:
707 0 : return;
708 : }
709 :
710 : WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
711 0 : rGrfNd.GetpSwAttrSet());
712 0 : WriteWindowMetafileBits(rStrm, aMeta);
713 :
714 0 : if (bSwapped)
715 0 : rGrf.SwapOut();
716 : }
717 : }
718 : }
719 :
720 0 : void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem)
721 : {
722 0 : sal_uInt16 nWidth = rItem.mnWid;
723 0 : sal_uInt16 nHeight = rItem.mnHei;
724 0 : sal_uInt32 nPos = rStrm.Tell(); // Grafik-Anfang merken
725 :
726 0 : const sw::Frame &rFly = rItem.maFly;
727 0 : switch (rFly.GetWriterType())
728 : {
729 : case sw::Frame::eGraphic:
730 : {
731 0 : const SwNode *pNode = rItem.maFly.GetContent();
732 0 : const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : 0;
733 : OSL_ENSURE(pNd, "Impossible");
734 0 : if (pNd)
735 0 : WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
736 : }
737 0 : break;
738 : case sw::Frame::eOle:
739 : {
740 : #ifdef OLE_PREVIEW_AS_EMF
741 0 : const SwNode *pNode = rItem.maFly.GetContent();
742 0 : const SwOLENode *pNd = pNode ? pNode->GetOLENode() : 0;
743 : OSL_ENSURE(pNd, "Impossible");
744 0 : if (!rWrt.bWrtWW8)
745 : {
746 0 : SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
747 : OSL_ENSURE( pOleNd, " Wer hat den OleNode versteckt ?" );
748 0 : SwOLEObj& rSObj= pOleNd->GetOLEObj();
749 0 : uno::Reference < embed::XEmbeddedObject > rObj( rSObj.GetOleRef() );
750 :
751 0 : comphelper::EmbeddedObjectContainer aCnt( pOleNd->GetDoc()->GetDocStorage() );
752 :
753 0 : SvStream* pGraphicStream = ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( rObj ) );
754 : OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
755 0 : if ( pGraphicStream && !pGraphicStream->GetError() )
756 : {
757 0 : Graphic aGr;
758 0 : GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
759 0 : if( rGF.ImportGraphic( aGr, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
760 : {
761 : //TODO/LATER: do we really want to use GDIMetafile?!
762 0 : GDIMetaFile aMtf;
763 0 : aMtf = aGr.GetGDIMetaFile();
764 0 : aMtf.WindStart();
765 : aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
766 0 : Size(2880, 2880));
767 : WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
768 0 : pNd->GetpSwAttrSet());
769 0 : WriteWindowMetafileBits(rStrm, aMtf);
770 0 : }
771 : }
772 : else
773 0 : delete pGraphicStream;
774 : }
775 : else
776 : {
777 : //Convert this ole2 preview in ww8+ to an EMF for better unicode
778 : //support (note that at this moment this breaks StarSymbol
779 : //using graphics because I need to embed starsymbol in exported
780 : //documents.
781 : WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
782 0 : pNd->GetpSwAttrSet());
783 0 : SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
784 0 : aInlineEscher.WriteOLEFlyFrame(rFly.GetFrmFmt(), 0x401);
785 0 : aInlineEscher.WritePictures();
786 : }
787 : #else
788 : // cast away const
789 : SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
790 : OSL_ENSURE( pOleNd, " Wer hat den OleNode versteckt ?" );
791 : SwOLEObj& rSObj= pOleNd->GetOLEObj();
792 :
793 : // TODO/LATER: do we need to load object?
794 : Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
795 :
796 : //TODO/LATER: do we really want to use GDIMetafile?!
797 : GDIMetaFile aMtf;
798 : if ( pGr )
799 : aMtf = pGr->GetGDIMetaFile();
800 :
801 : Size aS(aMtf.GetPrefSize());
802 : aMtf.WindStart();
803 : aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
804 : Size(2880, 2880));
805 :
806 : WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
807 : pNd->GetpSwAttrSet());
808 : WriteWindowMetafileBits(rStrm, aMtf);
809 : delete pGr;
810 : #endif
811 : }
812 0 : break;
813 : case sw::Frame::eDrawing:
814 : case sw::Frame::eTxtBox:
815 : case sw::Frame::eFormControl:
816 : OSL_ENSURE(rWrt.bWrtWW8,
817 : "You can't try and export these in WW8 format, a filter bug");
818 : /*
819 : #i3958# We only export an empty dummy picture frame here, this is
820 : what word does the escher export should contain an anchored to
821 : character element which is drawn over this dummy and the whole
822 : shebang surrounded with a SHAPE field. This isn't *my* hack :-),
823 : its what word does.
824 : */
825 0 : if (rWrt.bWrtWW8)
826 : {
827 0 : WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
828 0 : SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
829 0 : aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrmFmt(), 0x401);
830 : }
831 0 : break;
832 : default:
833 : OSL_ENSURE(!this,
834 : "Some inline export not implemented, remind cmc before we ship :-)");
835 0 : break;
836 : }
837 :
838 0 : sal_uInt32 nPos2 = rStrm.Tell(); // Ende merken
839 0 : rStrm.Seek( nPos );
840 : SVBT32 nLen;
841 0 : UInt32ToSVBT32( nPos2 - nPos, nLen ); // Grafik-Laenge ausrechnen
842 0 : rStrm.Write( nLen, 4 ); // im Header einpatchen
843 0 : rStrm.Seek( nPos2 ); // Pos wiederherstellen
844 0 : }
845 :
846 : // SwWW8WrGrf::Write() wird nach dem Text gerufen. Es schreibt die alle
847 : // Grafiken raus und merkt sich die File-Positionen der Grafiken, damit
848 : // beim Schreiben der Attribute die Positionen in die PicLocFc-Sprms
849 : // eingepatcht werden koennen.
850 : // Das Suchen in den Attributen nach dem Magic sal_uLong und das Patchen
851 : // passiert beim Schreiben der Attribute. Die SwWW8WrGrf-Klasse liefert
852 : // hierfuer nur mit GetFPos() sequentiell die Positionen.
853 4 : void SwWW8WrGrf::Write()
854 : {
855 4 : SvStream& rStrm = *rWrt.pDataStrm;
856 4 : myiter aEnd = maDetails.end();
857 4 : for (myiter aIter = maDetails.begin(); aIter != aEnd; ++aIter)
858 : {
859 0 : sal_uInt32 nPos = rStrm.Tell(); // auf 4 Bytes alignen
860 0 : if( nPos & 0x3 )
861 0 : SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
862 :
863 0 : bool bDuplicated = false;
864 0 : for (myiter aIter2 = maDetails.begin(); aIter2 != aIter; ++aIter2)
865 : {
866 0 : if (*aIter2 == *aIter)
867 : {
868 0 : aIter->mnPos = aIter2->mnPos;
869 0 : bDuplicated = true;
870 0 : break;
871 : }
872 : }
873 :
874 0 : if (!bDuplicated)
875 : {
876 0 : aIter->mnPos = rStrm.Tell();
877 0 : WriteGraphicNode(rStrm, *aIter);
878 : }
879 : }
880 22 : }
881 :
882 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|