bump product version to 4.1.6.2
[LibreOffice.git] / sw / source / filter / ww8 / wrtww8gr.cxx
blob80a078bad58bdbca0f1f8f7fc0d4d3c4ad21f2e4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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"
30 #include <svtools/embedhlp.hxx>
32 #include <vcl/virdev.hxx>
33 #include <vcl/svapp.hxx>
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>
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>
54 #include <doctok/sprmids.hxx>
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"
67 #include "docsh.hxx"
68 #include <cstdio>
70 #if OSL_DEBUG_LEVEL > 1
71 #include <stdio.h>
72 #endif
74 using namespace ::com::sun::star;
75 using namespace nsFieldFlags;
77 // TODO:
78 // 5. convert the MapModes that Widows can't handle
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 )
85 void WW8Export::OutputGrfNode( const SwGrfNode& /*rNode*/ )
87 OSL_TRACE("WW8Export::OutputGrfNode( const SwGrfNode& )" );
88 OSL_ENSURE( mpParentFrame, "frame not set!" );
89 if ( mpParentFrame )
91 OutGrf( *mpParentFrame );
92 pFib->fHasPic = 1;
96 bool WW8Export::TestOleNeedsGraphic(const SwAttrSet& rSet,
97 SvStorageRef xOleStg, SvStorageRef xObjStg, String &rStorageName,
98 SwOLENode *pOLENd)
100 bool bGraphicNeeded = false;
101 SfxItemIter aIter( rSet );
102 const SfxPoolItem* pItem = aIter.GetCurItem();
104 do {
105 switch (pItem->Which())
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.
116 case RES_FRM_SIZE:
117 case RES_CNTNT:
118 case RES_VERT_ORIENT:
119 case RES_ANCHOR:
120 break;
121 default:
122 bGraphicNeeded = true;
124 } while( !bGraphicNeeded && !aIter.IsAtEnd() &&
125 0 != ( pItem = aIter.NextItem() ) );
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
132 GDIMetaFile aWMF;
133 long nX=0,nY=0;
134 if (!bGraphicNeeded && SwWW8ImplReader::ImportOleWMF(xOleStg,aWMF,nX,nY))
136 // bGraphicNeeded set to true is right / fixes #i51670#.
137 bGraphicNeeded = true;
138 Point aTmpPoint;
139 Rectangle aRect( aTmpPoint, Size( nX, nY ) );
140 Graphic aGraph(aWMF);
142 ErrCode nErr = ERRCODE_NONE;
143 Rectangle aVisArea;
144 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
145 if ( pOLENd )
146 nAspect = pOLENd->GetAspect();
147 SdrOle2Obj *pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
148 rStorageName,xObjStg,pDoc->GetDocStorage(),aGraph,aRect,aVisArea,0,nErr,0,nAspect);
150 if (pRet)
152 uno::Reference< embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
153 if ( xObj.is() )
155 SvStream* pGraphicStream = NULL;
156 comphelper::EmbeddedObjectContainer aCnt( pDoc->GetDocStorage() );
159 uno::Reference< embed::XEmbedPersist > xPersist(
160 xObj,
161 uno::UNO_QUERY_THROW );
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 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) );
168 catch( const uno::Exception& )
171 OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
172 if ( pGraphicStream && !pGraphicStream->GetError() )
174 Graphic aGr1;
175 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
176 if( rGF.ImportGraphic( aGr1, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
178 Graphic aGr2;
179 delete pGraphicStream;
180 pGraphicStream =
181 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
182 if( rGF.ImportGraphic( aGr2, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
184 if ( aGr1 == aGr2 )
185 bGraphicNeeded = false;
189 else
190 delete pGraphicStream;
193 delete pRet;
196 else
197 bGraphicNeeded = true;
198 return bGraphicNeeded;
201 void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
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
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
218 if ( bWrtWW8 )
220 pSpecOLE = aSpecOLE_WW8;
221 nSize = sizeof( aSpecOLE_WW8 );
223 else
225 pSpecOLE = aSpecOLE_WW6;
226 nSize = sizeof( aSpecOLE_WW6 );
228 pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
230 SvStorageRef xObjStg = GetWriter().GetStorage().OpenSotStorage(
231 OUString(SL::aObjectPool), STREAM_READWRITE |
232 STREAM_SHARE_DENYALL );
234 if( xObjStg.Is() )
236 uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
237 if( xObj.is() )
239 const embed::XEmbeddedObject *pObj = xObj.get();
240 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 sal_Int32 nPictureId = SAL_MAX_INT32 - rPointerToObjId.size();
246 WW8OleMap::value_type entry = std::make_pair(pObj, nPictureId);
247 std::pair<WW8OleMap::iterator, bool> aRes = rPointerToObjId.insert(entry);
248 bool bIsNotDuplicate = aRes.second; //.second is false when element already existed
249 nPictureId = aRes.first->second;
250 Set_UInt32(pDataAdr, nPictureId);
251 String sStorageName = OUString('_');
252 sStorageName += OUString::number( nPictureId );
253 SvStorageRef xOleStg = xObjStg->OpenSotStorage( sStorageName,
254 STREAM_READWRITE| STREAM_SHARE_DENYALL );
255 if( xOleStg.Is() )
258 If this object storage has been written already don't
259 waste time rewriting it
261 if (bIsNotDuplicate)
263 sal_Int64 nAspect = rOLENode.GetAspect();
264 svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
265 GetOLEExp().ExportOLEObject( aObjRef, *xOleStg );
266 if ( nAspect == embed::Aspects::MSOLE_ICON )
268 OUString aObjInfo( "\3ObjInfo" );
269 if ( !xOleStg->IsStream( aObjInfo ) )
271 const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
272 SvStorageStreamRef rObjInfoStream = xOleStg->OpenSotStream( aObjInfo );
273 if ( rObjInfoStream.Is() && !rObjInfoStream->GetError() )
275 rObjInfoStream->Write( pObjInfoData, sizeof( pObjInfoData ) );
276 xOleStg->Commit();
282 // write as embedded field - the other things will be done
283 // in the escher export
284 String sServer(FieldString(ww::eEMBED));
285 sServer += xOleStg->GetUserName();
286 sServer += ' ';
288 OutputField(0, ww::eEMBED, sServer, WRITEFIELD_START |
289 WRITEFIELD_CMD_START | WRITEFIELD_CMD_END);
291 pChpPlc->AppendFkpEntry( Strm().Tell(),
292 nSize, pSpecOLE );
294 bool bEndCR = true;
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.
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.
304 bool bGraphicNeeded = false;
306 if (mpParentFrame)
308 bGraphicNeeded = true;
310 if (mpParentFrame->IsInline())
312 const SwAttrSet& rSet =
313 mpParentFrame->GetFrmFmt().GetAttrSet();
314 bEndCR = false;
315 bGraphicNeeded = TestOleNeedsGraphic(rSet,
316 xOleStg, xObjStg, sStorageName, const_cast<SwOLENode*>(&rOLENode));
320 if (!bGraphicNeeded)
321 WriteChar(0x1);
322 else
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
331 OutGrf(*mpParentFrame);
334 OutputField(0, ww::eEMBED, aEmptyStr,
335 WRITEFIELD_END | WRITEFIELD_CLOSE);
337 if (bEndCR) //No newline in inline case
338 WriteCR();
344 void WW8Export::OutputLinkedOLE( const OUString& rOleId )
346 uno::Reference< embed::XStorage > xDocStg = pDoc->GetDocStorage();
347 uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( "OLELinks", embed::ElementModes::READ );
348 SotStorageRef xObjSrc = SotStorage::OpenOLEStorage( xOleStg, rOleId, STREAM_READ );
350 SotStorageRef xObjStg = GetWriter().GetStorage().OpenSotStorage(
351 OUString(SL::aObjectPool), STREAM_READWRITE |
352 STREAM_SHARE_DENYALL );
354 if( xObjStg.Is() && xObjSrc.Is() )
356 SotStorageRef xOleDst = xObjStg->OpenSotStorage( rOleId,
357 STREAM_READWRITE | STREAM_SHARE_DENYALL );
358 if ( xOleDst.Is() )
359 xObjSrc->CopyTo( xOleDst );
361 if ( !xOleDst->GetError( ) )
363 xOleDst->Commit();
365 // Ouput the cPicLocation attribute
366 ww::bytes* pBuf = new ww::bytes();
367 GetWriter().InsUInt16( *pBuf, NS_sprm::LN_CPicLocation );
368 GetWriter().InsUInt32( *pBuf, rOleId.copy( 1 ).toInt32() );
370 GetWriter().InsUInt16( *pBuf, NS_sprm::LN_CFOle2 );
371 pBuf->push_back( 1 );
373 GetWriter().InsUInt16( *pBuf, NS_sprm::LN_CFSpec );
374 pBuf->push_back( 1 );
376 GetWriter().InsUInt16( *pBuf, NS_sprm::LN_CFObj );
377 pBuf->push_back( 1 );
379 pChpPlc->AppendFkpEntry( Strm().Tell(), pBuf->size(), pBuf->data() );
380 delete pBuf;
385 void WW8Export::OutGrf(const sw::Frame &rFrame)
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 const SwFmtURL& rURL = rFrame.GetFrmFmt().GetAttrSet().GetURL();
390 bool bURLStarted = false;
391 if( rURL.GetURL().Len() && rFrame.GetWriterType() == sw::Frame::eGraphic)
393 bURLStarted = true;
394 m_pAttrOutput->StartURL( rURL.GetURL(), rURL.GetTargetFrameName() );
397 // Store the graphic settings in GrfNode so they may be written-out later
398 pGrf->Insert(rFrame);
400 pChpPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
401 pO->clear();
403 // #i29408#
404 // linked, as-character anchored graphics have to be exported as fields.
405 const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
406 ? rFrame.GetContent()->GetGrfNode() : 0;
407 if ( pGrfNd && pGrfNd->IsLinkedFile() )
409 String sStr( FieldString(ww::eINCLUDEPICTURE) );
410 sStr.AppendAscii(" \"");
412 if ( pGrfNd )
414 String aFileURL;
415 pGrfNd->GetFileFilterNms( &aFileURL, 0 );
416 sStr += aFileURL;
419 sStr.AppendAscii("\" \\d");
421 OutputField( 0, ww::eINCLUDEPICTURE, sStr,
422 WRITEFIELD_START | WRITEFIELD_CMD_START | WRITEFIELD_CMD_END );
425 WriteChar( (char)1 ); // paste graphic symbols in the main text
427 sal_uInt8 aArr[ 18 ];
428 sal_uInt8* pArr = aArr;
430 const SwFrmFmt &rFlyFmt = rFrame.GetFrmFmt();
431 const RndStdIds eAn = rFlyFmt.GetAttrSet().GetAnchor(false).GetAnchorId();
432 if (eAn == FLY_AS_CHAR)
434 sal_Int16 eVert = rFlyFmt.GetVertOrient().GetVertOrient();
435 if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
437 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 if (pOutFmtNode && pOutFmtNode->ISA(SwCntntNode) )
442 const SwTxtNode* pTxtNd = (const SwTxtNode*)pOutFmtNode;
443 SwPosition aPos(*pTxtNd);
444 bVert = pDoc->IsInVerticalText(aPos);
446 if (!bVert)
448 SwTwips nHeight = rFlyFmt.GetFrmSize().GetHeight();
449 nHeight/=20; //nHeight was in twips, want it in half points, but
450 //then half of total height.
451 long nFontHeight = ((const SvxFontHeightItem&)
452 GetItem(RES_CHRATR_FONTSIZE)).GetHeight();
453 nHeight-=nFontHeight/20;
455 if (bWrtWW8)
456 Set_UInt16( pArr, NS_sprm::LN_CHpsPos );
457 else
458 Set_UInt8( pArr, 101 );
459 Set_UInt16( pArr, -((sal_Int16)nHeight));
464 // sprmCFSpec
465 if( bWrtWW8 )
466 Set_UInt16( pArr, 0x855 );
467 else
468 Set_UInt8( pArr, 117 );
469 Set_UInt8( pArr, 1 );
471 // sprmCPicLocation
472 if( bWrtWW8 )
473 Set_UInt16( pArr, NS_sprm::LN_CPicLocation );
474 else
476 Set_UInt8( pArr, 68 );
477 Set_UInt8( pArr, 4 );
479 Set_UInt32( pArr, GRF_MAGIC_321 );
481 // vary Magic, so that different graphic attributes will not be merged
482 static sal_uInt8 nAttrMagicIdx = 0;
483 --pArr;
484 Set_UInt8( pArr, nAttrMagicIdx++ );
485 pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
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 if ( !rFrame.IsInline() &&
492 ( ((eAn == FLY_AT_PARA) && ( bWrtWW8 || !IsInTable() )) ||
493 (eAn == FLY_AT_PAGE)) )
495 WriteChar( (char)0x0d ); // close the surrounding frame with CR
497 static sal_uInt8 nSty[2] = { 0, 0 };
498 pO->insert( pO->end(), nSty, nSty+2 ); // Style #0
499 bool bOldGrf = bOutGrf;
500 bOutGrf = true;
502 OutputFormat( rFrame.GetFrmFmt(), false, false, true ); // Fly-Attrs
504 bOutGrf = bOldGrf;
505 pPapPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
506 pO->clear();
508 // #i29408#
509 // linked, as-character anchored graphics have to be exported as fields.
510 else if ( pGrfNd && pGrfNd->IsLinkedFile() )
512 OutputField( 0, ww::eINCLUDEPICTURE, String(), WRITEFIELD_CLOSE );
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 if( bURLStarted )
517 m_pAttrOutput->EndURL();
520 GraphicDetails& GraphicDetails::operator=(const GraphicDetails &rOther)
522 maFly = rOther.maFly;
523 mnPos = rOther.mnPos;
524 mnWid = rOther.mnWid;
525 mnHei = rOther.mnHei;
526 return *this;
529 void SwWW8WrGrf::Insert(const sw::Frame &rFly)
531 const Size aSize( rFly.GetLayoutSize() );
532 const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
533 const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
534 maDetails.push_back(GraphicDetails(rFly, nWidth, nHeight));
537 void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const sw::Frame &rFly,
538 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
540 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
541 sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
543 // write Crop-Attribut content in Header ( if available )
544 const SfxPoolItem* pItem;
545 if (pAttrSet && (SFX_ITEM_ON
546 == pAttrSet->GetItemState(RES_GRFATR_CROPGRF, false, &pItem)))
548 const SwCropGrf& rCr = *(SwCropGrf*)pItem;
549 nCropL = (sal_Int16)rCr.GetLeft();
550 nCropR = (sal_Int16)rCr.GetRight();
551 nCropT = (sal_Int16)rCr.GetTop();
552 nCropB = (sal_Int16)rCr.GetBottom();
553 nXSizeAdd = nXSizeAdd - (sal_Int16)( rCr.GetLeft() + rCr.GetRight() );
554 nYSizeAdd = nYSizeAdd - (sal_Int16)( rCr.GetTop() + rCr.GetBottom() );
557 Size aGrTwipSz(rFly.GetSize());
558 bool bWrtWW8 = rWrt.bWrtWW8;
559 sal_uInt16 nHdrLen = bWrtWW8 ? 0x44 : 0x3A;
561 sal_uInt8 aArr[ 0x44 ] = { 0 };
563 sal_uInt8* pArr = aArr + 0x2E; // Do borders first
565 const SwAttrSet& rAttrSet = rFly.GetFrmFmt().GetAttrSet();
566 if (SFX_ITEM_ON == rAttrSet.GetItemState(RES_BOX, false, &pItem))
568 const SvxBoxItem* pBox = (const SvxBoxItem*)pItem;
569 if( pBox )
571 bool bShadow = false; // Shadow ?
572 const SvxShadowItem* pSI =
573 sw::util::HasItem<SvxShadowItem>(rAttrSet, RES_SHADOW);
574 if (pSI)
576 bShadow = (pSI->GetLocation() != SVX_SHADOW_NONE) &&
577 (pSI->GetWidth() != 0);
580 sal_uInt8 aLnArr[4] = { BOX_LINE_TOP, BOX_LINE_LEFT,
581 BOX_LINE_BOTTOM, BOX_LINE_RIGHT };
582 for( sal_uInt8 i = 0; i < 4; ++i )
584 const ::editeng::SvxBorderLine* pLn = pBox->GetLine( aLnArr[ i ] );
585 WW8_BRC aBrc;
586 if (pLn)
588 aBrc = rWrt.TranslateBorderLine( *pLn,
589 pBox->GetDistance( aLnArr[ i ] ), bShadow );
592 // use importer logic to determine how large the exported
593 // border will really be in word and adjust accordingly
594 short nSpacing;
595 short nThick = aBrc.DetermineBorderProperties(!bWrtWW8,
596 &nSpacing);
597 switch (aLnArr[ i ])
599 case BOX_LINE_TOP:
600 case BOX_LINE_BOTTOM:
601 nHeight -= bShadow ? nThick*2 : nThick;
602 nHeight = nHeight - nSpacing;
603 break;
604 case BOX_LINE_LEFT:
605 case BOX_LINE_RIGHT:
606 default:
607 nWidth -= bShadow ? nThick*2 : nThick;
608 nWidth = nWidth - nSpacing;
609 break;
611 memcpy( pArr, &aBrc.aBits1, 2);
612 pArr+=2;
614 if( bWrtWW8 )
616 memcpy( pArr, &aBrc.aBits2, 2);
617 pArr+=2;
623 pArr = aArr + 4; // skip lcb
624 Set_UInt16( pArr, nHdrLen ); // set cbHeader
626 Set_UInt16( pArr, mm ); // set mm
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.
633 const bool bIsSubstitutedSize = (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) ||
634 (aGrTwipSz.Width() < 0 ) || (aGrTwipSz.Height() < 0);
635 if ( bIsSubstitutedSize )
637 aGrTwipSz.Width() = nWidth;
638 aGrTwipSz.Height() = nHeight;
640 using namespace sw::types;
641 // set xExt & yExt
642 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width() * 254L / 144));
643 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height() * 254L / 144));
644 pArr += 16;
645 // skip hMF & rcWinMF
646 // set dxaGoal & dyaGoal
647 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
648 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
650 if ( aGrTwipSz.Width() + nXSizeAdd ) // set mx
652 if ( !bIsSubstitutedSize )
654 const double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd );
655 Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
657 else
659 Set_UInt16( pArr, 1000 );
662 else
664 pArr += 2;
667 if ( aGrTwipSz.Height() + nYSizeAdd ) // set my
669 if ( !bIsSubstitutedSize )
671 const double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
672 Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
674 else
676 Set_UInt16( pArr, 1000 );
679 else
681 pArr += 2;
684 if ( !bIsSubstitutedSize )
686 Set_UInt16( pArr, nCropL ); // set dxaCropLeft
687 Set_UInt16( pArr, nCropT ); // set dyaCropTop
688 Set_UInt16( pArr, nCropR ); // set dxaCropRight
689 Set_UInt16( pArr, nCropB ); // set dyaCropBottom
691 else
693 pArr += 8;
696 rStrm.Write( aArr, nHdrLen );
699 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd,
700 const sw::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
702 if (rGrfNd.IsLinkedFile()) // Linked File
704 String aFileN;
705 rGrfNd.GetFileFilterNms( &aFileN, 0 );
707 sal_uInt16 mm = 94; // 94 = BMP, GIF
709 WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
710 rGrfNd.GetpSwAttrSet());
711 rStrm << (sal_uInt8)aFileN.Len(); // write Pascal-String
712 SwWW8Writer::WriteString8(rStrm, aFileN, false,
713 RTL_TEXTENCODING_MS_1252);
715 else // Embedded File or DDE or something like that
717 if (rWrt.bWrtWW8)
719 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
720 rGrfNd.GetpSwAttrSet());
721 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
722 aInlineEscher.WriteGrfFlyFrame(rFly.GetFrmFmt(), 0x401);
723 aInlineEscher.WritePictures();
725 else
727 Graphic& rGrf = const_cast<Graphic&>(rGrfNd.GetGrf());
728 bool bSwapped = rGrf.IsSwapOut() ? true : false;
729 // immer ueber den Node einswappen!
730 const_cast<SwGrfNode&>(rGrfNd).SwapIn();
732 GDIMetaFile aMeta;
733 switch (rGrf.GetType())
735 case GRAPHIC_BITMAP: // Bitmap -> play in Metafile
737 VirtualDevice aVirt;
738 aMeta.Record(&aVirt);
739 aVirt.DrawBitmap( Point( 0,0 ), rGrf.GetBitmap() );
740 aMeta.Stop();
741 aMeta.WindStart();
742 aMeta.SetPrefMapMode( rGrf.GetPrefMapMode());
743 aMeta.SetPrefSize( rGrf.GetPrefSize());
745 break;
746 case GRAPHIC_GDIMETAFILE : // GDI ( =SV ) Metafile
747 aMeta = rGrf.GetGDIMetaFile();
748 break;
749 default:
750 return;
753 WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
754 rGrfNd.GetpSwAttrSet());
755 WriteWindowMetafileBits(rStrm, aMeta);
757 if (bSwapped)
758 rGrf.SwapOut();
762 //For i120928,export graphic info of bullet
763 void SwWW8WrGrf::WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf,
764 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
766 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
767 sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
769 Size aGrTwipSz(rGrf.GetPrefSize());
770 bool bWrtWW8 = rWrt.bWrtWW8;
771 sal_uInt16 nHdrLen = bWrtWW8 ? 0x44 : 0x3A;
773 sal_uInt8 aArr[ 0x44 ] = { 0 };
775 sal_uInt8* pArr = aArr + 0x2E; //Do borders first
777 sal_uInt8 aLnArr[4] = { BOX_LINE_TOP, BOX_LINE_LEFT,
778 BOX_LINE_BOTTOM, BOX_LINE_RIGHT };
779 for( sal_uInt8 i = 0; i < 4; ++i )
781 WW8_BRC aBrc;
783 short nSpacing;
784 short nThick = aBrc.DetermineBorderProperties(!bWrtWW8,
785 &nSpacing);
786 switch (aLnArr[ i ])
788 case BOX_LINE_TOP:
789 case BOX_LINE_BOTTOM:
790 nHeight -= nThick;
791 nHeight = nHeight - nSpacing;
792 break;
793 case BOX_LINE_LEFT:
794 case BOX_LINE_RIGHT:
795 default:
796 nWidth -= nThick;
797 nWidth = nWidth - nSpacing;
798 break;
800 memcpy( pArr, &aBrc.aBits1, 2);
801 pArr+=2;
803 if( bWrtWW8 )
805 memcpy( pArr, &aBrc.aBits2, 2);
806 pArr+=2;
810 pArr = aArr + 4; //skip lcb
811 Set_UInt16( pArr, nHdrLen ); // set cbHeader
813 Set_UInt16( pArr, mm ); // set mm
815 if ( (aGrTwipSz.Width() * 254L / 144 > USHRT_MAX) || (aGrTwipSz.Height() * 254L / 144 > USHRT_MAX)
816 || (aGrTwipSz.Width() < 0 ) || (aGrTwipSz.Height() < 0) )
818 aGrTwipSz.Width() = nWidth;
819 aGrTwipSz.Height() = nHeight;
821 using namespace sw::types;
822 // set xExt & yExt
823 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width() * 254L / 144));
824 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height() * 254L / 144));
825 pArr += 16;
826 // skip hMF & rcWinMF
827 // set dxaGoal & dyaGoal
828 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
829 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
831 if( aGrTwipSz.Width() + nXSizeAdd ) // set mx
833 double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
834 Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
836 else
837 pArr += 2;
839 if( aGrTwipSz.Height() + nYSizeAdd ) // set my
841 double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
842 Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
844 else
845 pArr += 2;
847 Set_UInt16( pArr, nCropL ); // set dxaCropLeft
848 Set_UInt16( pArr, nCropT ); // set dyaCropTop
849 Set_UInt16( pArr, nCropR ); // set dxaCropRight
850 Set_UInt16( pArr, nCropB ); // set dyaCropBottom
852 rStrm.Write( aArr, nHdrLen );
855 void SwWW8WrGrf::WriteGrfForBullet(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
857 if (rWrt.bWrtWW8)
859 WritePICBulletFHeader(rStrm,rGrf, 0x64,nWidth,nHeight);
860 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
861 aInlineEscher.WriteGrfBullet(rGrf);
862 aInlineEscher.WritePictures();
864 else
866 GDIMetaFile aMeta;
867 switch (rGrf.GetType())
869 case GRAPHIC_BITMAP: // Bitmap -> in Metafile abspielen
871 VirtualDevice aVirt;
872 aMeta.Record(&aVirt);
873 aVirt.DrawBitmap( Point( 0,0 ), rGrf.GetBitmap() );
874 aMeta.Stop();
875 aMeta.WindStart();
876 aMeta.SetPrefMapMode( rGrf.GetPrefMapMode());
877 aMeta.SetPrefSize( rGrf.GetPrefSize());
879 break;
880 case GRAPHIC_GDIMETAFILE : // GDI ( =SV ) Metafile
881 aMeta = rGrf.GetGDIMetaFile();
882 break;
883 default:
884 return;
886 WritePICBulletFHeader(rStrm, rGrf, 8, nWidth, nHeight);
887 WriteWindowMetafileBits(rStrm, aMeta);
891 void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem)
893 sal_uInt16 nWidth = rItem.mnWid;
894 sal_uInt16 nHeight = rItem.mnHei;
895 sal_uInt32 nPos = rStrm.Tell(); // store start of graphic
897 const sw::Frame &rFly = rItem.maFly;
898 switch (rFly.GetWriterType())
900 case sw::Frame::eGraphic:
902 const SwNode *pNode = rItem.maFly.GetContent();
903 const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : 0;
904 OSL_ENSURE(pNd, "Impossible");
905 if (pNd)
906 WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
908 break;
909 //For i120928,add branch to export graphic of bullet
910 case sw::Frame::eBulletGrf:
912 if (rItem.maFly.HasGraphic())
914 const Graphic& rGrf = rItem.maFly.GetGraphic();
915 WriteGrfForBullet(rStrm, rGrf, nWidth, nHeight);
918 break;
920 case sw::Frame::eOle:
922 #ifdef OLE_PREVIEW_AS_EMF
923 const SwNode *pNode = rItem.maFly.GetContent();
924 const SwOLENode *pNd = pNode ? pNode->GetOLENode() : 0;
925 OSL_ENSURE(pNd, "Impossible");
926 if (!rWrt.bWrtWW8)
928 SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
929 OSL_ENSURE( pOleNd, " Wer hat den OleNode versteckt ?" );
930 SwOLEObj& rSObj= pOleNd->GetOLEObj();
931 uno::Reference < embed::XEmbeddedObject > rObj( rSObj.GetOleRef() );
933 comphelper::EmbeddedObjectContainer aCnt( pOleNd->GetDoc()->GetDocStorage() );
935 SvStream* pGraphicStream = ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( rObj ) );
936 OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
937 if ( pGraphicStream && !pGraphicStream->GetError() )
939 Graphic aGr;
940 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
941 if( rGF.ImportGraphic( aGr, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK )
943 //TODO/LATER: do we really want to use GDIMetafile?!
944 GDIMetaFile aMtf;
945 aMtf = aGr.GetGDIMetaFile();
946 aMtf.WindStart();
947 aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
948 Size(2880, 2880));
949 WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
950 pNd->GetpSwAttrSet());
951 WriteWindowMetafileBits(rStrm, aMtf);
954 else
955 delete pGraphicStream;
957 else
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 pNd->GetpSwAttrSet());
965 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
966 aInlineEscher.WriteOLEFlyFrame(rFly.GetFrmFmt(), 0x401);
967 aInlineEscher.WritePictures();
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();
975 // TODO/LATER: do we need to load object?
976 Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
978 //TODO/LATER: do we really want to use GDIMetafile?!
979 GDIMetaFile aMtf;
980 if ( pGr )
981 aMtf = pGr->GetGDIMetaFile();
983 Size aS(aMtf.GetPrefSize());
984 aMtf.WindStart();
985 aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
986 Size(2880, 2880));
988 WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
989 pNd->GetpSwAttrSet());
990 WriteWindowMetafileBits(rStrm, aMtf);
991 delete pGr;
992 #endif
994 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");
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.
1007 if (rWrt.bWrtWW8)
1009 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
1010 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
1011 aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrmFmt(), 0x401);
1013 break;
1014 default:
1015 OSL_ENSURE(!this,
1016 "Some inline export not implemented, remind cmc before we ship :-)");
1017 break;
1020 sal_uInt32 nPos2 = rStrm.Tell(); // store the end
1021 rStrm.Seek( nPos );
1022 SVBT32 nLen;
1023 UInt32ToSVBT32( nPos2 - nPos, nLen ); // calculate graphic length
1024 rStrm.Write( nLen, 4 ); // patch it in the header
1025 rStrm.Seek( nPos2 ); // restore Pos
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 void SwWW8WrGrf::Write()
1036 SvStream& rStrm = *rWrt.pDataStrm;
1037 myiter aEnd = maDetails.end();
1038 for (myiter aIter = maDetails.begin(); aIter != aEnd; ++aIter)
1040 sal_uInt32 nPos = rStrm.Tell(); // align to 4 Bytes
1041 if( nPos & 0x3 )
1042 SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
1044 bool bDuplicated = false;
1045 for (myiter aIter2 = maDetails.begin(); aIter2 != aIter; ++aIter2)
1047 if (*aIter2 == *aIter)
1049 aIter->mnPos = aIter2->mnPos;
1050 bDuplicated = true;
1051 break;
1055 if (!bDuplicated)
1057 aIter->mnPos = rStrm.Tell();
1058 WriteGraphicNode(rStrm, *aIter);
1063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */