summaryrefslogtreecommitdiffstats
path: root/sw/source/filter/ww8/wrtww8gr.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/ww8/wrtww8gr.cxx')
-rw-r--r--sw/source/filter/ww8/wrtww8gr.cxx876
1 files changed, 876 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/wrtww8gr.cxx b/sw/source/filter/ww8/wrtww8gr.cxx
new file mode 100644
index 000000000..3ad22c34e
--- /dev/null
+++ b/sw/source/filter/ww8/wrtww8gr.cxx
@@ -0,0 +1,876 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <sal/log.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <vcl/gdimtf.hxx>
+#include <svl/itemiter.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <svtools/embedhlp.hxx>
+
+#include <hintids.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <filter/msfilter/msoleexp.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <svx/svdoole2.hxx>
+
+#include <unotools/ucbstreamhelper.hxx>
+#include <fmtanchr.hxx>
+#include <ndgrf.hxx>
+#include <frmfmt.hxx>
+#include <grfatr.hxx>
+#include <ndole.hxx>
+#include <fmtfsize.hxx>
+#include <fmtornt.hxx>
+
+#include "sprmids.hxx"
+
+#include <doc.hxx>
+#include "writerhelper.hxx"
+#include "writerwordglue.hxx"
+#include "ww8struc.hxx"
+#include "wrtww8.hxx"
+#include "ww8par.hxx"
+#include "escher.hxx"
+//Added for i120568
+#include "ww8attributeoutput.hxx"
+#include <fmturl.hxx>
+
+#include <IDocumentDrawModelAccess.hxx>
+#include <drawdoc.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+
+// TODO:
+// 5. convert the MapModes that Widows can't handle
+
+// OutGrf () is called for every GrfNode in the document. A PicLocFc-Sprm
+// will be inserted, which contains a magic number instead of an address.
+// The GrfNode-Ptr is saved in Graf-Class (used later for output of
+// the graphic and patching of the PicLocFc attributes)
+
+void WW8Export::OutputGrfNode( const SwGrfNode& /*rNode*/ )
+{
+ SAL_INFO("sw", "WW8Export::OutputGrfNode( const SwGrfNode& )" );
+ OSL_ENSURE( m_pParentFrame, "frame not set!" );
+ if ( m_pParentFrame )
+ {
+ OutGrf( *m_pParentFrame );
+ m_pFib->m_fHasPic = true;
+ }
+}
+
+bool WW8Export::TestOleNeedsGraphic(const SwAttrSet& rSet, tools::SvRef<SotStorage> const& xOleStg,
+ const tools::SvRef<SotStorage>& xObjStg,
+ OUString const& rStorageName, SwOLENode* pOLENd)
+{
+ bool bGraphicNeeded = false;
+ SfxItemIter aIter( rSet );
+ for (auto pItem = aIter.GetCurItem(); !bGraphicNeeded && pItem; pItem = aIter.NextItem())
+ {
+ switch (pItem->Which())
+ {
+ /*
+ For an inline object these properties are irrelevant because they
+ will be the same as the defaults that msword applies in their
+ absence, so if that is all that there is for these inline objects
+ then if there turns out to be enough information in the object
+ itself to regenerate the correct size and preview of the object
+ then we will not need to provide an additional graphics preview in
+ the data stream, which can save a lot of disk space.
+ */
+ case RES_FRM_SIZE:
+ case RES_CNTNT:
+ case RES_VERT_ORIENT:
+ case RES_ANCHOR:
+ break;
+ default:
+ bGraphicNeeded = true;
+ }
+ }
+
+ /*
+ Now we must see if the object contains a preview itself which is equal to
+ the preview that we are currently using. If the graphics are equal then we
+ don't need to store another preview
+ */
+ GDIMetaFile aWMF;
+ tools::Long nX=0,nY=0;
+ if (!bGraphicNeeded && SwWW8ImplReader::ImportOleWMF(xOleStg,aWMF,nX,nY))
+ {
+ // bGraphicNeeded set to true is right / fixes #i51670#.
+ bGraphicNeeded = true;
+ tools::Rectangle aRect( Point(), Size( nX, nY ) );
+ Graphic aGraph(aWMF);
+
+ ErrCode nErr = ERRCODE_NONE;
+ sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
+ if ( pOLENd )
+ nAspect = pOLENd->GetAspect();
+ SdrOle2Obj *pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
+ *m_rDoc.getIDocumentDrawModelAccess().GetOrCreateDrawModel(),
+ rStorageName,
+ xObjStg,
+ m_rDoc.GetDocStorage(),
+ aGraph,
+ aRect,
+ tools::Rectangle(),
+ nullptr,
+ nErr,
+ 0,
+ nAspect,
+ m_pWriter->GetBaseURL());
+
+ if (pRet)
+ {
+ uno::Reference< embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef();
+ if ( xObj.is() )
+ {
+ std::unique_ptr<SvStream> pGraphicStream;
+ comphelper::EmbeddedObjectContainer aCnt( m_rDoc.GetDocStorage() );
+ try
+ {
+ uno::Reference< embed::XEmbedPersist > xPersist(
+ xObj,
+ uno::UNO_QUERY_THROW );
+
+ // it makes no sense to search the object in the container by reference since the object was created
+ // outside of the container and was not inserted there, only the name makes sense
+ pGraphicStream =
+ ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) );
+ }
+ catch( const uno::Exception& )
+ {}
+
+ OSL_ENSURE( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" );
+ if ( pGraphicStream && !pGraphicStream->GetError() )
+ {
+ Graphic aGr1;
+ GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
+ if( rGF.ImportGraphic( aGr1, u"", *pGraphicStream ) == ERRCODE_NONE )
+ {
+ Graphic aGr2;
+ pGraphicStream =
+ ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) );
+ if( pGraphicStream && rGF.ImportGraphic( aGr2, u"", *pGraphicStream ) == ERRCODE_NONE )
+ {
+ if ( aGr1 == aGr2 )
+ bGraphicNeeded = false;
+ }
+ }
+ }
+ }
+
+ // always use SdrObject::Free(...) for SdrObjects (!)
+ SdrObject* pTemp(pRet);
+ SdrObject::Free(pTemp);
+ }
+ }
+ else
+ bGraphicNeeded = true;
+ return bGraphicNeeded;
+}
+
+void WW8Export::OutputOLENode( const SwOLENode& rOLENode )
+{
+ SAL_INFO("sw", "WW8Export::OutputOLENode( const SwOLENode& rOLENode )" );
+ sal_uInt8 *pSpecOLE;
+ sal_uInt8 *pDataAdr;
+ short nSize;
+ static sal_uInt8 aSpecOLE_WW8[] = {
+ 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation
+ 0x0a, 0x08, 1, // sprmCFOLE2
+ 0x56, 0x08, 1 // sprmCFObj
+ };
+
+ pSpecOLE = aSpecOLE_WW8;
+ nSize = sizeof( aSpecOLE_WW8 );
+ pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well.
+
+ tools::SvRef<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
+
+ if( !xObjStg.is() )
+ return;
+
+ uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef());
+ if( !xObj.is() )
+ return;
+
+ const embed::XEmbeddedObject *pObj = xObj.get();
+ //Don't want to use pointer ids, as is traditional, because we need
+ //to put this into a 32bit value, and on 64bit the bottom bits
+ //might collide and two unrelated ole objects end up considered the
+ //same. Don't want to simply start at 0 which is a special value
+ sal_Int32 nPictureId = SAL_MAX_INT32 - m_aOleMap.size();
+ WW8OleMap::value_type entry = std::make_pair(pObj, nPictureId);
+ std::pair<WW8OleMap::iterator, bool> aRes = m_aOleMap.insert(entry);
+ bool bIsNotDuplicate = aRes.second; //.second is false when element already existed
+ nPictureId = aRes.first->second;
+ Set_UInt32(pDataAdr, nPictureId);
+ OUString sStorageName = "_" + OUString::number( nPictureId );
+ tools::SvRef<SotStorage> xOleStg = xObjStg->OpenSotStorage( sStorageName );
+ if( !xOleStg.is() )
+ return;
+
+ /*
+ If this object storage has been written already don't
+ waste time rewriting it
+ */
+ if (bIsNotDuplicate)
+ {
+ sal_Int64 nAspect = rOLENode.GetAspect();
+ svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
+ m_pOLEExp->ExportOLEObject( aObjRef, *xOleStg );
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ {
+ OUString aObjInfo( "\3ObjInfo" );
+ if ( !xOleStg->IsStream( aObjInfo ) )
+ {
+ const sal_uInt8 pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 };
+ tools::SvRef<SotStorageStream> rObjInfoStream = xOleStg->OpenSotStream( aObjInfo );
+ if ( rObjInfoStream.is() && !rObjInfoStream->GetError() )
+ {
+ rObjInfoStream->WriteBytes(pObjInfoData, sizeof(pObjInfoData));
+ xOleStg->Commit();
+ }
+ }
+ }
+ }
+
+ // write as embedded field - the other things will be done
+ // in the escher export
+ OUString sServer = FieldString(ww::eEMBED) + xOleStg->GetUserName() + " ";
+
+ OutputField(nullptr, ww::eEMBED, sServer, FieldFlags::Start |
+ FieldFlags::CmdStart | FieldFlags::CmdEnd);
+
+ m_pChpPlc->AppendFkpEntry( Strm().Tell(),
+ nSize, pSpecOLE );
+
+ bool bEndCR = true;
+ /*
+ In the word filter we only need a preview image for
+ floating images, and then only (the usual case) if the
+ object doesn't contain enough information to reconstruct
+ what we need.
+
+ We don't need a graphic for inline objects, so we don't
+ even need the overhead of a graphic in that case.
+ */
+ bool bGraphicNeeded = false;
+
+ if (m_pParentFrame)
+ {
+ bGraphicNeeded = true;
+
+ if (m_pParentFrame->IsInline())
+ {
+ const SwAttrSet& rSet =
+ m_pParentFrame->GetFrameFormat().GetAttrSet();
+ bEndCR = false;
+ bGraphicNeeded = TestOleNeedsGraphic(rSet,
+ xOleStg, xObjStg, sStorageName, const_cast<SwOLENode*>(&rOLENode));
+ }
+ }
+
+ if (!bGraphicNeeded)
+ WriteChar(0x1);
+ else
+ {
+ /*
+ ##897##
+ We need to insert the graphic representation of
+ this object for the inline case, otherwise word
+ has no place to find the dimensions of the ole
+ object, and will not be able to draw it
+ */
+ OutGrf(*m_pParentFrame);
+ }
+
+ OutputField(nullptr, ww::eEMBED, OUString(),
+ FieldFlags::End | FieldFlags::Close);
+
+ if (bEndCR) //No newline in inline case
+ WriteCR();
+}
+
+void WW8Export::OutputLinkedOLE( const OUString& rOleId )
+{
+ uno::Reference< embed::XStorage > xDocStg = m_rDoc.GetDocStorage();
+ uno::Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( "OLELinks", embed::ElementModes::READ );
+ tools::SvRef<SotStorage> xObjSrc = SotStorage::OpenOLEStorage( xOleStg, rOleId, StreamMode::READ );
+
+ tools::SvRef<SotStorage> xObjStg = GetWriter().GetStorage().OpenSotStorage(SL::aObjectPool);
+
+ if( !(xObjStg.is() && xObjSrc.is()) )
+ return;
+
+ tools::SvRef<SotStorage> xOleDst = xObjStg->OpenSotStorage( rOleId );
+ if ( xOleDst.is() )
+ xObjSrc->CopyTo( xOleDst.get() );
+
+ if ( xOleDst->GetError( ) )
+ return;
+
+ xOleDst->Commit();
+
+ // Output the cPicLocation attribute
+ std::unique_ptr<ww::bytes> pBuf( new ww::bytes );
+ SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CPicLocation::val );
+ SwWW8Writer::InsUInt32( *pBuf, o3tl::toInt32(rOleId.subView( 1 )) );
+
+ SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFOle2::val );
+ pBuf->push_back( 1 );
+
+ SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFSpec::val );
+ pBuf->push_back( 1 );
+
+ SwWW8Writer::InsUInt16( *pBuf, NS_sprm::CFObj::val );
+ pBuf->push_back( 1 );
+
+ m_pChpPlc->AppendFkpEntry( Strm().Tell(), pBuf->size(), pBuf->data() );
+}
+
+void WW8Export::OutGrf(const ww8::Frame &rFrame)
+{
+ //Added for i120568,the hyperlink info within a graphic whose anchor type is "As character"
+ //will be exported to ensure the fidelity
+ const SwFormatURL& rURL = rFrame.GetFrameFormat().GetAttrSet().GetURL();
+ bool bURLStarted = false;
+ if( !rURL.GetURL().isEmpty() && rFrame.GetWriterType() == ww8::Frame::eGraphic)
+ {
+ bURLStarted = true;
+ m_pAttrOutput->StartURL( rURL.GetURL(), rURL.GetTargetFrameName() );
+ }
+
+ // Store the graphic settings in GrfNode so they may be written-out later
+ m_pGrf->Insert(rFrame);
+
+ m_pChpPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
+ m_pO->clear();
+
+ // #i29408#
+ // linked, as-character anchored graphics have to be exported as fields.
+ const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent()
+ ? rFrame.GetContent()->GetGrfNode() : nullptr;
+ if ( pGrfNd && pGrfNd->IsLinkedFile() )
+ {
+ OUString sStr;
+ pGrfNd->GetFileFilterNms(&sStr, nullptr);
+ sStr = FieldString(ww::eINCLUDEPICTURE) + " \"" + sStr + "\" \\d";
+
+ OutputField( nullptr, ww::eINCLUDEPICTURE, sStr,
+ FieldFlags::Start | FieldFlags::CmdStart | FieldFlags::CmdEnd );
+ }
+
+ WriteChar( char(1) ); // paste graphic symbols in the main text
+
+ sal_uInt8 aArr[ 18 ];
+ sal_uInt8* pArr = aArr;
+
+ const SwFrameFormat &rFlyFormat = rFrame.GetFrameFormat();
+ const RndStdIds eAn = rFlyFormat.GetAttrSet().GetAnchor(false).GetAnchorId();
+ if (eAn == RndStdIds::FLY_AS_CHAR)
+ {
+ sal_Int16 eVert = rFlyFormat.GetVertOrient().GetVertOrient();
+ if ((eVert == text::VertOrientation::CHAR_CENTER) || (eVert == text::VertOrientation::LINE_CENTER))
+ {
+ bool bVert = false;
+ //The default for word in vertical text mode is to center,
+ //otherwise a sub/super script hack is employed
+ if (auto pTextNd = dynamic_cast< const SwContentNode *>( m_pOutFormatNode ) )
+ {
+ SwPosition aPos(*pTextNd);
+ bVert = m_rDoc.IsInVerticalText(aPos);
+ }
+ if (!bVert)
+ {
+ SwTwips nHeight = rFlyFormat.GetFrameSize().GetHeight();
+ nHeight/=20; //nHeight was in twips, want it in half points, but
+ //then half of total height.
+ tools::Long nFontHeight = GetItem(RES_CHRATR_FONTSIZE).GetHeight();
+ nHeight-=nFontHeight/20;
+
+ Set_UInt16( pArr, NS_sprm::CHpsPos::val );
+ Set_UInt16( pArr, - static_cast<sal_Int16>(nHeight));
+ }
+ }
+ }
+
+ // sprmCFSpec
+ Set_UInt16( pArr, 0x855 );
+ Set_UInt8( pArr, 1 );
+
+ // sprmCPicLocation
+ Set_UInt16( pArr, NS_sprm::CPicLocation::val );
+ Set_UInt32( pArr, GRF_MAGIC_321 );
+
+ // vary Magic, so that different graphic attributes will not be merged
+ static sal_uInt8 nAttrMagicIdx = 0;
+ --pArr;
+ Set_UInt8( pArr, nAttrMagicIdx++ );
+ m_pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr );
+
+ // #i75464#
+ // Check, if graphic isn't exported as-character anchored.
+ // Otherwise, an additional paragraph is exported for a graphic, which is
+ // forced to be treated as inline, because it's anchored inside another frame.
+ if ( !rFrame.IsInline() &&
+ ( (eAn == RndStdIds::FLY_AT_PARA) ||
+ (eAn == RndStdIds::FLY_AT_PAGE) ) )
+ {
+ WriteChar( char(0x0d) ); // close the surrounding frame with CR
+
+ static sal_uInt8 nSty[2] = { 0, 0 };
+ m_pO->insert( m_pO->end(), nSty, nSty+2 ); // Style #0
+ bool bOldGrf = m_bOutGrf;
+ m_bOutGrf = true;
+
+ OutputFormat( rFrame.GetFrameFormat(), false, false, true ); // Fly-Attrs
+
+ m_bOutGrf = bOldGrf;
+ m_pPapPlc->AppendFkpEntry( Strm().Tell(), m_pO->size(), m_pO->data() );
+ m_pO->clear();
+ }
+ // #i29408#
+ // linked, as-character anchored graphics have to be exported as fields.
+ else if ( pGrfNd && pGrfNd->IsLinkedFile() )
+ {
+ OutputField( nullptr, ww::eINCLUDEPICTURE, OUString(), FieldFlags::Close );
+ }
+ //Added for i120568,the hyperlink info within a graphic whose anchor type is
+ //"As character" will be exported to ensure the fidelity
+ if( bURLStarted )
+ m_pAttrOutput->EndURL(false);
+}
+
+void SwWW8WrGrf::Insert(const ww8::Frame &rFly)
+{
+ const Size aSize( rFly.GetLayoutSize() );
+ const sal_uInt16 nWidth = static_cast< sal_uInt16 >(aSize.Width());
+ const sal_uInt16 nHeight = static_cast< sal_uInt16 >(aSize.Height());
+ maDetails.emplace_back(rFly, nWidth, nHeight);
+}
+
+void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const ww8::Frame &rFly,
+ sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight, const SwAttrSet* pAttrSet)
+{
+ sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
+ sal_Int16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0;
+
+ // write Crop-Attribute content in Header ( if available )
+ const SwCropGrf* pCropItem;
+ if (pAttrSet && (pCropItem
+ = pAttrSet->GetItemIfSet(RES_GRFATR_CROPGRF, false)))
+ {
+ nCropL = static_cast<sal_Int16>(pCropItem->GetLeft());
+ nCropR = static_cast<sal_Int16>(pCropItem->GetRight());
+ nCropT = static_cast<sal_Int16>(pCropItem->GetTop());
+ nCropB = static_cast<sal_Int16>(pCropItem->GetBottom());
+ nXSizeAdd = nXSizeAdd - static_cast<sal_Int16>( pCropItem->GetLeft() + pCropItem->GetRight() );
+ nYSizeAdd = nYSizeAdd - static_cast<sal_Int16>( pCropItem->GetTop() + pCropItem->GetBottom() );
+ }
+
+ Size aGrTwipSz(rFly.GetSize());
+ sal_uInt16 nHdrLen = 0x44;
+
+ sal_uInt8 aArr[ 0x44 ] = { 0 };
+
+ sal_uInt8* pArr = aArr + 0x2E; // Do borders first
+
+ const SwAttrSet& rAttrSet = rFly.GetFrameFormat().GetAttrSet();
+ if (const SvxBoxItem* pBox = rAttrSet.GetItemIfSet(RES_BOX, false))
+ {
+ bool bShadow = false; // Shadow ?
+ if (const SvxShadowItem* pSI = rAttrSet.GetItem<SvxShadowItem>(RES_SHADOW))
+ {
+ bShadow = (pSI->GetLocation() != SvxShadowLocation::NONE) &&
+ (pSI->GetWidth() != 0);
+ }
+
+ static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
+ SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
+ for(const SvxBoxItemLine & i : aLnArr)
+ {
+ const ::editeng::SvxBorderLine* pLn = pBox->GetLine( i );
+ WW8_BRC aBrc;
+ if (pLn)
+ {
+ WW8_BRCVer9 aBrc90 = WW8Export::TranslateBorderLine( *pLn,
+ pBox->GetDistance( i ), bShadow );
+ sal_uInt8 ico = msfilter::util::TransColToIco(msfilter::util::BGRToRGB(
+ aBrc90.cv()));
+ aBrc = WW8_BRC(aBrc90.dptLineWidth(), aBrc90.brcType(), ico,
+ aBrc90.dptSpace(), aBrc90.fShadow(), aBrc90.fFrame());
+ }
+
+ // use importer logic to determine how large the exported
+ // border will really be in word and adjust accordingly
+ short nSpacing;
+ short nThick = aBrc.DetermineBorderProperties(&nSpacing);
+ switch (i)
+ {
+ case SvxBoxItemLine::TOP:
+ case SvxBoxItemLine::BOTTOM:
+ nHeight -= bShadow ? nThick*2 : nThick;
+ nHeight = nHeight - nSpacing;
+ break;
+ case SvxBoxItemLine::LEFT:
+ case SvxBoxItemLine::RIGHT:
+ default:
+ nWidth -= bShadow ? nThick*2 : nThick;
+ nWidth = nWidth - nSpacing;
+ break;
+ }
+ memcpy( pArr, &aBrc.aBits1, 2);
+ pArr+=2;
+
+ memcpy( pArr, &aBrc.aBits2, 2);
+ pArr+=2;
+ }
+ }
+
+ pArr = aArr + 4; // skip lcb
+ Set_UInt16( pArr, nHdrLen ); // set cbHeader
+
+ Set_UInt16( pArr, mm ); // set mm
+
+ /*
+ Just in case our original size is too big to fit inside a ushort we can
+ substitute the final size and lose on retaining the scaling factor but
+ still keep the correct display size anyway.
+ */
+ const bool bIsSubstitutedSize = (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) ||
+ aGrTwipSz.IsEmpty();
+ if ( bIsSubstitutedSize )
+ {
+ aGrTwipSz.setWidth( nWidth );
+ aGrTwipSz.setHeight( nHeight );
+ }
+ using namespace sw::types;
+ // set xExt & yExt
+ Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
+ Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
+ pArr += 16;
+ // skip hMF & rcWinMF
+ // set dxaGoal & dyaGoal
+ Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
+ Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
+
+ if ( aGrTwipSz.Width() + nXSizeAdd ) // set mx
+ {
+ if ( !bIsSubstitutedSize )
+ {
+ const double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd );
+ Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
+ }
+ else
+ {
+ Set_UInt16( pArr, 1000 );
+ }
+ }
+ else
+ {
+ pArr += 2;
+ }
+
+ if ( aGrTwipSz.Height() + nYSizeAdd ) // set my
+ {
+ if ( !bIsSubstitutedSize )
+ {
+ const double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
+ Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
+ }
+ else
+ {
+ Set_UInt16( pArr, 1000 );
+ }
+ }
+ else
+ {
+ pArr += 2;
+ }
+
+ if ( !bIsSubstitutedSize )
+ {
+ Set_UInt16( pArr, nCropL ); // set dxaCropLeft
+ Set_UInt16( pArr, nCropT ); // set dyaCropTop
+ Set_UInt16( pArr, nCropR ); // set dxaCropRight
+ Set_UInt16( pArr, nCropB ); // set dyaCropBottom
+ }
+
+ rStrm.WriteBytes(aArr, nHdrLen);
+}
+
+void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd,
+ const ww8::Frame &rFly, sal_uInt16 nWidth, sal_uInt16 nHeight)
+{
+ if (rGrfNd.IsLinkedFile()) // Linked File
+ {
+ OUString aFileN;
+ rGrfNd.GetFileFilterNms( &aFileN, nullptr );
+
+ sal_uInt16 const mm = 94; // 94 = BMP, GIF
+
+ WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight,
+ rGrfNd.GetpSwAttrSet());
+ rStrm.WriteUChar( aFileN.getLength() ); // write Pascal-String
+ SwWW8Writer::WriteString8(rStrm, aFileN, false,
+ RTL_TEXTENCODING_MS_1252);
+ }
+ else // Embedded File or DDE or something like that
+ {
+ WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
+ rGrfNd.GetpSwAttrSet());
+ SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
+ aInlineEscher.WriteGrfFlyFrame(rFly.GetFrameFormat(), 0x401);
+ aInlineEscher.WritePictures();
+ }
+}
+//For i120928,export graphic info of bullet
+void SwWW8WrGrf::WritePICBulletFHeader(SvStream& rStrm, const Graphic &rGrf,
+ sal_uInt16 mm, sal_uInt16 nWidth, sal_uInt16 nHeight)
+{
+ sal_Int16 nXSizeAdd = 0, nYSizeAdd = 0;
+
+ Size aGrTwipSz(rGrf.GetPrefSize());
+ sal_uInt16 nHdrLen = 0x44;
+
+ sal_uInt8 aArr[ 0x44 ] = { 0 };
+
+ sal_uInt8* pArr = aArr + 0x2E; //Do borders first
+
+ static const SvxBoxItemLine aLnArr[4] = { SvxBoxItemLine::TOP, SvxBoxItemLine::LEFT,
+ SvxBoxItemLine::BOTTOM, SvxBoxItemLine::RIGHT };
+ for(const SvxBoxItemLine & i : aLnArr)
+ {
+ WW8_BRC aBrc;
+
+ short nSpacing;
+ short nThick = aBrc.DetermineBorderProperties(&nSpacing);
+ switch (i)
+ {
+ case SvxBoxItemLine::TOP:
+ case SvxBoxItemLine::BOTTOM:
+ nHeight -= nThick;
+ nHeight = nHeight - nSpacing;
+ break;
+ case SvxBoxItemLine::LEFT:
+ case SvxBoxItemLine::RIGHT:
+ default:
+ nWidth -= nThick;
+ nWidth = nWidth - nSpacing;
+ break;
+ }
+ memcpy( pArr, &aBrc.aBits1, 2);
+ pArr+=2;
+
+ memcpy(pArr, &aBrc.aBits2, 2);
+ pArr+=2;
+ }
+
+ pArr = aArr + 4; //skip lcb
+ Set_UInt16( pArr, nHdrLen ); // set cbHeader
+
+ Set_UInt16( pArr, mm ); // set mm
+
+ if ( (convertTwipToMm100(aGrTwipSz.Width()) > USHRT_MAX ) || ( convertTwipToMm100(aGrTwipSz.Height()) > USHRT_MAX )
+ || aGrTwipSz.IsEmpty() )
+ {
+ aGrTwipSz.setWidth( nWidth );
+ aGrTwipSz.setHeight( nHeight );
+ }
+ using namespace sw::types;
+ // set xExt & yExt
+ Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Width())));
+ Set_UInt16(pArr, msword_cast<sal_uInt16>(convertTwipToMm100(aGrTwipSz.Height())));
+ pArr += 16;
+ // skip hMF & rcWinMF
+ // set dxaGoal & dyaGoal
+ Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width()));
+ Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height()));
+
+ if( aGrTwipSz.Width() + nXSizeAdd ) // set mx
+ {
+ double fVal = nWidth * 1000.0 / (aGrTwipSz.Width() + nXSizeAdd);
+ Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
+ }
+ else
+ pArr += 2;
+
+ if( aGrTwipSz.Height() + nYSizeAdd ) // set my
+ {
+ double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd);
+ Set_UInt16( pArr, o3tl::narrowing<sal_uInt16>(::rtl::math::round(fVal)) );
+ }
+ else
+ pArr += 2;
+
+ Set_UInt16( pArr, 0 ); // set dxaCropLeft
+ Set_UInt16( pArr, 0 ); // set dyaCropTop
+ Set_UInt16( pArr, 0 ); // set dxaCropRight
+ Set_UInt16( pArr, 0 ); // set dyaCropBottom
+
+ rStrm.WriteBytes(aArr, nHdrLen);
+}
+
+void SwWW8WrGrf::WriteGrfForBullet(SvStream& rStrm, const Graphic &rGrf, sal_uInt16 nWidth, sal_uInt16 nHeight)
+{
+ WritePICBulletFHeader(rStrm,rGrf, 0x64,nWidth,nHeight);
+ SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
+ aInlineEscher.WriteGrfBullet(rGrf);
+ aInlineEscher.WritePictures();
+}
+
+void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem)
+{
+ sal_uInt16 nWidth = rItem.mnWid;
+ sal_uInt16 nHeight = rItem.mnHei;
+ sal_uInt32 nPos = rStrm.Tell(); // store start of graphic
+
+ const ww8::Frame &rFly = rItem.maFly;
+ switch (rFly.GetWriterType())
+ {
+ case ww8::Frame::eGraphic:
+ {
+ const SwNode *pNode = rItem.maFly.GetContent();
+ const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : nullptr;
+ OSL_ENSURE(pNd, "Impossible");
+ if (pNd)
+ WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight);
+ }
+ break;
+ //For i120928,add branch to export graphic of bullet
+ case ww8::Frame::eBulletGrf:
+ {
+ if (rItem.maFly.HasGraphic())
+ {
+ const Graphic& rGrf = rItem.maFly.GetGraphic();
+ WriteGrfForBullet(rStrm, rGrf, nWidth, nHeight);
+ }
+ }
+ break;
+
+ case ww8::Frame::eOle:
+ {
+ const SwNode *pNode = rItem.maFly.GetContent();
+ const SwOLENode *pNd = pNode ? pNode->GetOLENode() : nullptr;
+ OSL_ENSURE(pNd, "Impossible");
+ if (pNd)
+ {
+#ifdef OLE_PREVIEW_AS_EMF
+ //Convert this ole2 preview in ww8+ to an EMF for better unicode
+ //support (note that at this moment this breaks StarSymbol
+ //using graphics because I need to embed starsymbol in exported
+ //documents.
+ WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight,
+ pNd->GetpSwAttrSet());
+ SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
+ aInlineEscher.WriteOLEFlyFrame(rFly.GetFrameFormat(), 0x401);
+ aInlineEscher.WritePictures();
+#else
+ // cast away const
+ SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd);
+ SwOLEObj& rSObj= pOleNd->GetOLEObj();
+
+ // TODO/LATER: do we need to load object?
+ Graphic* pGr = SdrOle2Obj::GetGraphicFromObject( pOleNd->GetDoc()->GetDocStorage(), rObj );
+
+ //TODO/LATER: do we really want to use GDIMetafile?!
+ GDIMetaFile aMtf;
+ if ( pGr )
+ aMtf = pGr->GetGDIMetaFile();
+
+ Size aS(aMtf.GetPrefSize());
+ aMtf.WindStart();
+ aMtf.Play(Application::GetDefaultDevice(), Point(0, 0),
+ Size(2880, 2880));
+
+ WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight,
+ pNd->GetpSwAttrSet());
+ WriteWindowMetafileBits(rStrm, aMtf);
+ delete pGr;
+#endif
+ }
+ }
+ break;
+ case ww8::Frame::eDrawing:
+ case ww8::Frame::eTextBox:
+ case ww8::Frame::eFormControl:
+ /*
+ #i3958# We only export an empty dummy picture frame here, this is
+ what word does the escher export should contain an anchored to
+ character element which is drawn over this dummy and the whole
+ shebang surrounded with a SHAPE field. This isn't *my* hack :-),
+ it's what word does.
+ */
+ {
+ WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight);
+ SwBasicEscherEx aInlineEscher(&rStrm, m_rWrt);
+ aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrameFormat(), 0x401);
+ }
+ break;
+ default:
+ OSL_ENSURE(false, "Some inline export not implemented");
+ break;
+ }
+
+ sal_uInt32 nPos2 = rStrm.Tell(); // store the end
+ rStrm.Seek( nPos );
+ rStrm.WriteUInt32(nPos2 - nPos); // patch graphic length in the header
+ rStrm.Seek( nPos2 ); // restore Pos
+}
+
+// SwWW8WrGrf::Write() is called after the text.
+// It writes out all the graphics and remembers the file locations of the graphics,
+// so when writing the attributes of the items it can be patched into PicLocFc-SPRMs.
+// The search in the attributes for the Magic sal_uLong and patching
+// happens when writing the attributes. Class SwWW8WrGrf provides with
+// GetFPos() sequentially the positions
+void SwWW8WrGrf::Write()
+{
+ SvStream& rStrm = *m_rWrt.m_pDataStrm;
+ auto aEnd = maDetails.end();
+ for (auto aIter = maDetails.begin(); aIter != aEnd; ++aIter)
+ {
+ sal_uInt32 nPos = rStrm.Tell(); // align to 4 Bytes
+ if( nPos & 0x3 )
+ SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) );
+
+ auto aIter2 = std::find(maDetails.begin(), aIter, *aIter);
+ if (aIter2 != aIter)
+ {
+ aIter->mnPos = aIter2->mnPos;
+ }
+ else
+ {
+ aIter->mnPos = rStrm.Tell();
+ WriteGraphicNode(rStrm, *aIter);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */