1
0
Fork 0
libreoffice/svx/source/svdraw/svdfmtf.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

1617 lines
58 KiB
C++

/* -*- 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 "svdfmtf.hxx"
#include <math.h>
#include <editeng/eeitem.hxx>
#include <editeng/fhgtitem.hxx>
#include <editeng/wghtitem.hxx>
#include <editeng/postitem.hxx>
#include <editeng/udlnitem.hxx>
#include <editeng/crossedoutitem.hxx>
#include <editeng/shdditem.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xlnclit.hxx>
#include <svx/xlncapit.hxx>
#include <svx/xlnwtit.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xflclit.hxx>
#include <svx/xflgrit.hxx>
#include <editeng/fontitem.hxx>
#include <editeng/wrlmitem.hxx>
#include <editeng/contouritem.hxx>
#include <editeng/colritem.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/metric.hxx>
#include <editeng/charscaleitem.hxx>
#include <svx/xflhtit.hxx>
#include <svx/sdmetitm.hxx>
#include <svx/sdtagitm.hxx>
#include <svx/sdtaitm.hxx>
#include <svx/sdtditm.hxx>
#include <svx/sdtfsitm.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdobj.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 <tools/helpers.hxx>
#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 <svx/xflbmtit.hxx>
#include <svx/xflbstit.hxx>
#include <svx/svdpntv.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <svx/svditer.hxx>
#include <svx/svdogrp.hxx>
#include <vcl/BitmapTools.hxx>
#include <osl/diagnose.h>
using namespace com::sun::star;
ImpSdrGDIMetaFileImport::ImpSdrGDIMetaFileImport(
SdrModel& rModel,
SdrLayerID nLay,
const tools::Rectangle& rRect)
: mpVD(VclPtr<VirtualDevice>::Create()),
maScaleRect(rRect),
mpModel(&rModel),
mnLayer(nLay),
mnLineWidth(0),
maLineJoin(basegfx::B2DLineJoin::NONE),
maLineCap(css::drawing::LineCap_BUTT),
maDash(css::drawing::DashStyle_RECT, 0, 0, 0, 0, 0),
mbMov(false),
mbSize(false),
maOfs(0, 0),
mfScaleX(1.0),
mfScaleY(1.0),
maScaleX(1.0),
maScaleY(1.0),
mbFntDirty(true),
mbLastObjWasPolyWithoutLine(false),
mbNoLine(false),
mbNoFill(false),
mbLastObjWasLine(false)
{
mpVD->EnableOutput(false);
mpVD->SetLineColor();
mpVD->SetFillColor();
maOldLineColor.SetRed( mpVD->GetLineColor().GetRed() + 1 );
mpLineAttr = std::make_unique<SfxItemSetFixed<XATTR_LINE_FIRST, XATTR_LINE_LAST>>(rModel.GetItemPool());
mpFillAttr = std::make_unique<SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST>>(rModel.GetItemPool());
mpTextAttr = std::make_unique<SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END>>(rModel.GetItemPool());
checkClip();
}
void ImpSdrGDIMetaFileImport::DoLoopActions(GDIMetaFile const & rMtf, SvdProgressInfo* pProgrInfo, sal_uInt32* pActionsToReport)
{
const size_t nCount = rMtf.GetActionSize();
for(size_t 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 MetaActionType::PIXEL : break;
case MetaActionType::POINT : break;
case MetaActionType::LINE : DoAction(static_cast<MetaLineAction &>(*pAct)); break;
case MetaActionType::RECT : DoAction(static_cast<MetaRectAction &>(*pAct)); break;
case MetaActionType::ROUNDRECT : DoAction(static_cast<MetaRoundRectAction &>(*pAct)); break;
case MetaActionType::ELLIPSE : DoAction(static_cast<MetaEllipseAction &>(*pAct)); break;
case MetaActionType::ARC : DoAction(static_cast<MetaArcAction &>(*pAct)); break;
case MetaActionType::PIE : DoAction(static_cast<MetaPieAction &>(*pAct)); break;
case MetaActionType::CHORD : DoAction(static_cast<MetaChordAction &>(*pAct)); break;
case MetaActionType::POLYLINE : DoAction(static_cast<MetaPolyLineAction &>(*pAct)); break;
case MetaActionType::POLYGON : DoAction(static_cast<MetaPolygonAction &>(*pAct)); break;
case MetaActionType::POLYPOLYGON : DoAction(static_cast<MetaPolyPolygonAction &>(*pAct)); break;
case MetaActionType::TEXT : DoAction(static_cast<MetaTextAction &>(*pAct)); break;
case MetaActionType::TEXTARRAY : DoAction(static_cast<MetaTextArrayAction &>(*pAct)); break;
case MetaActionType::STRETCHTEXT : DoAction(static_cast<MetaStretchTextAction &>(*pAct)); break;
case MetaActionType::BMP : DoAction(static_cast<MetaBmpAction &>(*pAct)); break;
case MetaActionType::BMPSCALE : DoAction(static_cast<MetaBmpScaleAction &>(*pAct)); break;
case MetaActionType::BMPEX : DoAction(static_cast<MetaBmpExAction &>(*pAct)); break;
case MetaActionType::BMPEXSCALE : DoAction(static_cast<MetaBmpExScaleAction &>(*pAct)); break;
case MetaActionType::LINECOLOR : DoAction(static_cast<MetaLineColorAction &>(*pAct)); break;
case MetaActionType::FILLCOLOR : DoAction(static_cast<MetaFillColorAction &>(*pAct)); break;
case MetaActionType::TEXTCOLOR : DoAction(static_cast<MetaTextColorAction &>(*pAct)); break;
case MetaActionType::TEXTFILLCOLOR : DoAction(static_cast<MetaTextFillColorAction &>(*pAct)); break;
case MetaActionType::FONT : DoAction(static_cast<MetaFontAction &>(*pAct)); break;
case MetaActionType::TEXTALIGN : DoAction(static_cast<MetaTextAlignAction &>(*pAct)); break;
case MetaActionType::MAPMODE : DoAction(static_cast<MetaMapModeAction &>(*pAct)); break;
case MetaActionType::CLIPREGION : DoAction(static_cast<MetaClipRegionAction &>(*pAct)); break;
case MetaActionType::MOVECLIPREGION : DoAction(static_cast<MetaMoveClipRegionAction &>(*pAct)); break;
case MetaActionType::ISECTRECTCLIPREGION: DoAction(static_cast<MetaISectRectClipRegionAction&>(*pAct)); break;
case MetaActionType::ISECTREGIONCLIPREGION: DoAction(static_cast<MetaISectRegionClipRegionAction&>(*pAct)); break;
case MetaActionType::RASTEROP : DoAction(static_cast<MetaRasterOpAction &>(*pAct)); break;
case MetaActionType::PUSH : DoAction(static_cast<MetaPushAction &>(*pAct)); break;
case MetaActionType::POP : DoAction(static_cast<MetaPopAction &>(*pAct)); break;
case MetaActionType::HATCH : DoAction(static_cast<MetaHatchAction &>(*pAct)); break;
// #i125211# MetaCommentAction may change index, thus hand it over
case MetaActionType::COMMENT : DoAction(static_cast<MetaCommentAction&>(*pAct), rMtf, a);
break;
// missing actions added
case MetaActionType::TEXTRECT : DoAction(static_cast<MetaTextRectAction&>(*pAct)); break;
case MetaActionType::BMPSCALEPART : DoAction(static_cast<MetaBmpScalePartAction&>(*pAct)); break;
case MetaActionType::BMPEXSCALEPART : DoAction(static_cast<MetaBmpExScalePartAction&>(*pAct)); break;
case MetaActionType::MASK : DoAction(static_cast<MetaMaskAction&>(*pAct)); break;
case MetaActionType::MASKSCALE : DoAction(static_cast<MetaMaskScaleAction&>(*pAct)); break;
case MetaActionType::MASKSCALEPART : DoAction(static_cast<MetaMaskScalePartAction&>(*pAct)); break;
case MetaActionType::GRADIENT : DoAction(static_cast<MetaGradientAction&>(*pAct)); break;
case MetaActionType::WALLPAPER : OSL_ENSURE(false, "Tried to construct SdrObject from MetaWallpaperAction: not supported (!)"); break;
case MetaActionType::Transparent : DoAction(static_cast<MetaTransparentAction&>(*pAct)); break;
case MetaActionType::EPS : OSL_ENSURE(false, "Tried to construct SdrObject from MetaEPSAction: not supported (!)"); break;
case MetaActionType::REFPOINT : DoAction(static_cast<MetaRefPointAction&>(*pAct)); break;
case MetaActionType::TEXTLINECOLOR : DoAction(static_cast<MetaTextLineColorAction&>(*pAct)); break;
case MetaActionType::TEXTLINE : OSL_ENSURE(false, "Tried to construct SdrObject from MetaTextLineAction: not supported (!)"); break;
case MetaActionType::FLOATTRANSPARENT : DoAction(static_cast<MetaFloatTransparentAction&>(*pAct)); break;
case MetaActionType::GRADIENTEX : DoAction(static_cast<MetaGradientExAction&>(*pAct)); break;
case MetaActionType::LAYOUTMODE : DoAction(static_cast<MetaLayoutModeAction&>(*pAct)); break;
case MetaActionType::TEXTLANGUAGE : DoAction(static_cast<MetaTextLanguageAction&>(*pAct)); break;
case MetaActionType::OVERLINECOLOR : DoAction(static_cast<MetaOverlineColorAction&>(*pAct)); break;
default: break;
}
if(pProgrInfo && pActionsToReport)
{
(*pActionsToReport)++;
if(*pActionsToReport >= 16) // update all 16 actions
{
if(!pProgrInfo->ReportActions(*pActionsToReport))
break;
*pActionsToReport = 0;
}
}
}
}
size_t ImpSdrGDIMetaFileImport::DoImport(
const GDIMetaFile& rMtf,
SdrObjList& rOL,
size_t nInsPos,
SvdProgressInfo* pProgrInfo)
{
maPrefMapMode = rMtf.GetPrefMapMode();
mpVD->SetMapMode(maPrefMapMode);
// setup some global scale parameter
// mfScaleX, mfScaleY, maScaleX, maScaleY, mbMov, mbSize
mfScaleX = mfScaleY = 1.0;
const Size aMtfSize(rMtf.GetPrefSize());
if(aMtfSize.Width() & aMtfSize.Height() && (!maScaleRect.IsEmpty()))
{
maOfs = maScaleRect.TopLeft();
if(aMtfSize.Width() != (maScaleRect.GetWidth() - 1))
{
mfScaleX = static_cast<double>( maScaleRect.GetWidth() - 1 ) / static_cast<double>(aMtfSize.Width());
}
if(aMtfSize.Height() != (maScaleRect.GetHeight() - 1))
{
mfScaleY = static_cast<double>( maScaleRect.GetHeight() - 1 ) / static_cast<double>(aMtfSize.Height());
}
}
mbMov = maOfs.X()!=0 || maOfs.Y()!=0;
mbSize = false;
maScaleX = Fraction( 1, 1 );
maScaleY = Fraction( 1, 1 );
if(aMtfSize.Width() != (maScaleRect.GetWidth() - 1))
{
maScaleX = Fraction(maScaleRect.GetWidth() - 1, aMtfSize.Width());
mbSize = true;
}
if(aMtfSize.Height() != (maScaleRect.GetHeight() - 1))
{
maScaleY = Fraction(maScaleRect.GetHeight() - 1, aMtfSize.Height());
mbSize = true;
}
if(pProgrInfo)
{
pProgrInfo->SetActionCount(rMtf.GetActionSize());
}
sal_uInt32 nActionsToReport(0);
// execute
DoLoopActions(rMtf, pProgrInfo, &nActionsToReport);
if(pProgrInfo)
{
pProgrInfo->ReportActions(nActionsToReport);
nActionsToReport = 0;
}
// To calculate the progress meter, we use GetActionSize()*3.
// However, maTmpList has a lower entry count limit than GetActionSize(),
// so the actions that were assumed were too much have to be re-added.
nActionsToReport = (rMtf.GetActionSize() - maTmpList.size()) * 2;
// announce all currently unannounced rescales
if(pProgrInfo)
{
pProgrInfo->ReportRescales(nActionsToReport);
pProgrInfo->SetInsertCount(maTmpList.size());
}
nActionsToReport = 0;
// insert all objects cached in aTmpList now into rOL from nInsPos
nInsPos = std::min(nInsPos, rOL.GetObjCount());
for(rtl::Reference<SdrObject>& pObj : maTmpList)
{
rOL.NbcInsertObject(pObj.get(), nInsPos);
nInsPos++;
if(pProgrInfo)
{
nActionsToReport++;
if(nActionsToReport >= 32) // update all 32 actions
{
pProgrInfo->ReportInserts(nActionsToReport);
nActionsToReport = 0;
}
}
}
// report all remaining inserts for the last time
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 = mpVD->GetLineColor();
if(mpVD->IsLineColor())
{
mpLineAttr->Put(XLineStyleItem(drawing::LineStyle_SOLID));
mpLineAttr->Put(XLineColorItem(OUString(), mpVD->GetLineColor()));
}
else
{
mpLineAttr->Put(XLineStyleItem(drawing::LineStyle_NONE));
}
switch(maLineJoin)
{
case basegfx::B2DLineJoin::NONE:
mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_NONE));
break;
case basegfx::B2DLineJoin::Bevel:
mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_BEVEL));
break;
case basegfx::B2DLineJoin::Miter:
mpLineAttr->Put(XLineJointItem(css::drawing::LineJoint_MITER));
break;
case basegfx::B2DLineJoin::Round:
mpLineAttr->Put(XLineJointItem(css::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(OUString(), maDash));
}
else
{
mpLineAttr->Put(XLineDashItem(OUString(), XDash(css::drawing::DashStyle_RECT)));
}
}
else
{
mbNoLine = true;
}
if(bFill)
{
if(mpVD->IsFillColor())
{
mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_SOLID));
mpFillAttr->Put(XFillColorItem(OUString(), mpVD->GetFillColor()));
}
else
{
mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_NONE));
}
}
else
{
mbNoFill = true;
}
if(bText && mbFntDirty)
{
vcl::Font aFnt(mpVD->GetFont());
const sal_uInt32 nHeight(basegfx::fround(implMap(aFnt.GetFontSize()).Height() * mfScaleY));
mpTextAttr->Put( SvxFontItem( aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(), aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO ) );
mpTextAttr->Put( SvxFontItem( aFnt.GetFamilyType(), aFnt.GetFamilyName(), aFnt.GetStyleName(), aFnt.GetPitch(), aFnt.GetCharSet(), EE_CHAR_FONTINFO_CJK ) );
mpTextAttr->Put( SvxFontItem( aFnt.GetFamilyType(), aFnt.GetFamilyName(), 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(mpVD->GetTextColor(), EE_CHAR_COLOR));
//... svxfont textitem svditext
mbFntDirty = false;
}
if(!pObj)
return;
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* pObj1, bool bScale)
{
rtl::Reference<SdrObject> pObj = pObj1;
if(bScale && !maScaleRect.IsEmpty())
{
if(mbSize)
{
pObj->NbcResize(Point(), maScaleX, maScaleY);
}
if(mbMov)
{
pObj->NbcMove(Size(maOfs.X(), maOfs.Y()));
}
}
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.get());
const SdrTextObj* pSdrTextObj = DynCastSdrTextObj(pObj.get());
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::B2DPolyPolygon aTextContour(pSdrTextObj->TakeContour());
const basegfx::B2DRange aTextRange(aTextContour.getB2DRange());
const basegfx::B2DRange aClipRange(maClip.getB2DRange());
// no overlap -> completely outside
if(!aClipRange.overlaps(aTextRange))
{
pObj.clear();
break;
}
// when the clip is a rectangle fast check for inside is possible
if(basegfx::utils::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
rtl::Reference<SdrObject> pConverted = pSdrTextObj->ConvertToPolyObj(true, true);
pObj.clear();
if(pConverted)
{
// recursively add created conversion; per definition this shall not
// contain further SdrTextObjs. Visit only non-group objects
SdrObjListIter aIter(*pConverted, SdrIterMode::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 && dynamic_cast< SdrObjGroup* >(pCandidate) == nullptr, "SdrObjListIter with SdrIterMode::DeepNoGroups error (!)");
rtl::Reference<SdrObject> pNewClone(pCandidate->CloneSdrObject(pCandidate->getSdrModelFromSdrObject()));
if(pNewClone)
{
InsertObj(pNewClone.get(), false);
}
else
{
OSL_ENSURE(false, "SdrObject::Clone() failed (!)");
}
}
}
break;
}
}
else
{
BitmapEx aBitmapEx;
if(pSdrGrafObj)
{
aBitmapEx = pSdrGrafObj->GetGraphic().GetBitmapEx();
}
pObj.clear();
if(!aOldRange.isEmpty())
{
// clip against ClipRegion
const basegfx::B2DPolyPolygon aNewPoly(
basegfx::utils::clipPolyPolygonOnPolyPolygon(
aPoly,
maClip,
true,
!aPoly.isClosed()));
const basegfx::B2DRange aNewRange(aNewPoly.getB2DRange());
if(!aNewRange.isEmpty())
{
pObj = new SdrPathObj(
*mpModel,
aNewPoly.isClosed() ? SdrObjKind::Polygon : SdrObjKind::PolyLine,
aNewPoly);
pObj->SetLayer(aOldLayer);
pObj->SetMergedItemSet(aOldItemSet);
if(!aBitmapEx.IsEmpty())
{
// 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<tools::Long>(floor(std::max(0.0, aPixel.getMinX()))),
basegfx::fround<tools::Long>(floor(std::max(0.0, aPixel.getMinY()))));
const Size aClipSize(
basegfx::fround<tools::Long>(ceil(std::min(static_cast<double>(aOrigSizePixel.Width()), aPixel.getWidth()))),
basegfx::fround<tools::Long>(ceil(std::min(static_cast<double>(aOrigSizePixel.Height()), aPixel.getHeight()))));
const BitmapEx aClippedBitmap(
aBitmapEx,
aClipTopLeft,
aClipSize);
pObj->SetMergedItem(XFillStyleItem(drawing::FillStyle_BITMAP));
pObj->SetMergedItem(XFillBitmapItem(OUString(), Graphic(aClippedBitmap)));
pObj->SetMergedItem(XFillBmpTileItem(false));
pObj->SetMergedItem(XFillBmpStretchItem(true));
}
}
}
}
}
if(!pObj)
return;
// #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 = DynCastSdrTextObj(pObj.get());
if(pTextObj && pTextObj->HasText())
{
bVisible = true;
}
}
if(!bVisible)
{
SdrGrafObj* pGrafObj = dynamic_cast< SdrGrafObj* >(pObj.get());
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)
{
maTmpList.push_back(pObj);
if(dynamic_cast< SdrPathObj* >(pObj.get()))
{
const bool bClosed(pObj->IsClosedObj());
mbLastObjWasPolyWithoutLine = mbNoLine && bClosed;
mbLastObjWasLine = !bClosed;
}
else
{
mbLastObjWasPolyWithoutLine = false;
mbLastObjWasLine = false;
}
}
}
void ImpSdrGDIMetaFileImport::DoAction(MetaLineAction const & rAct)
{
// #i73407# reformulation to use new B2DPolygon classes
const basegfx::B2DPoint aStart(rAct.GetStartPoint().X(), rAct.GetStartPoint().Y());
const basegfx::B2DPoint aEnd(rAct.GetEndPoint().X(), rAct.GetEndPoint().Y());
if(aStart.equal(aEnd))
return;
basegfx::B2DPolygon aLine;
const basegfx::B2DHomMatrix aTransform(implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
aLine.append(aStart);
aLine.append(aEnd);
aLine.transform(aTransform);
const LineInfo& rLineInfo = rAct.GetLineInfo();
const sal_Int32 nNewLineWidth(rLineInfo.GetWidth());
bool bCreateLineObject(true);
if(mbLastObjWasLine && (nNewLineWidth == mnLineWidth) && CheckLastLineMerge(aLine))
{
bCreateLineObject = false;
}
if(!bCreateLineObject)
return;
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(
*mpModel,
SdrObjKind::Line,
basegfx::B2DPolyPolygon(aLine));
mnLineWidth = nNewLineWidth;
maLineJoin = rLineInfo.GetLineJoin();
maLineCap = rLineInfo.GetLineCap();
maDash = XDash(css::drawing::DashStyle_RECT,
rLineInfo.GetDotCount(), rLineInfo.GetDotLen(),
rLineInfo.GetDashCount(), rLineInfo.GetDashLen(),
rLineInfo.GetDistance());
SetAttributes(pPath.get());
mnLineWidth = 0;
maLineJoin = basegfx::B2DLineJoin::NONE;
maDash = XDash();
InsertObj(pPath.get(), false);
}
void ImpSdrGDIMetaFileImport::DoAction(MetaRectAction const & rAct)
{
rtl::Reference<SdrRectObj> pRect = new SdrRectObj(
*mpModel,
rAct.GetRect());
SetAttributes(pRect.get());
InsertObj(pRect.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaRoundRectAction const & rAct)
{
rtl::Reference<SdrRectObj> pRect = new SdrRectObj(
*mpModel,
rAct.GetRect());
SetAttributes(pRect.get());
tools::Long nRad=(rAct.GetHorzRound()+rAct.GetVertRound())/2;
if (nRad!=0) {
SfxItemSetFixed<SDRATTR_CORNER_RADIUS, SDRATTR_CORNER_RADIUS> aSet(*mpLineAttr->GetPool());
aSet.Put(SdrMetricItem(SDRATTR_CORNER_RADIUS, nRad));
pRect->SetMergedItemSet(aSet);
}
InsertObj(pRect.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaEllipseAction const & rAct)
{
rtl::Reference<SdrCircObj> pCirc=new SdrCircObj(
*mpModel,
SdrCircKind::Full,
rAct.GetRect());
SetAttributes(pCirc.get());
InsertObj(pCirc.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaArcAction const & rAct)
{
Point aCenter(rAct.GetRect().Center());
Degree100 nStart=GetAngle(rAct.GetStartPoint()-aCenter);
Degree100 nEnd=GetAngle(rAct.GetEndPoint()-aCenter);
rtl::Reference<SdrCircObj> pCirc = new SdrCircObj(
*mpModel,
SdrCircKind::Arc,
rAct.GetRect(),nStart,nEnd);
SetAttributes(pCirc.get());
InsertObj(pCirc.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaPieAction const & rAct)
{
Point aCenter(rAct.GetRect().Center());
Degree100 nStart=GetAngle(rAct.GetStartPoint()-aCenter);
Degree100 nEnd=GetAngle(rAct.GetEndPoint()-aCenter);
rtl::Reference<SdrCircObj> pCirc = new SdrCircObj(
*mpModel,
SdrCircKind::Section,
rAct.GetRect(),
nStart,
nEnd);
SetAttributes(pCirc.get());
InsertObj(pCirc.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaChordAction const & rAct)
{
Point aCenter(rAct.GetRect().Center());
Degree100 nStart=GetAngle(rAct.GetStartPoint()-aCenter);
Degree100 nEnd=GetAngle(rAct.GetEndPoint()-aCenter);
rtl::Reference<SdrCircObj> pCirc = new SdrCircObj(
*mpModel,
SdrCircKind::Cut,
rAct.GetRect(),
nStart,
nEnd);
SetAttributes(pCirc.get());
InsertObj(pCirc.get());
}
bool ImpSdrGDIMetaFileImport::CheckLastLineMerge(const basegfx::B2DPolygon& rSrcPoly)
{
// #i102706# Do not merge closed polygons
if(rSrcPoly.isClosed())
{
return false;
}
// #i73407# reformulation to use new B2DPolygon classes
if(mbLastObjWasLine && (maOldLineColor == mpVD->GetLineColor()) && rSrcPoly.count())
{
SdrObject* pTmpObj = !maTmpList.empty() ? maTmpList[maTmpList.size() - 1].get() : nullptr;
SdrPathObj* pLastPoly = dynamic_cast< SdrPathObj* >(pTmpObj);
if(pLastPoly)
{
if(1 == pLastPoly->GetPathPoly().count())
{
bool bOk(false);
basegfx::B2DPolygon aDstPoly(pLastPoly->GetPathPoly().getB2DPolygon(0));
// #i102706# Do not merge closed polygons
if(aDstPoly.isClosed())
{
return false;
}
if(aDstPoly.count())
{
const sal_uInt32 nMaxDstPnt(aDstPoly.count() - 1);
const sal_uInt32 nMaxSrcPnt(rSrcPoly.count() - 1);
if(aDstPoly.getB2DPoint(nMaxDstPnt) == rSrcPoly.getB2DPoint(0))
{
aDstPoly.append(rSrcPoly, 1, rSrcPoly.count() - 1);
bOk = true;
}
else if(aDstPoly.getB2DPoint(0) == rSrcPoly.getB2DPoint(nMaxSrcPnt))
{
basegfx::B2DPolygon aNew(rSrcPoly);
aNew.append(aDstPoly, 1, aDstPoly.count() - 1);
aDstPoly = std::move(aNew);
bOk = true;
}
else if(aDstPoly.getB2DPoint(0) == rSrcPoly.getB2DPoint(0))
{
aDstPoly.flip();
aDstPoly.append(rSrcPoly, 1, rSrcPoly.count() - 1);
bOk = true;
}
else if(aDstPoly.getB2DPoint(nMaxDstPnt) == rSrcPoly.getB2DPoint(nMaxSrcPnt))
{
basegfx::B2DPolygon aNew(rSrcPoly);
aNew.flip();
aDstPoly.append(aNew, 1, aNew.count() - 1);
bOk = true;
}
}
if(bOk)
{
pLastPoly->NbcSetPathPoly(basegfx::B2DPolyPolygon(aDstPoly));
}
return bOk;
}
}
}
return false;
}
bool ImpSdrGDIMetaFileImport::CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon & rPolyPolygon)
{
// #i73407# reformulation to use new B2DPolygon classes
if(mbLastObjWasPolyWithoutLine)
{
SdrObject* pTmpObj = !maTmpList.empty() ? maTmpList[maTmpList.size() - 1].get() : nullptr;
SdrPathObj* pLastPoly = dynamic_cast< SdrPathObj* >(pTmpObj);
if(pLastPoly)
{
if(pLastPoly->GetPathPoly() == rPolyPolygon)
{
SetAttributes(nullptr);
if(!mbNoLine && mbNoFill)
{
pLastPoly->SetMergedItemSet(*mpLineAttr);
return true;
}
}
}
}
return false;
}
void ImpSdrGDIMetaFileImport::checkClip()
{
if(!mpVD->IsClipRegion())
return;
maClip = mpVD->GetClipRegion().GetAsB2DPolyPolygon();
if(isClip())
{
const basegfx::B2DHomMatrix aTransform(
implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(
mfScaleX,
mfScaleY,
maOfs.X(),
maOfs.Y()));
maClip.transform(aTransform);
}
}
bool ImpSdrGDIMetaFileImport::isClip() const
{
return !maClip.getB2DRange().isEmpty();
}
void ImpSdrGDIMetaFileImport::DoAction( MetaPolyLineAction const & rAct )
{
// #i73407# reformulation to use new B2DPolygon classes
basegfx::B2DPolygon aSource(rAct.GetPolygon().getB2DPolygon());
if(aSource.count())
{
const basegfx::B2DHomMatrix aTransform(implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
aSource.transform(aTransform);
}
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)
return;
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(
*mpModel,
aSource.isClosed() ? SdrObjKind::Polygon : SdrObjKind::PolyLine,
basegfx::B2DPolyPolygon(aSource));
mnLineWidth = nNewLineWidth;
maLineJoin = rLineInfo.GetLineJoin();
maLineCap = rLineInfo.GetLineCap();
maDash = XDash(css::drawing::DashStyle_RECT,
rLineInfo.GetDotCount(), rLineInfo.GetDotLen(),
rLineInfo.GetDashCount(), rLineInfo.GetDashLen(),
rLineInfo.GetDistance());
SetAttributes(pPath.get());
mnLineWidth = 0;
maLineJoin = basegfx::B2DLineJoin::NONE;
maDash = XDash();
InsertObj(pPath.get(), false);
}
void ImpSdrGDIMetaFileImport::DoAction( MetaPolygonAction const & rAct )
{
// #i73407# reformulation to use new B2DPolygon classes
basegfx::B2DPolygon aSource(rAct.GetPolygon().getB2DPolygon());
if(!aSource.count())
return;
const basegfx::B2DHomMatrix aTransform(implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
aSource.transform(aTransform);
if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(basegfx::B2DPolyPolygon(aSource)))
{
// #i73407# make sure polygon is closed, it's a filled primitive
aSource.setClosed(true);
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(
*mpModel,
SdrObjKind::Polygon,
basegfx::B2DPolyPolygon(aSource));
SetAttributes(pPath.get());
InsertObj(pPath.get(), false);
}
}
void ImpSdrGDIMetaFileImport::DoAction(MetaPolyPolygonAction const & rAct)
{
// #i73407# reformulation to use new B2DPolygon classes
basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
if(!aSource.count())
return;
const basegfx::B2DHomMatrix aTransform(implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
aSource.transform(aTransform);
if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aSource))
{
// #i73407# make sure polygon is closed, it's a filled primitive
aSource.setClosed(true);
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(
*mpModel,
SdrObjKind::Polygon,
std::move(aSource));
SetAttributes(pPath.get());
InsertObj(pPath.get(), false);
}
}
Size ImpSdrGDIMetaFileImport::implMap(const Size& rSz) const
{
return OutputDevice::LogicToLogic(rSz, mpVD->GetMapMode(), maPrefMapMode);
}
Point ImpSdrGDIMetaFileImport::implMap(const Point& rPt) const
{
return OutputDevice::LogicToLogic(rPt, mpVD->GetMapMode(), maPrefMapMode);
}
basegfx::B2DHomMatrix ImpSdrGDIMetaFileImport::implMapMatrix() const
{
return OutputDevice::LogicToLogic(mpVD->GetMapMode(), maPrefMapMode);
}
void ImpSdrGDIMetaFileImport::ImportText( const Point& rPos, const OUString& rStr, const MetaAction& rAct )
{
// calc text box size, add 5% to make it fit safely
FontMetric aFontMetric( mpVD->GetFontMetric() );
vcl::Font aFnt( mpVD->GetFont() );
TextAlign eAlg( aFnt.GetAlignment() );
Size aTextSizeMapped(implMap(Size(mpVD->GetTextWidth(rStr), mpVD->GetTextHeight())));
sal_Int32 nTextWidth = static_cast<sal_Int32>(aTextSizeMapped.Width() * mfScaleX);
sal_Int32 nTextHeight = static_cast<sal_Int32>(aTextSizeMapped.Height() * mfScaleY);
Point aPosMapped(implMap(rPos));
Point aPos(basegfx::fround<tools::Long>(aPosMapped.X() * mfScaleX + maOfs.X()),
basegfx::fround<tools::Long>(aPosMapped.Y() * mfScaleY + maOfs.Y()));
Size aSize( nTextWidth, nTextHeight );
if ( eAlg == ALIGN_BASELINE )
{
auto nAscent = implMap(Size(0, aFontMetric.GetAscent())).Height();
aPos.AdjustY(basegfx::fround<tools::Long>(nAscent * -mfScaleY));
}
else if ( eAlg == ALIGN_BOTTOM )
aPos.AdjustY( -nTextHeight );
tools::Rectangle aTextRect( aPos, aSize );
rtl::Reference<SdrRectObj> pText = new SdrRectObj(
*mpModel,
SdrObjKind::Text,
aTextRect);
pText->SetMergedItem ( makeSdrTextUpperDistItem (0));
pText->SetMergedItem ( makeSdrTextLowerDistItem (0));
pText->SetMergedItem ( makeSdrTextRightDistItem (0));
pText->SetMergedItem ( makeSdrTextLeftDistItem (0));
if ( aFnt.GetAverageFontWidth() || ( rAct.GetType() == MetaActionType::STRETCHTEXT ) )
{
pText->ClearMergedItem( SDRATTR_TEXT_AUTOGROWWIDTH );
pText->SetMergedItem( makeSdrTextAutoGrowHeightItem( false ) );
// don't let the margins eat the space needed for the text
pText->SetMergedItem( SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_ALLLINES) );
}
else
{
pText->SetMergedItem( makeSdrTextAutoGrowWidthItem( true ) );
}
pText->SetLayer(mnLayer);
pText->NbcSetText( rStr );
SetAttributes( pText.get(), true );
pText->SetSnapRect( aTextRect );
if (!aFnt.IsTransparent())
{
SfxItemSetFixed<XATTR_FILL_FIRST, XATTR_FILL_LAST> aAttr(*mpFillAttr->GetPool());
aAttr.Put(XFillStyleItem(drawing::FillStyle_SOLID));
aAttr.Put(XFillColorItem(OUString(), aFnt.GetFillColor()));
pText->SetMergedItemSet(aAttr);
}
Degree100 nAngle = to<Degree100>(aFnt.GetOrientation());
if ( nAngle )
pText->SdrAttrObj::NbcRotate(aPos,nAngle);
InsertObj( pText.get(), false );
}
void ImpSdrGDIMetaFileImport::DoAction(MetaTextAction const & rAct)
{
OUString aStr(rAct.GetText());
aStr = aStr.copy(rAct.GetIndex(), rAct.GetLen());
ImportText( rAct.GetPoint(), aStr, rAct );
}
void ImpSdrGDIMetaFileImport::DoAction(MetaTextArrayAction const & rAct)
{
OUString aStr(rAct.GetText());
aStr = aStr.copy(rAct.GetIndex(), rAct.GetLen());
ImportText( rAct.GetPoint(), aStr, rAct );
}
void ImpSdrGDIMetaFileImport::DoAction(MetaStretchTextAction const & rAct)
{
OUString aStr(rAct.GetText());
aStr = aStr.copy(rAct.GetIndex(), rAct.GetLen());
ImportText( rAct.GetPoint(), aStr, rAct );
}
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpAction const & rAct)
{
tools::Rectangle aRect(rAct.GetPoint(),rAct.GetBitmap().GetSizePixel());
aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
Graphic(BitmapEx(rAct.GetBitmap())),
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpScaleAction const & rAct)
{
tools::Rectangle aRect(rAct.GetPoint(),rAct.GetSize());
aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
Graphic(BitmapEx(rAct.GetBitmap())),
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExAction const & rAct)
{
tools::Rectangle aRect(rAct.GetPoint(),rAct.GetBitmapEx().GetSizePixel());
aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
rAct.GetBitmapEx(),
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExScaleAction const & rAct)
{
tools::Rectangle aRect(rAct.GetPoint(),rAct.GetSize());
aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
rAct.GetBitmapEx(),
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction( MetaHatchAction const & rAct )
{
// #i73407# reformulation to use new B2DPolygon classes
basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
if(!aSource.count())
return;
const basegfx::B2DHomMatrix aTransform(implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
aSource.transform(aTransform);
if(mbLastObjWasPolyWithoutLine && CheckLastPolyLineAndFillMerge(aSource))
return;
const Hatch& rHatch = rAct.GetHatch();
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(
*mpModel,
SdrObjKind::Polygon,
std::move(aSource));
// #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
SfxItemSet aHatchAttr(mpModel->GetItemPool(), pPath->GetMergedItemSet().GetRanges());
css::drawing::HatchStyle eStyle;
switch(rHatch.GetStyle())
{
case HatchStyle::Triple :
{
eStyle = css::drawing::HatchStyle_TRIPLE;
break;
}
case HatchStyle::Double :
{
eStyle = css::drawing::HatchStyle_DOUBLE;
break;
}
default:
{
eStyle = css::drawing::HatchStyle_SINGLE;
break;
}
}
SetAttributes(pPath.get());
aHatchAttr.Put(XFillStyleItem(drawing::FillStyle_HATCH));
aHatchAttr.Put(XFillHatchItem(XHatch(rHatch.GetColor(), eStyle, rHatch.GetDistance(), rHatch.GetAngle())));
pPath->SetMergedItemSet(aHatchAttr);
InsertObj(pPath.get(), false);
}
void ImpSdrGDIMetaFileImport::DoAction(MetaLineColorAction& rAct)
{
rAct.Execute(mpVD);
}
void ImpSdrGDIMetaFileImport::DoAction(MetaMapModeAction& rAct)
{
rAct.Execute(mpVD);
mbLastObjWasPolyWithoutLine = false;
mbLastObjWasLine = false;
}
void ImpSdrGDIMetaFileImport::DoAction( MetaCommentAction const & rAct, GDIMetaFile const & rMtf, size_t& a) // GDIMetaFile* pMtf )
{
bool aSkipComment = false;
if (a < rMtf.GetActionSize() && rAct.GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN"))
{
// #i125211# Check if next action is a MetaGradientExAction
MetaGradientExAction* pAct = dynamic_cast< MetaGradientExAction* >(rMtf.GetAction(a + 1));
if( pAct && pAct->GetType() == MetaActionType::GRADIENTEX )
{
// #i73407# reformulation to use new B2DPolygon classes
basegfx::B2DPolyPolygon aSource(pAct->GetPolyPolygon().getB2DPolyPolygon());
if(aSource.count())
{
if(!mbLastObjWasPolyWithoutLine || !CheckLastPolyLineAndFillMerge(aSource))
{
const Gradient& rGrad = pAct->GetGradient();
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(
*mpModel,
SdrObjKind::Polygon,
std::move(aSource));
// #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
SfxItemSet aGradAttr(mpModel->GetItemPool(), pPath->GetMergedItemSet().GetRanges());
basegfx::BGradient aBGradient(
basegfx::BColorStops(
rGrad.GetStartColor().getBColor(),
rGrad.GetEndColor().getBColor()));
aBGradient.SetGradientStyle(rGrad.GetStyle());
aBGradient.SetAngle(rGrad.GetAngle());
aBGradient.SetBorder(rGrad.GetBorder());
aBGradient.SetXOffset(rGrad.GetOfsX());
aBGradient.SetYOffset(rGrad.GetOfsY());
aBGradient.SetStartIntens(rGrad.GetStartIntensity());
aBGradient.SetEndIntens(rGrad.GetEndIntensity());
aBGradient.SetSteps(rGrad.GetSteps());
// no need to use SetAttributes(..) here since line and fill style
// need to be set individually
// SetAttributes(pPath);
// switch line off; if there was one there will be a
// MetaActionType::POLYLINE following creating another object
aGradAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
// add detected gradient fillstyle
aGradAttr.Put(XFillStyleItem(drawing::FillStyle_GRADIENT));
aGradAttr.Put(XFillGradientItem(aBGradient));
pPath->SetMergedItemSet(aGradAttr);
InsertObj(pPath.get());
}
}
aSkipComment = true;
}
}
if(aSkipComment)
{
// #i125211# forward until closing MetaCommentAction
MetaAction* pSkipAct = rMtf.GetAction(++a);
while( pSkipAct
&& ((pSkipAct->GetType() != MetaActionType::COMMENT )
|| !(static_cast<MetaCommentAction*>(pSkipAct)->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END"))))
{
pSkipAct = rMtf.GetAction(++a);
}
}
}
void ImpSdrGDIMetaFileImport::DoAction(MetaTextRectAction const & rAct)
{
GDIMetaFile aTemp;
mpVD->AddTextRectActions(rAct.GetRect(), rAct.GetText(), rAct.GetStyle(), aTemp);
DoLoopActions(aTemp, nullptr, nullptr);
}
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpScalePartAction const & rAct)
{
tools::Rectangle aRect(rAct.GetDestPoint(), rAct.GetDestSize());
BitmapEx aBitmapEx(rAct.GetBitmap());
aRect.AdjustRight( 1 );
aRect.AdjustBottom( 1 );
aBitmapEx.Crop(tools::Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
aBitmapEx,
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaBmpExScalePartAction const & rAct)
{
tools::Rectangle aRect(rAct.GetDestPoint(),rAct.GetDestSize());
BitmapEx aBitmapEx(rAct.GetBitmapEx());
aRect.AdjustRight( 1 );
aRect.AdjustBottom( 1 );
aBitmapEx.Crop(tools::Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
aBitmapEx,
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaMaskAction const & rAct)
{
tools::Rectangle aRect(rAct.GetPoint(), rAct.GetBitmap().GetSizePixel());
BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
aBitmapEx,
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaMaskScaleAction const & rAct)
{
tools::Rectangle aRect(rAct.GetPoint(), rAct.GetSize());
BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
aBitmapEx,
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaMaskScalePartAction const & rAct)
{
tools::Rectangle aRect(rAct.GetDestPoint(), rAct.GetDestSize());
BitmapEx aBitmapEx(rAct.GetBitmap(), rAct.GetColor());
aRect.AdjustRight( 1 ); aRect.AdjustBottom( 1 );
aBitmapEx.Crop(tools::Rectangle(rAct.GetSrcPoint(), rAct.GetSrcSize()));
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
aBitmapEx,
aRect);
// This action is not creating line and fill, set directly, do not use SetAttributes(..)
pGraf->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
void ImpSdrGDIMetaFileImport::DoAction(MetaGradientAction const & rAct)
{
basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(rAct.GetRect());
if(aRange.isEmpty())
return;
const basegfx::B2DHomMatrix aTransform(implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
aRange.transform(aTransform);
const Gradient& rGradient = rAct.GetGradient();
rtl::Reference<SdrRectObj> pRect = new SdrRectObj(
*mpModel,
tools::Rectangle(
floor(aRange.getMinX()),
floor(aRange.getMinY()),
ceil(aRange.getMaxX()),
ceil(aRange.getMaxY())));
// #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
SfxItemSet aGradientAttr(mpModel->GetItemPool(), pRect->GetMergedItemSet().GetRanges());
const XFillGradientItem aXFillGradientItem(
basegfx::BGradient(
basegfx::BColorStops(
rGradient.GetStartColor().getBColor(),
rGradient.GetEndColor().getBColor()),
rGradient.GetStyle(),
rGradient.GetAngle(),
rGradient.GetOfsX(),
rGradient.GetOfsY(),
rGradient.GetBorder(),
rGradient.GetStartIntensity(),
rGradient.GetEndIntensity(),
rGradient.GetSteps()));
SetAttributes(pRect.get());
aGradientAttr.Put(XFillStyleItem(drawing::FillStyle_GRADIENT)); // #i125211#
aGradientAttr.Put(aXFillGradientItem);
pRect->SetMergedItemSet(aGradientAttr);
InsertObj(pRect.get(), false);
}
void ImpSdrGDIMetaFileImport::DoAction(MetaTransparentAction const & rAct)
{
basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
if(!aSource.count())
return;
const basegfx::B2DHomMatrix aTransform(implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
aSource.transform(aTransform);
aSource.setClosed(true);
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(
*mpModel,
SdrObjKind::Polygon,
std::move(aSource));
SetAttributes(pPath.get());
pPath->SetMergedItem(XFillTransparenceItem(rAct.GetTransparence()));
InsertObj(pPath.get(), false);
}
void ImpSdrGDIMetaFileImport::DoAction(MetaGradientExAction const & rAct)
{
basegfx::B2DPolyPolygon aSource(rAct.GetPolyPolygon().getB2DPolyPolygon());
if(!aSource.count())
return;
const basegfx::B2DHomMatrix aTransform(implMapMatrix() *
basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX, mfScaleY, maOfs.X(), maOfs.Y()));
aSource.transform(aTransform);
if(mbLastObjWasPolyWithoutLine && CheckLastPolyLineAndFillMerge(aSource))
return;
const Gradient& rGradient = rAct.GetGradient();
rtl::Reference<SdrPathObj> pPath = new SdrPathObj(
*mpModel,
SdrObjKind::Polygon,
std::move(aSource));
// #i125211# Use the ranges from the SdrObject to create a new empty SfxItemSet
SfxItemSet aGradientAttr(mpModel->GetItemPool(), pPath->GetMergedItemSet().GetRanges());
const XFillGradientItem aXFillGradientItem(
basegfx::BGradient(
basegfx::BColorStops(
rGradient.GetStartColor().getBColor(),
rGradient.GetEndColor().getBColor()),
rGradient.GetStyle(),
rGradient.GetAngle(),
rGradient.GetOfsX(),
rGradient.GetOfsY(),
rGradient.GetBorder(),
rGradient.GetStartIntensity(),
rGradient.GetEndIntensity(),
rGradient.GetSteps()));
SetAttributes(pPath.get());
aGradientAttr.Put(XFillStyleItem(drawing::FillStyle_GRADIENT)); // #i125211#
aGradientAttr.Put(aXFillGradientItem);
pPath->SetMergedItemSet(aGradientAttr);
InsertObj(pPath.get(), false);
}
void ImpSdrGDIMetaFileImport::DoAction(MetaFloatTransparentAction const & rAct)
{
const GDIMetaFile& rMtf = rAct.GetGDIMetaFile();
if(!rMtf.GetActionSize())
return;
const tools::Rectangle aRect(rAct.GetPoint(),rAct.GetSize());
// convert metafile sub-content to BitmapEx
BitmapEx aBitmapEx(
convertMetafileToBitmapEx(
rMtf,
vcl::unotools::b2DRectangleFromRectangle(aRect),
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 *= static_cast<double>(rGradient.GetStartIntensity()) / 100.0;
}
if(100 != rGradient.GetEndIntensity())
{
aEnd *= static_cast<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(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
ScopedVclPtrInstance< VirtualDevice > pVDev;
pVDev->SetOutputSizePixel(aBitmapEx.GetBitmap().GetSizePixel());
pVDev->DrawGradient(tools::Rectangle(Point(0, 0), pVDev->GetOutputSizePixel()), rGradient);
aNewMask = AlphaMask(pVDev->GetBitmap(Point(0, 0), pVDev->GetOutputSizePixel()));
aNewMask.Invert(); // convert transparency to alpha
bHasNewMask = true;
}
if(!bCreateObject)
return;
if(bHasNewMask || bFixedTransparence)
{
if(!aBitmapEx.IsAlpha())
{
// no transparence yet, apply new one
if(bFixedTransparence)
{
sal_uInt8 nTransparence(basegfx::fround(fTransparence * 255.0));
aNewMask = AlphaMask(aBitmapEx.GetBitmap().GetSizePixel(), &nTransparence);
}
aBitmapEx = BitmapEx(aBitmapEx.GetBitmap(), aNewMask);
}
else
{
vcl::bitmap::DrawAlphaBitmapAndAlphaGradient(aBitmapEx, bFixedTransparence, fTransparence, aNewMask);
}
}
// create and add object
rtl::Reference<SdrGrafObj> pGraf = new SdrGrafObj(
*mpModel,
aBitmapEx,
aRect);
// 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(drawing::LineStyle_NONE));
pGraf->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE));
InsertObj(pGraf.get());
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */