tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / sw / source / filter / ww8 / wrtww8gr.cxx
blob721cd574be0874cb3fd0cc8b79e989e96441e632
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, rtl::Reference<SotStorage> const& xOleStg,
87 const rtl::Reference<SotStorage>& xObjStg,
88 OUString const& rStorageName, SwOLENode& rOLENd)
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 = rOLENd.GetAspect();
131 rtl::Reference<SdrOle2Obj> pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
132 m_rDoc.getIDocumentDrawModelAccess().GetOrCreateDrawModel(),
133 rStorageName,
134 xObjStg,
135 m_rDoc.GetDocStorage(),
136 aGraph,
137 aRect,
138 tools::Rectangle(),
139 nullptr,
140 nErr,
142 nAspect,
143 m_pWriter->GetBaseURL());
145 if (pRet)
147 uno::Reference< embed::XEmbeddedObject > xObj = rOLENd.GetOLEObj().GetOleRef();
148 if ( xObj.is() )
150 std::unique_ptr<SvStream> pGraphicStream;
151 comphelper::EmbeddedObjectContainer aCnt( m_rDoc.GetDocStorage() );
154 uno::Reference< embed::XEmbedPersist > xPersist(xObj, uno::UNO_QUERY );
155 if (xPersist)
157 // it makes no sense to search the object in the container by reference since the object was created
158 // outside of the container and was not inserted there, only the name makes sense
159 pGraphicStream =
160 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) );
163 catch( const uno::Exception& )
166 OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
167 if ( pGraphicStream && !pGraphicStream->GetError() )
169 Graphic aGr1;
170 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
171 if( rGF.ImportGraphic( aGr1, u"", *pGraphicStream ) == ERRCODE_NONE )
173 Graphic aGr2;
174 pGraphicStream =
175 ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
176 if( pGraphicStream && rGF.ImportGraphic( aGr2, u"", *pGraphicStream ) == ERRCODE_NONE )
178 if ( aGr1 == aGr2 )
179 bGraphicNeeded = false;
186 else
187 bGraphicNeeded = true;
188 return bGraphicNeeded;
191 void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
193 SAL_INFO("sw", "WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
194 sal_uInt8 *pSpecOLE;
195 sal_uInt8 *pDataAdr;
196 short nSize;
197 static sal_uInt8 aSpecOLE_WW8[] = {
198 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
199 0x0a, 0x08, 1, // sprmCFOLE2
200 0x56, 0x08, 1 // sprmCFObj
203 pSpecOLE = aSpecOLE_WW8;
204 nSize = sizeof( aSpecOLE_WW8 );
205 pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
207 rtl::Reference<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
209 if( !xObjStg.is() )
210 return;
212 uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
213 if( !xObj.is() )
214 return;
216 const embed::XEmbeddedObject *pObj = xObj.get();
217 //Don't want to use pointer ids, as is traditional, because we need
218 //to put this into a 32bit value, and on 64bit the bottom bits
219 //might collide and two unrelated ole objects end up considered the
220 //same. Don't want to simply start at 0 which is a special value
221 sal_Int32 nPictureId = SAL_MAX_INT32 - m_aOleMap.size();
222 WW8OleMap::value_type entry = std::make_pair(pObj, nPictureId);
223 std::pair<WW8OleMap::iterator, bool> aRes = m_aOleMap.insert(entry);
224 bool bIsNotDuplicate = aRes.second; //.second is false when element already existed
225 nPictureId = aRes.first->second;
226 Set_UInt32(pDataAdr, nPictureId);
227 OUString sStorageName = "_" + OUString::number( nPictureId );
228 rtl::Reference<SotStorage> xOleStg = xObjStg->OpenSotStorage(sStorageName);
229 if( !xOleStg.is() )
230 return;
233 If this object storage has been written already don't
234 waste time rewriting it
236 if (bIsNotDuplicate)
238 sal_Int64 nAspect = rOLENode.GetAspect();
239 svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
240 m_oOLEExp->ExportOLEObject( aObjRef, *xOleStg );
241 if ( nAspect == embed::Aspects::MSOLE_ICON )
243 OUString aObjInfo( u"\3ObjInfo"_ustr );
244 if ( !xOleStg->IsStream( aObjInfo ) )
246 const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
247 rtl::Reference<SotStorageStream> rObjInfoStream = xOleStg->OpenSotStream(aObjInfo);
248 if ( rObjInfoStream.is() && !rObjInfoStream->GetError() )
250 rObjInfoStream->WriteBytes(pObjInfoData, sizeof(pObjInfoData));
251 xOleStg->Commit();
257 // write as embedded field - the other things will be done
258 // in the escher export
259 OUString sServer = FieldString(ww::eEMBED) + xOleStg->GetUserName() + " ";
261 OutputField(nullptr, ww::eEMBED, sServer, FieldFlags::Start |
262 FieldFlags::CmdStart | FieldFlags::CmdEnd);
264 m_pChpPlc->AppendFkpEntry( Strm().Tell(),
265 nSize, pSpecOLE );
267 bool bEndCR = true;
269 In the word filter we only need a preview image for
270 floating images, and then only (the usual case) if the
271 object doesn't contain enough information to reconstruct
272 what we need.
274 We don't need a graphic for inline objects, so we don't
275 even need the overhead of a graphic in that case.
277 bool bGraphicNeeded = false;
279 if (m_pParentFrame)
281 bGraphicNeeded = true;
283 if (m_pParentFrame->IsInline())
285 const SwAttrSet& rSet =
286 m_pParentFrame->GetFrameFormat().GetAttrSet();
287 bEndCR = false;
288 bGraphicNeeded = TestOleNeedsGraphic(rSet,
289 xOleStg, xObjStg, sStorageName, const_cast<SwOLENode&>(rOLENode));
293 if (!bGraphicNeeded)
294 WriteChar(0x1);
295 else
298 ##897##
299 We need to insert the graphic representation of
300 this object for the inline case, otherwise word
301 has no place to find the dimensions of the ole
302 object, and will not be able to draw it
304 OutGrf(*m_pParentFrame);
307 OutputField(nullptr, ww::eEMBED, OUString(),
308 FieldFlags::End | FieldFlags::Close);
310 if (bEndCR) //No newline in inline case
311 WriteCR();
314 void WW8Export::OutputLinkedOLE( const OUString& rOleId )
316 uno::Reference< embed::XStorage > xDocStg = m_rDoc.GetDocStorage();
317 uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( u"OLELinks"_ustr, embed::ElementModes::READ );
318 rtl::Reference<SotStorage> xObjSrc = SotStorage::OpenOLEStorage( xOleStg, rOleId, StreamMode::READ );
320 rtl::Reference<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
322 if( !(xObjStg.is() && xObjSrc.is()) )
323 return;
325 rtl::Reference<SotStorage> xOleDst = xObjStg->OpenSotStorage(rOleId);
326 if ( xOleDst.is() )
327 xObjSrc->CopyTo( xOleDst.get() );
329 if ( xOleDst->GetError( ) )
330 return;
332 xOleDst->Commit();
334 // Output the cPicLocation attribute
335 std::unique_ptr<ww::bytes> pBuf( new ww::bytes );
336 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CPicLocation::val );
337 SwWW8Writer::InsUInt32( *pBuf, o3tl::toInt32(rOleId.subView( 1 )) );
339 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFOle2::val );
340 pBuf->push_back( 1 );
342 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFSpec::val );
343 pBuf->push_back( 1 );
345 SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFObj::val );
346 pBuf->push_back( 1 );
348 m_pChpPlc->AppendFkpEntry( Strm().Tell(), pBuf->size(), pBuf->data() );
351 void WW8Export::OutGrf(const ww8::Frame &rFrame)
353 //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
354 //will be exported to ensure the fidelity
355 const SwFormatURL& rURL = rFrame.GetFrameFormat().GetAttrSet().GetURL();
356 bool bURLStarted = false;
357 if( !rURL.GetURL().isEmpty() && rFrame.GetWriterType() == ww8::Frame::eGraphic)
359 bURLStarted = true;
360 m_pAttrOutput->StartURL( rURL.GetURL(), rURL.GetTargetFrameName() );
363 // Store the graphic settings in GrfNode so they may be written-out later
364 m_pGrf->Insert(rFrame);
366 m_pChpPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
367 m_pO->clear();
369 // #i29408#
370 // linked, as-character anchored graphics have to be exported as fields.
371 const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
372 ? rFrame.GetContent()->GetGrfNode() : nullptr;
373 if ( pGrfNd && pGrfNd->IsLinkedFile() )
375 OUString sStr;
376 pGrfNd->GetFileFilterNms(&sStr, nullptr);
377 sStr = FieldString(ww::eINCLUDEPICTURE) + " \"" + sStr + "\" \\d";
379 OutputField( nullptr, ww::eINCLUDEPICTURE, sStr,
380 FieldFlags::Start | FieldFlags::CmdStart | FieldFlags::CmdEnd );
383 WriteChar( char(1) ); // paste graphic symbols in the main text
385 sal_uInt8 aArr[ 18 ];
386 sal_uInt8* pArr = aArr;
388 const SwFrameFormat &rFlyFormat = rFrame.GetFrameFormat();
389 const RndStdIds eAn = rFlyFormat.GetAttrSet().GetAnchor(false).GetAnchorId();
390 if (eAn == RndStdIds::FLY_AS_CHAR)
392 sal_Int16 eVert = rFlyFormat.GetVertOrient().GetVertOrient();
393 if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
395 bool bVert = false;
396 //The default for word in vertical text mode is to center,
397 //otherwise a sub/super script hack is employed
398 if (auto pTextNd = dynamic_cast< const SwContentNode *>( m_pOutFormatNode ) )
400 SwPosition aPos(*pTextNd);
401 bVert = m_rDoc.IsInVerticalText(aPos);
403 if (!bVert)
405 SwTwips nHeight = rFlyFormat.GetFrameSize().GetHeight();
406 nHeight/=20; //nHeight was in twips, want it in half points, but
407 //then half of total height.
408 tools::Long nFontHeight = GetItem(RES_CHRATR_FONTSIZE).GetHeight();
409 nHeight-=nFontHeight/20;
411 Set_UInt16( pArr, NS_sprm::CHpsPos::val );
412 Set_UInt16( pArr, - static_cast<sal_Int16>(nHeight));
417 // sprmCFSpec
418 Set_UInt16( pArr, 0x855 );
419 Set_UInt8( pArr, 1 );
421 // sprmCPicLocation
422 Set_UInt16( pArr, NS_sprm::CPicLocation::val );
423 Set_UInt32( pArr, GRF_MAGIC_321 );
425 // vary Magic, so that different graphic attributes will not be merged
426 static sal_uInt8 nAttrMagicIdx = 0;
427 --pArr;
428 Set_UInt8( pArr, nAttrMagicIdx++ );
429 m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
431 // #i75464#
432 // Check, if graphic isn't exported as-character anchored.
433 // Otherwise, an additional paragraph is exported for a graphic, which is
434 // forced to be treated as inline, because it's anchored inside another frame.
435 if ( !rFrame.IsInline() &&
436 ( (eAn == RndStdIds::FLY_AT_PARA) ||
437 (eAn == RndStdIds::FLY_AT_PAGE) ) )
439 WriteChar( char(0x0d) ); // close the surrounding frame with CR
441 static sal_uInt8 nSty[2] = { 0, 0 };
442 m_pO->insert( m_pO->end(), nSty, nSty+2 ); // Style #0
443 bool bOldGrf = m_bOutGrf;
444 m_bOutGrf = true;
446 OutputFormat( rFrame.GetFrameFormat(), false, false, true ); // Fly-Attrs
448 m_bOutGrf = bOldGrf;
449 m_pPapPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
450 m_pO->clear();
452 // #i29408#
453 // linked, as-character anchored graphics have to be exported as fields.
454 else if ( pGrfNd && pGrfNd->IsLinkedFile() )
456 OutputField( nullptr, ww::eINCLUDEPICTURE, OUString(), FieldFlags::Close );
458 //Added for i120568,the hyperlink info within a graphic whose anchor type is
459 //"As character" will be exported to ensure the fidelity
460 if( bURLStarted )
461 m_pAttrOutput->EndURL(false);
464 void SwWW8WrGrf::Insert(const ww8::Frame &rFly)
466 const Size aSize( rFly.GetLayoutSize() );
467 const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
468 const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
469 maDetails.emplace_back(rFly, nWidth, nHeight);
472 void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const ww8::Frame &rFly,
473 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
475 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
476 sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
478 // write Crop-Attribute content in Header ( if available )
479 const SwCropGrf* pCropItem;
480 if (pAttrSet && (pCropItem
481 = pAttrSet->GetItemIfSet(RES_GRFATR_CROPGRF, false)))
483 nCropL = static_cast<sal_Int16>(pCropItem->GetLeft());
484 nCropR = static_cast<sal_Int16>(pCropItem->GetRight());
485 nCropT = static_cast<sal_Int16>(pCropItem->GetTop());
486 nCropB = static_cast<sal_Int16>(pCropItem->GetBottom());
487 nXSizeAdd = nXSizeAdd - static_cast<sal_Int16>( pCropItem->GetLeft() + pCropItem->GetRight() );
488 nYSizeAdd = nYSizeAdd - static_cast<sal_Int16>( pCropItem->GetTop() + pCropItem->GetBottom() );
491 Size aGrTwipSz(rFly.GetSize());
492 sal_uInt16 nHdrLen = 0x44;
494 sal_uInt8 aArr[ 0x44 ] = { 0 };
496 sal_uInt8* pArr = aArr + 0x2E; // Do borders first
498 const SwAttrSet& rAttrSet = rFly.GetFrameFormat().GetAttrSet();
499 if (const SvxBoxItem* pBox = rAttrSet.GetItemIfSet(RES_BOX, false))
501 bool bShadow = false; // Shadow ?
502 if (const SvxShadowItem* pSI = rAttrSet.GetItem<SvxShadowItem>(RES_SHADOW))
504 bShadow = (pSI->GetLocation() != SvxShadowLocation::NONE) &&
505 (pSI->GetWidth() != 0);
508 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
509 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
510 for(const SvxBoxItemLine & i : aLnArr)
512 const ::editeng::SvxBorderLine* pLn = pBox->GetLine( i );
513 WW8_BRC aBrc;
514 if (pLn)
516 WW8_BRCVer9 aBrc90 = WW8Export::TranslateBorderLine( *pLn,
517 pBox->GetDistance( i ), bShadow );
518 sal_uInt8 ico = msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
519 aBrc90.cv()));
520 aBrc = WW8_BRC(aBrc90.dptLineWidth(), aBrc90.brcType(), ico,
521 aBrc90.dptSpace(), aBrc90.fShadow(), aBrc90.fFrame());
524 // use importer logic to determine how large the exported
525 // border will really be in word and adjust accordingly
526 short nSpacing;
527 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
528 switch (i)
530 case SvxBoxItemLine::TOP:
531 case SvxBoxItemLine::BOTTOM:
532 nHeight -= bShadow ? nThick*2 : nThick;
533 nHeight = nHeight - nSpacing;
534 break;
535 case SvxBoxItemLine::LEFT:
536 case SvxBoxItemLine::RIGHT:
537 default:
538 nWidth -= bShadow ? nThick*2 : nThick;
539 nWidth = nWidth - nSpacing;
540 break;
542 memcpy( pArr, &aBrc.aBits1, 2);
543 pArr+=2;
545 memcpy( pArr, &aBrc.aBits2, 2);
546 pArr+=2;
550 pArr = aArr + 4; // skip lcb
551 Set_UInt16( pArr, nHdrLen ); // set cbHeader
553 Set_UInt16( pArr, mm ); // set mm
556 Just in case our original size is too big to fit inside a ushort we can
557 substitute the final size and lose on retaining the scaling factor but
558 still keep the correct display size anyway.
560 const bool bIsSubstitutedSize = (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) ||
561 aGrTwipSz.IsEmpty();
562 if ( bIsSubstitutedSize )
564 aGrTwipSz.setWidth( nWidth );
565 aGrTwipSz.setHeight( nHeight );
567 using namespace sw::types;
568 // set xExt & yExt
569 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
570 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
571 pArr += 16;
572 // skip hMF & rcWinMF
573 // set dxaGoal & dyaGoal
574 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
575 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
577 if ( aGrTwipSz.Width() + nXSizeAdd ) // set mx
579 if ( !bIsSubstitutedSize )
581 const double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd );
582 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
584 else
586 Set_UInt16( pArr, 1000 );
589 else
591 pArr += 2;
594 if ( aGrTwipSz.Height() + nYSizeAdd ) // set my
596 if ( !bIsSubstitutedSize )
598 const double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
599 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
601 else
603 Set_UInt16( pArr, 1000 );
606 else
608 pArr += 2;
611 if ( !bIsSubstitutedSize )
613 Set_UInt16( pArr, nCropL ); // set dxaCropLeft
614 Set_UInt16( pArr, nCropT ); // set dyaCropTop
615 Set_UInt16( pArr, nCropR ); // set dxaCropRight
616 Set_UInt16( pArr, nCropB ); // set dyaCropBottom
619 rStrm.WriteBytes(aArr, nHdrLen);
622 void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd,
623 const ww8::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
625 if (rGrfNd.IsLinkedFile()) // Linked File
627 OUString aFileN;
628 rGrfNd.GetFileFilterNms( &aFileN, nullptr );
630 sal_uInt16 const mm = 94; // 94 = BMP, GIF
632 WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
633 rGrfNd.GetpSwAttrSet());
634 rStrm.WriteUChar( aFileN.getLength() ); // write Pascal-String
635 SwWW8Writer::WriteString8(rStrm, aFileN, false,
636 RTL_TEXTENCODING_MS_1252);
638 else // Embedded File or DDE or something like that
640 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
641 rGrfNd.GetpSwAttrSet());
642 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
643 aInlineEscher.WriteGrfFlyFrame(rFly.GetFrameFormat(), 0x401);
644 aInlineEscher.WritePictures();
647 //For i120928,export graphic info of bullet
648 void SwWW8WrGrf::WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf,
649 sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
651 sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
653 Size aGrTwipSz(rGrf.GetPrefSize());
654 sal_uInt16 nHdrLen = 0x44;
656 sal_uInt8 aArr[ 0x44 ] = { 0 };
658 sal_uInt8* pArr = aArr + 0x2E; //Do borders first
660 static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
661 SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
662 for(const SvxBoxItemLine & i : aLnArr)
664 WW8_BRC aBrc;
666 short nSpacing;
667 short nThick = aBrc.DetermineBorderProperties(&nSpacing);
668 switch (i)
670 case SvxBoxItemLine::TOP:
671 case SvxBoxItemLine::BOTTOM:
672 nHeight -= nThick;
673 nHeight = nHeight - nSpacing;
674 break;
675 case SvxBoxItemLine::LEFT:
676 case SvxBoxItemLine::RIGHT:
677 default:
678 nWidth -= nThick;
679 nWidth = nWidth - nSpacing;
680 break;
682 memcpy( pArr, &aBrc.aBits1, 2);
683 pArr+=2;
685 memcpy(pArr, &aBrc.aBits2, 2);
686 pArr+=2;
689 pArr = aArr + 4; //skip lcb
690 Set_UInt16( pArr, nHdrLen ); // set cbHeader
692 Set_UInt16( pArr, mm ); // set mm
694 if ( (convertTwipToMm100(aGrTwipSz.Width()) > USHRT_MAX ) || ( convertTwipToMm100(aGrTwipSz.Height()) > USHRT_MAX )
695 || aGrTwipSz.IsEmpty() )
697 aGrTwipSz.setWidth( nWidth );
698 aGrTwipSz.setHeight( nHeight );
700 using namespace sw::types;
701 // set xExt & yExt
702 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
703 Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
704 pArr += 16;
705 // skip hMF & rcWinMF
706 // set dxaGoal & dyaGoal
707 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
708 Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
710 if( aGrTwipSz.Width() + nXSizeAdd ) // set mx
712 double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
713 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
715 else
716 pArr += 2;
718 if( aGrTwipSz.Height() + nYSizeAdd ) // set my
720 double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
721 Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
723 else
724 pArr += 2;
726 Set_UInt16( pArr, 0 ); // set dxaCropLeft
727 Set_UInt16( pArr, 0 ); // set dyaCropTop
728 Set_UInt16( pArr, 0 ); // set dxaCropRight
729 Set_UInt16( pArr, 0 ); // set dyaCropBottom
731 rStrm.WriteBytes(aArr, nHdrLen);
734 void SwWW8WrGrf::WriteGrfForBullet(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
736 WritePICBulletFHeader(rStrm,rGrf, 0x64,nWidth,nHeight);
737 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
738 aInlineEscher.WriteGrfBullet(rGrf);
739 aInlineEscher.WritePictures();
742 void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem)
744 sal_uInt16 nWidth = rItem.mnWid;
745 sal_uInt16 nHeight = rItem.mnHei;
746 sal_uInt64 nPos = rStrm.Tell(); // store start of graphic
748 const ww8::Frame &rFly = rItem.maFly;
749 switch (rFly.GetWriterType())
751 case ww8::Frame::eGraphic:
753 const SwNode *pNode = rItem.maFly.GetContent();
754 const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : nullptr;
755 OSL_ENSURE(pNd, "Impossible");
756 if (pNd)
757 WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
759 break;
760 //For i120928,add branch to export graphic of bullet
761 case ww8::Frame::eBulletGrf:
763 if (rItem.maFly.HasGraphic())
765 const Graphic& rGrf = rItem.maFly.GetGraphic();
766 WriteGrfForBullet(rStrm, rGrf, nWidth, nHeight);
769 break;
771 case ww8::Frame::eOle:
773 const SwNode *pNode = rItem.maFly.GetContent();
774 const SwOLENode *pNd = pNode ? pNode->GetOLENode() : nullptr;
775 OSL_ENSURE(pNd, "Impossible");
776 if (pNd)
778 #ifdef OLE_PREVIEW_AS_EMF
779 //Convert this ole2 preview in ww8+ to an EMF for better unicode
780 //support (note that at this moment this breaks StarSymbol
781 //using graphics because I need to embed starsymbol in exported
782 //documents.
783 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
784 pNd->GetpSwAttrSet());
785 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
786 aInlineEscher.WriteOLEFlyFrame(rFly.GetFrameFormat(), 0x401);
787 aInlineEscher.WritePictures();
788 #else
789 // cast away const
790 SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
791 SwOLEObj& rSObj= pOleNd->GetOLEObj();
793 // TODO/LATER: do we need to load object?
794 Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
796 //TODO/LATER: do we really want to use GDIMetafile?!
797 GDIMetaFile aMtf;
798 if ( pGr )
799 aMtf = pGr->GetGDIMetaFile();
801 Size aS(aMtf.GetPrefSize());
802 aMtf.WindStart();
803 aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
804 Size(2880, 2880));
806 WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
807 pNd->GetpSwAttrSet());
808 WriteWindowMetafileBits(rStrm, aMtf);
809 delete pGr;
810 #endif
813 break;
814 case ww8::Frame::eDrawing:
815 case ww8::Frame::eTextBox:
816 case ww8::Frame::eFormControl:
818 #i3958# We only export an empty dummy picture frame here, this is
819 what word does the escher export should contain an anchored to
820 character element which is drawn over this dummy and the whole
821 shebang surrounded with a SHAPE field. This isn't *my* hack :-),
822 it's what word does.
825 WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
826 SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
827 aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrameFormat(), 0x401);
829 break;
830 default:
831 OSL_ENSURE(false, "Some inline export not implemented");
832 break;
835 sal_uInt64 nPos2 = rStrm.Tell(); // store the end
836 rStrm.Seek( nPos );
837 rStrm.WriteUInt32(nPos2 - nPos); // patch graphic length in the header
838 rStrm.Seek( nPos2 ); // restore Pos
841 // SwWW8WrGrf::Write() is called after the text.
842 // It writes out all the graphics and remembers the file locations of the graphics,
843 // so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
844 // The search in the attributes for the Magic sal_uLong and patching
845 // happens when writing the attributes. Class SwWW8WrGrf provides with
846 // GetFPos() sequentially the positions
847 void SwWW8WrGrf::Write()
849 SvStream& rStrm = *m_rWrt.m_pDataStrm;
850 auto aEnd = maDetails.end();
851 for (auto aIter = maDetails.begin(); aIter != aEnd; ++aIter)
853 sal_uInt64 nPos = rStrm.Tell(); // align to 4 Bytes
854 if( nPos & 0x3 )
855 SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
857 auto aIter2 = std::find(maDetails.begin(), aIter, *aIter);
858 if (aIter2 != aIter)
860 aIter->mnPos = aIter2->mnPos;
862 else
864 aIter->mnPos = rStrm.Tell();
865 WriteGraphicNode(rStrm, *aIter);
870 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */