android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / ww8 / wrtww8gr.cxx
blob6ec9cc6e8f08e910a03bb94b32be862df6090eb8
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 <fmtfsize.hxx>
46 #include <fmtornt.hxx>
48 #include "sprmids.hxx"
50 #include <doc.hxx>
51 #include "writerhelper.hxx"
52 #include "writerwordglue.hxx"
53 #include "ww8struc.hxx"
54 #include "wrtww8.hxx"
55 #include "ww8par.hxx"
56 #include "escher.hxx"
57 //Added for i120568
58 #include "ww8attributeoutput.hxx"
59 #include <fmturl.hxx>
61 #include <IDocumentDrawModelAccess.hxx>
62 #include <drawdoc.hxx>
63 #include <o3tl/string_view.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 m_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 rtl::Reference<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, u"", *pGraphicStream ) == ERRCODE_NONE )
175 Graphic aGr2;
176 pGraphicStream =
177 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
178 if( pGraphicStream && rGF.ImportGraphic( aGr2, u"", *pGraphicStream ) == ERRCODE_NONE )
180 if ( aGr1 == aGr2 )
181 bGraphicNeeded = false;
188 else
189 bGraphicNeeded = true;
190 return bGraphicNeeded;
193 void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
195 SAL_INFO("sw", "WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
196 sal_uInt8 *pSpecOLE;
197 sal_uInt8 *pDataAdr;
198 short nSize;
199 static sal_uInt8 aSpecOLE_WW8[] = {
200 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
201 0x0a, 0x08, 1, // sprmCFOLE2
202 0x56, 0x08, 1 // sprmCFObj
205 pSpecOLE = aSpecOLE_WW8;
206 nSize = sizeof( aSpecOLE_WW8 );
207 pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
209 tools::SvRef<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
211 if( !xObjStg.is() )
212 return;
214 uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
215 if( !xObj.is() )
216 return;
218 const embed::XEmbeddedObject *pObj = xObj.get();
219 //Don't want to use pointer ids, as is traditional, because we need
220 //to put this into a 32bit value, and on 64bit the bottom bits
221 //might collide and two unrelated ole objects end up considered the
222 //same. Don't want to simply start at 0 which is a special value
223 sal_Int32 nPictureId = SAL_MAX_INT32 - m_aOleMap.size();
224 WW8OleMap::value_type entry = std::make_pair(pObj, nPictureId);
225 std::pair<WW8OleMap::iterator, bool> aRes = m_aOleMap.insert(entry);
226 bool bIsNotDuplicate = aRes.second; //.second is false when element already existed
227 nPictureId = aRes.first->second;
228 Set_UInt32(pDataAdr, nPictureId);
229 OUString sStorageName = "_" + OUString::number( nPictureId );
230 tools::SvRef<SotStorage> xOleStg = xObjStg->OpenSotStorage( sStorageName );
231 if( !xOleStg.is() )
232 return;
235 If this object storage has been written already don't
236 waste time rewriting it
238 if (bIsNotDuplicate)
240 sal_Int64 nAspect = rOLENode.GetAspect();
241 svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
242 m_oOLEExp->ExportOLEObject( aObjRef, *xOleStg );
243 if ( nAspect == embed::Aspects::MSOLE_ICON )
245 OUString aObjInfo( "\3ObjInfo" );
246 if ( !xOleStg->IsStream( aObjInfo ) )
248 const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
249 tools::SvRef<SotStorageStream> rObjInfoStream = xOleStg->OpenSotStream( aObjInfo );
250 if ( rObjInfoStream.is() && !rObjInfoStream->GetError() )
252 rObjInfoStream->WriteBytes(pObjInfoData, sizeof(pObjInfoData));
253 xOleStg->Commit();
259 // write as embedded field - the other things will be done
260 // in the escher export
261 OUString sServer = FieldString(ww::eEMBED) + xOleStg->GetUserName() + " ";
263 OutputField(nullptr, ww::eEMBED, sServer, FieldFlags::Start |
264 FieldFlags::CmdStart | FieldFlags::CmdEnd);
266 m_pChpPlc->AppendFkpEntry( Strm().Tell(),
267 nSize, pSpecOLE );
269 bool bEndCR = true;
271 In the word filter we only need a preview image for
272 floating images, and then only (the usual case) if the
273 object doesn't contain enough information to reconstruct
274 what we need.
276 We don't need a graphic for inline objects, so we don't
277 even need the overhead of a graphic in that case.
279 bool bGraphicNeeded = false;
281 if (m_pParentFrame)
283 bGraphicNeeded = true;
285 if (m_pParentFrame->IsInline())
287 const SwAttrSet& rSet =
288 m_pParentFrame->GetFrameFormat().GetAttrSet();
289 bEndCR = false;
290 bGraphicNeeded = TestOleNeedsGraphic(rSet,
291 xOleStg, xObjStg, sStorageName, const_cast<SwOLENode*>(&rOLENode));
295 if (!bGraphicNeeded)
296 WriteChar(0x1);
297 else
300 ##897##
301 We need to insert the graphic representation of
302 this object for the inline case, otherwise word
303 has no place to find the dimensions of the ole
304 object, and will not be able to draw it
306 OutGrf(*m_pParentFrame);
309 OutputField(nullptr, ww::eEMBED, OUString(),
310 FieldFlags::End | FieldFlags::Close);
312 if (bEndCR) //No newline in inline case
313 WriteCR();
316 void WW8Export::OutputLinkedOLE( const OUString& rOleId )
318 uno::Reference< embed::XStorage > xDocStg = m_rDoc.GetDocStorage();
319 uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( "OLELinks", embed::ElementModes::READ );
320 tools::SvRef<SotStorage> xObjSrc = SotStorage::OpenOLEStorage( xOleStg, rOleId, StreamMode::READ );
322 tools::SvRef<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
324 if( !(xObjStg.is() && xObjSrc.is()) )
325 return;
327 tools::SvRef<SotStorage> xOleDst = xObjStg->OpenSotStorage( rOleId );
328 if ( xOleDst.is() )
329 xObjSrc->CopyTo( xOleDst.get() );
331 if ( xOleDst->GetError( ) )
332 return;
334 xOleDst->Commit();
336 // Output the cPicLocation attribute
337 std::unique_ptr<ww::bytes> pBuf( new ww::bytes );
338 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CPicLocation::val );
339 SwWW8Writer::InsUInt32( *pBuf, o3tl::toInt32(rOleId.subView( 1 )) );
341 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFOle2::val );
342 pBuf->push_back( 1 );
344 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFSpec::val );
345 pBuf->push_back( 1 );
347 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFObj::val );
348 pBuf->push_back( 1 );
350 m_pChpPlc->AppendFkpEntry( Strm().Tell(), pBuf->size(), pBuf->data() );
353 void WW8Export::OutGrf(const ww8::Frame &rFrame)
355 //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
356 //will be exported to ensure the fidelity
357 const SwFormatURL& rURL = rFrame.GetFrameFormat().GetAttrSet().GetURL();
358 bool bURLStarted = false;
359 if( !rURL.GetURL().isEmpty() && rFrame.GetWriterType() == ww8::Frame::eGraphic)
361 bURLStarted = true;
362 m_pAttrOutput->StartURL( rURL.GetURL(), rURL.GetTargetFrameName() );
365 // Store the graphic settings in GrfNode so they may be written-out later
366 m_pGrf->Insert(rFrame);
368 m_pChpPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
369 m_pO->clear();
371 // #i29408#
372 // linked, as-character anchored graphics have to be exported as fields.
373 const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
374 ? rFrame.GetContent()->GetGrfNode() : nullptr;
375 if ( pGrfNd && pGrfNd->IsLinkedFile() )
377 OUString sStr;
378 pGrfNd->GetFileFilterNms(&sStr, nullptr);
379 sStr = FieldString(ww::eINCLUDEPICTURE) + " \"" + sStr + "\" \\d";
381 OutputField( nullptr, ww::eINCLUDEPICTURE, sStr,
382 FieldFlags::Start | FieldFlags::CmdStart | FieldFlags::CmdEnd );
385 WriteChar( char(1) ); // paste graphic symbols in the main text
387 sal_uInt8 aArr[ 18 ];
388 sal_uInt8* pArr = aArr;
390 const SwFrameFormat &rFlyFormat = rFrame.GetFrameFormat();
391 const RndStdIds eAn = rFlyFormat.GetAttrSet().GetAnchor(false).GetAnchorId();
392 if (eAn == RndStdIds::FLY_AS_CHAR)
394 sal_Int16 eVert = rFlyFormat.GetVertOrient().GetVertOrient();
395 if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
397 bool bVert = false;
398 //The default for word in vertical text mode is to center,
399 //otherwise a sub/super script hack is employed
400 if (auto pTextNd = dynamic_cast< const SwContentNode *>( m_pOutFormatNode ) )
402 SwPosition aPos(*pTextNd);
403 bVert = m_rDoc.IsInVerticalText(aPos);
405 if (!bVert)
407 SwTwips nHeight = rFlyFormat.GetFrameSize().GetHeight();
408 nHeight/=20; //nHeight was in twips, want it in half points, but
409 //then half of total height.
410 tools::Long nFontHeight = GetItem(RES_CHRATR_FONTSIZE).GetHeight();
411 nHeight-=nFontHeight/20;
413 Set_UInt16( pArr, NS_sprm::CHpsPos::val );
414 Set_UInt16( pArr, - static_cast<sal_Int16>(nHeight));
419 // sprmCFSpec
420 Set_UInt16( pArr, 0x855 );
421 Set_UInt8( pArr, 1 );
423 // sprmCPicLocation
424 Set_UInt16( pArr, NS_sprm::CPicLocation::val );
425 Set_UInt32( pArr, GRF_MAGIC_321 );
427 // vary Magic, so that different graphic attributes will not be merged
428 static sal_uInt8 nAttrMagicIdx = 0;
429 --pArr;
430 Set_UInt8( pArr, nAttrMagicIdx++ );
431 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
433 // #i75464#
434 // Check, if graphic isn't exported as-character anchored.
435 // Otherwise, an additional paragraph is exported for a graphic, which is
436 // forced to be treated as inline, because it's anchored inside another frame.
437 if ( !rFrame.IsInline() &&
438 ( (eAn == RndStdIds::FLY_AT_PARA) ||
439 (eAn == RndStdIds::FLY_AT_PAGE) ) )
441 WriteChar( char(0x0d) ); // close the surrounding frame with CR
443 static sal_uInt8 nSty[2] = { 0, 0 };
444 m_pO->insert( m_pO->end(), nSty, nSty+2 ); // Style #0
445 bool bOldGrf = m_bOutGrf;
446 m_bOutGrf = true;
448 OutputFormat( rFrame.GetFrameFormat(), false, false, true ); // Fly-Attrs
450 m_bOutGrf = bOldGrf;
451 m_pPapPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
452 m_pO->clear();
454 // #i29408#
455 // linked, as-character anchored graphics have to be exported as fields.
456 else if ( pGrfNd && pGrfNd->IsLinkedFile() )
458 OutputField( nullptr, ww::eINCLUDEPICTURE, OUString(), FieldFlags::Close );
460 //Added for i120568,the hyperlink info within a graphic whose anchor type is
461 //"As character" will be exported to ensure the fidelity
462 if( bURLStarted )
463 m_pAttrOutput->EndURL(false);
466 void SwWW8WrGrf::Insert(const ww8::Frame &rFly)
468 const Size aSize( rFly.GetLayoutSize() );
469 const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
470 const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
471 maDetails.emplace_back(rFly, nWidth, nHeight);
474 void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const ww8::Frame &rFly,
475 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
477 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
478 sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
480 // write Crop-Attribute content in Header ( if available )
481 const SwCropGrf* pCropItem;
482 if (pAttrSet && (pCropItem
483 = pAttrSet->GetItemIfSet(RES_GRFATR_CROPGRF, false)))
485 nCropL = static_cast<sal_Int16>(pCropItem->GetLeft());
486 nCropR = static_cast<sal_Int16>(pCropItem->GetRight());
487 nCropT = static_cast<sal_Int16>(pCropItem->GetTop());
488 nCropB = static_cast<sal_Int16>(pCropItem->GetBottom());
489 nXSizeAdd = nXSizeAdd - static_cast<sal_Int16>( pCropItem->GetLeft() + pCropItem->GetRight() );
490 nYSizeAdd = nYSizeAdd - static_cast<sal_Int16>( pCropItem->GetTop() + pCropItem->GetBottom() );
493 Size aGrTwipSz(rFly.GetSize());
494 sal_uInt16 nHdrLen = 0x44;
496 sal_uInt8 aArr[ 0x44 ] = { 0 };
498 sal_uInt8* pArr = aArr + 0x2E; // Do borders first
500 const SwAttrSet& rAttrSet = rFly.GetFrameFormat().GetAttrSet();
501 if (const SvxBoxItem* pBox = rAttrSet.GetItemIfSet(RES_BOX, false))
503 bool bShadow = false; // Shadow ?
504 if (const SvxShadowItem* pSI = rAttrSet.GetItem<SvxShadowItem>(RES_SHADOW))
506 bShadow = (pSI->GetLocation() != SvxShadowLocation::NONE) &&
507 (pSI->GetWidth() != 0);
510 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
511 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
512 for(const SvxBoxItemLine & i : aLnArr)
514 const ::editeng::SvxBorderLine* pLn = pBox->GetLine( i );
515 WW8_BRC aBrc;
516 if (pLn)
518 WW8_BRCVer9 aBrc90 = WW8Export::TranslateBorderLine( *pLn,
519 pBox->GetDistance( i ), bShadow );
520 sal_uInt8 ico = msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
521 aBrc90.cv()));
522 aBrc = WW8_BRC(aBrc90.dptLineWidth(), aBrc90.brcType(), ico,
523 aBrc90.dptSpace(), aBrc90.fShadow(), aBrc90.fFrame());
526 // use importer logic to determine how large the exported
527 // border will really be in word and adjust accordingly
528 short nSpacing;
529 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
530 switch (i)
532 case SvxBoxItemLine::TOP:
533 case SvxBoxItemLine::BOTTOM:
534 nHeight -= bShadow ? nThick*2 : nThick;
535 nHeight = nHeight - nSpacing;
536 break;
537 case SvxBoxItemLine::LEFT:
538 case SvxBoxItemLine::RIGHT:
539 default:
540 nWidth -= bShadow ? nThick*2 : nThick;
541 nWidth = nWidth - nSpacing;
542 break;
544 memcpy( pArr, &aBrc.aBits1, 2);
545 pArr+=2;
547 memcpy( pArr, &aBrc.aBits2, 2);
548 pArr+=2;
552 pArr = aArr + 4; // skip lcb
553 Set_UInt16( pArr, nHdrLen ); // set cbHeader
555 Set_UInt16( pArr, mm ); // set mm
558 Just in case our original size is too big to fit inside a ushort we can
559 substitute the final size and lose on retaining the scaling factor but
560 still keep the correct display size anyway.
562 const bool bIsSubstitutedSize = (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) ||
563 aGrTwipSz.IsEmpty();
564 if ( bIsSubstitutedSize )
566 aGrTwipSz.setWidth( nWidth );
567 aGrTwipSz.setHeight( nHeight );
569 using namespace sw::types;
570 // set xExt & yExt
571 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
572 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
573 pArr += 16;
574 // skip hMF & rcWinMF
575 // set dxaGoal & dyaGoal
576 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
577 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
579 if ( aGrTwipSz.Width() + nXSizeAdd ) // set mx
581 if ( !bIsSubstitutedSize )
583 const double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd );
584 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
586 else
588 Set_UInt16( pArr, 1000 );
591 else
593 pArr += 2;
596 if ( aGrTwipSz.Height() + nYSizeAdd ) // set my
598 if ( !bIsSubstitutedSize )
600 const double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
601 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
603 else
605 Set_UInt16( pArr, 1000 );
608 else
610 pArr += 2;
613 if ( !bIsSubstitutedSize )
615 Set_UInt16( pArr, nCropL ); // set dxaCropLeft
616 Set_UInt16( pArr, nCropT ); // set dyaCropTop
617 Set_UInt16( pArr, nCropR ); // set dxaCropRight
618 Set_UInt16( pArr, nCropB ); // set dyaCropBottom
621 rStrm.WriteBytes(aArr, nHdrLen);
624 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd,
625 const ww8::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
627 if (rGrfNd.IsLinkedFile()) // Linked File
629 OUString aFileN;
630 rGrfNd.GetFileFilterNms( &aFileN, nullptr );
632 sal_uInt16 const mm = 94; // 94 = BMP, GIF
634 WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
635 rGrfNd.GetpSwAttrSet());
636 rStrm.WriteUChar( aFileN.getLength() ); // write Pascal-String
637 SwWW8Writer::WriteString8(rStrm, aFileN, false,
638 RTL_TEXTENCODING_MS_1252);
640 else // Embedded File or DDE or something like that
642 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
643 rGrfNd.GetpSwAttrSet());
644 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
645 aInlineEscher.WriteGrfFlyFrame(rFly.GetFrameFormat(), 0x401);
646 aInlineEscher.WritePictures();
649 //For i120928,export graphic info of bullet
650 void SwWW8WrGrf::WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf,
651 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
653 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
655 Size aGrTwipSz(rGrf.GetPrefSize());
656 sal_uInt16 nHdrLen = 0x44;
658 sal_uInt8 aArr[ 0x44 ] = { 0 };
660 sal_uInt8* pArr = aArr + 0x2E; //Do borders first
662 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
663 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
664 for(const SvxBoxItemLine & i : aLnArr)
666 WW8_BRC aBrc;
668 short nSpacing;
669 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
670 switch (i)
672 case SvxBoxItemLine::TOP:
673 case SvxBoxItemLine::BOTTOM:
674 nHeight -= nThick;
675 nHeight = nHeight - nSpacing;
676 break;
677 case SvxBoxItemLine::LEFT:
678 case SvxBoxItemLine::RIGHT:
679 default:
680 nWidth -= nThick;
681 nWidth = nWidth - nSpacing;
682 break;
684 memcpy( pArr, &aBrc.aBits1, 2);
685 pArr+=2;
687 memcpy(pArr, &aBrc.aBits2, 2);
688 pArr+=2;
691 pArr = aArr + 4; //skip lcb
692 Set_UInt16( pArr, nHdrLen ); // set cbHeader
694 Set_UInt16( pArr, mm ); // set mm
696 if ( (convertTwipToMm100(aGrTwipSz.Width()) > USHRT_MAX ) || ( convertTwipToMm100(aGrTwipSz.Height()) > USHRT_MAX )
697 || aGrTwipSz.IsEmpty() )
699 aGrTwipSz.setWidth( nWidth );
700 aGrTwipSz.setHeight( nHeight );
702 using namespace sw::types;
703 // set xExt & yExt
704 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
705 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
706 pArr += 16;
707 // skip hMF & rcWinMF
708 // set dxaGoal & dyaGoal
709 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
710 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
712 if( aGrTwipSz.Width() + nXSizeAdd ) // set mx
714 double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
715 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
717 else
718 pArr += 2;
720 if( aGrTwipSz.Height() + nYSizeAdd ) // set my
722 double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
723 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
725 else
726 pArr += 2;
728 Set_UInt16( pArr, 0 ); // set dxaCropLeft
729 Set_UInt16( pArr, 0 ); // set dyaCropTop
730 Set_UInt16( pArr, 0 ); // set dxaCropRight
731 Set_UInt16( pArr, 0 ); // set dyaCropBottom
733 rStrm.WriteBytes(aArr, nHdrLen);
736 void SwWW8WrGrf::WriteGrfForBullet(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
738 WritePICBulletFHeader(rStrm,rGrf, 0x64,nWidth,nHeight);
739 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
740 aInlineEscher.WriteGrfBullet(rGrf);
741 aInlineEscher.WritePictures();
744 void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem)
746 sal_uInt16 nWidth = rItem.mnWid;
747 sal_uInt16 nHeight = rItem.mnHei;
748 sal_uInt32 nPos = rStrm.Tell(); // store start of graphic
750 const ww8::Frame &rFly = rItem.maFly;
751 switch (rFly.GetWriterType())
753 case ww8::Frame::eGraphic:
755 const SwNode *pNode = rItem.maFly.GetContent();
756 const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : nullptr;
757 OSL_ENSURE(pNd, "Impossible");
758 if (pNd)
759 WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
761 break;
762 //For i120928,add branch to export graphic of bullet
763 case ww8::Frame::eBulletGrf:
765 if (rItem.maFly.HasGraphic())
767 const Graphic& rGrf = rItem.maFly.GetGraphic();
768 WriteGrfForBullet(rStrm, rGrf, nWidth, nHeight);
771 break;
773 case ww8::Frame::eOle:
775 const SwNode *pNode = rItem.maFly.GetContent();
776 const SwOLENode *pNd = pNode ? pNode->GetOLENode() : nullptr;
777 OSL_ENSURE(pNd, "Impossible");
778 if (pNd)
780 #ifdef OLE_PREVIEW_AS_EMF
781 //Convert this ole2 preview in ww8+ to an EMF for better unicode
782 //support (note that at this moment this breaks StarSymbol
783 //using graphics because I need to embed starsymbol in exported
784 //documents.
785 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
786 pNd->GetpSwAttrSet());
787 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
788 aInlineEscher.WriteOLEFlyFrame(rFly.GetFrameFormat(), 0x401);
789 aInlineEscher.WritePictures();
790 #else
791 // cast away const
792 SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
793 SwOLEObj& rSObj= pOleNd->GetOLEObj();
795 // TODO/LATER: do we need to load object?
796 Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
798 //TODO/LATER: do we really want to use GDIMetafile?!
799 GDIMetaFile aMtf;
800 if ( pGr )
801 aMtf = pGr->GetGDIMetaFile();
803 Size aS(aMtf.GetPrefSize());
804 aMtf.WindStart();
805 aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
806 Size(2880, 2880));
808 WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
809 pNd->GetpSwAttrSet());
810 WriteWindowMetafileBits(rStrm, aMtf);
811 delete pGr;
812 #endif
815 break;
816 case ww8::Frame::eDrawing:
817 case ww8::Frame::eTextBox:
818 case ww8::Frame::eFormControl:
820 #i3958# We only export an empty dummy picture frame here, this is
821 what word does the escher export should contain an anchored to
822 character element which is drawn over this dummy and the whole
823 shebang surrounded with a SHAPE field. This isn't *my* hack :-),
824 it's what word does.
827 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
828 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
829 aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrameFormat(), 0x401);
831 break;
832 default:
833 OSL_ENSURE(false, "Some inline export not implemented");
834 break;
837 sal_uInt32 nPos2 = rStrm.Tell(); // store the end
838 rStrm.Seek( nPos );
839 rStrm.WriteUInt32(nPos2 - nPos); // patch graphic length in the header
840 rStrm.Seek( nPos2 ); // restore Pos
843 // SwWW8WrGrf::Write() is called after the text.
844 // It writes out all the graphics and remembers the file locations of the graphics,
845 // so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
846 // The search in the attributes for the Magic sal_uLong and patching
847 // happens when writing the attributes. Class SwWW8WrGrf provides with
848 // GetFPos() sequentially the positions
849 void SwWW8WrGrf::Write()
851 SvStream& rStrm = *m_rWrt.m_pDataStrm;
852 auto aEnd = maDetails.end();
853 for (auto aIter = maDetails.begin(); aIter != aEnd; ++aIter)
855 sal_uInt32 nPos = rStrm.Tell(); // align to 4 Bytes
856 if( nPos & 0x3 )
857 SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
859 auto aIter2 = std::find(maDetails.begin(), aIter, *aIter);
860 if (aIter2 != aIter)
862 aIter->mnPos = aIter2->mnPos;
864 else
866 aIter->mnPos = rStrm.Tell();
867 WriteGraphicNode(rStrm, *aIter);
872 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */