build fix
[LibreOffice.git] / sw / source / filter / ww8 / wrtww8gr.cxx
blob51b0de6d606b4805ff3dc730e7557c5a28864d8f
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 .
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>
29 #include <svtools/embedhlp.hxx>
31 #include <vcl/virdev.hxx>
32 #include <vcl/svapp.hxx>
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>
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>
53 #include <sprmids.hxx>
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"
66 #include "docsh.hxx"
67 #include <cstdio>
68 #include <o3tl/enumrange.hxx>
70 using namespace ::com::sun::star;
71 using namespace nsFieldFlags;
73 // TODO:
74 // 5. convert the MapModes that Widows can't handle
76 // OutGrf () is called for every GrafNode in the document. 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 )
81 void WW8Export::OutputGrfNode( const SwGrfNode& /*rNode*/ )
83 OSL_TRACE("WW8Export::OutputGrfNode( const SwGrfNode& )" );
84 OSL_ENSURE( m_pParentFrame, "frame not set!" );
85 if ( m_pParentFrame )
87 OutGrf( *m_pParentFrame );
88 pFib->m_fHasPic = true;
92 bool WW8Export::TestOleNeedsGraphic(const SwAttrSet& rSet,
93 tools::SvRef<SotStorage> const & xOleStg, tools::SvRef<SotStorage> xObjStg, OUString &rStorageName,
94 SwOLENode *pOLENd)
96 bool bGraphicNeeded = false;
97 SfxItemIter aIter( rSet );
98 const SfxPoolItem* pItem = aIter.GetCurItem();
100 do {
101 switch (pItem->Which())
104 For an inline object these properties are irrelevant 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.
112 case RES_FRM_SIZE:
113 case RES_CNTNT:
114 case RES_VERT_ORIENT:
115 case RES_ANCHOR:
116 break;
117 default:
118 bGraphicNeeded = true;
120 } while( !bGraphicNeeded && !aIter.IsAtEnd() &&
121 nullptr != ( pItem = aIter.NextItem() ) );
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 don't need to store another preview
128 GDIMetaFile aWMF;
129 long nX=0,nY=0;
130 if (!bGraphicNeeded && SwWW8ImplReader::ImportOleWMF(xOleStg,aWMF,nX,nY))
132 // bGraphicNeeded set to true is right / fixes #i51670#.
133 bGraphicNeeded = true;
134 Point aTmpPoint;
135 Rectangle aRect( aTmpPoint, Size( nX, nY ) );
136 Graphic aGraph(aWMF);
138 ErrCode nErr = ERRCODE_NONE;
139 Rectangle aVisArea;
140 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
141 if ( pOLENd )
142 nAspect = pOLENd->GetAspect();
143 SdrOle2Obj *pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
144 rStorageName,xObjStg,m_pDoc->GetDocStorage(),aGraph,aRect,aVisArea,nullptr,nErr,0,nAspect, m_pWriter->GetBaseURL());
146 if (pRet)
148 uno::Reference< embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
149 if ( xObj.is() )
151 SvStream* pGraphicStream = nullptr;
152 comphelper::EmbeddedObjectContainer aCnt( m_pDoc->GetDocStorage() );
155 uno::Reference< embed::XEmbedPersist > xPersist(
156 xObj,
157 uno::UNO_QUERY_THROW );
159 // it makes no sense 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 sense
161 pGraphicStream =
162 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) );
164 catch( const uno::Exception& )
167 OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
168 if ( pGraphicStream && !pGraphicStream->GetError() )
170 Graphic aGr1;
171 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
172 if( rGF.ImportGraphic( aGr1, OUString(), *pGraphicStream ) == GRFILTER_OK )
174 Graphic aGr2;
175 delete pGraphicStream;
176 pGraphicStream =
177 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
178 if( pGraphicStream && rGF.ImportGraphic( aGr2, OUString(), *pGraphicStream ) == GRFILTER_OK )
180 if ( aGr1 == aGr2 )
181 bGraphicNeeded = false;
185 delete pGraphicStream;
188 delete pRet;
191 else
192 bGraphicNeeded = true;
193 return bGraphicNeeded;
196 void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
198 OSL_TRACE("WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
199 sal_uInt8 *pSpecOLE;
200 sal_uInt8 *pDataAdr;
201 short nSize;
202 static sal_uInt8 aSpecOLE_WW8[] = {
203 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
204 0x0a, 0x08, 1, // sprmCFOLE2
205 0x56, 0x08, 1 // sprmCFObj
208 pSpecOLE = aSpecOLE_WW8;
209 nSize = sizeof( aSpecOLE_WW8 );
210 pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
212 tools::SvRef<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(
213 OUString(SL::aObjectPool) );
215 if( xObjStg.Is() )
217 uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
218 if( xObj.is() )
220 const embed::XEmbeddedObject *pObj = xObj.get();
221 //Don't want to use pointer ids, as is traditional, because we need
222 //to put this into a 32bit value, and on 64bit the bottom bits
223 //might collide and two unrelated ole objects end up considered the
224 //same. Don't want to simply start at 0 which is a special value
225 sal_Int32 nPictureId = SAL_MAX_INT32 - m_aOleMap.size();
226 WW8OleMap::value_type entry = std::make_pair(pObj, nPictureId);
227 std::pair<WW8OleMap::iterator, bool> aRes = m_aOleMap.insert(entry);
228 bool bIsNotDuplicate = aRes.second; //.second is false when element already existed
229 nPictureId = aRes.first->second;
230 Set_UInt32(pDataAdr, nPictureId);
231 OUString sStorageName('_');
232 sStorageName += OUString::number( nPictureId );
233 tools::SvRef<SotStorage> xOleStg = xObjStg->OpenSotStorage( sStorageName );
234 if( xOleStg.Is() )
237 If this object storage has been written already don't
238 waste time rewriting it
240 if (bIsNotDuplicate)
242 sal_Int64 nAspect = rOLENode.GetAspect();
243 svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
244 GetOLEExp().ExportOLEObject( aObjRef, *xOleStg );
245 if ( nAspect == embed::Aspects::MSOLE_ICON )
247 OUString aObjInfo( "\3ObjInfo" );
248 if ( !xOleStg->IsStream( aObjInfo ) )
250 const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
251 tools::SvRef<SotStorageStream> rObjInfoStream = xOleStg->OpenSotStream( aObjInfo );
252 if ( rObjInfoStream.Is() && !rObjInfoStream->GetError() )
254 rObjInfoStream->WriteBytes(pObjInfoData, sizeof(pObjInfoData));
255 xOleStg->Commit();
261 // write as embedded field - the other things will be done
262 // in the escher export
263 OUString sServer = FieldString(ww::eEMBED) + xOleStg->GetUserName() + " ";
265 OutputField(nullptr, ww::eEMBED, sServer, WRITEFIELD_START |
266 WRITEFIELD_CMD_START | WRITEFIELD_CMD_END);
268 m_pChpPlc->AppendFkpEntry( Strm().Tell(),
269 nSize, pSpecOLE );
271 bool bEndCR = true;
273 In the word filter we only need a preview image for
274 floating images, and then only (the usual case) if the
275 object doesn't contain enough information to reconstruct
276 what we need.
278 We don't need a graphic for inline objects, so we don't
279 even need the overhead of a graphic in that case.
281 bool bGraphicNeeded = false;
283 if (m_pParentFrame)
285 bGraphicNeeded = true;
287 if (m_pParentFrame->IsInline())
289 const SwAttrSet& rSet =
290 m_pParentFrame->GetFrameFormat().GetAttrSet();
291 bEndCR = false;
292 bGraphicNeeded = TestOleNeedsGraphic(rSet,
293 xOleStg, xObjStg, sStorageName, const_cast<SwOLENode*>(&rOLENode));
297 if (!bGraphicNeeded)
298 WriteChar(0x1);
299 else
302 ##897##
303 We need to insert the graphic representation of
304 this object for the inline case, otherwise word
305 has no place to find the dimensions of the ole
306 object, and will not be able to draw it
308 OutGrf(*m_pParentFrame);
311 OutputField(nullptr, ww::eEMBED, OUString(),
312 WRITEFIELD_END | WRITEFIELD_CLOSE);
314 if (bEndCR) //No newline in inline case
315 WriteCR();
321 void WW8Export::OutputLinkedOLE( const OUString& rOleId )
323 uno::Reference< embed::XStorage > xDocStg = m_pDoc->GetDocStorage();
324 uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( "OLELinks", embed::ElementModes::READ );
325 tools::SvRef<SotStorage> xObjSrc = SotStorage::OpenOLEStorage( xOleStg, rOleId, StreamMode::READ );
327 tools::SvRef<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(
328 OUString(SL::aObjectPool) );
330 if( xObjStg.Is() && xObjSrc.Is() )
332 tools::SvRef<SotStorage> xOleDst = xObjStg->OpenSotStorage( rOleId );
333 if ( xOleDst.Is() )
334 xObjSrc->CopyTo( xOleDst.get() );
336 if ( !xOleDst->GetError( ) )
338 xOleDst->Commit();
340 // Ouput the cPicLocation attribute
341 std::unique_ptr<ww::bytes> pBuf( new ww::bytes );
342 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::LN_CPicLocation );
343 SwWW8Writer::InsUInt32( *pBuf, rOleId.copy( 1 ).toInt32() );
345 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::LN_CFOle2 );
346 pBuf->push_back( 1 );
348 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::LN_CFSpec );
349 pBuf->push_back( 1 );
351 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::LN_CFObj );
352 pBuf->push_back( 1 );
354 m_pChpPlc->AppendFkpEntry( Strm().Tell(), pBuf->size(), pBuf->data() );
359 void WW8Export::OutGrf(const ww8::Frame &rFrame)
361 //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
362 //will be exported to ensure the fidelity
363 const SwFormatURL& rURL = rFrame.GetFrameFormat().GetAttrSet().GetURL();
364 bool bURLStarted = false;
365 if( !rURL.GetURL().isEmpty() && rFrame.GetWriterType() == ww8::Frame::eGraphic)
367 bURLStarted = true;
368 m_pAttrOutput->StartURL( rURL.GetURL(), rURL.GetTargetFrameName() );
371 // Store the graphic settings in GrfNode so they may be written-out later
372 m_pGrf->Insert(rFrame);
374 m_pChpPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
375 pO->clear();
377 // #i29408#
378 // linked, as-character anchored graphics have to be exported as fields.
379 const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
380 ? rFrame.GetContent()->GetGrfNode() : nullptr;
381 if ( pGrfNd && pGrfNd->IsLinkedFile() )
383 OUString sStr( FieldString(ww::eINCLUDEPICTURE) );
384 sStr += " \"";
386 if ( pGrfNd )
388 OUString aFileURL;
389 pGrfNd->GetFileFilterNms( &aFileURL, nullptr );
390 sStr += aFileURL;
393 sStr += "\" \\d";
395 OutputField( nullptr, ww::eINCLUDEPICTURE, sStr,
396 WRITEFIELD_START | WRITEFIELD_CMD_START | WRITEFIELD_CMD_END );
399 WriteChar( (char)1 ); // paste graphic symbols in the main text
401 sal_uInt8 aArr[ 18 ];
402 sal_uInt8* pArr = aArr;
404 const SwFrameFormat &rFlyFormat = rFrame.GetFrameFormat();
405 const RndStdIds eAn = rFlyFormat.GetAttrSet().GetAnchor(false).GetAnchorId();
406 if (eAn == FLY_AS_CHAR)
408 sal_Int16 eVert = rFlyFormat.GetVertOrient().GetVertOrient();
409 if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
411 bool bVert = false;
412 //The default for word in vertical text mode is to center,
413 //otherwise a sub/super script hack is employed
414 if (m_pOutFormatNode && dynamic_cast< const SwContentNode *>( m_pOutFormatNode ) != nullptr )
416 const SwTextNode* pTextNd = static_cast<const SwTextNode*>(m_pOutFormatNode);
417 SwPosition aPos(*pTextNd);
418 bVert = m_pDoc->IsInVerticalText(aPos);
420 if (!bVert)
422 SwTwips nHeight = rFlyFormat.GetFrameSize().GetHeight();
423 nHeight/=20; //nHeight was in twips, want it in half points, but
424 //then half of total height.
425 long nFontHeight = static_cast<const SvxFontHeightItem&>(
426 GetItem(RES_CHRATR_FONTSIZE)).GetHeight();
427 nHeight-=nFontHeight/20;
429 Set_UInt16( pArr, NS_sprm::LN_CHpsPos );
430 Set_UInt16( pArr, -((sal_Int16)nHeight));
435 // sprmCFSpec
436 Set_UInt16( pArr, 0x855 );
437 Set_UInt8( pArr, 1 );
439 // sprmCPicLocation
440 Set_UInt16( pArr, NS_sprm::LN_CPicLocation );
441 Set_UInt32( pArr, GRF_MAGIC_321 );
443 // vary Magic, so that different graphic attributes will not be merged
444 static sal_uInt8 nAttrMagicIdx = 0;
445 --pArr;
446 Set_UInt8( pArr, nAttrMagicIdx++ );
447 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
449 // #i75464#
450 // Check, if graphic isn't exported as-character anchored.
451 // Otherwise, an additional paragraph is exported for a graphic, which is
452 // forced to be treated as inline, because it's anchored inside another frame.
453 if ( !rFrame.IsInline() &&
454 ( ((eAn == FLY_AT_PARA)) ||
455 (eAn == FLY_AT_PAGE)) )
457 WriteChar( (char)0x0d ); // close the surrounding frame with CR
459 static sal_uInt8 nSty[2] = { 0, 0 };
460 pO->insert( pO->end(), nSty, nSty+2 ); // Style #0
461 bool bOldGrf = m_bOutGrf;
462 m_bOutGrf = true;
464 OutputFormat( rFrame.GetFrameFormat(), false, false, true ); // Fly-Attrs
466 m_bOutGrf = bOldGrf;
467 m_pPapPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
468 pO->clear();
470 // #i29408#
471 // linked, as-character anchored graphics have to be exported as fields.
472 else if ( pGrfNd && pGrfNd->IsLinkedFile() )
474 OutputField( nullptr, ww::eINCLUDEPICTURE, OUString(), WRITEFIELD_CLOSE );
476 //Added for i120568,the hyperlink info within a graphic whose anchor type is
477 //"As character" will be exported to ensure the fidelity
478 if( bURLStarted )
479 m_pAttrOutput->EndURL(false);
482 GraphicDetails& GraphicDetails::operator=(const GraphicDetails &rOther)
484 maFly = rOther.maFly;
485 mnPos = rOther.mnPos;
486 mnWid = rOther.mnWid;
487 mnHei = rOther.mnHei;
488 return *this;
491 void SwWW8WrGrf::Insert(const ww8::Frame &rFly)
493 const Size aSize( rFly.GetLayoutSize() );
494 const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
495 const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
496 maDetails.push_back(GraphicDetails(rFly, nWidth, nHeight));
499 void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const ww8::Frame &rFly,
500 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
502 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
503 sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
505 // write Crop-Attribut content in Header ( if available )
506 const SfxPoolItem* pItem;
507 if (pAttrSet && (SfxItemState::SET
508 == pAttrSet->GetItemState(RES_GRFATR_CROPGRF, false, &pItem)))
510 const SwCropGrf& rCr = *static_cast<const SwCropGrf*>(pItem);
511 nCropL = (sal_Int16)rCr.GetLeft();
512 nCropR = (sal_Int16)rCr.GetRight();
513 nCropT = (sal_Int16)rCr.GetTop();
514 nCropB = (sal_Int16)rCr.GetBottom();
515 nXSizeAdd = nXSizeAdd - (sal_Int16)( rCr.GetLeft() + rCr.GetRight() );
516 nYSizeAdd = nYSizeAdd - (sal_Int16)( rCr.GetTop() + rCr.GetBottom() );
519 Size aGrTwipSz(rFly.GetSize());
520 sal_uInt16 nHdrLen = 0x44;
522 sal_uInt8 aArr[ 0x44 ] = { 0 };
524 sal_uInt8* pArr = aArr + 0x2E; // Do borders first
526 const SwAttrSet& rAttrSet = rFly.GetFrameFormat().GetAttrSet();
527 if (SfxItemState::SET == rAttrSet.GetItemState(RES_BOX, false, &pItem))
529 const SvxBoxItem* pBox = static_cast<const SvxBoxItem*>(pItem);
530 if( pBox )
532 bool bShadow = false; // Shadow ?
533 if (const SvxShadowItem* pSI = rAttrSet.GetItem<SvxShadowItem>(RES_SHADOW))
535 bShadow = (pSI->GetLocation() != SVX_SHADOW_NONE) &&
536 (pSI->GetWidth() != 0);
539 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
540 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
541 for(const SvxBoxItemLine & i : aLnArr)
543 const ::editeng::SvxBorderLine* pLn = pBox->GetLine( i );
544 WW8_BRC aBrc;
545 if (pLn)
547 WW8_BRCVer9 aBrc90 = WW8Export::TranslateBorderLine( *pLn,
548 pBox->GetDistance( i ), bShadow );
549 sal_uInt8 ico = msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
550 aBrc90.cv()));
551 aBrc = WW8_BRC(aBrc90.dptLineWidth(), aBrc90.brcType(), ico,
552 aBrc90.dptSpace(), aBrc90.fShadow(), aBrc90.fFrame());
555 // use importer logic to determine how large the exported
556 // border will really be in word and adjust accordingly
557 short nSpacing;
558 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
559 switch (i)
561 case SvxBoxItemLine::TOP:
562 case SvxBoxItemLine::BOTTOM:
563 nHeight -= bShadow ? nThick*2 : nThick;
564 nHeight = nHeight - nSpacing;
565 break;
566 case SvxBoxItemLine::LEFT:
567 case SvxBoxItemLine::RIGHT:
568 default:
569 nWidth -= bShadow ? nThick*2 : nThick;
570 nWidth = nWidth - nSpacing;
571 break;
573 memcpy( pArr, &aBrc.aBits1, 2);
574 pArr+=2;
576 memcpy( pArr, &aBrc.aBits2, 2);
577 pArr+=2;
582 pArr = aArr + 4; // skip lcb
583 Set_UInt16( pArr, nHdrLen ); // set cbHeader
585 Set_UInt16( pArr, mm ); // set mm
588 Just in case our original size is too big to fit inside a ushort we can
589 substitute the final size and lose on retaining the scaling factor but
590 still keep the correct display size anyway.
592 const bool bIsSubstitutedSize = (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) ||
593 (aGrTwipSz.Width() < 0 ) || (aGrTwipSz.Height() < 0);
594 if ( bIsSubstitutedSize )
596 aGrTwipSz.Width() = nWidth;
597 aGrTwipSz.Height() = nHeight;
599 using namespace sw::types;
600 // set xExt & yExt
601 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width() * 254L / 144));
602 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height() * 254L / 144));
603 pArr += 16;
604 // skip hMF & rcWinMF
605 // set dxaGoal & dyaGoal
606 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
607 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
609 if ( aGrTwipSz.Width() + nXSizeAdd ) // set mx
611 if ( !bIsSubstitutedSize )
613 const double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd );
614 Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
616 else
618 Set_UInt16( pArr, 1000 );
621 else
623 pArr += 2;
626 if ( aGrTwipSz.Height() + nYSizeAdd ) // set my
628 if ( !bIsSubstitutedSize )
630 const double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
631 Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
633 else
635 Set_UInt16( pArr, 1000 );
638 else
640 pArr += 2;
643 if ( !bIsSubstitutedSize )
645 Set_UInt16( pArr, nCropL ); // set dxaCropLeft
646 Set_UInt16( pArr, nCropT ); // set dyaCropTop
647 Set_UInt16( pArr, nCropR ); // set dxaCropRight
648 Set_UInt16( pArr, nCropB ); // set dyaCropBottom
651 rStrm.WriteBytes(aArr, nHdrLen);
654 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd,
655 const ww8::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
657 if (rGrfNd.IsLinkedFile()) // Linked File
659 OUString aFileN;
660 rGrfNd.GetFileFilterNms( &aFileN, nullptr );
662 sal_uInt16 mm = 94; // 94 = BMP, GIF
664 WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
665 rGrfNd.GetpSwAttrSet());
666 rStrm.WriteUChar( aFileN.getLength() ); // write Pascal-String
667 SwWW8Writer::WriteString8(rStrm, aFileN, false,
668 RTL_TEXTENCODING_MS_1252);
670 else // Embedded File or DDE or something like that
672 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
673 rGrfNd.GetpSwAttrSet());
674 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
675 aInlineEscher.WriteGrfFlyFrame(rFly.GetFrameFormat(), 0x401);
676 aInlineEscher.WritePictures();
679 //For i120928,export graphic info of bullet
680 void SwWW8WrGrf::WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf,
681 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
683 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
684 sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
686 Size aGrTwipSz(rGrf.GetPrefSize());
687 sal_uInt16 nHdrLen = 0x44;
689 sal_uInt8 aArr[ 0x44 ] = { 0 };
691 sal_uInt8* pArr = aArr + 0x2E; //Do borders first
693 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
694 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
695 for(const SvxBoxItemLine & i : aLnArr)
697 WW8_BRC aBrc;
699 short nSpacing;
700 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
701 switch (i)
703 case SvxBoxItemLine::TOP:
704 case SvxBoxItemLine::BOTTOM:
705 nHeight -= nThick;
706 nHeight = nHeight - nSpacing;
707 break;
708 case SvxBoxItemLine::LEFT:
709 case SvxBoxItemLine::RIGHT:
710 default:
711 nWidth -= nThick;
712 nWidth = nWidth - nSpacing;
713 break;
715 memcpy( pArr, &aBrc.aBits1, 2);
716 pArr+=2;
718 memcpy(pArr, &aBrc.aBits2, 2);
719 pArr+=2;
722 pArr = aArr + 4; //skip lcb
723 Set_UInt16( pArr, nHdrLen ); // set cbHeader
725 Set_UInt16( pArr, mm ); // set mm
727 if ( (aGrTwipSz.Width() * 254L / 144 > USHRT_MAX) || (aGrTwipSz.Height() * 254L / 144 > USHRT_MAX)
728 || (aGrTwipSz.Width() < 0 ) || (aGrTwipSz.Height() < 0) )
730 aGrTwipSz.Width() = nWidth;
731 aGrTwipSz.Height() = nHeight;
733 using namespace sw::types;
734 // set xExt & yExt
735 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width() * 254L / 144));
736 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height() * 254L / 144));
737 pArr += 16;
738 // skip hMF & rcWinMF
739 // set dxaGoal & dyaGoal
740 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
741 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
743 if( aGrTwipSz.Width() + nXSizeAdd ) // set mx
745 double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
746 Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
748 else
749 pArr += 2;
751 if( aGrTwipSz.Height() + nYSizeAdd ) // set my
753 double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
754 Set_UInt16( pArr, (sal_uInt16)::rtl::math::round(fVal) );
756 else
757 pArr += 2;
759 Set_UInt16( pArr, nCropL ); // set dxaCropLeft
760 Set_UInt16( pArr, nCropT ); // set dyaCropTop
761 Set_UInt16( pArr, nCropR ); // set dxaCropRight
762 Set_UInt16( pArr, nCropB ); // set dyaCropBottom
764 rStrm.WriteBytes(aArr, nHdrLen);
767 void SwWW8WrGrf::WriteGrfForBullet(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
769 WritePICBulletFHeader(rStrm,rGrf, 0x64,nWidth,nHeight);
770 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
771 aInlineEscher.WriteGrfBullet(rGrf);
772 aInlineEscher.WritePictures();
775 void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem)
777 sal_uInt16 nWidth = rItem.mnWid;
778 sal_uInt16 nHeight = rItem.mnHei;
779 sal_uInt32 nPos = rStrm.Tell(); // store start of graphic
781 const ww8::Frame &rFly = rItem.maFly;
782 switch (rFly.GetWriterType())
784 case ww8::Frame::eGraphic:
786 const SwNode *pNode = rItem.maFly.GetContent();
787 const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : nullptr;
788 OSL_ENSURE(pNd, "Impossible");
789 if (pNd)
790 WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
792 break;
793 //For i120928,add branch to export graphic of bullet
794 case ww8::Frame::eBulletGrf:
796 if (rItem.maFly.HasGraphic())
798 const Graphic& rGrf = rItem.maFly.GetGraphic();
799 WriteGrfForBullet(rStrm, rGrf, nWidth, nHeight);
802 break;
804 case ww8::Frame::eOle:
806 const SwNode *pNode = rItem.maFly.GetContent();
807 const SwOLENode *pNd = pNode ? pNode->GetOLENode() : nullptr;
808 OSL_ENSURE(pNd, "Impossible");
809 if (pNd)
811 #ifdef OLE_PREVIEW_AS_EMF
812 //Convert this ole2 preview in ww8+ to an EMF for better unicode
813 //support (note that at this moment this breaks StarSymbol
814 //using graphics because I need to embed starsymbol in exported
815 //documents.
816 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
817 pNd->GetpSwAttrSet());
818 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
819 aInlineEscher.WriteOLEFlyFrame(rFly.GetFrameFormat(), 0x401);
820 aInlineEscher.WritePictures();
821 #else
822 // cast away const
823 SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
824 SwOLEObj& rSObj= pOleNd->GetOLEObj();
826 // TODO/LATER: do we need to load object?
827 Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
829 //TODO/LATER: do we really want to use GDIMetafile?!
830 GDIMetaFile aMtf;
831 if ( pGr )
832 aMtf = pGr->GetGDIMetaFile();
834 Size aS(aMtf.GetPrefSize());
835 aMtf.WindStart();
836 aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
837 Size(2880, 2880));
839 WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
840 pNd->GetpSwAttrSet());
841 WriteWindowMetafileBits(rStrm, aMtf);
842 delete pGr;
843 #endif
846 break;
847 case ww8::Frame::eDrawing:
848 case ww8::Frame::eTextBox:
849 case ww8::Frame::eFormControl:
851 #i3958# We only export an empty dummy picture frame here, this is
852 what word does the escher export should contain an anchored to
853 character element which is drawn over this dummy and the whole
854 shebang surrounded with a SHAPE field. This isn't *my* hack :-),
855 its what word does.
858 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
859 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
860 aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrameFormat(), 0x401);
862 break;
863 default:
864 OSL_ENSURE(false, "Some inline export not implemented");
865 break;
868 sal_uInt32 nPos2 = rStrm.Tell(); // store the end
869 rStrm.Seek( nPos );
870 rStrm.WriteUInt32(nPos2 - nPos); // patch graphic length in the header
871 rStrm.Seek( nPos2 ); // restore Pos
874 // SwWW8WrGrf::Write() is called after the text.
875 // It writes out all the graphics and remembers the file locations of the graphics,
876 // so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
877 // The search in the attributes for the Magic sal_uLong and patching
878 // happens when writing the attributes. Class SwWW8WrGrf-Klasse provides with
879 // GetFPos() sequentially the positions
880 void SwWW8WrGrf::Write()
882 SvStream& rStrm = *rWrt.pDataStrm;
883 myiter aEnd = maDetails.end();
884 for (myiter aIter = maDetails.begin(); aIter != aEnd; ++aIter)
886 sal_uInt32 nPos = rStrm.Tell(); // align to 4 Bytes
887 if( nPos & 0x3 )
888 SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
890 bool bDuplicated = false;
891 for (myiter aIter2 = maDetails.begin(); aIter2 != aIter; ++aIter2)
893 if (*aIter2 == *aIter)
895 aIter->mnPos = aIter2->mnPos;
896 bDuplicated = true;
897 break;
901 if (!bDuplicated)
903 aIter->mnPos = rStrm.Tell();
904 WriteGraphicNode(rStrm, *aIter);
909 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */