nss: upgrade to release 3.73
[LibreOffice.git] / sw / source / filter / ww8 / wrtww8gr.cxx
blobaaa5dcead82759de032bea27574a373a56c372c0
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 <memory>
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 <sal/log.hxx>
25 #include <vcl/graphicfilter.hxx>
26 #include <vcl/gdimtf.hxx>
27 #include <svl/itemiter.hxx>
28 #include <tools/UnitConversion.hxx>
30 #include <svtools/embedhlp.hxx>
32 #include <hintids.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/shaditem.hxx>
35 #include <filter/msfilter/msoleexp.hxx>
36 #include <editeng/fhgtitem.hxx>
37 #include <svx/svdoole2.hxx>
39 #include <unotools/ucbstreamhelper.hxx>
40 #include <fmtanchr.hxx>
41 #include <ndgrf.hxx>
42 #include <frmfmt.hxx>
43 #include <grfatr.hxx>
44 #include <ndole.hxx>
45 #include <ndtxt.hxx>
46 #include <fmtfsize.hxx>
47 #include <fmtornt.hxx>
49 #include "sprmids.hxx"
51 #include <doc.hxx>
52 #include "writerhelper.hxx"
53 #include "writerwordglue.hxx"
54 #include "ww8struc.hxx"
55 #include "wrtww8.hxx"
56 #include "ww8par.hxx"
57 #include "escher.hxx"
58 //Added for i120568
59 #include "ww8attributeoutput.hxx"
60 #include <fmturl.hxx>
62 #include <IDocumentDrawModelAccess.hxx>
63 #include <drawdoc.hxx>
65 using namespace ::com::sun::star;
67 // TODO:
68 // 5. convert the MapModes that Widows can't handle
70 // OutGrf () is called for every GrfNode in the document. A PicLocFc-Sprm
71 // will be inserted, which contains a magic number instead of an address.
72 // The GrfNode-Ptr is saved in Graf-Class (used later for output of
73 // the graphic and patching of the PicLocFc attributes)
75 void WW8Export::OutputGrfNode( const SwGrfNode& /*rNode*/ )
77 SAL_INFO("sw", "WW8Export::OutputGrfNode( const SwGrfNode& )" );
78 OSL_ENSURE( m_pParentFrame, "frame not set!" );
79 if ( m_pParentFrame )
81 OutGrf( *m_pParentFrame );
82 pFib->m_fHasPic = true;
86 bool WW8Export::TestOleNeedsGraphic(const SwAttrSet& rSet, tools::SvRef<SotStorage> const& xOleStg,
87 const tools::SvRef<SotStorage>& xObjStg,
88 OUString const& rStorageName, SwOLENode* pOLENd)
90 bool bGraphicNeeded = false;
91 SfxItemIter aIter( rSet );
92 for (auto pItem = aIter.GetCurItem(); !bGraphicNeeded && pItem; pItem = aIter.NextItem())
94 switch (pItem->Which())
97 For an inline object these properties are irrelevant because they
98 will be the same as the defaults that msword applies in their
99 absence, so if that is all that there is for these inline objects
100 then if there turns out to be enough information in the object
101 itself to regenerate the correct size and preview of the object
102 then we will not need to provide an additional graphics preview in
103 the data stream, which can save a lot of disk space.
105 case RES_FRM_SIZE:
106 case RES_CNTNT:
107 case RES_VERT_ORIENT:
108 case RES_ANCHOR:
109 break;
110 default:
111 bGraphicNeeded = true;
116 Now we must see if the object contains a preview itself which is equal to
117 the preview that we are currently using. If the graphics are equal then we
118 don't need to store another preview
120 GDIMetaFile aWMF;
121 tools::Long nX=0,nY=0;
122 if (!bGraphicNeeded && SwWW8ImplReader::ImportOleWMF(xOleStg,aWMF,nX,nY))
124 // bGraphicNeeded set to true is right / fixes #i51670#.
125 bGraphicNeeded = true;
126 tools::Rectangle aRect( Point(), Size( nX, nY ) );
127 Graphic aGraph(aWMF);
129 ErrCode nErr = ERRCODE_NONE;
130 sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
131 if ( pOLENd )
132 nAspect = pOLENd->GetAspect();
133 SdrOle2Obj *pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
134 *m_rDoc.getIDocumentDrawModelAccess().GetOrCreateDrawModel(),
135 rStorageName,
136 xObjStg,
137 m_rDoc.GetDocStorage(),
138 aGraph,
139 aRect,
140 tools::Rectangle(),
141 nullptr,
142 nErr,
144 nAspect,
145 m_pWriter->GetBaseURL());
147 if (pRet)
149 uno::Reference< embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
150 if ( xObj.is() )
152 std::unique_ptr<SvStream> pGraphicStream;
153 comphelper::EmbeddedObjectContainer aCnt( m_rDoc.GetDocStorage() );
156 uno::Reference< embed::XEmbedPersist > xPersist(
157 xObj,
158 uno::UNO_QUERY_THROW );
160 // it makes no sense to search the object in the container by reference since the object was created
161 // outside of the container and was not inserted there, only the name makes sense
162 pGraphicStream =
163 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) );
165 catch( const uno::Exception& )
168 OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
169 if ( pGraphicStream && !pGraphicStream->GetError() )
171 Graphic aGr1;
172 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
173 if( rGF.ImportGraphic( aGr1, OUString(), *pGraphicStream ) == ERRCODE_NONE )
175 Graphic aGr2;
176 pGraphicStream =
177 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
178 if( pGraphicStream && rGF.ImportGraphic( aGr2, OUString(), *pGraphicStream ) == ERRCODE_NONE )
180 if ( aGr1 == aGr2 )
181 bGraphicNeeded = false;
187 // always use SdrObject::Free(...) for SdrObjects (!)
188 SdrObject* pTemp(pRet);
189 SdrObject::Free(pTemp);
192 else
193 bGraphicNeeded = true;
194 return bGraphicNeeded;
197 void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
199 SAL_INFO("sw", "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
209 pSpecOLE = aSpecOLE_WW8;
210 nSize = sizeof( aSpecOLE_WW8 );
211 pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
213 tools::SvRef<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
215 if( !xObjStg.is() )
216 return;
218 uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
219 if( !xObj.is() )
220 return;
222 const embed::XEmbeddedObject *pObj = xObj.get();
223 //Don't want to use pointer ids, as is traditional, because we need
224 //to put this into a 32bit value, and on 64bit the bottom bits
225 //might collide and two unrelated ole objects end up considered the
226 //same. Don't want to simply start at 0 which is a special value
227 sal_Int32 nPictureId = SAL_MAX_INT32 - m_aOleMap.size();
228 WW8OleMap::value_type entry = std::make_pair(pObj, nPictureId);
229 std::pair<WW8OleMap::iterator, bool> aRes = m_aOleMap.insert(entry);
230 bool bIsNotDuplicate = aRes.second; //.second is false when element already existed
231 nPictureId = aRes.first->second;
232 Set_UInt32(pDataAdr, nPictureId);
233 OUString sStorageName = "_" + OUString::number( nPictureId );
234 tools::SvRef<SotStorage> xOleStg = xObjStg->OpenSotStorage( sStorageName );
235 if( !xOleStg.is() )
236 return;
239 If this object storage has been written already don't
240 waste time rewriting it
242 if (bIsNotDuplicate)
244 sal_Int64 nAspect = rOLENode.GetAspect();
245 svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
246 m_pOLEExp->ExportOLEObject( aObjRef, *xOleStg );
247 if ( nAspect == embed::Aspects::MSOLE_ICON )
249 OUString aObjInfo( "\3ObjInfo" );
250 if ( !xOleStg->IsStream( aObjInfo ) )
252 const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
253 tools::SvRef<SotStorageStream> rObjInfoStream = xOleStg->OpenSotStream( aObjInfo );
254 if ( rObjInfoStream.is() && !rObjInfoStream->GetError() )
256 rObjInfoStream->WriteBytes(pObjInfoData, sizeof(pObjInfoData));
257 xOleStg->Commit();
263 // write as embedded field - the other things will be done
264 // in the escher export
265 OUString sServer = FieldString(ww::eEMBED) + xOleStg->GetUserName() + " ";
267 OutputField(nullptr, ww::eEMBED, sServer, FieldFlags::Start |
268 FieldFlags::CmdStart | FieldFlags::CmdEnd);
270 m_pChpPlc->AppendFkpEntry( Strm().Tell(),
271 nSize, pSpecOLE );
273 bool bEndCR = true;
275 In the word filter we only need a preview image for
276 floating images, and then only (the usual case) if the
277 object doesn't contain enough information to reconstruct
278 what we need.
280 We don't need a graphic for inline objects, so we don't
281 even need the overhead of a graphic in that case.
283 bool bGraphicNeeded = false;
285 if (m_pParentFrame)
287 bGraphicNeeded = true;
289 if (m_pParentFrame->IsInline())
291 const SwAttrSet& rSet =
292 m_pParentFrame->GetFrameFormat().GetAttrSet();
293 bEndCR = false;
294 bGraphicNeeded = TestOleNeedsGraphic(rSet,
295 xOleStg, xObjStg, sStorageName, const_cast<SwOLENode*>(&rOLENode));
299 if (!bGraphicNeeded)
300 WriteChar(0x1);
301 else
304 ##897##
305 We need to insert the graphic representation of
306 this object for the inline case, otherwise word
307 has no place to find the dimensions of the ole
308 object, and will not be able to draw it
310 OutGrf(*m_pParentFrame);
313 OutputField(nullptr, ww::eEMBED, OUString(),
314 FieldFlags::End | FieldFlags::Close);
316 if (bEndCR) //No newline in inline case
317 WriteCR();
320 void WW8Export::OutputLinkedOLE( const OUString& rOleId )
322 uno::Reference< embed::XStorage > xDocStg = m_rDoc.GetDocStorage();
323 uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( "OLELinks", embed::ElementModes::READ );
324 tools::SvRef<SotStorage> xObjSrc = SotStorage::OpenOLEStorage( xOleStg, rOleId, StreamMode::READ );
326 tools::SvRef<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
328 if( !(xObjStg.is() && xObjSrc.is()) )
329 return;
331 tools::SvRef<SotStorage> xOleDst = xObjStg->OpenSotStorage( rOleId );
332 if ( xOleDst.is() )
333 xObjSrc->CopyTo( xOleDst.get() );
335 if ( xOleDst->GetError( ) )
336 return;
338 xOleDst->Commit();
340 // Output the cPicLocation attribute
341 std::unique_ptr<ww::bytes> pBuf( new ww::bytes );
342 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CPicLocation::val );
343 SwWW8Writer::InsUInt32( *pBuf, rOleId.copy( 1 ).toInt32() );
345 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFOle2::val );
346 pBuf->push_back( 1 );
348 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFSpec::val );
349 pBuf->push_back( 1 );
351 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFObj::val );
352 pBuf->push_back( 1 );
354 m_pChpPlc->AppendFkpEntry( Strm().Tell(), pBuf->size(), pBuf->data() );
357 void WW8Export::OutGrf(const ww8::Frame &rFrame)
359 //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
360 //will be exported to ensure the fidelity
361 const SwFormatURL& rURL = rFrame.GetFrameFormat().GetAttrSet().GetURL();
362 bool bURLStarted = false;
363 if( !rURL.GetURL().isEmpty() && rFrame.GetWriterType() == ww8::Frame::eGraphic)
365 bURLStarted = true;
366 m_pAttrOutput->StartURL( rURL.GetURL(), rURL.GetTargetFrameName() );
369 // Store the graphic settings in GrfNode so they may be written-out later
370 m_pGrf->Insert(rFrame);
372 m_pChpPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
373 pO->clear();
375 // #i29408#
376 // linked, as-character anchored graphics have to be exported as fields.
377 const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
378 ? rFrame.GetContent()->GetGrfNode() : nullptr;
379 if ( pGrfNd && pGrfNd->IsLinkedFile() )
381 OUString sStr;
382 pGrfNd->GetFileFilterNms(&sStr, nullptr);
383 sStr = FieldString(ww::eINCLUDEPICTURE) + " \"" + sStr + "\" \\d";
385 OutputField( nullptr, ww::eINCLUDEPICTURE, sStr,
386 FieldFlags::Start | FieldFlags::CmdStart | FieldFlags::CmdEnd );
389 WriteChar( char(1) ); // paste graphic symbols in the main text
391 sal_uInt8 aArr[ 18 ];
392 sal_uInt8* pArr = aArr;
394 const SwFrameFormat &rFlyFormat = rFrame.GetFrameFormat();
395 const RndStdIds eAn = rFlyFormat.GetAttrSet().GetAnchor(false).GetAnchorId();
396 if (eAn == RndStdIds::FLY_AS_CHAR)
398 sal_Int16 eVert = rFlyFormat.GetVertOrient().GetVertOrient();
399 if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
401 bool bVert = false;
402 //The default for word in vertical text mode is to center,
403 //otherwise a sub/super script hack is employed
404 if (auto pTextNd = dynamic_cast< const SwContentNode *>( m_pOutFormatNode ) )
406 SwPosition aPos(*pTextNd);
407 bVert = m_rDoc.IsInVerticalText(aPos);
409 if (!bVert)
411 SwTwips nHeight = rFlyFormat.GetFrameSize().GetHeight();
412 nHeight/=20; //nHeight was in twips, want it in half points, but
413 //then half of total height.
414 tools::Long nFontHeight = GetItem(RES_CHRATR_FONTSIZE).GetHeight();
415 nHeight-=nFontHeight/20;
417 Set_UInt16( pArr, NS_sprm::CHpsPos::val );
418 Set_UInt16( pArr, - static_cast<sal_Int16>(nHeight));
423 // sprmCFSpec
424 Set_UInt16( pArr, 0x855 );
425 Set_UInt8( pArr, 1 );
427 // sprmCPicLocation
428 Set_UInt16( pArr, NS_sprm::CPicLocation::val );
429 Set_UInt32( pArr, GRF_MAGIC_321 );
431 // vary Magic, so that different graphic attributes will not be merged
432 static sal_uInt8 nAttrMagicIdx = 0;
433 --pArr;
434 Set_UInt8( pArr, nAttrMagicIdx++ );
435 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
437 // #i75464#
438 // Check, if graphic isn't exported as-character anchored.
439 // Otherwise, an additional paragraph is exported for a graphic, which is
440 // forced to be treated as inline, because it's anchored inside another frame.
441 if ( !rFrame.IsInline() &&
442 ( (eAn == RndStdIds::FLY_AT_PARA) ||
443 (eAn == RndStdIds::FLY_AT_PAGE) ) )
445 WriteChar( char(0x0d) ); // close the surrounding frame with CR
447 static sal_uInt8 nSty[2] = { 0, 0 };
448 pO->insert( pO->end(), nSty, nSty+2 ); // Style #0
449 bool bOldGrf = m_bOutGrf;
450 m_bOutGrf = true;
452 OutputFormat( rFrame.GetFrameFormat(), false, false, true ); // Fly-Attrs
454 m_bOutGrf = bOldGrf;
455 m_pPapPlc->AppendFkpEntry( Strm().Tell(), pO->size(), pO->data() );
456 pO->clear();
458 // #i29408#
459 // linked, as-character anchored graphics have to be exported as fields.
460 else if ( pGrfNd && pGrfNd->IsLinkedFile() )
462 OutputField( nullptr, ww::eINCLUDEPICTURE, OUString(), FieldFlags::Close );
464 //Added for i120568,the hyperlink info within a graphic whose anchor type is
465 //"As character" will be exported to ensure the fidelity
466 if( bURLStarted )
467 m_pAttrOutput->EndURL(false);
470 void SwWW8WrGrf::Insert(const ww8::Frame &rFly)
472 const Size aSize( rFly.GetLayoutSize() );
473 const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
474 const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
475 maDetails.emplace_back(rFly, nWidth, nHeight);
478 void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const ww8::Frame &rFly,
479 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
481 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
482 sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
484 // write Crop-Attribute content in Header ( if available )
485 const SfxPoolItem* pItem;
486 if (pAttrSet && (SfxItemState::SET
487 == pAttrSet->GetItemState(RES_GRFATR_CROPGRF, false, &pItem)))
489 const SwCropGrf& rCr = *static_cast<const SwCropGrf*>(pItem);
490 nCropL = static_cast<sal_Int16>(rCr.GetLeft());
491 nCropR = static_cast<sal_Int16>(rCr.GetRight());
492 nCropT = static_cast<sal_Int16>(rCr.GetTop());
493 nCropB = static_cast<sal_Int16>(rCr.GetBottom());
494 nXSizeAdd = nXSizeAdd - static_cast<sal_Int16>( rCr.GetLeft() + rCr.GetRight() );
495 nYSizeAdd = nYSizeAdd - static_cast<sal_Int16>( rCr.GetTop() + rCr.GetBottom() );
498 Size aGrTwipSz(rFly.GetSize());
499 sal_uInt16 nHdrLen = 0x44;
501 sal_uInt8 aArr[ 0x44 ] = { 0 };
503 sal_uInt8* pArr = aArr + 0x2E; // Do borders first
505 const SwAttrSet& rAttrSet = rFly.GetFrameFormat().GetAttrSet();
506 if (SfxItemState::SET == rAttrSet.GetItemState(RES_BOX, false, &pItem))
508 const SvxBoxItem* pBox = static_cast<const SvxBoxItem*>(pItem);
509 if( pBox )
511 bool bShadow = false; // Shadow ?
512 if (const SvxShadowItem* pSI = rAttrSet.GetItem<SvxShadowItem>(RES_SHADOW))
514 bShadow = (pSI->GetLocation() != SvxShadowLocation::NONE) &&
515 (pSI->GetWidth() != 0);
518 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
519 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
520 for(const SvxBoxItemLine & i : aLnArr)
522 const ::editeng::SvxBorderLine* pLn = pBox->GetLine( i );
523 WW8_BRC aBrc;
524 if (pLn)
526 WW8_BRCVer9 aBrc90 = WW8Export::TranslateBorderLine( *pLn,
527 pBox->GetDistance( i ), bShadow );
528 sal_uInt8 ico = msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
529 aBrc90.cv()));
530 aBrc = WW8_BRC(aBrc90.dptLineWidth(), aBrc90.brcType(), ico,
531 aBrc90.dptSpace(), aBrc90.fShadow(), aBrc90.fFrame());
534 // use importer logic to determine how large the exported
535 // border will really be in word and adjust accordingly
536 short nSpacing;
537 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
538 switch (i)
540 case SvxBoxItemLine::TOP:
541 case SvxBoxItemLine::BOTTOM:
542 nHeight -= bShadow ? nThick*2 : nThick;
543 nHeight = nHeight - nSpacing;
544 break;
545 case SvxBoxItemLine::LEFT:
546 case SvxBoxItemLine::RIGHT:
547 default:
548 nWidth -= bShadow ? nThick*2 : nThick;
549 nWidth = nWidth - nSpacing;
550 break;
552 memcpy( pArr, &aBrc.aBits1, 2);
553 pArr+=2;
555 memcpy( pArr, &aBrc.aBits2, 2);
556 pArr+=2;
561 pArr = aArr + 4; // skip lcb
562 Set_UInt16( pArr, nHdrLen ); // set cbHeader
564 Set_UInt16( pArr, mm ); // set mm
567 Just in case our original size is too big to fit inside a ushort we can
568 substitute the final size and lose on retaining the scaling factor but
569 still keep the correct display size anyway.
571 const bool bIsSubstitutedSize = (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) ||
572 aGrTwipSz.IsEmpty();
573 if ( bIsSubstitutedSize )
575 aGrTwipSz.setWidth( nWidth );
576 aGrTwipSz.setHeight( nHeight );
578 using namespace sw::types;
579 // set xExt & yExt
580 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
581 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
582 pArr += 16;
583 // skip hMF & rcWinMF
584 // set dxaGoal & dyaGoal
585 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
586 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
588 if ( aGrTwipSz.Width() + nXSizeAdd ) // set mx
590 if ( !bIsSubstitutedSize )
592 const double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd );
593 Set_UInt16( pArr, static_cast<sal_uInt16>(::rtl::math::round(fVal)) );
595 else
597 Set_UInt16( pArr, 1000 );
600 else
602 pArr += 2;
605 if ( aGrTwipSz.Height() + nYSizeAdd ) // set my
607 if ( !bIsSubstitutedSize )
609 const double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
610 Set_UInt16( pArr, static_cast<sal_uInt16>(::rtl::math::round(fVal)) );
612 else
614 Set_UInt16( pArr, 1000 );
617 else
619 pArr += 2;
622 if ( !bIsSubstitutedSize )
624 Set_UInt16( pArr, nCropL ); // set dxaCropLeft
625 Set_UInt16( pArr, nCropT ); // set dyaCropTop
626 Set_UInt16( pArr, nCropR ); // set dxaCropRight
627 Set_UInt16( pArr, nCropB ); // set dyaCropBottom
630 rStrm.WriteBytes(aArr, nHdrLen);
633 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd,
634 const ww8::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
636 if (rGrfNd.IsLinkedFile()) // Linked File
638 OUString aFileN;
639 rGrfNd.GetFileFilterNms( &aFileN, nullptr );
641 sal_uInt16 const mm = 94; // 94 = BMP, GIF
643 WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
644 rGrfNd.GetpSwAttrSet());
645 rStrm.WriteUChar( aFileN.getLength() ); // write Pascal-String
646 SwWW8Writer::WriteString8(rStrm, aFileN, false,
647 RTL_TEXTENCODING_MS_1252);
649 else // Embedded File or DDE or something like that
651 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
652 rGrfNd.GetpSwAttrSet());
653 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
654 aInlineEscher.WriteGrfFlyFrame(rFly.GetFrameFormat(), 0x401);
655 aInlineEscher.WritePictures();
658 //For i120928,export graphic info of bullet
659 void SwWW8WrGrf::WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf,
660 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
662 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
664 Size aGrTwipSz(rGrf.GetPrefSize());
665 sal_uInt16 nHdrLen = 0x44;
667 sal_uInt8 aArr[ 0x44 ] = { 0 };
669 sal_uInt8* pArr = aArr + 0x2E; //Do borders first
671 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
672 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
673 for(const SvxBoxItemLine & i : aLnArr)
675 WW8_BRC aBrc;
677 short nSpacing;
678 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
679 switch (i)
681 case SvxBoxItemLine::TOP:
682 case SvxBoxItemLine::BOTTOM:
683 nHeight -= nThick;
684 nHeight = nHeight - nSpacing;
685 break;
686 case SvxBoxItemLine::LEFT:
687 case SvxBoxItemLine::RIGHT:
688 default:
689 nWidth -= nThick;
690 nWidth = nWidth - nSpacing;
691 break;
693 memcpy( pArr, &aBrc.aBits1, 2);
694 pArr+=2;
696 memcpy(pArr, &aBrc.aBits2, 2);
697 pArr+=2;
700 pArr = aArr + 4; //skip lcb
701 Set_UInt16( pArr, nHdrLen ); // set cbHeader
703 Set_UInt16( pArr, mm ); // set mm
705 if ( (convertTwipToMm100(aGrTwipSz.Width()) > USHRT_MAX ) || ( convertTwipToMm100(aGrTwipSz.Height()) > USHRT_MAX )
706 || aGrTwipSz.IsEmpty() )
708 aGrTwipSz.setWidth( nWidth );
709 aGrTwipSz.setHeight( nHeight );
711 using namespace sw::types;
712 // set xExt & yExt
713 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
714 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
715 pArr += 16;
716 // skip hMF & rcWinMF
717 // set dxaGoal & dyaGoal
718 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
719 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
721 if( aGrTwipSz.Width() + nXSizeAdd ) // set mx
723 double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
724 Set_UInt16( pArr, static_cast<sal_uInt16>(::rtl::math::round(fVal)) );
726 else
727 pArr += 2;
729 if( aGrTwipSz.Height() + nYSizeAdd ) // set my
731 double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
732 Set_UInt16( pArr, static_cast<sal_uInt16>(::rtl::math::round(fVal)) );
734 else
735 pArr += 2;
737 Set_UInt16( pArr, 0 ); // set dxaCropLeft
738 Set_UInt16( pArr, 0 ); // set dyaCropTop
739 Set_UInt16( pArr, 0 ); // set dxaCropRight
740 Set_UInt16( pArr, 0 ); // set dyaCropBottom
742 rStrm.WriteBytes(aArr, nHdrLen);
745 void SwWW8WrGrf::WriteGrfForBullet(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
747 WritePICBulletFHeader(rStrm,rGrf, 0x64,nWidth,nHeight);
748 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
749 aInlineEscher.WriteGrfBullet(rGrf);
750 aInlineEscher.WritePictures();
753 void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem)
755 sal_uInt16 nWidth = rItem.mnWid;
756 sal_uInt16 nHeight = rItem.mnHei;
757 sal_uInt32 nPos = rStrm.Tell(); // store start of graphic
759 const ww8::Frame &rFly = rItem.maFly;
760 switch (rFly.GetWriterType())
762 case ww8::Frame::eGraphic:
764 const SwNode *pNode = rItem.maFly.GetContent();
765 const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : nullptr;
766 OSL_ENSURE(pNd, "Impossible");
767 if (pNd)
768 WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
770 break;
771 //For i120928,add branch to export graphic of bullet
772 case ww8::Frame::eBulletGrf:
774 if (rItem.maFly.HasGraphic())
776 const Graphic& rGrf = rItem.maFly.GetGraphic();
777 WriteGrfForBullet(rStrm, rGrf, nWidth, nHeight);
780 break;
782 case ww8::Frame::eOle:
784 const SwNode *pNode = rItem.maFly.GetContent();
785 const SwOLENode *pNd = pNode ? pNode->GetOLENode() : nullptr;
786 OSL_ENSURE(pNd, "Impossible");
787 if (pNd)
789 #ifdef OLE_PREVIEW_AS_EMF
790 //Convert this ole2 preview in ww8+ to an EMF for better unicode
791 //support (note that at this moment this breaks StarSymbol
792 //using graphics because I need to embed starsymbol in exported
793 //documents.
794 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
795 pNd->GetpSwAttrSet());
796 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
797 aInlineEscher.WriteOLEFlyFrame(rFly.GetFrameFormat(), 0x401);
798 aInlineEscher.WritePictures();
799 #else
800 // cast away const
801 SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
802 SwOLEObj& rSObj= pOleNd->GetOLEObj();
804 // TODO/LATER: do we need to load object?
805 Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
807 //TODO/LATER: do we really want to use GDIMetafile?!
808 GDIMetaFile aMtf;
809 if ( pGr )
810 aMtf = pGr->GetGDIMetaFile();
812 Size aS(aMtf.GetPrefSize());
813 aMtf.WindStart();
814 aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
815 Size(2880, 2880));
817 WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
818 pNd->GetpSwAttrSet());
819 WriteWindowMetafileBits(rStrm, aMtf);
820 delete pGr;
821 #endif
824 break;
825 case ww8::Frame::eDrawing:
826 case ww8::Frame::eTextBox:
827 case ww8::Frame::eFormControl:
829 #i3958# We only export an empty dummy picture frame here, this is
830 what word does the escher export should contain an anchored to
831 character element which is drawn over this dummy and the whole
832 shebang surrounded with a SHAPE field. This isn't *my* hack :-),
833 it's what word does.
836 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
837 SwBasicEscherEx aInlineEscher(&rStrm, rWrt);
838 aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrameFormat(), 0x401);
840 break;
841 default:
842 OSL_ENSURE(false, "Some inline export not implemented");
843 break;
846 sal_uInt32 nPos2 = rStrm.Tell(); // store the end
847 rStrm.Seek( nPos );
848 rStrm.WriteUInt32(nPos2 - nPos); // patch graphic length in the header
849 rStrm.Seek( nPos2 ); // restore Pos
852 // SwWW8WrGrf::Write() is called after the text.
853 // It writes out all the graphics and remembers the file locations of the graphics,
854 // so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
855 // The search in the attributes for the Magic sal_uLong and patching
856 // happens when writing the attributes. Class SwWW8WrGrf provides with
857 // GetFPos() sequentially the positions
858 void SwWW8WrGrf::Write()
860 SvStream& rStrm = *rWrt.pDataStrm;
861 auto aEnd = maDetails.end();
862 for (auto aIter = maDetails.begin(); aIter != aEnd; ++aIter)
864 sal_uInt32 nPos = rStrm.Tell(); // align to 4 Bytes
865 if( nPos & 0x3 )
866 SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
868 auto aIter2 = std::find(maDetails.begin(), aIter, *aIter);
869 if (aIter2 != aIter)
871 aIter->mnPos = aIter2->mnPos;
873 else
875 aIter->mnPos = rStrm.Tell();
876 WriteGraphicNode(rStrm, *aIter);
881 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */