diff options
Diffstat (limited to 'sw/source/filter/ww8/wrtww8gr.cxx')
-rw-r--r-- | sw/source/filter/ww8/wrtww8gr.cxx | 887 |
1 files changed, 887 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/wrtww8gr.cxx b/sw/source/filter/ww8/wrtww8gr.cxx new file mode 100644 index 000000000000..5d96a74b009d --- /dev/null +++ b/sw/source/filter/ww8/wrtww8gr.cxx @@ -0,0 +1,887 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" + +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ + +#if OSL_DEBUG_LEVEL > 0 +# include <cstdio> +#endif + +#include <com/sun/star/embed/XEmbedPersist.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <rtl/math.hxx> +#include <svtools/filter.hxx> +#include <svl/itemiter.hxx> +#include "svl/urihelper.hxx" + +#include <svtools/embedhlp.hxx> + +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> + +#include <hintids.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/shaditem.hxx> +#include <filter/msfilter/msoleexp.hxx> +#include <editeng/lrspitem.hxx> // SvxLRSpaceItem +#include <editeng/ulspitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <svx/svdoole2.hxx> + +#include <unotools/ucbstreamhelper.hxx> +#include <fmtanchr.hxx> +#include <ndgrf.hxx> +#include <frmfmt.hxx> // class SwFlyFrmFmt +#include <grfatr.hxx> // class SwCropGrf +#include <ndole.hxx> +#include <ndtxt.hxx> +#include <fmtfsize.hxx> +#include <fmtornt.hxx> + +#include <writerfilter/doctok/sprmids.hxx> + +#include <doc.hxx> +#include "writerhelper.hxx" +#include "writerwordglue.hxx" +#include "ww8struc.hxx" +#include "wrtww8.hxx" +#include "ww8par.hxx" +#include "escher.hxx" + +#include "docsh.hxx" +#include <cstdio> + +using namespace ::com::sun::star; +using namespace nsFieldFlags; + +// Damit KA debuggen kann, ohne sich den ganzen Writer zu holen, ist +// temporaer dieses Debug gesetzt. Ist ausserdem noch das passende IniFlag +// gesetzt, dann werden in d:\ Hilfsdateien erzeugt. +// !! sollte demnaechst wieder entfernt werden !! +// #define DEBUG_KA + + +// ToDo: +// 5. Die MapModes, die Win nicht kann, umrechnen + +// OutGrf() wird fuer jeden GrafNode im Doc gerufen. Es wird ein PicLocFc-Sprm +// eingefuegt, der statt Adresse ein Magic ULONG enthaelt. Ausserdem wird +// in der Graf-Klasse der GrfNode-Ptr gemerkt ( fuers spaetere Ausgeben der +// Grafiken und Patchen der PicLocFc-Attribute ) + +void WW8Export::OutputGrfNode( const SwGrfNode& /*rNode*/ ) +{ + OSL_TRACE("WW8Export::OutputGrfNode( const SwGrfNode& )\n" ); + ASSERT( mpParentFrame, "frame not set!" ); + if ( mpParentFrame ) + { + OutGrf( *mpParentFrame ); + pFib->fHasPic = 1; + } +} + +bool WW8Export::TestOleNeedsGraphic(const SwAttrSet& rSet, + SvStorageRef xOleStg, SvStorageRef xObjStg, String &rStorageName, + SwOLENode *pOLENd) +{ +#ifdef NO_OLE_SIZE_OPTIMIZE + return true; +#else + bool bGraphicNeeded = false; + SfxItemIter aIter( rSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + + do { + switch (pItem->Which()) + { + /* + For an inline object these properties are irrelevent 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; + } + } while( !bGraphicNeeded && !aIter.IsAtEnd() && + 0 != ( pItem = aIter.NextItem() ) ); + + /* + 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 + dont need to store another preview + */ + GDIMetaFile aWMF; + long nX=0,nY=0; + if (!bGraphicNeeded && SwWW8ImplReader::ImportOleWMF(xOleStg,aWMF,nX,nY)) + { + // bGraphicNeeded set to true is right / fixes #i51670#. + bGraphicNeeded = true; + Point aTmpPoint; + Rectangle aRect( aTmpPoint, Size( nX, nY ) ); + Graphic aGraph(aWMF); + + ErrCode nErr = ERRCODE_NONE; + Rectangle aVisArea; + sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT; + if ( pOLENd ) + nAspect = pOLENd->GetAspect(); + SdrOle2Obj *pRet = SvxMSDffManager::CreateSdrOLEFromStorage( + rStorageName,xObjStg,pDoc->GetDocStorage(),aGraph,aRect,aVisArea,0,nErr,0,nAspect); + + if (pRet) + { + uno::Reference< embed::XEmbeddedObject > xObj = pOLENd->GetOLEObj().GetOleRef(); + if ( xObj.is() ) + { + SvStream* pGraphicStream = NULL; + comphelper::EmbeddedObjectContainer aCnt( pDoc->GetDocStorage() ); + try + { + uno::Reference< embed::XEmbedPersist > xPersist( + xObj, + uno::UNO_QUERY_THROW ); + + // it makes no sence 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 sence + pGraphicStream = + ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( xPersist->getEntryName() ) ); + } + catch( uno::Exception& ) + {} + + DBG_ASSERT( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" ); + if ( pGraphicStream && !pGraphicStream->GetError() ) + { + Graphic aGr1; + GraphicFilter* pGF = GraphicFilter::GetGraphicFilter(); + if( pGF->ImportGraphic( aGr1, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK ) + { + Graphic aGr2; + delete pGraphicStream; + pGraphicStream = + ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( pRet->GetObjRef() ) ); + if( pGF->ImportGraphic( aGr2, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK ) + { + if ( aGr1 == aGr2 ) + bGraphicNeeded = false; + } + } + } + else + delete pGraphicStream; + } + + delete pRet; + } + } + else + bGraphicNeeded = true; + return bGraphicNeeded; +#endif +} + +void WW8Export::OutputOLENode( const SwOLENode& rOLENode ) +{ + OSL_TRACE("WW8Export::OutputOLENode( const SwOLENode& rOLENode )\n" ); + BYTE *pSpecOLE; + BYTE *pDataAdr; + short nSize; + static BYTE aSpecOLE_WW8[] = { + 0x03, 0x6a, 0, 0, 0, 0, // sprmCPicLocation + 0x0a, 0x08, 1, // sprmCFOLE2 + 0x56, 0x08, 1 // sprmCFObj + }; + static BYTE aSpecOLE_WW6[] = { + 68, 4, 0, 0, 0, 0, // sprmCPicLocation (len is 4) + 75, 1, // sprmCFOLE2 + 118, 1 // sprmCFObj + }; + + if ( bWrtWW8 ) + { + pSpecOLE = aSpecOLE_WW8; + nSize = sizeof( aSpecOLE_WW8 ); + } + else + { + pSpecOLE = aSpecOLE_WW6; + nSize = sizeof( aSpecOLE_WW6 ); + } + pDataAdr = pSpecOLE + 2; //WW6 sprm is 1 but has 1 byte len as well. + + SvStorageRef xObjStg = GetWriter().GetStorage().OpenSotStorage( + CREATE_CONST_ASC(SL::aObjectPool), STREAM_READWRITE | + STREAM_SHARE_DENYALL ); + + if( xObjStg.Is() ) + { + uno::Reference < embed::XEmbeddedObject > xObj(const_cast<SwOLENode&>(rOLENode).GetOLEObj().GetOleRef()); + if( xObj.is() ) + { + embed::XEmbeddedObject *pObj = xObj.get(); + sal_uInt32 nPictureId = (sal_uInt32)(sal_uIntPtr)pObj; + Set_UInt32(pDataAdr, nPictureId); + + WW8OleMap *pMap = new WW8OleMap(nPictureId); + bool bDuplicate = false; + WW8OleMaps &rOleMap = GetOLEMap(); + USHORT nPos; + if ( rOleMap.Seek_Entry(pMap, &nPos) ) + { + bDuplicate = true; + delete pMap; + } + else if( 0 == rOleMap.Insert( pMap) ) + delete pMap; + + String sStorageName( '_' ); + sStorageName += String::CreateFromInt32( nPictureId ); + SvStorageRef xOleStg = xObjStg->OpenSotStorage( sStorageName, + STREAM_READWRITE| STREAM_SHARE_DENYALL ); + if( xOleStg.Is() ) + { + /* + If this object storage has been written already don't + waste time rewriting it + */ + if (!bDuplicate) + { + sal_Int64 nAspect = rOLENode.GetAspect(); + svt::EmbeddedObjectRef aObjRef( xObj, nAspect ); + GetOLEExp().ExportOLEObject( aObjRef, *xOleStg ); + if ( nAspect == embed::Aspects::MSOLE_ICON ) + { + ::rtl::OUString aObjInfo( RTL_CONSTASCII_USTRINGPARAM( "\3ObjInfo" ) ); + if ( !xOleStg->IsStream( aObjInfo ) ) + { + const BYTE pObjInfoData[] = { 0x40, 0x00, 0x03, 0x00 }; + SvStorageStreamRef rObjInfoStream = xOleStg->OpenSotStream( aObjInfo ); + if ( rObjInfoStream.Is() && !rObjInfoStream->GetError() ) + { + rObjInfoStream->Write( pObjInfoData, sizeof( pObjInfoData ) ); + xOleStg->Commit(); + } + } + } + } + + // write as embedded field - the other things will be done + // in the escher export + String sServer(FieldString(ww::eEMBED)); + sServer += xOleStg->GetUserName(); + sServer += ' '; + + OutputField(0, ww::eEMBED, sServer, WRITEFIELD_START | + WRITEFIELD_CMD_START | WRITEFIELD_CMD_END); + + 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 (mpParentFrame) + { + bGraphicNeeded = true; + + if (mpParentFrame->IsInline()) + { + const SwAttrSet& rSet = + mpParentFrame->GetFrmFmt().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(*mpParentFrame); + } + + OutputField(0, ww::eEMBED, aEmptyStr, + WRITEFIELD_END | WRITEFIELD_CLOSE); + + if (bEndCR) //No newline in inline case + WriteCR(); + } + } + } +} + +void WW8Export::OutGrf(const sw::Frame &rFrame) +{ + // GrfNode fuer spaeteres rausschreiben der Grafik merken + pGrf->Insert(rFrame); + + pChpPlc->AppendFkpEntry( Strm().Tell(), pO->Count(), pO->GetData() ); + pO->Remove( 0, pO->Count() ); // leeren + + // --> OD 2007-06-06 #i29408# + // linked, as-character anchored graphics have to be exported as fields. + const SwGrfNode* pGrfNd = rFrame.IsInline() && rFrame.GetContent() + ? rFrame.GetContent()->GetGrfNode() : 0; + if ( pGrfNd && pGrfNd->IsLinkedFile() ) + { + String sStr( FieldString(ww::eINCLUDEPICTURE) ); + sStr.APPEND_CONST_ASC(" \""); + { + if ( pGrfNd ) + { + String aFileURL; + pGrfNd->GetFileFilterNms( &aFileURL, 0 ); + sStr += aFileURL; + } + } + sStr.APPEND_CONST_ASC("\" \\d"); + + OutputField( 0, ww::eINCLUDEPICTURE, sStr, + WRITEFIELD_START | WRITEFIELD_CMD_START | WRITEFIELD_CMD_END ); + } + // <-- + + WriteChar( (char)1 ); // Grafik-Sonderzeichen in Haupttext einfuegen + + BYTE aArr[ 18 ]; + BYTE* pArr = aArr; + + const SwFrmFmt &rFlyFmt = rFrame.GetFrmFmt(); + const RndStdIds eAn = rFlyFmt.GetAttrSet().GetAnchor(false).GetAnchorId(); + if (eAn == FLY_AS_CHAR) + { + sal_Int16 eVert = rFlyFmt.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 (pOutFmtNode && pOutFmtNode->ISA(SwCntntNode) ) + { + const SwTxtNode* pTxtNd = (const SwTxtNode*)pOutFmtNode; + SwPosition aPos(*pTxtNd); + bVert = pDoc->IsInVerticalText(aPos) ? true : false; + } + if (!bVert) + { + SwTwips nHeight = rFlyFmt.GetFrmSize().GetHeight(); + nHeight/=20; //nHeight was in twips, want it in half points, but + //then half of total height. + long nFontHeight = ((const SvxFontHeightItem&) + GetItem(RES_CHRATR_FONTSIZE)).GetHeight(); + nHeight-=nFontHeight/20; + + if (bWrtWW8) + Set_UInt16( pArr, NS_sprm::LN_CHpsPos ); + else + Set_UInt8( pArr, 101 ); + Set_UInt16( pArr, -((INT16)nHeight)); + } + } + } + + // sprmCFSpec + if( bWrtWW8 ) + Set_UInt16( pArr, 0x855 ); + else + Set_UInt8( pArr, 117 ); + Set_UInt8( pArr, 1 ); + + // sprmCPicLocation + if( bWrtWW8 ) + Set_UInt16( pArr, NS_sprm::LN_CPicLocation ); + else + { + Set_UInt8( pArr, 68 ); + Set_UInt8( pArr, 4 ); + } + Set_UInt32( pArr, GRF_MAGIC_321 ); + + // Magic variieren, damit verschiedene Grafik-Attribute nicht + // gemerged werden + static BYTE nAttrMagicIdx = 0; + --pArr; + Set_UInt8( pArr, nAttrMagicIdx++ ); + pChpPlc->AppendFkpEntry( Strm().Tell(), static_cast< short >(pArr - aArr), aArr ); + + // --> OD 2007-04-23 #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 == FLY_AT_PARA) && ( bWrtWW8 || !bIsInTable )) || + (eAn == FLY_AT_PAGE)) ) + // <-- + { + WriteChar( (char)0x0d ); // umgebenden Rahmen mit CR abschliessen + + static BYTE __READONLY_DATA nSty[2] = { 0, 0 }; + pO->Insert( nSty, 2, pO->Count() ); // Style #0 + bool bOldGrf = bOutGrf; + bOutGrf = true; + + OutputFormat( rFrame.GetFrmFmt(), false, false, true ); // Fly-Attrs + + bOutGrf = bOldGrf; + pPapPlc->AppendFkpEntry( Strm().Tell(), pO->Count(), pO->GetData() ); + pO->Remove( 0, pO->Count() ); // leeren + } + // --> OD 2007-06-06 #i29408# + // linked, as-character anchored graphics have to be exported as fields. + else if ( pGrfNd && pGrfNd->IsLinkedFile() ) + { + OutputField( 0, ww::eINCLUDEPICTURE, String(), WRITEFIELD_CLOSE ); + } + // <-- +} + +GraphicDetails& GraphicDetails::operator=(const GraphicDetails &rOther) +{ + maFly = rOther.maFly; + mnPos = rOther.mnPos; + mnWid = rOther.mnWid; + mnHei = rOther.mnHei; + return *this; +} + +void SwWW8WrGrf::Insert(const sw::Frame &rFly) +{ + const Size aSize( rFly.GetLayoutSize() ); + const UINT16 nWidth = static_cast< UINT16 >(aSize.Width()); + const UINT16 nHeight = static_cast< UINT16 >(aSize.Height()); + maDetails.push_back(GraphicDetails(rFly, nWidth, nHeight)); +} + +void SwWW8WrGrf::WritePICFHeader(SvStream& rStrm, const sw::Frame &rFly, + UINT16 mm, UINT16 nWidth, UINT16 nHeight, const SwAttrSet* pAttrSet) +{ + INT16 nXSizeAdd = 0, nYSizeAdd = 0; + INT16 nCropL = 0, nCropR = 0, nCropT = 0, nCropB = 0; + + // Crop-AttributInhalt in Header schreiben ( falls vorhanden ) + const SfxPoolItem* pItem; + if (pAttrSet && (SFX_ITEM_ON + == pAttrSet->GetItemState(RES_GRFATR_CROPGRF, false, &pItem))) + { + const SwCropGrf& rCr = *(SwCropGrf*)pItem; + nCropL = (INT16)rCr.GetLeft(); + nCropR = (INT16)rCr.GetRight(); + nCropT = (INT16)rCr.GetTop(); + nCropB = (INT16)rCr.GetBottom(); + nXSizeAdd = nXSizeAdd - (INT16)( rCr.GetLeft() + rCr.GetRight() ); + nYSizeAdd = nYSizeAdd - (INT16)( rCr.GetTop() + rCr.GetBottom() ); + } + + Size aGrTwipSz(rFly.GetSize()); + bool bWrtWW8 = rWrt.bWrtWW8; + UINT16 nHdrLen = bWrtWW8 ? 0x44 : 0x3A; + + BYTE aArr[ 0x44 ] = { 0 }; + + BYTE* pArr = aArr + 0x2E; //Do borders first + + const SwAttrSet& rAttrSet = rFly.GetFrmFmt().GetAttrSet(); + if (SFX_ITEM_ON == rAttrSet.GetItemState(RES_BOX, false, &pItem)) + { + const SvxBoxItem* pBox = (const SvxBoxItem*)pItem; + if( pBox ) + { + bool bShadow = false; // Shadow ? + const SvxShadowItem* pSI = + sw::util::HasItem<SvxShadowItem>(rAttrSet, RES_SHADOW); + if (pSI) + { + bShadow = (pSI->GetLocation() != SVX_SHADOW_NONE) && + (pSI->GetWidth() != 0); + } + + BYTE aLnArr[4] = { BOX_LINE_TOP, BOX_LINE_LEFT, + BOX_LINE_BOTTOM, BOX_LINE_RIGHT }; + for( BYTE i = 0; i < 4; ++i ) + { + const SvxBorderLine* pLn = pBox->GetLine( aLnArr[ i ] ); + WW8_BRC aBrc; + if (pLn) + { + aBrc = rWrt.TranslateBorderLine( *pLn, + pBox->GetDistance( aLnArr[ i ] ), bShadow ); + } + + //use importer logic to determine how large the exported + //border will really be in word and adjust accordingly + short nSpacing; + short nThick = aBrc.DetermineBorderProperties(!bWrtWW8, + &nSpacing); + switch (aLnArr[ i ]) + { + case BOX_LINE_TOP: + case BOX_LINE_BOTTOM: + nHeight -= bShadow ? nThick*2 : nThick; + nHeight = nHeight - nSpacing; + break; + case BOX_LINE_LEFT: + case BOX_LINE_RIGHT: + default: + nWidth -= bShadow ? nThick*2 : nThick; + nWidth = nWidth - nSpacing; + break; + } + memcpy( pArr, &aBrc.aBits1, 2); + pArr+=2; + + if( bWrtWW8 ) + { + memcpy( pArr, &aBrc.aBits2, 2); + pArr+=2; + } + } + } + } + + pArr = aArr + 4; //skip lcb + Set_UInt16( pArr, nHdrLen ); // set cbHeader + + Set_UInt16( pArr, mm ); // set mm + + /* + #92494# + Just in case our original size is too big to fit inside a ushort we can + substitute the final size and loose on retaining the scaling factor but + still keep the correct display size anyway. + */ + if ( (aGrTwipSz.Width() > SHRT_MAX) || (aGrTwipSz.Height() > SHRT_MAX) + || (aGrTwipSz.Width() < 0 ) || (aGrTwipSz.Height() < 0) ) + { + aGrTwipSz.Width() = nWidth; + aGrTwipSz.Height() = nHeight; + } + using namespace sw::types; + // set xExt & yExt + Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Width() * 254L / 144)); + Set_UInt16(pArr, msword_cast<sal_uInt16>(aGrTwipSz.Height() * 254L / 144)); + 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, (USHORT)::rtl::math::round(fVal) ); + } + else + pArr += 2; + + if( aGrTwipSz.Height() + nYSizeAdd ) // set my + { + double fVal = nHeight * 1000.0 / (aGrTwipSz.Height() + nYSizeAdd); + Set_UInt16( pArr, (USHORT)::rtl::math::round(fVal) ); + } + else + pArr += 2; + + 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.Write( aArr, nHdrLen ); +} + +void SwWW8WrGrf::WriteGrfFromGrfNode(SvStream& rStrm, const SwGrfNode &rGrfNd, + const sw::Frame &rFly, UINT16 nWidth, UINT16 nHeight) +{ + if (rGrfNd.IsLinkedFile()) // Linked File + { + String aFileN; + rGrfNd.GetFileFilterNms( &aFileN, 0 ); + + // --> OD 2007-06-06 #i29408# - take the file URL as it is. +// aFileN = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), +// aFileN); +// INetURLObject aUrl( aFileN ); +// if( aUrl.GetProtocol() == INET_PROT_FILE ) +// aFileN = aUrl.PathToFileName(); + // <-- + +//JP 05.12.98: nach einigen tests hat sich gezeigt, das WW mit 99 nicht +// klarkommt. Sie selbst schreiben aber bei Verknuepfunfen, +// egal um welchen Type es sich handelt, immer den Wert 94. +// Bug 59859 +// if ( COMPARE_EQUAL == aFiltN.ICompare( "TIF", 3 ) ) +// mm = 99; // 99 = TIFF +// else + UINT16 mm = 94; // 94 = BMP, GIF + + WritePICFHeader(rStrm, rFly, mm, nWidth, nHeight, + rGrfNd.GetpSwAttrSet()); + rStrm << (BYTE)aFileN.Len(); // Pascal-String schreiben + SwWW8Writer::WriteString8(rStrm, aFileN, false, + RTL_TEXTENCODING_MS_1252); + } + else // Embedded File oder DDE oder so was + { + if (rWrt.bWrtWW8) + { + WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight, + rGrfNd.GetpSwAttrSet()); + SwBasicEscherEx aInlineEscher(&rStrm, rWrt); + aInlineEscher.WriteGrfFlyFrame(rFly.GetFrmFmt(), 0x401); + aInlineEscher.WritePictures(); + } + else + { + Graphic& rGrf = const_cast<Graphic&>(rGrfNd.GetGrf()); + bool bSwapped = rGrf.IsSwapOut() ? true : false; + // immer ueber den Node einswappen! + const_cast<SwGrfNode&>(rGrfNd).SwapIn(); + + GDIMetaFile aMeta; + switch (rGrf.GetType()) + { + case GRAPHIC_BITMAP: // Bitmap -> in Metafile abspielen + { + VirtualDevice aVirt; + aMeta.Record(&aVirt); + aVirt.DrawBitmap( Point( 0,0 ), rGrf.GetBitmap() ); + aMeta.Stop(); + aMeta.WindStart(); + aMeta.SetPrefMapMode( rGrf.GetPrefMapMode()); + aMeta.SetPrefSize( rGrf.GetPrefSize()); + } + break; + case GRAPHIC_GDIMETAFILE : // GDI ( =SV ) Metafile + aMeta = rGrf.GetGDIMetaFile(); + break; + default: + return; + } + + WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight, + rGrfNd.GetpSwAttrSet()); + WriteWindowMetafileBits(rStrm, aMeta); + + if (bSwapped) + rGrf.SwapOut(); + } + } +} + +void SwWW8WrGrf::WriteGraphicNode(SvStream& rStrm, const GraphicDetails &rItem) +{ + UINT16 nWidth = rItem.mnWid; + UINT16 nHeight = rItem.mnHei; + UINT32 nPos = rStrm.Tell(); // Grafik-Anfang merken + + const sw::Frame &rFly = rItem.maFly; + switch (rFly.GetWriterType()) + { + case sw::Frame::eGraphic: + { + const SwNode *pNode = rItem.maFly.GetContent(); + const SwGrfNode *pNd = pNode ? pNode->GetGrfNode() : 0; + ASSERT(pNd, "Impossible"); + if (pNd) + WriteGrfFromGrfNode(rStrm, *pNd, rItem.maFly, nWidth, nHeight); + } + break; + case sw::Frame::eOle: + { +#ifdef OLE_PREVIEW_AS_EMF + const SwNode *pNode = rItem.maFly.GetContent(); + const SwOLENode *pNd = pNode ? pNode->GetOLENode() : 0; + ASSERT(pNd, "Impossible"); + if (!rWrt.bWrtWW8) + { + SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd); + ASSERT( pOleNd, " Wer hat den OleNode versteckt ?" ); + SwOLEObj& rSObj= pOleNd->GetOLEObj(); + uno::Reference < embed::XEmbeddedObject > rObj( rSObj.GetOleRef() ); + + comphelper::EmbeddedObjectContainer aCnt( pOleNd->GetDoc()->GetDocStorage() ); + + SvStream* pGraphicStream = ::utl::UcbStreamHelper::CreateStream( aCnt.GetGraphicStream( rObj ) ); + DBG_ASSERT( pGraphicStream && !pGraphicStream->GetError(), "No graphic stream available!" ); + if ( pGraphicStream && !pGraphicStream->GetError() ) + { + Graphic aGr; + GraphicFilter* pGF = GraphicFilter::GetGraphicFilter(); + if( pGF->ImportGraphic( aGr, aEmptyStr, *pGraphicStream, GRFILTER_FORMAT_DONTKNOW ) == GRFILTER_OK ) + { + //TODO/LATER: do we really want to use GDIMetafile?! + GDIMetaFile aMtf; + aMtf = aGr.GetGDIMetaFile(); + aMtf.WindStart(); + aMtf.Play(Application::GetDefaultDevice(), Point(0, 0), + Size(2880, 2880)); + WritePICFHeader(rStrm, rFly, 8, nWidth, nHeight, + pNd->GetpSwAttrSet()); + WriteWindowMetafileBits(rStrm, aMtf); + } + } + else + delete pGraphicStream; + } + else + { + //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, rWrt); + aInlineEscher.WriteOLEFlyFrame(rFly.GetFrmFmt(), 0x401); + aInlineEscher.WritePictures(); + } +#else + // cast away const + SwOLENode *pOleNd = const_cast<SwOLENode*>(pNd); + ASSERT( pOleNd, " Wer hat den OleNode versteckt ?" ); + 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 sw::Frame::eDrawing: + case sw::Frame::eTxtBox: + case sw::Frame::eFormControl: + ASSERT(rWrt.bWrtWW8, + "You can't try and export these in WW8 format, a filter bug"); + /* + #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 :-), + its what word does. + */ + if (rWrt.bWrtWW8) + { + WritePICFHeader(rStrm, rFly, 0x64, nWidth, nHeight); + SwBasicEscherEx aInlineEscher(&rStrm, rWrt); + aInlineEscher.WriteEmptyFlyFrame(rFly.GetFrmFmt(), 0x401); + } + break; + default: + ASSERT(!this, + "Some inline export not implemented, remind cmc before we ship :-)"); + break; + } + + UINT32 nPos2 = rStrm.Tell(); // Ende merken + rStrm.Seek( nPos ); + SVBT32 nLen; + UInt32ToSVBT32( nPos2 - nPos, nLen ); // Grafik-Laenge ausrechnen + rStrm.Write( nLen, 4 ); // im Header einpatchen + rStrm.Seek( nPos2 ); // Pos wiederherstellen +} + +// SwWW8WrGrf::Write() wird nach dem Text gerufen. Es schreibt die alle +// Grafiken raus und merkt sich die File-Positionen der Grafiken, damit +// beim Schreiben der Attribute die Positionen in die PicLocFc-Sprms +// eingepatcht werden koennen. +// Das Suchen in den Attributen nach dem Magic ULONG und das Patchen +// passiert beim Schreiben der Attribute. Die SwWW8WrGrf-Klasse liefert +// hierfuer nur mit GetFPos() sequentiell die Positionen. +void SwWW8WrGrf::Write() +{ + SvStream& rStrm = *rWrt.pDataStrm; + myiter aEnd = maDetails.end(); + for (myiter aIter = maDetails.begin(); aIter != aEnd; ++aIter) + { + UINT32 nPos = rStrm.Tell(); // auf 4 Bytes alignen + if( nPos & 0x3 ) + SwWW8Writer::FillCount( rStrm, 4 - ( nPos & 0x3 ) ); + + bool bDuplicated = false; + for (myiter aIter2 = maDetails.begin(); aIter2 != aIter; ++aIter2) + { + if (*aIter2 == *aIter) + { + aIter->mnPos = aIter2->mnPos; + bDuplicated = true; + break; + } + } + + if (!bDuplicated) + { + aIter->mnPos = rStrm.Tell(); + WriteGraphicNode(rStrm, *aIter); + } + } +} + +/* vi:set tabstop=4 shiftwidth=4 expandtab: */ |