blob: abf02d1eaaefb56e1f9208598702daba163c2772 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svx.hxx"
#include "svdfmtf.hxx"
#include <editeng/editdata.hxx>
#include <math.h>
#include <svx/xpoly.hxx>
#include <vcl/svapp.hxx>
#include <editeng/eeitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/crsditem.hxx>
#include <editeng/shdditem.hxx>
#include <svx/xlnclit.hxx>
#include <svx/xlncapit.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/xflclit.hxx>
#include <svx/xgrad.hxx>
#include <svx/xflgrit.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/akrnitem.hxx>
#include <editeng/wrlmitem.hxx>
#include <editeng/cntritem.hxx>
#include <editeng/colritem.hxx>
#include <vcl/metric.hxx>
#include <editeng/charscaleitem.hxx>
#include <svx/xflhtit.hxx>
#include <svx/svdattr.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdobj.hxx>
#include "svx/svditext.hxx"
#include <svx/svdotext.hxx>
#include <svx/svdorect.hxx>
#include <svx/svdocirc.hxx>
#include <svx/svdograf.hxx>
#include <svx/svdopath.hxx>
#include <svx/svdetc.hxx>
#include <svl/itemset.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <vcl/salbtype.hxx> // FRound
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <svx/xlinjoit.hxx>
#include <svx/xlndsit.hxx>
#include <basegfx/polygon/b2dpolygonclipper.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/xfltrit.hxx>
#include <vcl/bmpacc.hxx>
#include <svx/xflbmtit.hxx>
#include <svx/xflbstit.hxx>
#include <svx/svdpntv.hxx>
#include <svx/svdlegacy.hxx>
#include <svx/svdtrans.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <svx/svditer.hxx>
#include <svx/svdogrp.hxx>
////////////////////////////////////////////////////////////////////////////////////////////////////
ImpSdrGDIMetaFileImport::ImpSdrGDIMetaFileImport(
SdrModel& rModel,
SdrLayerID nLay,
const basegfx::B2DHomMatrix& rObjectTransform)
: maTmpList(),
maVD(),
maObjectTransform(rObjectTransform),
maMetaToUnit(),
maCurrent(),
mpLineAttr(0),
mpFillAttr(0),
mpTextAttr(0),
mrModel(rModel),
mnLayer(nLay),
maOldLineColor(),
mnLineWidth(0),
maLineJoin(basegfx::B2DLINEJOIN_NONE),
maLineCap(com::sun::star::drawing::LineCap_BUTT),
maDash(XDASH_RECT, 0, 0, 0, 0, 0),
maClip(),
mbFntDirty(true),
mbLastObjWasPolyWithoutLine(false),
mbNoLine(false),
mbNoFill(false),
mbLastObjWasLine(false)
{
maVD.EnableOutput(false);
maVD.SetLineColor();
maVD.SetFillColor();
maOldLineColor.SetRed(maVD.GetLineColor().GetRed() + 1);
mpLineAttr = new SfxItemSet(rModel.GetItemPool(), XATTR_LINE_FIRST, XATTR_LINE_LAST, 0, 0);
mpFillAttr = new SfxItemSet(rModel.GetItemPool(), XATTR_FILL_FIRST, XATTR_FILL_LAST, 0, 0);
mpTextAttr = new SfxItemSet(rModel.GetItemPool(), EE_ITEMS_START, EE_ITEMS_END, 0, 0);
checkClip();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ImpSdrGDIMetaFileImport::~ImpSdrGDIMetaFileImport()
{
delete mpLineAttr;
delete mpFillAttr;
delete mpTextAttr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoLoopActions(GDIMetaFile& rMtf, SvdProgressInfo* pProgrInfo, sal_uInt32* pActionsToReport)
{
const sal_uLong nCount(rMtf.GetActionCount());
for(sal_uLong a(0); a < nCount; a++)
{
MetaAction* pAct = rMtf.GetAction(a);
if(!pAct)
{
OSL_ENSURE(false, "OOps, no action at valid position (!)");
pAct = rMtf.GetAction(0);
}
switch (pAct->GetType())
{
case META_PIXEL_ACTION : DoAction((MetaPixelAction &)*pAct); break;
case META_POINT_ACTION : DoAction((MetaPointAction &)*pAct); break;
case META_LINE_ACTION : DoAction((MetaLineAction &)*pAct); break;
case META_RECT_ACTION : DoAction((MetaRectAction &)*pAct); break;
case META_ROUNDRECT_ACTION : DoAction((MetaRoundRectAction &)*pAct); break;
case META_ELLIPSE_ACTION : DoAction((MetaEllipseAction &)*pAct); break;
case META_ARC_ACTION : DoAction((MetaArcAction &)*pAct); break;
case META_PIE_ACTION : DoAction((MetaPieAction &)*pAct); break;
case META_CHORD_ACTION : DoAction((MetaChordAction &)*pAct); break;
case META_POLYLINE_ACTION : DoAction((MetaPolyLineAction &)*pAct); break;
case META_POLYGON_ACTION : DoAction((MetaPolygonAction &)*pAct); break;
case META_POLYPOLYGON_ACTION : DoAction((MetaPolyPolygonAction &)*pAct); break;
case META_TEXT_ACTION : DoAction((MetaTextAction &)*pAct); break;
case META_TEXTARRAY_ACTION : DoAction((MetaTextArrayAction &)*pAct); break;
case META_STRETCHTEXT_ACTION : DoAction((MetaStretchTextAction &)*pAct); break;
case META_BMP_ACTION : DoAction((MetaBmpAction &)*pAct); break;
case META_BMPSCALE_ACTION : DoAction((MetaBmpScaleAction &)*pAct); break;
case META_BMPEX_ACTION : DoAction((MetaBmpExAction &)*pAct); break;
case META_BMPEXSCALE_ACTION : DoAction((MetaBmpExScaleAction &)*pAct); break;
case META_LINECOLOR_ACTION : DoAction((MetaLineColorAction &)*pAct); break;
case META_FILLCOLOR_ACTION : DoAction((MetaFillColorAction &)*pAct); break;
case META_TEXTCOLOR_ACTION : DoAction((MetaTextColorAction &)*pAct); break;
case META_TEXTFILLCOLOR_ACTION : DoAction((MetaTextFillColorAction &)*pAct); break;
case META_FONT_ACTION : DoAction((MetaFontAction &)*pAct); break;
case META_TEXTALIGN_ACTION : DoAction((MetaTextAlignAction &)*pAct); break;
case META_MAPMODE_ACTION : DoAction((MetaMapModeAction &)*pAct); break;
case META_CLIPREGION_ACTION : DoAction((MetaClipRegionAction &)*pAct); break;
case META_MOVECLIPREGION_ACTION : DoAction((MetaMoveClipRegionAction &)*pAct); break;
case META_ISECTRECTCLIPREGION_ACTION: DoAction((MetaISectRectClipRegionAction&)*pAct); break;
case META_ISECTREGIONCLIPREGION_ACTION: DoAction((MetaISectRegionClipRegionAction&)*pAct); break;
case META_RASTEROP_ACTION : DoAction((MetaRasterOpAction &)*pAct); break;
case META_PUSH_ACTION : DoAction((MetaPushAction &)*pAct); break;
case META_POP_ACTION : DoAction((MetaPopAction &)*pAct); break;
case META_HATCH_ACTION : DoAction((MetaHatchAction &)*pAct); break;
// #i125211# MetaCommentAction may change index, thus hand it over
case META_COMMENT_ACTION : DoAction((MetaCommentAction&)*pAct, rMtf, a);
break;
// missing actions added
case META_TEXTRECT_ACTION : DoAction((MetaTextRectAction&)*pAct); break;
case META_BMPSCALEPART_ACTION : DoAction((MetaBmpScalePartAction&)*pAct); break;
case META_BMPEXSCALEPART_ACTION : DoAction((MetaBmpExScalePartAction&)*pAct); break;
case META_MASK_ACTION : DoAction((MetaMaskAction&)*pAct); break;
case META_MASKSCALE_ACTION : DoAction((MetaMaskScaleAction&)*pAct); break;
case META_MASKSCALEPART_ACTION : DoAction((MetaMaskScalePartAction&)*pAct); break;
case META_GRADIENT_ACTION : DoAction((MetaGradientAction&)*pAct); break;
case META_WALLPAPER_ACTION : DoAction((MetaWallpaperAction&)*pAct); break;
case META_TRANSPARENT_ACTION : DoAction((MetaTransparentAction&)*pAct); break;
case META_EPS_ACTION : DoAction((MetaEPSAction&)*pAct); break;
case META_REFPOINT_ACTION : DoAction((MetaRefPointAction&)*pAct); break;
case META_TEXTLINECOLOR_ACTION : DoAction((MetaTextLineColorAction&)*pAct); break;
case META_TEXTLINE_ACTION : DoAction((MetaTextLineAction&)*pAct); break;
case META_FLOATTRANSPARENT_ACTION : DoAction((MetaFloatTransparentAction&)*pAct); break;
case META_GRADIENTEX_ACTION : DoAction((MetaGradientExAction&)*pAct); break;
case META_LAYOUTMODE_ACTION : DoAction((MetaLayoutModeAction&)*pAct); break;
case META_TEXTLANGUAGE_ACTION : DoAction((MetaTextLanguageAction&)*pAct); break;
case META_OVERLINECOLOR_ACTION : DoAction((MetaOverlineColorAction&)*pAct); break;
}
if(pProgrInfo && pActionsToReport)
{
(*pActionsToReport)++;
if(*pActionsToReport >= 16) // Alle 16 Action updaten
{
if(!pProgrInfo->ReportActions(*pActionsToReport))
break;
*pActionsToReport = 0;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
sal_uInt32 ImpSdrGDIMetaFileImport::DoImport(
const GDIMetaFile& rMtf,
SdrObjList& rOL,
sal_uInt32 nInsPos,
SvdProgressInfo* pProgrInfo)
{
const sal_uInt32 nActionCount(rMtf.GetActionCount());
if(nActionCount)
{
// create mapping from MetaFile coordinates to unit coordinates
maMetaToUnit.identity();
maMetaToUnit.translate(-rMtf.GetPrefMapMode().GetOrigin().X(), -rMtf.GetPrefMapMode().GetOrigin().X());
maMetaToUnit.scale(
rMtf.GetPrefSize().Width() ? 1.0 / rMtf.GetPrefSize().Width() : 1.0,
rMtf.GetPrefSize().Height() ? 1.0 / rMtf.GetPrefSize().Height() : 1.0);
// create full mapping; first to unit coordinates, then apply object transformation
maCurrent = maObjectTransform * maMetaToUnit;
if(pProgrInfo)
{
pProgrInfo->SetActionCount(nActionCount);
}
sal_uInt32 nActionsToReport(0);
// execute
DoLoopActions(const_cast< GDIMetaFile& >(rMtf), pProgrInfo, &nActionsToReport);
if(pProgrInfo)
{
pProgrInfo->ReportActions(nActionsToReport);
nActionsToReport = 0;
}
// Beim berechnen der Fortschrittsanzeige wird GetActionCount()*3 benutzt.
// Da in maTmpList allerdings weniger eintraege als GetActionCount()
// existieren koennen, muessen hier die zuviel vermuteten Actionen wieder
// hinzugefuegt werden.
nActionsToReport = (rMtf.GetActionCount() - maTmpList.size()) * 2;
// Alle noch nicht gemeldeten Rescales melden
if(pProgrInfo)
{
pProgrInfo->ReportRescales(nActionsToReport);
pProgrInfo->SetInsertCount(maTmpList.size());
}
nActionsToReport = 0;
// alle in maTmpList zwischengespeicherten Objekte nun in rOL ab der Position nInsPos einfuegen
if(nInsPos > rOL.GetObjCount())
{
nInsPos = rOL.GetObjCount();
}
for(sal_uInt32 i(0); i < maTmpList.size(); i++)
{
SdrObject* pObj = maTmpList[i];
rOL.InsertObjectToSdrObjList(*pObj, nInsPos);
nInsPos++;
if(pProgrInfo)
{
nActionsToReport++;
if(nActionsToReport >= 32) // Alle 32 Action updaten
{
pProgrInfo->ReportInserts(nActionsToReport);
nActionsToReport = 0;
}
}
}
// ein letztesmal alle verbliebennen Inserts reporten
if(pProgrInfo)
{
pProgrInfo->ReportInserts(nActionsToReport);
}
}
return maTmpList.size();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::SetAttributes(SdrObject* pObj, bool bForceTextAttr)
{
mbNoLine = false;
mbNoFill = false;
bool bLine(!bForceTextAttr);
bool bFill(!pObj || (pObj->IsClosedObj() && !bForceTextAttr));
bool bText(bForceTextAttr || (pObj && pObj->GetOutlinerParaObject()));
if(bLine)
{
if(mnLineWidth)
{
mpLineAttr->Put(XLineWidthItem(mnLineWidth));
}
else
{
mpLineAttr->Put(XLineWidthItem(0));
}
maOldLineColor = maVD.GetLineColor();
if(maVD.IsLineColor())
{
mpLineAttr->Put(XLineStyleItem(XLINE_SOLID));
mpLineAttr->Put(XLineColorItem(String(), maVD.GetLineColor()));
}
else
{
mpLineAttr->Put(XLineStyleItem(XLINE_NONE));
}
switch(maLineJoin)
{
default : // basegfx::B2DLINEJOIN_NONE
mpLineAttr->Put(XLineJointItem(com::sun::star::drawing::LineJoint_NONE));
break;
case basegfx::B2DLINEJOIN_MIDDLE:
mpLineAttr->Put(XLineJointItem(com::sun::star::drawing::LineJoint_MIDDLE));
break;
case basegfx::B2DLINEJOIN_BEVEL:
mpLineAttr->Put(XLineJointItem(com::sun::star::drawing::LineJoint_BEVEL));
break;
case basegfx::B2DLINEJOIN_MITER:
mpLineAttr->Put(XLineJointItem(com::sun::star::drawing::LineJoint_MITER));
break;
case basegfx::B2DLINEJOIN_ROUND:
mpLineAttr->Put(XLineJointItem(com::sun::star::drawing::LineJoint_ROUND));
break;
}
// Add LineCap support
mpLineAttr->Put(XLineCapItem(maLineCap));
if(((maDash.GetDots() && maDash.GetDotLen()) || (maDash.GetDashes() && maDash.GetDashLen())) && maDash.GetDistance())
{
mpLineAttr->Put(XLineDashItem(String(), maDash));
}
else
{
mpLineAttr->Put(XLineDashItem(String(), XDash(XDASH_RECT)));
}
}
else
{
mbNoLine = true;
}
if(bFill)
{
if(maVD.IsFillColor())
{
mpFillAttr->Put(XFillStyleItem(XFILL_SOLID));
mpFillAttr->Put(XFillColorItem(String(), maVD.GetFillColor()));
}
else
{
mpFillAttr->Put(XFillStyleItem(XFILL_NONE));
}
}
else
{
mbNoFill = true;
}
if(bText && mbFntDirty)
{
Font aFnt(maVD.GetFont());
const double fUnitInReal((maCurrent * basegfx::B2DVector(0.0, 1.0)).getLength());
const sal_uInt32 nHeight(FRound(aFnt.GetSize().Height() * fUnitInReal));
mpTextAttr->Put( SvxFontItem( aFnt.GetFamily(), aFnt.GetName(), aFnt.GetStyleName(), aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO ) );
mpTextAttr->Put( SvxFontItem( aFnt.GetFamily(), aFnt.GetName(), aFnt.GetStyleName(), aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CJK ) );
mpTextAttr->Put( SvxFontItem( aFnt.GetFamily(), aFnt.GetName(), aFnt.GetStyleName(), aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CTL ) );
mpTextAttr->Put(SvxPostureItem(aFnt.GetItalic(), EE_CHAR_ITALIC));
mpTextAttr->Put(SvxWeightItem(aFnt.GetWeight(), EE_CHAR_WEIGHT));
mpTextAttr->Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
mpTextAttr->Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
mpTextAttr->Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
mpTextAttr->Put(SvxCharScaleWidthItem(100, EE_CHAR_FONTWIDTH));
mpTextAttr->Put(SvxUnderlineItem(aFnt.GetUnderline(), EE_CHAR_UNDERLINE));
mpTextAttr->Put(SvxOverlineItem(aFnt.GetOverline(), EE_CHAR_OVERLINE));
mpTextAttr->Put(SvxCrossedOutItem(aFnt.GetStrikeout(), EE_CHAR_STRIKEOUT));
mpTextAttr->Put(SvxShadowedItem(aFnt.IsShadow(), EE_CHAR_SHADOW));
// #i118485# Setting this item leads to problems (written #i118498# for this)
// mpTextAttr->Put(SvxAutoKernItem(aFnt.IsKerning(), EE_CHAR_KERNING));
mpTextAttr->Put(SvxWordLineModeItem(aFnt.IsWordLineMode(), EE_CHAR_WLM));
mpTextAttr->Put(SvxContourItem(aFnt.IsOutline(), EE_CHAR_OUTLINE));
mpTextAttr->Put(SvxColorItem(maVD.GetTextColor(), EE_CHAR_COLOR));
//... svxfont textitem svditext
mbFntDirty = false;
}
if(pObj)
{
pObj->SetLayer(mnLayer);
if(bLine)
{
pObj->SetMergedItemSet(*mpLineAttr);
}
if(bFill)
{
pObj->SetMergedItemSet(*mpFillAttr);
}
if(bText)
{
pObj->SetMergedItemSet(*mpTextAttr);
pObj->SetMergedItem(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT));
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::InsertObj(SdrObject* pObj)
{
if(isClip())
{
const basegfx::B2DPolyPolygon aPoly(pObj->TakeXorPoly());
const basegfx::B2DRange aOldRange(aPoly.getB2DRange());
const SdrLayerID aOldLayer(pObj->GetLayer());
const SfxItemSet aOldItemSet(pObj->GetMergedItemSet());
const SdrGrafObj* pSdrGrafObj = dynamic_cast< SdrGrafObj* >(pObj);
const SdrTextObj* pSdrTextObj = dynamic_cast< SdrTextObj* >(pObj);
if(pSdrTextObj && pSdrTextObj->HasText())
{
// all text objects are created from ImportText and have no line or fill attributes, so
// it is okay to concentrate on the text itself
while(true)
{
const basegfx::B2DRange aTextRange(pSdrTextObj->getObjectRange(0)); // TTTT: Check if this works
const basegfx::B2DRange aClipRange(maClip.getB2DRange());
// no overlap -> completely outside
if(!aClipRange.overlaps(aTextRange))
{
deleteSdrObjectSafeAndClearPointer(pObj);
break;
}
// when the clip is a rectangle fast check for inside is possible
if(basegfx::tools::isRectangle(maClip) && aClipRange.isInside(aTextRange))
{
// completely inside ClipRect
break;
}
// here text needs to be clipped; to do so, convert to SdrObjects with polygons
// and add these recursively. Delete original object, do not add in this run
SdrObject* pConverted = pSdrTextObj->ConvertToPolyObj(true, true);
deleteSdrObjectSafeAndClearPointer(pObj);
if(pConverted)
{
// recursively add created conversion; per definition this shall not
// contain further SdrTextObjs. Visit only non-group objects
SdrObjListIter aIter(*pConverted, IM_DEEPNOGROUPS);
// work with clones; the created conversion may contain group objects
// and when working with the original objects the loop itself could
// break and the cleanup later would be pretty complicated (only delete group
// objects, are these empty, ...?)
while(aIter.IsMore())
{
SdrObject* pCandidate = aIter.Next();
OSL_ENSURE(pCandidate && 0 == dynamic_cast< SdrObjGroup* >(pCandidate), "SdrObjListIter with IM_DEEPNOGROUPS error (!)");
SdrObject* pNewClone = pCandidate->CloneSdrObject();
if(pNewClone)
{
InsertObj(pNewClone);
}
else
{
OSL_ENSURE(false, "SdrObject::Clone() failed (!)");
}
}
// cleanup temporary conversion objects
deleteSdrObjectSafeAndClearPointer(pConverted);
}
break;
}
}
else
{
BitmapEx aBitmapEx;
if(pSdrGrafObj)
{
aBitmapEx = pSdrGrafObj->GetGraphic().GetBitmapEx();
}
deleteSdrObjectSafeAndClearPointer(pObj);
if(!aOldRange.isEmpty())
{
// clip against ClipRegion
const basegfx::B2DPolyPolygon aNewPoly(
basegfx::tools::clipPolyPolygonOnPolyPolygon(
aPoly,
maClip,
true,
aPoly.isClosed() ? false : true));
const basegfx::B2DRange aNewRange(aNewPoly.getB2DRange());
if(!aNewRange.isEmpty())
{
pObj = new SdrPathObj(
mrModel,
aNewPoly);
pObj->SetLayer(aOldLayer);
pObj->SetMergedItemSet(aOldItemSet);
if(!!aBitmapEx)
{
// aNewRange is inside of aOldRange and defines which part of aBitmapEx is used
const double fScaleX(aBitmapEx.GetSizePixel().Width() / (aOldRange.getWidth() ? aOldRange.getWidth() : 1.0));
const double fScaleY(aBitmapEx.GetSizePixel().Height() / (aOldRange.getHeight() ? aOldRange.getHeight() : 1.0));
basegfx::B2DRange aPixel(aNewRange);
basegfx::B2DHomMatrix aTrans;
aTrans.translate(-aOldRange.getMinX(), -aOldRange.getMinY());
aTrans.scale(fScaleX, fScaleY);
aPixel.transform(aTrans);
const Size aOrigSizePixel(aBitmapEx.GetSizePixel());
const Point aClipTopLeft(
basegfx::fround(floor(std::max(0.0, aPixel.getMinX()))),
basegfx::fround(floor(std::max(0.0, aPixel.getMinY()))));
const Size aClipSize(
basegfx::fround(ceil(std::min((double)aOrigSizePixel.Width(), aPixel.getWidth()))),
basegfx::fround(ceil(std::min((double)aOrigSizePixel.Height(), aPixel.getHeight()))));
const BitmapEx aClippedBitmap(
aBitmapEx,
aClipTopLeft,
aClipSize);
pObj->SetMergedItem(XFillStyleItem(XFILL_BITMAP));
pObj->SetMergedItem(XFillBitmapItem(String(), Graphic(aClippedBitmap)));
pObj->SetMergedItem(XFillBmpTileItem(false));
pObj->SetMergedItem(XFillBmpStretchItem(true));
}
}
}
}
}
if(pObj)
{
// #i111954# check object for visibility
// used are SdrPathObj, SdrRectObj, SdrCircObj, SdrGrafObj
bool bVisible(false);
if(pObj->HasLineStyle())
{
bVisible = true;
}
if(!bVisible && pObj->HasFillStyle())
{
bVisible = true;
}
if(!bVisible)
{
SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >(pObj);
if(pTextObj && pTextObj->HasText())
{
bVisible = true;
}
}
if(!bVisible)
{
SdrGrafObj* pGrafObj = dynamic_cast< SdrGrafObj* >(pObj);
if(pGrafObj)
{
// this may be refined to check if the graphic really is visible. It
// is here to ensure that graphic objects without fill, line and text
// get created
bVisible = true;
}
}
if(!bVisible)
{
deleteSdrObjectSafeAndClearPointer(pObj);
}
else
{
maTmpList.push_back(pObj);
if(dynamic_cast< SdrPathObj* >(pObj))
{
const bool bClosed(pObj->IsClosedObj());
mbLastObjWasPolyWithoutLine = mbNoLine && bClosed;
mbLastObjWasLine = !bClosed;
}
else
{
mbLastObjWasPolyWithoutLine = false;
mbLastObjWasLine = false;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaPixelAction& /*rAct*/)
{
OSL_ENSURE(false, "Tried to construct SdrObject from MetaPixelAction: not supported (!)");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaPointAction& /*rAct*/)
{
OSL_ENSURE(false, "Tried to construct SdrObject from MetaPointAction: not supported (!)");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaLineAction& rAct)
{
const basegfx::B2DPoint aStart(rAct.GetStartPoint().X(), rAct.GetStartPoint().Y());
const basegfx::B2DPoint aEnd(rAct.GetEndPoint().X(), rAct.GetEndPoint().Y());
if(!aStart.equal(aEnd))
{
basegfx::B2DPolygon aLine;
aLine.append(aStart);
aLine.append(aEnd);
aLine.transform(maCurrent);
const LineInfo& rLineInfo = rAct.GetLineInfo();
const sal_Int32 nNewLineWidth(rLineInfo.GetWidth());
bool bCreateLineObject(true);
if(mbLastObjWasLine && (nNewLineWidth == mnLineWidth) && CheckLastLineMerge(aLine))
{
bCreateLineObject = false;
}
if(bCreateLineObject)
{
SdrPathObj* pPath = new SdrPathObj(
mrModel,
basegfx::B2DPolyPolygon(aLine));
mnLineWidth = nNewLineWidth;
maLineJoin = rLineInfo.GetLineJoin();
maLineCap = rLineInfo.GetLineCap();
maDash = XDash(XDASH_RECT,
rLineInfo.GetDotCount(), rLineInfo.GetDotLen(),
rLineInfo.GetDashCount(), rLineInfo.GetDashLen(),
rLineInfo.GetDistance());
SetAttributes(pPath);
mnLineWidth = 0;
maLineJoin = basegfx::B2DLINEJOIN_NONE;
maDash = XDash();
InsertObj(pPath);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaRectAction& rAct)
{
const Rectangle& rRect(rAct.GetRect());
SdrRectObj* pRect = new SdrRectObj(
mrModel,
maCurrent * basegfx::tools::createScaleTranslateB2DHomMatrix(
rRect.getWidth(), rRect.getHeight(),
rRect.Left(), rRect.Top()));
SetAttributes(pRect);
InsertObj(pRect);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaRoundRectAction& rAct)
{
const Rectangle& rRect(rAct.GetRect());
SdrRectObj* pRect = new SdrRectObj(
mrModel,
maCurrent * basegfx::tools::createScaleTranslateB2DHomMatrix(
rRect.getWidth(), rRect.getHeight(),
rRect.Left(), rRect.Top()));
SetAttributes(pRect);
const sal_uInt32 nRad((rAct.GetHorzRound() + rAct.GetVertRound()) / 2);
if(nRad)
{
pRect->SetMergedItem(SdrMetricItem(SDRATTR_ECKENRADIUS, nRad));
}
InsertObj(pRect);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaEllipseAction& rAct)
{
const Rectangle& rRect(rAct.GetRect());
SdrCircObj* pCirc = new SdrCircObj(
mrModel,
CircleType_Circle,
maCurrent * basegfx::tools::createScaleTranslateB2DHomMatrix(
rRect.getWidth(), rRect.getHeight(),
rRect.Left(), rRect.Top()));
SetAttributes(pCirc);
InsertObj(pCirc);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace
{
void impPrepareAngles(const Point& rCenter, const Point& rStart, const Point& rEnd, double& o_Start, double& o_End)
{
o_Start = atan2((double)(rStart.Y() - rCenter.Y()), (double)(rStart.X() - rCenter.X()));
if(o_Start < 0.0)
{
o_Start += F_2PI;
}
o_End = atan2((double)(rEnd.Y() - rCenter.Y()), (double)(rEnd.X() - rCenter.X()));
if(o_End < 0.0)
{
o_End += F_2PI;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaArcAction& rAct)
{
double fStart(0.0);
double fEnd(F_2PI);
const Rectangle& rRect(rAct.GetRect());
impPrepareAngles(rRect.Center(), rAct.GetStartPoint(), rAct.GetEndPoint(), fStart, fEnd);
SdrCircObj* pCirc = new SdrCircObj(
mrModel,
CircleType_Circle,
maCurrent * basegfx::tools::createScaleTranslateB2DHomMatrix(
rRect.getWidth(), rRect.getHeight(),
rRect.Left(), rRect.Top()),
fStart,
fEnd);
SetAttributes(pCirc);
InsertObj(pCirc);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaPieAction& rAct)
{
double fStart(0.0);
double fEnd(F_2PI);
const Rectangle& rRect(rAct.GetRect());
impPrepareAngles(rRect.Center(), rAct.GetStartPoint(), rAct.GetEndPoint(), fStart, fEnd);
SdrCircObj* pCirc = new SdrCircObj(
mrModel,
CircleType_Sector,
maCurrent * basegfx::tools::createScaleTranslateB2DHomMatrix(
rRect.getWidth(), rRect.getHeight(),
rRect.Left(), rRect.Top()),
fStart,
fEnd);
SetAttributes(pCirc);
InsertObj(pCirc);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaChordAction& rAct)
{
double fStart(0.0);
double fEnd(F_2PI);
const Rectangle& rRect(rAct.GetRect());
impPrepareAngles(rRect.Center(), rAct.GetStartPoint(), rAct.GetEndPoint(), fStart, fEnd);
SdrCircObj* pCirc = new SdrCircObj(
mrModel,
CircleType_Segment,
maCurrent * basegfx::tools::createScaleTranslateB2DHomMatrix(
rRect.getWidth(), rRect.getHeight(),
rRect.Left(), rRect.Top()),
fStart,
fEnd);
SetAttributes(pCirc);
InsertObj(pCirc);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool ImpSdrGDIMetaFileImport::CheckLastLineMerge(const basegfx::B2DPolygon& rSrcPoly)
{
// #i102706# Do not merge closed polygons
if(rSrcPoly.isClosed())
{
return false;
}
if(mbLastObjWasLine && (maOldLineColor == maVD.GetLineColor()) && rSrcPoly.count())
{
SdrObject* pTmpObj = maTmpList.size() ? maTmpList[maTmpList.size() - 1] : 0;
SdrPathObj* pLastPoly = dynamic_cast< SdrPathObj* >(pTmpObj);
if(pLastPoly)
{
if(1 == pLastPoly->getB2DPolyPolygonInObjectCoordinates().count())
{
bool bOk(false);
basegfx::B2DPolygon aDstPoly(pLastPoly->getB2DPolyPolygonInObjectCoordinates().getB2DPolygon(0));
// #i102706# Do not merge closed polygons
if(aDstPoly.isClosed())
{
return false;
}
if(aDstPoly.count())
{
const sal_uInt32 nMaxDstPnt(aDstPoly.count() - 1L);
const sal_uInt32 nMaxSrcPnt(rSrcPoly.count() - 1L);
if(aDstPoly.getB2DPoint(nMaxDstPnt) == rSrcPoly.getB2DPoint(0L))
{
aDstPoly.append(rSrcPoly, 1L, rSrcPoly.count() - 1L);
bOk = true;
}
else if(aDstPoly.getB2DPoint(0L) == rSrcPoly.getB2DPoint(nMaxSrcPnt))
{
basegfx::B2DPolygon aNew(rSrcPoly);
aNew.append(aDstPoly, 1L, aDstPoly.count() - 1L);
aDstPoly = aNew;
bOk = true;
}
else if(aDstPoly.getB2DPoint(0L) == rSrcPoly.getB2DPoint(0L))
{
aDstPoly.flip();
aDstPoly.append(rSrcPoly, 1L, rSrcPoly.count() - 1L);
bOk = true;
}
else if(aDstPoly.getB2DPoint(nMaxDstPnt) == rSrcPoly.getB2DPoint(nMaxSrcPnt))
{
basegfx::B2DPolygon aNew(rSrcPoly);
aNew.flip();
aDstPoly.append(aNew, 1L, aNew.count() - 1L);
bOk = true;
}
}
if(bOk)
{
pLastPoly->setB2DPolyPolygonInObjectCoordinates(basegfx::B2DPolyPolygon(aDstPoly));
}
return bOk;
}
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool ImpSdrGDIMetaFileImport::CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon & rPolyPolygon)
{
if(mbLastObjWasPolyWithoutLine)
{
SdrObject* pTmpObj = maTmpList.size() ? maTmpList[maTmpList.size() - 1] : 0;
SdrPathObj* pLastPoly = dynamic_cast< SdrPathObj* >(pTmpObj);
if(pLastPoly)
{
if(pLastPoly->getB2DPolyPolygonInObjectCoordinates() == rPolyPolygon)
{
SetAttributes(0);
if(!mbNoLine && mbNoFill)
{
pLastPoly->SetMergedItemSet(*mpLineAttr);
return true;
}
}
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::checkClip()
{
if(maVD.IsClipRegion())
{
maClip = maVD.GetClipRegion().GetAsB2DPolyPolygon();
if(isClip())
{
maClip.transform(maCurrent);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool ImpSdrGDIMetaFileImport::isClip() const
{
return !maClip.getB2DRange().isEmpty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction( MetaPolyLineAction& rAct )
{
basegfx::B2DPolygon aSource(rAct.GetPolygon().getB2DPolygon());
if(aSource.count())
{
aSource.transform(maCurrent);
const LineInfo& rLineInfo = rAct.GetLineInfo();
const sal_Int32 nNewLineWidth(rLineInfo.GetWidth());
bool bCreateLineObject(true);
if(mbLastObjWasLine && (nNewLineWidth == mnLineWidth) && CheckLastLineMerge(aSource))
{
bCreateLineObject = false;
}
else if(mbLastObjWasPolyWithoutLine && CheckLastPolyLineAndFillMerge(basegfx::B2DPolyPolygon(aSource)))
{
bCreateLineObject = false;
}
if(bCreateLineObject)
{
SdrPathObj* pPath = new SdrPathObj(
mrModel,
basegfx::B2DPolyPolygon(aSource));
mnLineWidth = nNewLineWidth;
maLineJoin = rLineInfo.GetLineJoin();
maLineCap = rLineInfo.GetLineCap();
maDash = XDash(XDASH_RECT,
rLineInfo.GetDotCount(), rLineInfo.GetDotLen(),
rLineInfo.GetDashCount(), rLineInfo.GetDashLen(),
rLineInfo.GetDistance());
SetAttributes(pPath);
mnLineWidth = 0;
maLineJoin = basegfx::B2DLINEJOIN_NONE;
maDash = XDash();
InsertObj(pPath);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaPolygonAction& rAct)
{
basegfx::B2DPolygon aSource(rAct.GetPolygon().getB2DPolygon());
if(aSource.count())
{
aSource.transform(maCurrent);
if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(basegfx::B2DPolyPolygon(aSource)))
{
// #i73407# make sure polygon is closed, it's a filled primitive
aSource.setClosed(true);
SdrPathObj* pPath = new SdrPathObj(
mrModel,
basegfx::B2DPolyPolygon(aSource));
SetAttributes(pPath);
InsertObj(pPath);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaPolyPolygonAction& rAct)
{
basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
if(aSource.count())
{
aSource.transform(maCurrent);
if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aSource))
{
// #i73407# make sure polygon is closed, it's a filled primitive
aSource.setClosed(true);
SdrPathObj* pPath = new SdrPathObj(
mrModel,
aSource);
SetAttributes(pPath);
InsertObj(pPath);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::ImportText( const Point& rPos, const XubString& rStr, const MetaAction& rAct )
{
// calc text box size
const FontMetric aFontMetric(maVD.GetFontMetric());
const Font aFnt(maVD.GetFont());
const FontAlign eAlg(aFnt.GetAlign());
basegfx::B2DVector aTextScale(maVD.GetTextWidth(rStr), maVD.GetTextHeight());
basegfx::B2DPoint aTextPos(rPos.X(), rPos.Y());
basegfx::B2DHomMatrix aTextMatrix;
if(ALIGN_BASELINE == eAlg)
{
aTextPos.setY(aTextPos.getY() - aFontMetric.GetAscent());
}
else if(ALIGN_BOTTOM == eAlg)
{
aTextPos.setY(aTextPos.getY() - aTextScale.getY());
}
aTextScale = maCurrent * aTextScale;
aTextPos = maCurrent * aTextPos;
if(aFnt.GetOrientation())
{
aTextMatrix.rotate(F_PI180 * (aFnt.GetOrientation() * 0.10));
}
aTextMatrix.scale(aTextScale);
aTextMatrix.translate(aTextPos);
SdrRectObj* pText = new SdrRectObj(
mrModel,
aTextMatrix,
OBJ_TEXT,
true);
pText->SetMergedItem(SdrMetricItem(SDRATTR_TEXT_UPPERDIST, 0));
pText->SetMergedItem(SdrMetricItem(SDRATTR_TEXT_LOWERDIST, 0));
pText->SetMergedItem(SdrMetricItem(SDRATTR_TEXT_RIGHTDIST, 0));
pText->SetMergedItem(SdrMetricItem(SDRATTR_TEXT_LEFTDIST, 0));
if ( aFnt.GetWidth() || ( rAct.GetType() == META_STRETCHTEXT_ACTION ) )
{
pText->ClearMergedItem( SDRATTR_TEXT_AUTOGROWWIDTH );
pText->SetMergedItem( SdrOnOffItem(SDRATTR_TEXT_AUTOGROWHEIGHT, false) );
// don't let the margins eat the space needed for the text
pText->SetMergedItem( SdrTextFitToSizeTypeItem( SDRTEXTFIT_ALLLINES ) );
}
else
{
pText->SetMergedItem( SdrOnOffItem(SDRATTR_TEXT_AUTOGROWWIDTH, true ) );
}
pText->SetLayer(mnLayer);
pText->SetText(rStr);
SetAttributes(pText, true);
if (!aFnt.IsTransparent())
{
SfxItemSet aAttr(*mpFillAttr->GetPool(), XATTR_FILL_FIRST, XATTR_FILL_LAST, 0, 0);
aAttr.Put(XFillStyleItem(XFILL_SOLID));
aAttr.Put(XFillColorItem(String(), aFnt.GetFillColor()));
pText->SetMergedItemSet(aAttr);
}
InsertObj(pText);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaTextAction& rAct)
{
XubString aStr(rAct.GetText());
aStr.Erase(0,rAct.GetIndex());
aStr.Erase(rAct.GetLen());
ImportText( rAct.GetPoint(), aStr, rAct );
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaTextArrayAction& rAct)
{
XubString aStr(rAct.GetText());
aStr.Erase(0,rAct.GetIndex());
aStr.Erase(rAct.GetLen());
ImportText( rAct.GetPoint(), aStr, rAct );
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaStretchTextAction& rAct)
{
XubString aStr(rAct.GetText());
aStr.Erase(0,rAct.GetIndex());
aStr.Erase(rAct.GetLen());
ImportText( rAct.GetPoint(), aStr, rAct );
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpAction& rAct)
{
const Rectangle aRect(rAct.GetPoint(), rAct.GetBitmap().GetSizePixel());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
Graphic(rAct.GetBitmap()),
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpScaleAction& rAct)
{
const Rectangle aRect(rAct.GetPoint(), rAct.GetSize());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
Graphic(rAct.GetBitmap()),
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExAction& rAct)
{
const Rectangle aRect(rAct.GetPoint(), rAct.GetBitmapEx().GetSizePixel());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
rAct.GetBitmapEx(),
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExScaleAction& rAct)
{
const Rectangle aRect(rAct.GetPoint(), rAct.GetSize());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
rAct.GetBitmapEx(),
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction( MetaHatchAction& rAct )
{
basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
if(aSource.count())
{
aSource.transform(maCurrent);
if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aSource))
{
const Hatch& rHatch = rAct.GetHatch();
SdrPathObj* pPath = new SdrPathObj(
mrModel,
aSource);
// #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
SfxItemSet aHatchAttr(pPath->GetObjectItemPool(), pPath->GetMergedItemSet().GetRanges());
XHatchStyle eStyle;
switch(rHatch.GetStyle())
{
case(HATCH_TRIPLE) :
{
eStyle = XHATCH_TRIPLE;
break;
}
case(HATCH_DOUBLE) :
{
eStyle = XHATCH_DOUBLE;
break;
}
default:
{
eStyle = XHATCH_SINGLE;
break;
}
}
SetAttributes(pPath);
aHatchAttr.Put(XFillStyleItem(XFILL_HATCH));
aHatchAttr.Put(XFillHatchItem(&pPath->GetObjectItemPool(), XHatch(rHatch.GetColor(), eStyle, rHatch.GetDistance(), rHatch.GetAngle())));
pPath->SetMergedItemSet(aHatchAttr);
InsertObj(pPath);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaMapModeAction& rAct)
{
rAct.Execute(&maVD);
// create new transformation since this action may set a relative mapping action.
// thus, first apply new mapping, then from metafuile to unit, and then object transformation
maCurrent = maObjectTransform * maMetaToUnit * maVD.GetViewTransformation();
mbLastObjWasPolyWithoutLine = false;
mbLastObjWasLine = false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction( MetaCommentAction& rAct, GDIMetaFile& rMtf, sal_uLong& a) // GDIMetaFile* pMtf )
{
ByteString aSkipComment;
if( a < rMtf.GetActionCount() && rAct.GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL )
{
// #i125211# Check if next action is a MetaGradientExAction
MetaGradientExAction* pAct = dynamic_cast< MetaGradientExAction* >(rMtf.GetAction(a + 1));
if( pAct && pAct->GetType() == META_GRADIENTEX_ACTION )
{
basegfx::B2DPolyPolygon aSource(pAct->GetPolyPolygon().getB2DPolyPolygon());
if(aSource.count())
{
aSource.transform(maCurrent); // TTTT: needed? was missing before
if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aSource))
{
const Gradient& rGrad = pAct->GetGradient();
SdrPathObj* pPath = new SdrPathObj(
mrModel,
aSource);
// #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
SfxItemSet aGradAttr(pPath->GetObjectItemPool(), pPath->GetMergedItemSet().GetRanges());
XGradient aXGradient;
aXGradient.SetGradientStyle((XGradientStyle)rGrad.GetStyle());
aXGradient.SetStartColor(rGrad.GetStartColor());
aXGradient.SetEndColor(rGrad.GetEndColor());
aXGradient.SetAngle((sal_uInt16)rGrad.GetAngle());
aXGradient.SetBorder(rGrad.GetBorder());
aXGradient.SetXOffset(rGrad.GetOfsX());
aXGradient.SetYOffset(rGrad.GetOfsY());
aXGradient.SetStartIntens(rGrad.GetStartIntensity());
aXGradient.SetEndIntens(rGrad.GetEndIntensity());
aXGradient.SetSteps(rGrad.GetSteps());
// no need to use SetAttributes(..) here since line and fill style
// need to be set individually
// SetAttributes(pPath);
// switch line off; when there was one there will be a
// META_POLYLINE_ACTION following creating another object
aGradAttr.Put(XLineStyleItem(XLINE_NONE));
// add detected gradient fillstyle
aGradAttr.Put(XFillStyleItem(XFILL_GRADIENT));
aGradAttr.Put(XFillGradientItem(&mrModel.GetItemPool(), aXGradient));
pPath->SetMergedItemSet(aGradAttr);
InsertObj(pPath);
}
}
aSkipComment = "XGRAD_SEQ_END";
}
}
if(aSkipComment.Len())
{
// #i125211# forward until closing MetaCommentAction
MetaAction* pSkipAct = rMtf.GetAction(++a);
while( pSkipAct
&& ((pSkipAct->GetType() != META_COMMENT_ACTION )
|| (((MetaCommentAction*)pSkipAct)->GetComment().CompareIgnoreCaseToAscii(aSkipComment.GetBuffer()) != COMPARE_EQUAL)))
{
pSkipAct = rMtf.GetAction(++a);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaTextRectAction& rAct)
{
GDIMetaFile aTemp;
// dismantle MetaTextRectActions to own metafile and execute
maVD.AddTextRectActions(rAct.GetRect(), rAct.GetText(), rAct.GetStyle(), aTemp);
DoLoopActions(aTemp, 0, 0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpScalePartAction& rAct)
{
const Rectangle aRect(rAct.GetDestPoint(), rAct.GetDestSize());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
Bitmap aBitmap(rAct.GetBitmap());
aBitmap.Crop(Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
aBitmap,
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExScalePartAction& rAct)
{
const Rectangle aRect(rAct.GetDestPoint(), rAct.GetDestSize());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
BitmapEx aBitmapEx(rAct.GetBitmapEx());
aBitmapEx.Crop(Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
aBitmapEx,
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaMaskAction& rAct)
{
const Rectangle aRect(rAct.GetPoint(), rAct.GetBitmap().GetSizePixel());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
const BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
aBitmapEx,
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaMaskScaleAction& rAct)
{
const Rectangle aRect(rAct.GetPoint(), rAct.GetSize());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
const BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
aBitmapEx,
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaMaskScalePartAction& rAct)
{
const Rectangle aRect(rAct.GetDestPoint(), rAct.GetDestSize());
const basegfx::B2DHomMatrix aGrafMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRect.getWidth() + 1, aRect.getHeight() + 1,
aRect.Left(), aRect.Top()));
BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
aBitmapEx.Crop(Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
aBitmapEx,
maCurrent * aGrafMatrix);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
XGradientStyle getXGradientStyleFromGradientStyle(const GradientStyle& rGradientStyle)
{
XGradientStyle aXGradientStyle(XGRAD_LINEAR);
switch(rGradientStyle)
{
case GRADIENT_LINEAR: aXGradientStyle = XGRAD_LINEAR; break;
case GRADIENT_AXIAL: aXGradientStyle = XGRAD_AXIAL; break;
case GRADIENT_RADIAL: aXGradientStyle = XGRAD_RADIAL; break;
case GRADIENT_ELLIPTICAL: aXGradientStyle = XGRAD_ELLIPTICAL; break;
case GRADIENT_SQUARE: aXGradientStyle = XGRAD_SQUARE; break;
case GRADIENT_RECT: aXGradientStyle = XGRAD_RECT; break;
// Needed due to GRADIENT_FORCE_EQUAL_SIZE; this again is needed
// to force the enum defines in VCL to a defined size for the compilers,
// so despite it is never used it cannot be removed (would break the
// API implementation probably).
default: break;
}
return aXGradientStyle;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaGradientAction& rAct)
{
basegfx::B2DRange aRange(
rAct.GetRect().Left(),
rAct.GetRect().Top(),
rAct.GetRect().Right() + 1,
rAct.GetRect().Bottom() + 1);
if(!aRange.isEmpty())
{
basegfx::B2DHomMatrix aObjectTransform(
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRange.getRange(),
aRange.getMinimum()));
SdrRectObj* pRect = new SdrRectObj(
mrModel,
maCurrent * aObjectTransform);
// #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
SfxItemSet aGradientAttr(mrModel.GetItemPool(), pRect->GetMergedItemSet().GetRanges());
const Gradient& rGradient = rAct.GetGradient();
const XGradientStyle aXGradientStyle(getXGradientStyleFromGradientStyle(rGradient.GetStyle()));
const XFillGradientItem aXFillGradientItem(
&mrModel.GetItemPool(),
XGradient(
rGradient.GetStartColor(),
rGradient.GetEndColor(),
aXGradientStyle,
rGradient.GetAngle(),
rGradient.GetOfsX(),
rGradient.GetOfsY(),
rGradient.GetBorder(),
rGradient.GetStartIntensity(),
rGradient.GetEndIntensity(),
rGradient.GetSteps()));
SetAttributes(pRect);
aGradientAttr.Put(XFillStyleItem(XFILL_GRADIENT)); // #i125211#
aGradientAttr.Put(aXFillGradientItem);
pRect->SetMergedItemSet(aGradientAttr);
InsertObj(pRect);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaWallpaperAction& /*rAct*/)
{
OSL_ENSURE(false, "Tried to construct SdrObject from MetaWallpaperAction: not supported (!)");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaTransparentAction& rAct)
{
basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
if(aSource.count())
{
aSource.transform(maCurrent);
aSource.setClosed(true);
SdrPathObj* pPath = new SdrPathObj(
mrModel,
aSource);
SetAttributes(pPath);
pPath->SetMergedItem(XFillTransparenceItem(rAct.GetTransparence()));
InsertObj(pPath);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaEPSAction& /*rAct*/)
{
OSL_ENSURE(false, "Tried to construct SdrObject from MetaEPSAction: not supported (!)");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaTextLineAction& /*rAct*/)
{
OSL_ENSURE(false, "Tried to construct SdrObject from MetaTextLineAction: not supported (!)");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ImpSdrGDIMetaFileImport::DoAction(MetaGradientExAction& rAct)
{
basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
if(aSource.count())
{
aSource.transform(maCurrent);
if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aSource))
{
// #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
SdrPathObj* pPath = new SdrPathObj(
mrModel,
aSource);
SfxItemSet aGradientAttr(mrModel.GetItemPool(), pPath->GetMergedItemSet().GetRanges());
const Gradient& rGradient = rAct.GetGradient();
const XGradientStyle aXGradientStyle(getXGradientStyleFromGradientStyle(rGradient.GetStyle()));
const XFillGradientItem aXFillGradientItem(
&mrModel.GetItemPool(),
XGradient(
rGradient.GetStartColor(),
rGradient.GetEndColor(),
aXGradientStyle,
rGradient.GetAngle(),
rGradient.GetOfsX(),
rGradient.GetOfsY(),
rGradient.GetBorder(),
rGradient.GetStartIntensity(),
rGradient.GetEndIntensity(),
rGradient.GetSteps()));
SetAttributes(pPath);
aGradientAttr.Put(XFillStyleItem(XFILL_GRADIENT)); // #i125211#
aGradientAttr.Put(aXFillGradientItem);
pPath->SetMergedItemSet(aGradientAttr);
InsertObj(pPath);
}
}
}
void ImpSdrGDIMetaFileImport::DoAction(MetaFloatTransparentAction& rAct)
{
const GDIMetaFile& rMtf = rAct.GetGDIMetaFile();
if(rMtf.GetActionCount())
{
const Rectangle aRect(rAct.GetPoint(), rAct.GetSize());
basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());
// go to object target coordinates to get a good relative size
aRange.transform(maCurrent);
// convert metafile sub-content to BitmapEx
BitmapEx aBitmapEx(
convertMetafileToBitmapEx(
rMtf,
aRange,
125000));
// handle colors
const Gradient& rGradient = rAct.GetGradient();
basegfx::BColor aStart(rGradient.GetStartColor().getBColor());
basegfx::BColor aEnd(rGradient.GetEndColor().getBColor());
if(100 != rGradient.GetStartIntensity())
{
aStart *= (double)rGradient.GetStartIntensity() / 100.0;
}
if(100 != rGradient.GetEndIntensity())
{
aEnd *= (double)rGradient.GetEndIntensity() / 100.0;
}
const bool bEqualColors(aStart == aEnd);
const bool bNoSteps(1 == rGradient.GetSteps());
bool bCreateObject(true);
bool bHasNewMask(false);
AlphaMask aNewMask;
double fTransparence(0.0);
bool bFixedTransparence(false);
if(bEqualColors || bNoSteps)
{
// single transparence
const basegfx::BColor aMedium(basegfx::average(aStart, aEnd));
fTransparence = aMedium.luminance();
if(basegfx::fTools::lessOrEqual(fTransparence, 0.0))
{
// no transparence needed, all done
}
else if(basegfx::fTools::moreOrEqual(fTransparence, 1.0))
{
// all transparent, no object
bCreateObject = false;
}
else
{
// 0.0 < transparence < 1.0, apply fixed transparence
bFixedTransparence = true;
}
}
else
{
// gradient transparence
VirtualDevice aVDev;
aVDev.SetOutputSizePixel(aBitmapEx.GetBitmap().GetSizePixel());
aVDev.DrawGradient(Rectangle(Point(0, 0), aVDev.GetOutputSizePixel()), rGradient);
aNewMask = AlphaMask(aVDev.GetBitmap(Point(0, 0), aVDev.GetOutputSizePixel()));
bHasNewMask = true;
}
if(bCreateObject)
{
if(bHasNewMask || bFixedTransparence)
{
if(!aBitmapEx.IsAlpha() && !aBitmapEx.IsTransparent())
{
// no transparence yet, apply new one
if(bFixedTransparence)
{
sal_uInt8 aAlpha(static_cast< sal_uInt8 >(basegfx::fround(fTransparence * 255.0)));
aNewMask = AlphaMask(aBitmapEx.GetBitmap().GetSizePixel(), &aAlpha);
}
aBitmapEx = BitmapEx(aBitmapEx.GetBitmap(), aNewMask);
}
else
{
// mix existing and new alpha mask
AlphaMask aOldMask;
if(aBitmapEx.IsAlpha())
{
aOldMask = aBitmapEx.GetAlpha();
}
else if(TRANSPARENT_BITMAP == aBitmapEx.GetTransparentType())
{
aOldMask = aBitmapEx.GetMask();
}
else if(TRANSPARENT_COLOR == aBitmapEx.GetTransparentType())
{
aOldMask = aBitmapEx.GetBitmap().CreateMask(aBitmapEx.GetTransparentColor());
}
BitmapWriteAccess* pOld = aOldMask.AcquireWriteAccess();
if(pOld)
{
const double fFactor(1.0 / 255.0);
if(bFixedTransparence)
{
const double fOpNew(1.0 - fTransparence);
for(sal_uInt32 y(0); y < static_cast< sal_uInt32 >(pOld->Height()); y++)
{
for(sal_uInt32 x(0); x < static_cast< sal_uInt32 >(pOld->Width()); x++)
{
const double fOpOld(1.0 - (pOld->GetPixel(y, x).GetIndex() * fFactor));
const sal_uInt8 aCol(static_cast< sal_uInt8 >(basegfx::fround((1.0 - (fOpOld * fOpNew)) * 255.0)));
pOld->SetPixel(y, x, BitmapColor(aCol));
}
}
}
else
{
BitmapReadAccess* pNew = aNewMask.AcquireReadAccess();
if(pNew)
{
if(pOld->Width() == pNew->Width() && pOld->Height() == pNew->Height())
{
for(sal_uInt32 y(0); y < static_cast< sal_uInt32 >(pOld->Height()); y++)
{
for(sal_uInt32 x(0); x < static_cast< sal_uInt32 >(pOld->Width()); x++)
{
const double fOpOld(1.0 - (pOld->GetPixel(y, x).GetIndex() * fFactor));
const double fOpNew(1.0 - (pNew->GetPixel(y, x).GetIndex() * fFactor));
const sal_uInt8 aCol(static_cast< sal_uInt8 >(basegfx::fround((1.0 - (fOpOld * fOpNew)) * 255.0)));
pOld->SetPixel(y, x, BitmapColor(aCol));
}
}
}
else
{
OSL_ENSURE(false, "Alpha masks have different sizes (!)");
}
aNewMask.ReleaseAccess(pNew);
}
else
{
OSL_ENSURE(false, "Got no access to new alpha mask (!)");
}
}
aOldMask.ReleaseAccess(pOld);
}
else
{
OSL_ENSURE(false, "Got no access to old alpha mask (!)");
}
// apply combined bitmap as mask
aBitmapEx = BitmapEx(aBitmapEx.GetBitmap(), aOldMask);
}
}
// create and add object
SdrGrafObj* pGraf = new SdrGrafObj(
mrModel,
aBitmapEx,
basegfx::tools::createScaleTranslateB2DHomMatrix(
aRange.getRange(),
aRange.getMinimum()));
// for MetaFloatTransparentAction, do not use SetAttributes(...)
// since these metafile content is not used to draw line/fill
// dependent of these setting at the device content
pGraf->SetMergedItem(XLineStyleItem(XLINE_NONE));
pGraf->SetMergedItem(XFillStyleItem(XFILL_NONE));
InsertObj(pGraf);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// eof