summaryrefslogtreecommitdiff
path: root/drawinglayer/source/primitive2d/metafileprimitive2d.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer/source/primitive2d/metafileprimitive2d.cxx')
-rw-r--r--drawinglayer/source/primitive2d/metafileprimitive2d.cxx3287
1 files changed, 0 insertions, 3287 deletions
diff --git a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx b/drawinglayer/source/primitive2d/metafileprimitive2d.cxx
deleted file mode 100644
index e7795981ea..0000000000
--- a/drawinglayer/source/primitive2d/metafileprimitive2d.cxx
+++ /dev/null
@@ -1,3287 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*************************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * Copyright 2000, 2010 Oracle and/or its affiliates.
- *
- * OpenOffice.org - a multi-platform office productivity suite
- *
- * This file is part of OpenOffice.org.
- *
- * OpenOffice.org is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License version 3
- * only, as published by the Free Software Foundation.
- *
- * OpenOffice.org is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License version 3 for more details
- * (a copy is included in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU Lesser General Public License
- * version 3 along with OpenOffice.org. If not, see
- * <http://www.openoffice.org/license.html>
- * for a copy of the LGPLv3 License.
- *
- ************************************************************************/
-
-// MARKER(update_precomp.py): autogen include statement, do not remove
-#include "precompiled_drawinglayer.hxx"
-
-#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
-#include <basegfx/tools/canvastools.hxx>
-#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
-#include <basegfx/color/bcolor.hxx>
-#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
-#include <vcl/lineinfo.hxx>
-#include <drawinglayer/attribute/lineattribute.hxx>
-#include <drawinglayer/attribute/strokeattribute.hxx>
-#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
-#include <vcl/metaact.hxx>
-#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
-#include <basegfx/matrix/b2dhommatrixtools.hxx>
-#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
-#include <basegfx/polygon/b2dpolygontools.hxx>
-#include <drawinglayer/primitive2d/discretebitmapprimitive2d.hxx>
-#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
-#include <vcl/salbtype.hxx>
-#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
-#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
-#include <vcl/svapp.hxx>
-#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
-#include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
-#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
-#include <basegfx/polygon/b2dpolygonclipper.hxx>
-#include <drawinglayer/primitive2d/invertprimitive2d.hxx>
-#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
-#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
-#include <drawinglayer/primitive2d/wallpaperprimitive2d.hxx>
-#include <drawinglayer/primitive2d/textprimitive2d.hxx>
-#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
-#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
-#include <i18npool/mslangid.hxx>
-#include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
-#include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
-#include <drawinglayer/primitive2d/epsprimitive2d.hxx>
-#include <drawinglayer/primitive2d/rendergraphicprimitive2d.hxx>
-#include <numeric>
-
-//////////////////////////////////////////////////////////////////////////////
-
-using namespace com::sun::star;
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace
-{
- /** helper class for graphic context
-
- This class allows to hold a complete status of classic
- VCL OutputDevice stati. This data is needed for correct
- interpretation of the MetaFile action flow.
- */
- class PropertyHolder
- {
- private:
- /// current transformation (aka MapMode)
- basegfx::B2DHomMatrix maTransformation;
- MapUnit maMapUnit;
-
- /// current colors
- basegfx::BColor maLineColor;
- basegfx::BColor maFillColor;
- basegfx::BColor maTextColor;
- basegfx::BColor maTextFillColor;
- basegfx::BColor maTextLineColor;
- basegfx::BColor maOverlineColor;
-
- /// clipping
- basegfx::B2DPolyPolygon maClipPolyPoygon;
-
- /// font, etc.
- Font maFont;
- RasterOp maRasterOp;
- sal_uInt32 mnLayoutMode;
- LanguageType maLanguageType;
- sal_uInt16 mnPushFlags;
-
- /// bitfield
- /// contains all active markers
- bool mbLineColor : 1;
- bool mbFillColor : 1;
- bool mbTextColor : 1;
- bool mbTextFillColor : 1;
- bool mbTextLineColor : 1;
- bool mbOverlineColor : 1;
- bool mbClipPolyPolygonActive : 1;
-
- public:
- PropertyHolder()
- : maTransformation(),
- maMapUnit(MAP_100TH_MM),
- maLineColor(),
- maFillColor(),
- maTextColor(COL_BLACK),
- maTextFillColor(),
- maTextLineColor(),
- maOverlineColor(),
- maClipPolyPoygon(),
- maFont(),
- maRasterOp(ROP_OVERPAINT),
- mnLayoutMode(0),
- maLanguageType(0),
- mnPushFlags(0),
- mbLineColor(false),
- mbFillColor(false),
- mbTextColor(true),
- mbTextFillColor(false),
- mbTextLineColor(false),
- mbOverlineColor(false),
- mbClipPolyPolygonActive(false)
- {
- }
-
- ~PropertyHolder()
- {
- }
-
- /// read/write accesses
- const basegfx::B2DHomMatrix& getTransformation() const { return maTransformation; }
- void setTransformation(const basegfx::B2DHomMatrix& rNew) { if(rNew != maTransformation) maTransformation = rNew; }
-
- MapUnit getMapUnit() const { return maMapUnit; }
- void setMapUnit(MapUnit eNew) { if(eNew != maMapUnit) maMapUnit = eNew; }
-
- const basegfx::BColor& getLineColor() const { return maLineColor; }
- void setLineColor(const basegfx::BColor& rNew) { if(rNew != maLineColor) maLineColor = rNew; }
- bool getLineColorActive() const { return mbLineColor; }
- void setLineColorActive(bool bNew) { if(bNew != mbLineColor) mbLineColor = bNew; }
-
- const basegfx::BColor& getFillColor() const { return maFillColor; }
- void setFillColor(const basegfx::BColor& rNew) { if(rNew != maFillColor) maFillColor = rNew; }
- bool getFillColorActive() const { return mbFillColor; }
- void setFillColorActive(bool bNew) { if(bNew != mbFillColor) mbFillColor = bNew; }
-
- const basegfx::BColor& getTextColor() const { return maTextColor; }
- void setTextColor(const basegfx::BColor& rNew) { if(rNew != maTextColor) maTextColor = rNew; }
- bool getTextColorActive() const { return mbTextColor; }
- void setTextColorActive(bool bNew) { if(bNew != mbTextColor) mbTextColor = bNew; }
-
- const basegfx::BColor& getTextFillColor() const { return maTextFillColor; }
- void setTextFillColor(const basegfx::BColor& rNew) { if(rNew != maTextFillColor) maTextFillColor = rNew; }
- bool getTextFillColorActive() const { return mbTextFillColor; }
- void setTextFillColorActive(bool bNew) { if(bNew != mbTextFillColor) mbTextFillColor = bNew; }
-
- const basegfx::BColor& getTextLineColor() const { return maTextLineColor; }
- void setTextLineColor(const basegfx::BColor& rNew) { if(rNew != maTextLineColor) maTextLineColor = rNew; }
- bool getTextLineColorActive() const { return mbTextLineColor; }
- void setTextLineColorActive(bool bNew) { if(bNew != mbTextLineColor) mbTextLineColor = bNew; }
-
- const basegfx::BColor& getOverlineColor() const { return maOverlineColor; }
- void setOverlineColor(const basegfx::BColor& rNew) { if(rNew != maOverlineColor) maOverlineColor = rNew; }
- bool getOverlineColorActive() const { return mbOverlineColor; }
- void setOverlineColorActive(bool bNew) { if(bNew != mbOverlineColor) mbOverlineColor = bNew; }
-
- const basegfx::B2DPolyPolygon& getClipPolyPolygon() const { return maClipPolyPoygon; }
- void setClipPolyPolygon(const basegfx::B2DPolyPolygon& rNew) { if(rNew != maClipPolyPoygon) maClipPolyPoygon = rNew; }
- bool getClipPolyPolygonActive() const { return mbClipPolyPolygonActive; }
- void setClipPolyPolygonActive(bool bNew) { if(bNew != mbClipPolyPolygonActive) mbClipPolyPolygonActive = bNew; }
-
- const Font& getFont() const { return maFont; }
- void setFont(const Font& rFont) { if(rFont != maFont) maFont = rFont; }
-
- const RasterOp& getRasterOp() const { return maRasterOp; }
- void setRasterOp(const RasterOp& rRasterOp) { if(rRasterOp != maRasterOp) maRasterOp = rRasterOp; }
- bool isRasterOpInvert() const { return (ROP_XOR == maRasterOp || ROP_INVERT == maRasterOp); }
- bool isRasterOpForceBlack() const { return ROP_0 == maRasterOp; }
- bool isRasterOpActive() const { return isRasterOpInvert() || isRasterOpForceBlack(); }
-
- sal_uInt32 getLayoutMode() const { return mnLayoutMode; }
- void setLayoutMode(sal_uInt32 nNew) { if(nNew != mnLayoutMode) mnLayoutMode = nNew; }
-
- LanguageType getLanguageType() const { return maLanguageType; }
- void setLanguageType(LanguageType aNew) { if(aNew != maLanguageType) maLanguageType = aNew; }
-
- sal_uInt16 getPushFlags() const { return mnPushFlags; }
- void setPushFlags(sal_uInt16 nNew) { if(nNew != mnPushFlags) mnPushFlags = nNew; }
-
- bool getLineOrFillActive() const { return (mbLineColor || mbFillColor); }
- };
-} // end of anonymous namespace
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace
-{
- /** stack for properites
-
- This class builds a stack based on the PropertyHolder
- class. It encapsulates the pointer/new/delete usage to
- make it safe and implements the push/pop as needed by a
- VCL Metafile interpreter. The critical part here are the
- flag values VCL OutputDevice uses here; not all stuff is
- pushed and thus needs to be copied at pop.
- */
- class PropertyHolders
- {
- private:
- std::vector< PropertyHolder* > maPropertyHolders;
-
- public:
- PropertyHolders()
- {
- maPropertyHolders.push_back(new PropertyHolder());
- }
-
- sal_uInt32 size() const
- {
- return maPropertyHolders.size();
- }
-
- void PushDefault()
- {
- PropertyHolder* pNew = new PropertyHolder();
- maPropertyHolders.push_back(pNew);
- }
-
- void Push(sal_uInt16 nPushFlags)
- {
- if(nPushFlags)
- {
- OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: PUSH with no property holders (!)");
- if ( !maPropertyHolders.empty() )
- {
- PropertyHolder* pNew = new PropertyHolder(*maPropertyHolders.back());
- pNew->setPushFlags(nPushFlags);
- maPropertyHolders.push_back(pNew);
- }
- }
- }
-
- void Pop()
- {
- OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: POP with no property holders (!)");
- const sal_uInt32 nSize(maPropertyHolders.size());
-
- if(nSize)
- {
- const PropertyHolder* pTip = maPropertyHolders.back();
- const sal_uInt16 nPushFlags(pTip->getPushFlags());
-
- if(nPushFlags)
- {
- if(nSize > 1)
- {
- // copy back content for all non-set flags
- PropertyHolder* pLast = maPropertyHolders[nSize - 2];
-
- if(PUSH_ALL != nPushFlags)
- {
- if(!(nPushFlags & PUSH_LINECOLOR ))
- {
- pLast->setLineColor(pTip->getLineColor());
- pLast->setLineColorActive(pTip->getLineColorActive());
- }
- if(!(nPushFlags & PUSH_FILLCOLOR ))
- {
- pLast->setFillColor(pTip->getFillColor());
- pLast->setFillColorActive(pTip->getFillColorActive());
- }
- if(!(nPushFlags & PUSH_FONT ))
- {
- pLast->setFont(pTip->getFont());
- }
- if(!(nPushFlags & PUSH_TEXTCOLOR ))
- {
- pLast->setTextColor(pTip->getTextColor());
- pLast->setTextColorActive(pTip->getTextColorActive());
- }
- if(!(nPushFlags & PUSH_MAPMODE ))
- {
- pLast->setTransformation(pTip->getTransformation());
- pLast->setMapUnit(pTip->getMapUnit());
- }
- if(!(nPushFlags & PUSH_CLIPREGION ))
- {
- pLast->setClipPolyPolygon(pTip->getClipPolyPolygon());
- pLast->setClipPolyPolygonActive(pTip->getClipPolyPolygonActive());
- }
- if(!(nPushFlags & PUSH_RASTEROP ))
- {
- pLast->setRasterOp(pTip->getRasterOp());
- }
- if(!(nPushFlags & PUSH_TEXTFILLCOLOR ))
- {
- pLast->setTextFillColor(pTip->getTextFillColor());
- pLast->setTextFillColorActive(pTip->getTextFillColorActive());
- }
- if(!(nPushFlags & PUSH_TEXTALIGN ))
- {
- if(pLast->getFont().GetAlign() != pTip->getFont().GetAlign())
- {
- Font aFont(pLast->getFont());
- aFont.SetAlign(pTip->getFont().GetAlign());
- pLast->setFont(aFont);
- }
- }
- if(!(nPushFlags & PUSH_REFPOINT ))
- {
- // not supported
- }
- if(!(nPushFlags & PUSH_TEXTLINECOLOR ))
- {
- pLast->setTextLineColor(pTip->getTextLineColor());
- pLast->setTextLineColorActive(pTip->getTextLineColorActive());
- }
- if(!(nPushFlags & PUSH_TEXTLAYOUTMODE ))
- {
- pLast->setLayoutMode(pTip->getLayoutMode());
- }
- if(!(nPushFlags & PUSH_TEXTLANGUAGE ))
- {
- pLast->setLanguageType(pTip->getLanguageType());
- }
- if(!(nPushFlags & PUSH_OVERLINECOLOR ))
- {
- pLast->setOverlineColor(pTip->getOverlineColor());
- pLast->setOverlineColorActive(pTip->getOverlineColorActive());
- }
- }
- }
- }
-
- // execute the pop
- delete maPropertyHolders.back();
- maPropertyHolders.pop_back();
- }
- }
-
- PropertyHolder& Current()
- {
- static PropertyHolder aDummy;
- OSL_ENSURE(maPropertyHolders.size(), "PropertyHolders: CURRENT with no property holders (!)");
- return maPropertyHolders.empty() ? aDummy : *maPropertyHolders.back();
- }
-
- ~PropertyHolders()
- {
- while(!maPropertyHolders.empty())
- {
- delete maPropertyHolders.back();
- maPropertyHolders.pop_back();
- }
- }
- };
-} // end of anonymous namespace
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace
-{
- /** helper to convert a Region to a B2DPolyPolygon
- when it does not yet contain one. In the future
- this may be expanded to merge the polygons created
- from rectangles or use a special algo to directly turn
- the spans of regions to a single, already merged
- PolyPolygon.
- */
- basegfx::B2DPolyPolygon getB2DPolyPolygonFromRegion(const Region& rRegion)
- {
- basegfx::B2DPolyPolygon aRetval;
-
- if(!rRegion.IsEmpty())
- {
- Region aRegion(rRegion);
- aRetval = aRegion.GetB2DPolyPolygon();
-
- if(!aRetval.count())
- {
- RegionHandle aRegionHandle(aRegion.BeginEnumRects());
- Rectangle aRegionRectangle;
-
- while(aRegion.GetEnumRects(aRegionHandle, aRegionRectangle))
- {
- if(!aRegionRectangle.IsEmpty())
- {
- const basegfx::B2DRange aRegionRange(
- aRegionRectangle.Left(), aRegionRectangle.Top(),
- aRegionRectangle.Right(), aRegionRectangle.Bottom());
- aRetval.append(basegfx::tools::createPolygonFromRect(aRegionRange));
- }
- }
-
- aRegion.EndEnumRects(aRegionHandle);
- }
- }
-
- return aRetval;
- }
-} // end of anonymous namespace
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace
-{
- /** Helper class to buffer and hold a Primive target vector. It
- encapsulates the new/delete functionality and aloows to work
- on pointers of the implementation classes. All data will
- be converted to uno sequences of uno references when accessing the
- data.
- */
- class TargetHolder
- {
- private:
- std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargets;
-
- public:
- TargetHolder()
- : aTargets()
- {
- }
-
- ~TargetHolder()
- {
- const sal_uInt32 nCount(aTargets.size());
-
- for(sal_uInt32 a(0); a < nCount; a++)
- {
- delete aTargets[a];
- }
- }
-
- sal_uInt32 size() const
- {
- return aTargets.size();
- }
-
- void append(drawinglayer::primitive2d::BasePrimitive2D* pCandidate)
- {
- if(pCandidate)
- {
- aTargets.push_back(pCandidate);
- }
- }
-
- drawinglayer::primitive2d::Primitive2DSequence getPrimitive2DSequence(const PropertyHolder& rPropertyHolder)
- {
- const sal_uInt32 nCount(aTargets.size());
- drawinglayer::primitive2d::Primitive2DSequence xRetval(nCount);
-
- for(sal_uInt32 a(0); a < nCount; a++)
- {
- xRetval[a] = aTargets[a];
- }
-
- // All Targets were pointers, but do not need to be deleted since they
- // were converted to UNO API references now, so they stay as long as
- // referenced. Do NOT delete the C++ implementation classes here, but clear
- // the buffer to not delete them in the destructor.
- aTargets.clear();
-
- if(xRetval.hasElements() && rPropertyHolder.getClipPolyPolygonActive())
- {
- const basegfx::B2DPolyPolygon& rClipPolyPolygon = rPropertyHolder.getClipPolyPolygon();
-
- if(rClipPolyPolygon.count())
- {
- const drawinglayer::primitive2d::Primitive2DReference xMask(
- new drawinglayer::primitive2d::MaskPrimitive2D(
- rClipPolyPolygon,
- xRetval));
-
- xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xMask, 1);
- }
- }
-
- return xRetval;
- }
- };
-} // end of anonymous namespace
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace
-{
- /** Helper class which builds a stack on the TargetHolder class */
- class TargetHolders
- {
- private:
- std::vector< TargetHolder* > maTargetHolders;
-
- public:
- TargetHolders()
- {
- maTargetHolders.push_back(new TargetHolder());
- }
-
- sal_uInt32 size() const
- {
- return maTargetHolders.size();
- }
-
- void Push()
- {
- maTargetHolders.push_back(new TargetHolder());
- }
-
- void Pop()
- {
- OSL_ENSURE(maTargetHolders.size(), "TargetHolders: POP with no property holders (!)");
- if(!maTargetHolders.empty())
- {
- delete maTargetHolders.back();
- maTargetHolders.pop_back();
- }
- }
-
- TargetHolder& Current()
- {
- OSL_ENSURE(maTargetHolders.size(), "TargetHolders: CURRENT with no property holders (!)");
- return *maTargetHolders.back();
- }
-
- ~TargetHolders()
- {
- while(!maTargetHolders.empty())
- {
- delete maTargetHolders.back();
- maTargetHolders.pop_back();
- }
- }
- };
-} // end of anonymous namespace
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace drawinglayer
-{
- namespace primitive2d
- {
- /** NonOverlappingFillGradientPrimitive2D class
-
- This is a special version of the FillGradientPrimitive2D which decomposes
- to a non-overlapping geometry version of the gradient. This needs to be
- used to support the old XOR paint-'trick'.
-
- It does not need an own identifier since a renderer who wants to interpret
- it itself may do so. It just overloads the decomposition of the C++
- implementation class to do an alternative decomposition.
- */
- class NonOverlappingFillGradientPrimitive2D : public FillGradientPrimitive2D
- {
- protected:
- /// local decomposition.
- virtual Primitive2DSequence create2DDecomposition(
- const geometry::ViewInformation2D& rViewInformation) const;
-
- public:
- /// constructor
- NonOverlappingFillGradientPrimitive2D(
- const basegfx::B2DRange& rObjectRange,
- const attribute::FillGradientAttribute& rFillGradient)
- : FillGradientPrimitive2D(rObjectRange, rFillGradient)
- {
- }
- };
-
- Primitive2DSequence NonOverlappingFillGradientPrimitive2D::create2DDecomposition(
- const geometry::ViewInformation2D& /*rViewInformation*/) const
- {
- if(!getFillGradient().isDefault())
- {
- return createFill(false);
- }
- else
- {
- return Primitive2DSequence();
- }
- }
- } // end of namespace primitive2d
-} // end of namespace drawinglayer
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace
-{
- /** helper to convert a MapMode to a transformation */
- basegfx::B2DHomMatrix getTransformFromMapMode(const MapMode& rMapMode)
- {
- basegfx::B2DHomMatrix aMapping;
- const Fraction aNoScale(1, 1);
- const Point& rOrigin(rMapMode.GetOrigin());
-
- if(0 != rOrigin.X() || 0 != rOrigin.Y())
- {
- aMapping.translate(rOrigin.X(), rOrigin.Y());
- }
-
- if(rMapMode.GetScaleX() != aNoScale || rMapMode.GetScaleY() != aNoScale)
- {
- aMapping.scale(
- double(rMapMode.GetScaleX()),
- double(rMapMode.GetScaleY()));
- }
-
- return aMapping;
- }
-
- /** helper to create a PointArrayPrimitive2D based on current context */
- void createPointArrayPrimitive(
- const std::vector< basegfx::B2DPoint >& rPositions,
- TargetHolder& rTarget,
- PropertyHolder& rProperties,
- basegfx::BColor aBColor)
- {
- if(!rPositions.empty())
- {
- if(rProperties.getTransformation().isIdentity())
- {
- rTarget.append(
- new drawinglayer::primitive2d::PointArrayPrimitive2D(
- rPositions,
- aBColor));
- }
- else
- {
- std::vector< basegfx::B2DPoint > aPositions(rPositions);
-
- for(sal_uInt32 a(0); a < aPositions.size(); a++)
- {
- aPositions[a] = rProperties.getTransformation() * aPositions[a];
- }
-
- rTarget.append(
- new drawinglayer::primitive2d::PointArrayPrimitive2D(
- aPositions,
- aBColor));
- }
- }
- }
-
- /** helper to create a PolygonHairlinePrimitive2D based on current context */
- void createHairlinePrimitive(
- const basegfx::B2DPolygon& rLinePolygon,
- TargetHolder& rTarget,
- PropertyHolder& rProperties)
- {
- if(rLinePolygon.count())
- {
- basegfx::B2DPolygon aLinePolygon(rLinePolygon);
- aLinePolygon.transform(rProperties.getTransformation());
- rTarget.append(
- new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
- aLinePolygon,
- rProperties.getLineColor()));
- }
- }
-
- /** helper to create a PolyPolygonColorPrimitive2D based on current context */
- void createFillPrimitive(
- const basegfx::B2DPolyPolygon& rFillPolyPolygon,
- TargetHolder& rTarget,
- PropertyHolder& rProperties)
- {
- if(rFillPolyPolygon.count())
- {
- basegfx::B2DPolyPolygon aFillPolyPolygon(rFillPolyPolygon);
- aFillPolyPolygon.transform(rProperties.getTransformation());
- rTarget.append(
- new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
- aFillPolyPolygon,
- rProperties.getFillColor()));
- }
- }
-
- /** helper to create a PolygonStrokePrimitive2D based on current context */
- void createLinePrimitive(
- const basegfx::B2DPolygon& rLinePolygon,
- const LineInfo& rLineInfo,
- TargetHolder& rTarget,
- PropertyHolder& rProperties)
- {
- if(rLinePolygon.count())
- {
- const bool bDashDotUsed(LINE_DASH == rLineInfo.GetStyle());
- const bool bWidthUsed(rLineInfo.GetWidth() > 1);
-
- if(bDashDotUsed || bWidthUsed)
- {
- basegfx::B2DPolygon aLinePolygon(rLinePolygon);
- aLinePolygon.transform(rProperties.getTransformation());
- const drawinglayer::attribute::LineAttribute aLineAttribute(
- rProperties.getLineColor(),
- bWidthUsed ? rLineInfo.GetWidth() : 0.0,
- rLineInfo.GetLineJoin());
-
- if(bDashDotUsed)
- {
- ::std::vector< double > fDotDashArray;
- const double fDashLen(rLineInfo.GetDashLen());
- const double fDotLen(rLineInfo.GetDotLen());
- const double fDistance(rLineInfo.GetDistance());
-
- for(sal_uInt16 a(0); a < rLineInfo.GetDashCount(); a++)
- {
- fDotDashArray.push_back(fDashLen);
- fDotDashArray.push_back(fDistance);
- }
-
- for(sal_uInt16 b(0); b < rLineInfo.GetDotCount(); b++)
- {
- fDotDashArray.push_back(fDotLen);
- fDotDashArray.push_back(fDistance);
- }
-
- const double fAccumulated(::std::accumulate(fDotDashArray.begin(), fDotDashArray.end(), 0.0));
- const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(
- fDotDashArray,
- fAccumulated);
-
- rTarget.append(
- new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
- aLinePolygon,
- aLineAttribute,
- aStrokeAttribute));
- }
- else
- {
- rTarget.append(
- new drawinglayer::primitive2d::PolygonStrokePrimitive2D(
- aLinePolygon,
- aLineAttribute));
- }
- }
- else
- {
- createHairlinePrimitive(rLinePolygon, rTarget, rProperties);
- }
- }
- }
-
- /** helper to create needed line and fill primitives based on current context */
- void createHairlineAndFillPrimitive(
- const basegfx::B2DPolygon& rPolygon,
- TargetHolder& rTarget,
- PropertyHolder& rProperties)
- {
- if(rProperties.getFillColorActive())
- {
- createFillPrimitive(basegfx::B2DPolyPolygon(rPolygon), rTarget, rProperties);
- }
-
- if(rProperties.getLineColorActive())
- {
- createHairlinePrimitive(rPolygon, rTarget, rProperties);
- }
- }
-
- /** helper to create needed line and fill primitives based on current context */
- void createHairlineAndFillPrimitive(
- const basegfx::B2DPolyPolygon& rPolyPolygon,
- TargetHolder& rTarget,
- PropertyHolder& rProperties)
- {
- if(rProperties.getFillColorActive())
- {
- createFillPrimitive(rPolyPolygon, rTarget, rProperties);
- }
-
- if(rProperties.getLineColorActive())
- {
- for(sal_uInt32 a(0); a < rPolyPolygon.count(); a++)
- {
- createHairlinePrimitive(rPolyPolygon.getB2DPolygon(a), rTarget, rProperties);
- }
- }
- }
-
- /** helper to create DiscreteBitmapPrimitive2D based on current context.
- The DiscreteBitmapPrimitive2D is especially created for this usage
- since no other usage defines a bitmap visualisation based on top-left
- position and size in pixels. At the end it will create a view-dependent
- transformed embedding of a BitmapPrimitive2D.
- */
- void createBitmapExPrimitive(
- const BitmapEx& rBitmapEx,
- const Point& rPoint,
- TargetHolder& rTarget,
- PropertyHolder& rProperties)
- {
- if(!rBitmapEx.IsEmpty())
- {
- basegfx::B2DPoint aPoint(rPoint.X(), rPoint.Y());
- aPoint = rProperties.getTransformation() * aPoint;
-
- rTarget.append(
- new drawinglayer::primitive2d::DiscreteBitmapPrimitive2D(
- rBitmapEx,
- aPoint));
- }
- }
-
- /** helper to create BitmapPrimitive2D based on current context */
- void createBitmapExPrimitive(
- const BitmapEx& rBitmapEx,
- const Point& rPoint,
- const Size& rSize,
- TargetHolder& rTarget,
- PropertyHolder& rProperties)
- {
- if(!rBitmapEx.IsEmpty())
- {
- basegfx::B2DHomMatrix aObjectTransform;
-
- aObjectTransform.set(0, 0, rSize.Width());
- aObjectTransform.set(1, 1, rSize.Height());
- aObjectTransform.set(0, 2, rPoint.X());
- aObjectTransform.set(1, 2, rPoint.Y());
-
- aObjectTransform = rProperties.getTransformation() * aObjectTransform;
-
- rTarget.append(
- new drawinglayer::primitive2d::BitmapPrimitive2D(
- rBitmapEx,
- aObjectTransform));
- }
- }
-
- /** helper to create a regular BotmapEx from a MaskAction (definitions
- which use a bitmap without transparence but define one of the colors as
- transparent)
- */
- BitmapEx createMaskBmpEx(const Bitmap& rBitmap, const Color& rMaskColor)
- {
- const Color aWhite(COL_WHITE);
- BitmapPalette aBiLevelPalette(2);
-
- aBiLevelPalette[0] = aWhite;
- aBiLevelPalette[1] = rMaskColor;
-
- Bitmap aMask(rBitmap.CreateMask(aWhite));
- Bitmap aSolid(rBitmap.GetSizePixel(), 1, &aBiLevelPalette);
-
- aSolid.Erase(rMaskColor);
-
- return BitmapEx(aSolid, aMask);
- }
-
- /** helper to convert from a VCL Gradient definition to the corresponding
- data for primitive representation
- */
- drawinglayer::attribute::FillGradientAttribute createFillGradientAttribute(const Gradient& rGradient)
- {
- const Color aStartColor(rGradient.GetStartColor());
- const sal_uInt16 nStartIntens(rGradient.GetStartIntensity());
- basegfx::BColor aStart(aStartColor.getBColor());
-
- if(nStartIntens != 100)
- {
- const basegfx::BColor aBlack;
- aStart = interpolate(aBlack, aStart, (double)nStartIntens * 0.01);
- }
-
- const Color aEndColor(rGradient.GetEndColor());
- const sal_uInt16 nEndIntens(rGradient.GetEndIntensity());
- basegfx::BColor aEnd(aEndColor.getBColor());
-
- if(nEndIntens != 100)
- {
- const basegfx::BColor aBlack;
- aEnd = interpolate(aBlack, aEnd, (double)nEndIntens * 0.01);
- }
-
- drawinglayer::attribute::GradientStyle aGradientStyle(drawinglayer::attribute::GRADIENTSTYLE_RECT);
-
- switch(rGradient.GetStyle())
- {
- case GRADIENT_LINEAR :
- {
- aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_LINEAR;
- break;
- }
- case GRADIENT_AXIAL :
- {
- aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_AXIAL;
- break;
- }
- case GRADIENT_RADIAL :
- {
- aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RADIAL;
- break;
- }
- case GRADIENT_ELLIPTICAL :
- {
- aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_ELLIPTICAL;
- break;
- }
- case GRADIENT_SQUARE :
- {
- aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_SQUARE;
- break;
- }
- default : // GRADIENT_RECT
- {
- aGradientStyle = drawinglayer::attribute::GRADIENTSTYLE_RECT;
- break;
- }
- }
-
- return drawinglayer::attribute::FillGradientAttribute(
- aGradientStyle,
- (double)rGradient.GetBorder() * 0.01,
- (double)rGradient.GetOfsX() * 0.01,
- (double)rGradient.GetOfsY() * 0.01,
- (double)rGradient.GetAngle() * F_PI1800,
- aStart,
- aEnd,
- rGradient.GetSteps());
- }
-
- /** helper to convert from a VCL Hatch definition to the corresponding
- data for primitive representation
- */
- drawinglayer::attribute::FillHatchAttribute createFillHatchAttribute(const Hatch& rHatch)
- {
- drawinglayer::attribute::HatchStyle aHatchStyle(drawinglayer::attribute::HATCHSTYLE_SINGLE);
-
- switch(rHatch.GetStyle())
- {
- default : // case HATCH_SINGLE :
- {
- aHatchStyle = drawinglayer::attribute::HATCHSTYLE_SINGLE;
- break;
- }
- case HATCH_DOUBLE :
- {
- aHatchStyle = drawinglayer::attribute::HATCHSTYLE_DOUBLE;
- break;
- }
- case HATCH_TRIPLE :
- {
- aHatchStyle = drawinglayer::attribute::HATCHSTYLE_TRIPLE;
- break;
- }
- }
-
- return drawinglayer::attribute::FillHatchAttribute(
- aHatchStyle,
- (double)rHatch.GetDistance(),
- (double)rHatch.GetAngle() * F_PI1800,
- rHatch.GetColor().getBColor(),
- false);
- }
-
- /** helper to take needed action on ClipRegion change. This method needs to be called
- on any Region change, e.g. at the obvious actions doing this, but also at pop-calls
- whcih change the Region of the current context. It takes care of creating the
- current embeddec context, set the new Region at the context and eventually prepare
- a new target for embracing new geometry to the current region
- */
- void HandleNewClipRegion(
- const basegfx::B2DPolyPolygon& rClipPolyPolygon,
- TargetHolders& rTargetHolders,
- PropertyHolders& rPropertyHolders)
- {
- const bool bNewActive(rClipPolyPolygon.count());
-
- // #i108636# The handlig of new ClipPolyPolygons was not done as good as possible
- // in the first version of this interpreter; e.g. when a ClipPolyPolygon was set
- // initially and then using a lot of push/pop actions, the pop always leads
- // to setting a 'new' ClipPolyPolygon which indeed is the return to the ClipPolyPolygon
- // of the properties next on the stack.
- //
- // This ClipPolyPolygon is identical to the current one, so there is no need to
- // create a MaskPrimitive2D containing the up-to-now created primitives, but
- // this was done before. While this does not lead to wrong primitive
- // representations of the metafile data, it creates unneccesarily expensive
- // representations. Just detecting when no really 'new' ClipPolyPolygon gets set
- // solves the problem.
-
- if(!rPropertyHolders.Current().getClipPolyPolygonActive() && !bNewActive)
- {
- // no active ClipPolyPolygon exchanged by no new one, done
- return;
- }
-
- if(rPropertyHolders.Current().getClipPolyPolygonActive() && bNewActive)
- {
- // active ClipPolyPolygon and new active ClipPolyPolygon
- if(rPropertyHolders.Current().getClipPolyPolygon() == rClipPolyPolygon)
- {
- // new is the same as old, done
- return;
- }
- }
-
- // Here the old and the new are definitively different, maybe
- // old one and/or new one is not active.
-
- // Handle deletion of old ClipPolyPolygon. The process evtl. created primitives which
- // belong to this active ClipPolyPolygon. These need to be embedded to a
- // MaskPrimitive2D accordingly.
- if(rPropertyHolders.Current().getClipPolyPolygonActive() && rTargetHolders.size() > 1)
- {
- drawinglayer::primitive2d::Primitive2DSequence aSubContent;
-
- if(rPropertyHolders.Current().getClipPolyPolygon().count()
- && rTargetHolders.Current().size())
- {
- aSubContent = rTargetHolders.Current().getPrimitive2DSequence(
- rPropertyHolders.Current());
- }
-
- rTargetHolders.Pop();
-
- if(aSubContent.hasElements())
- {
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::GroupPrimitive2D(
- aSubContent));
- }
- }
-
- // apply new settings to current properties by setting
- // the new region now
- rPropertyHolders.Current().setClipPolyPolygonActive(bNewActive);
-
- if(bNewActive)
- {
- rPropertyHolders.Current().setClipPolyPolygon(rClipPolyPolygon);
-
- // prepare new content holder for new active region
- rTargetHolders.Push();
- }
- }
-
- /** helper to handle the change of RasterOp. It takes care of encapsulating all current
- geometry to the current RasterOp (if changed) and needs to be called on any RasterOp
- change. It will also start a new geometry target to embrace to the new RasterOp if
- a changuing RasterOp is used. Currently, ROP_XOR and ROP_INVERT are supported using
- InvertPrimitive2D, and ROP_0 by using a ModifiedColorPrimitive2D to force to black paint
- */
- void HandleNewRasterOp(
- RasterOp aRasterOp,
- TargetHolders& rTargetHolders,
- PropertyHolders& rPropertyHolders)
- {
- // check if currently active
- if(rPropertyHolders.Current().isRasterOpActive() && rTargetHolders.size() > 1)
- {
- drawinglayer::primitive2d::Primitive2DSequence aSubContent;
-
- if(rTargetHolders.Current().size())
- {
- aSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
- }
-
- rTargetHolders.Pop();
-
- if(aSubContent.hasElements())
- {
- if(rPropertyHolders.Current().isRasterOpForceBlack())
- {
- // force content to black
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
- aSubContent,
- basegfx::BColorModifier(basegfx::BColor(0.0, 0.0, 0.0))));
- }
- else // if(rPropertyHolders.Current().isRasterOpInvert())
- {
- // invert content
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::InvertPrimitive2D(
- aSubContent));
- }
- }
- }
-
- // apply new settings
- rPropertyHolders.Current().setRasterOp(aRasterOp);
-
- // check if now active
- if(rPropertyHolders.Current().isRasterOpActive())
- {
- // prepare new content holder for new invert
- rTargetHolders.Push();
- }
- }
-
- /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
- It is a quite mighty action. This helper is for simple color filled background.
- */
- drawinglayer::primitive2d::BasePrimitive2D* CreateColorWallpaper(
- const basegfx::B2DRange& rRange,
- const basegfx::BColor& rColor,
- PropertyHolder& rPropertyHolder)
- {
- basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(rRange));
- aOutline.transform(rPropertyHolder.getTransformation());
-
- return new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
- basegfx::B2DPolyPolygon(aOutline),
- rColor);
- }
-
- /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
- It is a quite mighty action. This helper is for gradient filled background.
- */
- drawinglayer::primitive2d::BasePrimitive2D* CreateGradientWallpaper(
- const basegfx::B2DRange& rRange,
- const Gradient& rGradient,
- PropertyHolder& rPropertyHolder)
- {
- const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
-
- if(aAttribute.getStartColor() == aAttribute.getEndColor())
- {
- // not really a gradient. Create filled rectangle
- return CreateColorWallpaper(rRange, aAttribute.getStartColor(), rPropertyHolder);
- }
- else
- {
- // really a gradient
- drawinglayer::primitive2d::BasePrimitive2D* pRetval =
- new drawinglayer::primitive2d::FillGradientPrimitive2D(
- rRange,
- aAttribute);
-
- if(!rPropertyHolder.getTransformation().isIdentity())
- {
- const drawinglayer::primitive2d::Primitive2DReference xPrim(pRetval);
- const drawinglayer::primitive2d::Primitive2DSequence xSeq(&xPrim, 1);
-
- pRetval = new drawinglayer::primitive2d::TransformPrimitive2D(
- rPropertyHolder.getTransformation(),
- xSeq);
- }
-
- return pRetval;
- }
- }
-
- /** helper to create needed data to emulate the VCL Wallpaper Metafile action.
- It is a quite mighty action. This helper decides if color and/or gradient
- background is needed for the wnated bitmap fill and then creates the needed
- WallpaperBitmapPrimitive2D. This primitive was created for this purpose and
- takes over all needed logic of orientations and tiling.
- */
- void CreateAndAppendBitmapWallpaper(
- basegfx::B2DRange aWallpaperRange,
- const Wallpaper& rWallpaper,
- TargetHolder& rTarget,
- PropertyHolder& rProperty)
- {
- const BitmapEx aBitmapEx(rWallpaper.GetBitmap());
- const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
-
- // if bitmap visualisation is transparent, maybe background
- // needs to be filled. Create background
- if(aBitmapEx.IsTransparent()
- || (WALLPAPER_TILE != eWallpaperStyle && WALLPAPER_SCALE != eWallpaperStyle))
- {
- if(rWallpaper.IsGradient())
- {
- rTarget.append(
- CreateGradientWallpaper(
- aWallpaperRange,
- rWallpaper.GetGradient(),
- rProperty));
- }
- else if(!rWallpaper.GetColor().GetTransparency())
- {
- rTarget.append(
- CreateColorWallpaper(
- aWallpaperRange,
- rWallpaper.GetColor().getBColor(),
- rProperty));
- }
- }
-
- // use wallpaper rect if set
- if(rWallpaper.IsRect() && !rWallpaper.GetRect().IsEmpty())
- {
- aWallpaperRange = basegfx::B2DRange(
- rWallpaper.GetRect().Left(), rWallpaper.GetRect().Top(),
- rWallpaper.GetRect().Right(), rWallpaper.GetRect().Bottom());
- }
-
- drawinglayer::primitive2d::BasePrimitive2D* pBitmapWallpaperFill =
- new drawinglayer::primitive2d::WallpaperBitmapPrimitive2D(
- aWallpaperRange,
- aBitmapEx,
- eWallpaperStyle);
-
- if(rProperty.getTransformation().isIdentity())
- {
- // add directly
- rTarget.append(pBitmapWallpaperFill);
- }
- else
- {
- // when a transformation is set, embed to it
- const drawinglayer::primitive2d::Primitive2DReference xPrim(pBitmapWallpaperFill);
-
- rTarget.append(
- new drawinglayer::primitive2d::TransformPrimitive2D(
- rProperty.getTransformation(),
- drawinglayer::primitive2d::Primitive2DSequence(&xPrim, 1)));
- }
- }
-
- /** helper to decide UnderlineAbove for text primitives */
- bool isUnderlineAbove(const Font& rFont)
- {
- if(!rFont.IsVertical())
- {
- return false;
- }
-
- if((LANGUAGE_JAPANESE == rFont.GetLanguage()) || (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()))
- {
- // the underline is right for Japanese only
- return true;
- }
-
- return false;
- }
-
- void createFontAttributeTransformAndAlignment(
- drawinglayer::attribute::FontAttribute& rFontAttribute,
- basegfx::B2DHomMatrix& rTextTransform,
- basegfx::B2DVector& rAlignmentOffset,
- PropertyHolder& rProperty)
- {
- const Font& rFont = rProperty.getFont();
- basegfx::B2DVector aFontScaling;
-
- rFontAttribute = drawinglayer::attribute::FontAttribute(
- drawinglayer::primitive2d::getFontAttributeFromVclFont(
- aFontScaling,
- rFont,
- 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_RTL),
- 0 != (rProperty.getLayoutMode() & TEXT_LAYOUT_BIDI_STRONG)));
-
- // add FontScaling
- rTextTransform.scale(aFontScaling.getX(), aFontScaling.getY());
-
- // take text align into account
- if(ALIGN_BASELINE != rFont.GetAlign())
- {
- drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
- aTextLayouterDevice.setFont(rFont);
-
- if(ALIGN_TOP == rFont.GetAlign())
- {
- rAlignmentOffset.setY(aTextLayouterDevice.getFontAscent());
- }
- else // ALIGN_BOTTOM
- {
- rAlignmentOffset.setY(-aTextLayouterDevice.getFontDescent());
- }
-
- rTextTransform.translate(rAlignmentOffset.getX(), rAlignmentOffset.getY());
- }
-
- // add FontRotation (if used)
- if(rFont.GetOrientation())
- {
- rTextTransform.rotate(-rFont.GetOrientation() * F_PI1800);
- }
- }
-
- /** helper which takes complete care for creating the needed text primitives. It
- takes care of decorated stuff and all the geometry adaptions needed
- */
- void proccessMetaTextAction(
- const Point& rTextStartPosition,
- const XubString& rText,
- sal_uInt16 nTextStart,
- sal_uInt16 nTextLength,
- const ::std::vector< double >& rDXArray,
- TargetHolder& rTarget,
- PropertyHolder& rProperty)
- {
- drawinglayer::primitive2d::BasePrimitive2D* pResult = 0;
- const Font& rFont = rProperty.getFont();
- basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
-
- if(nTextLength)
- {
- drawinglayer::attribute::FontAttribute aFontAttribute;
- basegfx::B2DHomMatrix aTextTransform;
-
- // fill parameters derived from current font
- createFontAttributeTransformAndAlignment(
- aFontAttribute,
- aTextTransform,
- aAlignmentOffset,
- rProperty);
-
- // add TextStartPosition
- aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
-
- // prepare FontColor and Locale
- const basegfx::BColor aFontColor(rProperty.getTextColor());
- const com::sun::star::lang::Locale aLocale(MsLangId::convertLanguageToLocale(rProperty.getLanguageType()));
- const bool bWordLineMode(rFont.IsWordLineMode());
-
- const bool bDecoratedIsNeeded(
- UNDERLINE_NONE != rFont.GetOverline()
- || UNDERLINE_NONE != rFont.GetUnderline()
- || STRIKEOUT_NONE != rFont.GetStrikeout()
- || EMPHASISMARK_NONE != (rFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
- || RELIEF_NONE != rFont.GetRelief()
- || rFont.IsShadow()
- || bWordLineMode);
-
- if(bDecoratedIsNeeded)
- {
- // prepare overline, underline and srikeout data
- const drawinglayer::primitive2d::TextLine eFontOverline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetOverline()));
- const drawinglayer::primitive2d::TextLine eFontUnderline(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rFont.GetUnderline()));
- const drawinglayer::primitive2d::TextStrikeout eTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rFont.GetStrikeout()));
-
- // check UndelineAbove
- const bool bUnderlineAbove(drawinglayer::primitive2d::TEXT_LINE_NONE != eFontUnderline && isUnderlineAbove(rFont));
-
- // prepare emphasis mark data
- drawinglayer::primitive2d::TextEmphasisMark eTextEmphasisMark(drawinglayer::primitive2d::TEXT_EMPHASISMARK_NONE);
-
- switch(rFont.GetEmphasisMark() & EMPHASISMARK_STYLE)
- {
- case EMPHASISMARK_DOT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DOT; break;
- case EMPHASISMARK_CIRCLE : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_CIRCLE; break;
- case EMPHASISMARK_DISC : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_DISC; break;
- case EMPHASISMARK_ACCENT : eTextEmphasisMark = drawinglayer::primitive2d::TEXT_EMPHASISMARK_ACCENT; break;
- }
-
- const bool bEmphasisMarkAbove(rFont.GetEmphasisMark() & EMPHASISMARK_POS_ABOVE);
- const bool bEmphasisMarkBelow(rFont.GetEmphasisMark() & EMPHASISMARK_POS_BELOW);
-
- // prepare font relief data
- drawinglayer::primitive2d::TextRelief eTextRelief(drawinglayer::primitive2d::TEXT_RELIEF_NONE);
-
- switch(rFont.GetRelief())
- {
- case RELIEF_EMBOSSED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_EMBOSSED; break;
- case RELIEF_ENGRAVED : eTextRelief = drawinglayer::primitive2d::TEXT_RELIEF_ENGRAVED; break;
- default : break; // RELIEF_NONE, FontRelief_FORCE_EQUAL_SIZE
- }
-
- // prepare shadow/outline data
- const bool bShadow(rFont.IsShadow());
-
- // TextDecoratedPortionPrimitive2D is needed, create one
- pResult = new drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D(
-
- // attributes for TextSimplePortionPrimitive2D
- aTextTransform,
- rText,
- nTextStart,
- nTextLength,
- rDXArray,
- aFontAttribute,
- aLocale,
- aFontColor,
-
- // attributes for TextDecoratedPortionPrimitive2D
- rProperty.getOverlineColorActive() ? rProperty.getOverlineColor() : aFontColor,
- rProperty.getTextLineColorActive() ? rProperty.getTextLineColor() : aFontColor,
- eFontOverline,
- eFontUnderline,
- bUnderlineAbove,
- eTextStrikeout,
- bWordLineMode,
- eTextEmphasisMark,
- bEmphasisMarkAbove,
- bEmphasisMarkBelow,
- eTextRelief,
- bShadow);
- }
- else
- {
- // TextSimplePortionPrimitive2D is enough
- pResult = new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
- aTextTransform,
- rText,
- nTextStart,
- nTextLength,
- rDXArray,
- aFontAttribute,
- aLocale,
- aFontColor);
- }
- }
-
- if(pResult && rProperty.getTextFillColorActive())
- {
- // text background is requested, add and encapsulate both to new primitive
- drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
- aTextLayouterDevice.setFont(rFont);
-
- // get text width
- double fTextWidth(0.0);
-
- if(rDXArray.empty())
- {
- fTextWidth = aTextLayouterDevice.getTextWidth(rText, nTextStart, nTextLength);
- }
- else
- {
- fTextWidth = rDXArray.back();
- }
-
- if(basegfx::fTools::more(fTextWidth, 0.0))
- {
- // build text range
- const basegfx::B2DRange aTextRange(
- 0.0, -aTextLayouterDevice.getFontAscent(),
- fTextWidth, aTextLayouterDevice.getFontDescent());
-
- // create Transform
- basegfx::B2DHomMatrix aTextTransform;
-
- aTextTransform.translate(aAlignmentOffset.getX(), aAlignmentOffset.getY());
-
- if(rFont.GetOrientation())
- {
- aTextTransform.rotate(-rFont.GetOrientation() * F_PI1800);
- }
-
- aTextTransform.translate(rTextStartPosition.X(), rTextStartPosition.Y());
-
- // prepare Primitive2DSequence, put text in foreground
- drawinglayer::primitive2d::Primitive2DSequence aSequence(2);
- aSequence[1] = drawinglayer::primitive2d::Primitive2DReference(pResult);
-
- // prepare filled polygon
- basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aTextRange));
- aOutline.transform(aTextTransform);
-
- aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(
- new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
- basegfx::B2DPolyPolygon(aOutline),
- rProperty.getTextFillColor()));
-
- // set as group at pResult
- pResult = new drawinglayer::primitive2d::GroupPrimitive2D(aSequence);
- }
- }
-
- if(pResult)
- {
- // add created text primitive to target
- if(rProperty.getTransformation().isIdentity())
- {
- rTarget.append(pResult);
- }
- else
- {
- // when a transformation is set, embed to it
- const drawinglayer::primitive2d::Primitive2DReference aReference(pResult);
-
- rTarget.append(
- new drawinglayer::primitive2d::TransformPrimitive2D(
- rProperty.getTransformation(),
- drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1)));
- }
- }
- }
-
- /** helper which takes complete care for creating the needed textLine primitives */
- void proccessMetaTextLineAction(
- const MetaTextLineAction& rAction,
- TargetHolder& rTarget,
- PropertyHolder& rProperty)
- {
- const double fLineWidth(fabs((double)rAction.GetWidth()));
-
- if(fLineWidth > 0.0)
- {
- const drawinglayer::primitive2d::TextLine aOverlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetOverline()));
- const drawinglayer::primitive2d::TextLine aUnderlineMode(drawinglayer::primitive2d::mapFontUnderlineToTextLine(rAction.GetUnderline()));
- const drawinglayer::primitive2d::TextStrikeout aTextStrikeout(drawinglayer::primitive2d::mapFontStrikeoutToTextStrikeout(rAction.GetStrikeout()));
-
- const bool bOverlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aOverlineMode);
- const bool bUnderlineUsed(drawinglayer::primitive2d::TEXT_LINE_NONE != aUnderlineMode);
- const bool bStrikeoutUsed(drawinglayer::primitive2d::TEXT_STRIKEOUT_NONE != aTextStrikeout);
-
- if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed)
- {
- std::vector< drawinglayer::primitive2d::BasePrimitive2D* > aTargetVector;
- basegfx::B2DVector aAlignmentOffset(0.0, 0.0);
- drawinglayer::attribute::FontAttribute aFontAttribute;
- basegfx::B2DHomMatrix aTextTransform;
-
- // fill parameters derived from current font
- createFontAttributeTransformAndAlignment(
- aFontAttribute,
- aTextTransform,
- aAlignmentOffset,
- rProperty);
-
- // add TextStartPosition
- aTextTransform.translate(rAction.GetStartPoint().X(), rAction.GetStartPoint().Y());
-
- // prepare TextLayouter (used in most cases)
- drawinglayer::primitive2d::TextLayouterDevice aTextLayouter;
- aTextLayouter.setFont(rProperty.getFont());
-
- if(bOverlineUsed)
- {
- // create primitive geometry for overline
- aTargetVector.push_back(
- new drawinglayer::primitive2d::TextLinePrimitive2D(
- aTextTransform,
- fLineWidth,
- aTextLayouter.getOverlineOffset(),
- aTextLayouter.getOverlineHeight(),
- aOverlineMode,
- rProperty.getOverlineColor()));
- }
-
- if(bUnderlineUsed)
- {
- // create primitive geometry for underline
- aTargetVector.push_back(
- new drawinglayer::primitive2d::TextLinePrimitive2D(
- aTextTransform,
- fLineWidth,
- aTextLayouter.getUnderlineOffset(),
- aTextLayouter.getUnderlineHeight(),
- aUnderlineMode,
- rProperty.getTextLineColor()));
- }
-
- if(bStrikeoutUsed)
- {
- // create primitive geometry for strikeout
- if(drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout
- || drawinglayer::primitive2d::TEXT_STRIKEOUT_X == aTextStrikeout)
- {
- // strikeout with character
- const sal_Unicode aStrikeoutChar(
- drawinglayer::primitive2d::TEXT_STRIKEOUT_SLASH == aTextStrikeout ? '/' : 'X');
- const com::sun::star::lang::Locale aLocale(MsLangId::convertLanguageToLocale(
- rProperty.getLanguageType()));
-
- aTargetVector.push_back(
- new drawinglayer::primitive2d::TextCharacterStrikeoutPrimitive2D(
- aTextTransform,
- fLineWidth,
- rProperty.getTextColor(),
- aStrikeoutChar,
- aFontAttribute,
- aLocale));
- }
- else
- {
- // strikeout with geometry
- aTargetVector.push_back(
- new drawinglayer::primitive2d::TextGeometryStrikeoutPrimitive2D(
- aTextTransform,
- fLineWidth,
- rProperty.getTextColor(),
- aTextLayouter.getUnderlineHeight(),
- aTextLayouter.getStrikeoutOffset(),
- aTextStrikeout));
- }
- }
-
- if(!aTargetVector.empty())
- {
- // add created text primitive to target
- if(rProperty.getTransformation().isIdentity())
- {
- for(sal_uInt32 a(0); a < aTargetVector.size(); a++)
- {
- rTarget.append(aTargetVector[a]);
- }
- }
- else
- {
- // when a transformation is set, embed to it
- drawinglayer::primitive2d::Primitive2DSequence xTargets(aTargetVector.size());
-
- for(sal_uInt32 a(0); a < aTargetVector.size(); a++)
- {
- xTargets[a] = drawinglayer::primitive2d::Primitive2DReference(aTargetVector[a]);
- }
-
- rTarget.append(
- new drawinglayer::primitive2d::TransformPrimitive2D(
- rProperty.getTransformation(),
- xTargets));
- }
- }
- }
- }
-
- }
-
- /** This is the main interpreter method. It is designed to handle the given Metafile
- completely inside the given context and target. It may use and modify the context and
- target. This design allows to call itself recursively wich adapted contexts and
- targets as e.g. needed for the META_FLOATTRANSPARENT_ACTION where the content is expressed
- as a metafile as sub-content.
-
- This interpreter is as free of VCL functionality as possible. It uses VCL data classes
- (else reading the data would not be possible), but e.g. does NOT use a local OutputDevice
- as most other MetaFile interpreters/exporters do to hold and work with the current context.
- This is necessary to be able to get away from the strong internal VCL-binding.
-
- It tries to combine e.g. pixel and/or point actions and to stitch together single line primitives
- where possible (which is not trivial with the possible line geometry definitions).
-
- It tries to handle clipping no longer as Regions and spans of Rectangles, but as PolyPolygon
- ClipRegions with (where possible) high precision by using the best possible data quality
- from the Region. The Region is unavoidable as data container, but nowadays allows the transport
- of Polygon-based clip regions. Where this is not used, a Polygon is constructed from the
- Region ranges. All primitive clipping uses the MaskPrimitive2D with Polygon-based clipping.
-
- I have marked the single MetaActions with:
-
- SIMPLE, DONE:
- Simple, e.g nothing to do or value setting in the context
-
- CHECKED, WORKS WELL:
- Thoroughly tested with extra written test code which created a replacement
- Metafile just to test this action in various combinations
-
- NEEDS IMPLEMENTATION:
- Not implemented and asserted, but also no usage found, neither in own Metafile
- creations, nor in EMF/WMF imports (checked with a whole bunch of critical EMF/WMF
- bugdocs)
-
- For more commens, see the single action implementations.
- */
- void interpretMetafile(
- const GDIMetaFile& rMetaFile,
- TargetHolders& rTargetHolders,
- PropertyHolders& rPropertyHolders,
- const drawinglayer::geometry::ViewInformation2D& rViewInformation)
- {
- const size_t nCount(rMetaFile.GetActionSize());
-
- for(size_t nAction(0); nAction < nCount; nAction++)
- {
- MetaAction* pAction = rMetaFile.GetAction(nAction);
-
- switch(pAction->GetType())
- {
- case META_NULL_ACTION :
- {
- /** SIMPLE, DONE */
- break;
- }
- case META_PIXEL_ACTION :
- {
- /** CHECKED, WORKS WELL */
- std::vector< basegfx::B2DPoint > aPositions;
- Color aLastColor(COL_BLACK);
-
- while(META_PIXEL_ACTION == pAction->GetType() && nAction < nCount)
- {
- const MetaPixelAction* pA = (const MetaPixelAction*)pAction;
-
- if(pA->GetColor() != aLastColor)
- {
- if(!aPositions.empty())
- {
- createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
- aPositions.clear();
- }
-
- aLastColor = pA->GetColor();
- }
-
- const Point& rPoint = pA->GetPoint();
- aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y()));
- nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
- }
-
- nAction--;
-
- if(!aPositions.empty())
- {
- createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), aLastColor.getBColor());
- }
-
- break;
- }
- case META_POINT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineColorActive())
- {
- std::vector< basegfx::B2DPoint > aPositions;
-
- while(META_POINT_ACTION == pAction->GetType() && nAction < nCount)
- {
- const MetaPointAction* pA = (const MetaPointAction*)pAction;
- const Point& rPoint = pA->GetPoint();
- aPositions.push_back(basegfx::B2DPoint(rPoint.X(), rPoint.Y()));
- nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
- }
-
- nAction--;
-
- if(!aPositions.empty())
- {
- createPointArrayPrimitive(aPositions, rTargetHolders.Current(), rPropertyHolders.Current(), rPropertyHolders.Current().getLineColor());
- }
- }
-
- break;
- }
- case META_LINE_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineColorActive())
- {
- basegfx::B2DPolygon aLinePolygon;
- LineInfo aLineInfo;
-
- while(META_LINE_ACTION == pAction->GetType() && nAction < nCount)
- {
- const MetaLineAction* pA = (const MetaLineAction*)pAction;
- const Point& rStartPoint = pA->GetStartPoint();
- const Point& rEndPoint = pA->GetEndPoint();
- const basegfx::B2DPoint aStart(rStartPoint.X(), rStartPoint.Y());
- const basegfx::B2DPoint aEnd(rEndPoint.X(), rEndPoint.Y());
-
- if(aLinePolygon.count())
- {
- if(pA->GetLineInfo() == aLineInfo
- && aStart == aLinePolygon.getB2DPoint(aLinePolygon.count() - 1))
- {
- aLinePolygon.append(aEnd);
- }
- else
- {
- aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE
- createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
- aLinePolygon.clear();
- aLineInfo = pA->GetLineInfo();
- aLinePolygon.append(aStart);
- aLinePolygon.append(aEnd);
- }
- }
- else
- {
- aLineInfo = pA->GetLineInfo();
- aLinePolygon.append(aStart);
- aLinePolygon.append(aEnd);
- }
-
- nAction++; if(nAction < nCount) pAction = rMetaFile.GetAction(nAction);
- }
-
- nAction--;
-
- if(aLinePolygon.count())
- {
- aLineInfo.SetLineJoin(basegfx::B2DLINEJOIN_NONE); // It were lines; force to NONE
- createLinePrimitive(aLinePolygon, aLineInfo, rTargetHolders.Current(), rPropertyHolders.Current());
- }
- }
-
- break;
- }
- case META_RECT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineOrFillActive())
- {
- const MetaRectAction* pA = (const MetaRectAction*)pAction;
- const Rectangle& rRectangle = pA->GetRect();
-
- if(!rRectangle.IsEmpty())
- {
- const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
-
- if(!aRange.isEmpty())
- {
- const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
- createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
- }
- }
-
- break;
- }
- case META_ROUNDRECT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- /** The original OutputDevice::DrawRect paints nothing when nHor or nVer is zero; but just
- because the tools::Polygon operator creating the rounding does produce nonsense. I assume
- this an error and create an unrounded rectangle in that case (implicit in
- createPolygonFromRect)
- */
- if(rPropertyHolders.Current().getLineOrFillActive())
- {
- const MetaRoundRectAction* pA = (const MetaRoundRectAction*)pAction;
- const Rectangle& rRectangle = pA->GetRect();
-
- if(!rRectangle.IsEmpty())
- {
- const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
-
- if(!aRange.isEmpty())
- {
- const sal_uInt32 nHor(pA->GetHorzRound());
- const sal_uInt32 nVer(pA->GetVertRound());
- basegfx::B2DPolygon aOutline;
-
- if(nHor || nVer)
- {
- double fRadiusX((nHor * 2.0) / (aRange.getWidth() > 0.0 ? aRange.getWidth() : 1.0));
- double fRadiusY((nVer * 2.0) / (aRange.getHeight() > 0.0 ? aRange.getHeight() : 1.0));
- fRadiusX = std::max(0.0, std::min(1.0, fRadiusX));
- fRadiusY = std::max(0.0, std::min(1.0, fRadiusY));
-
- aOutline = basegfx::tools::createPolygonFromRect(aRange, fRadiusX, fRadiusY);
- }
- else
- {
- aOutline = basegfx::tools::createPolygonFromRect(aRange);
- }
-
- createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
- }
- }
-
- break;
- }
- case META_ELLIPSE_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineOrFillActive())
- {
- const MetaEllipseAction* pA = (const MetaEllipseAction*)pAction;
- const Rectangle& rRectangle = pA->GetRect();
-
- if(!rRectangle.IsEmpty())
- {
- const basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
-
- if(!aRange.isEmpty())
- {
- const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromEllipse(
- aRange.getCenter(), aRange.getWidth() * 0.5, aRange.getHeight() * 0.5));
-
- createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
- }
- }
-
- break;
- }
- case META_ARC_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineColorActive())
- {
- const MetaArcAction* pA = (const MetaArcAction*)pAction;
- const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC);
- const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
-
- createHairlinePrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_PIE_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineOrFillActive())
- {
- const MetaPieAction* pA = (const MetaPieAction*)pAction;
- const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE);
- const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
-
- createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_CHORD_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineOrFillActive())
- {
- const MetaChordAction* pA = (const MetaChordAction*)pAction;
- const Polygon aToolsPoly(pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD);
- const basegfx::B2DPolygon aOutline(aToolsPoly.getB2DPolygon());
-
- createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_POLYLINE_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineColorActive())
- {
- const MetaPolyLineAction* pA = (const MetaPolyLineAction*)pAction;
- createLinePrimitive(pA->GetPolygon().getB2DPolygon(), pA->GetLineInfo(), rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_POLYGON_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineOrFillActive())
- {
- const MetaPolygonAction* pA = (const MetaPolygonAction*)pAction;
- basegfx::B2DPolygon aOutline(pA->GetPolygon().getB2DPolygon());
-
- // the metafile play interprets the polygons from MetaPolygonAction
- // always as closed and always paints an edge from last to first point,
- // so force to closed here to emulate that
- if(aOutline.count() > 1 && !aOutline.isClosed())
- {
- aOutline.setClosed(true);
- }
-
- createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_POLYPOLYGON_ACTION :
- {
- /** CHECKED, WORKS WELL */
- if(rPropertyHolders.Current().getLineOrFillActive())
- {
- const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*)pAction;
- basegfx::B2DPolyPolygon aPolyPolygonOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
-
- // the metafile play interprets the single polygons from MetaPolyPolygonAction
- // always as closed and always paints an edge from last to first point,
- // so force to closed here to emulate that
- for(sal_uInt32 b(0); b < aPolyPolygonOutline.count(); b++)
- {
- basegfx::B2DPolygon aPolygonOutline(aPolyPolygonOutline.getB2DPolygon(b));
-
- if(aPolygonOutline.count() > 1 && !aPolygonOutline.isClosed())
- {
- aPolygonOutline.setClosed(true);
- aPolyPolygonOutline.setB2DPolygon(b, aPolygonOutline);
- }
- }
-
- createHairlineAndFillPrimitive(aPolyPolygonOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_TEXT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaTextAction* pA = (const MetaTextAction*)pAction;
- sal_uInt32 nTextLength(pA->GetLen());
- const sal_uInt32 nTextIndex(pA->GetIndex());
- const sal_uInt32 nStringLength(pA->GetText().Len());
-
- if(nTextLength + nTextIndex > nStringLength)
- {
- nTextLength = nStringLength - nTextIndex;
- }
-
- if(nTextLength && rPropertyHolders.Current().getTextColorActive())
- {
- const std::vector< double > aDXArray;
- proccessMetaTextAction(
- pA->GetPoint(),
- pA->GetText(),
- nTextIndex,
- nTextLength,
- aDXArray,
- rTargetHolders.Current(),
- rPropertyHolders.Current());
- }
-
- break;
- }
- case META_TEXTARRAY_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaTextArrayAction* pA = (const MetaTextArrayAction*)pAction;
- sal_uInt32 nTextLength(pA->GetLen());
- const sal_uInt32 nTextIndex(pA->GetIndex());
- const sal_uInt32 nStringLength(pA->GetText().Len());
-
- if(nTextLength + nTextIndex > nStringLength)
- {
- nTextLength = nTextIndex > nStringLength ? 0 : nStringLength - nTextIndex;
- }
-
- if(nTextLength && rPropertyHolders.Current().getTextColorActive())
- {
- // preapare DXArray (if used)
- std::vector< double > aDXArray;
- sal_Int32* pDXArray = pA->GetDXArray();
-
- if(pDXArray)
- {
- aDXArray.reserve(nTextLength);
-
- for(sal_uInt32 a(0); a < nTextLength; a++)
- {
- aDXArray.push_back((double)(*(pDXArray + a)));
- }
- }
-
- proccessMetaTextAction(
- pA->GetPoint(),
- pA->GetText(),
- nTextIndex,
- nTextLength,
- aDXArray,
- rTargetHolders.Current(),
- rPropertyHolders.Current());
- }
-
- break;
- }
- case META_STRETCHTEXT_ACTION :
- {
- // #i108440# StarMath uses MetaStretchTextAction, thus support is needed.
- // It looks as if it pretty never really uses a width different from
- // the default text-layout width, but it's not possible to be sure.
- // Implemented getting the DXArray and checking for scale at all. If
- // scale is more than 3.5% different, scale the DXArray before usage.
- // New status:
-
- /** CHECKED, WORKS WELL */
- const MetaStretchTextAction* pA = (const MetaStretchTextAction*)pAction;
- sal_uInt32 nTextLength(pA->GetLen());
- const sal_uInt32 nTextIndex(pA->GetIndex());
- const sal_uInt32 nStringLength(pA->GetText().Len());
-
- if(nTextLength + nTextIndex > nStringLength)
- {
- nTextLength = nStringLength - nTextIndex;
- }
-
- if(nTextLength && rPropertyHolders.Current().getTextColorActive())
- {
- drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
- aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
-
- ::std::vector< double > aTextArray(
- aTextLayouterDevice.getTextArray(
- pA->GetText(),
- nTextIndex,
- nTextLength));
-
- if(!aTextArray.empty())
- {
- const double fTextLength(aTextArray.back());
-
- if(0.0 != fTextLength && pA->GetWidth())
- {
- const double fRelative(pA->GetWidth() / fTextLength);
-
- if(fabs(fRelative - 1.0) >= 0.035)
- {
- // when derivation is more than 3,5% from default text size,
- // scale the DXArray
- for(sal_uInt32 a(0); a < aTextArray.size(); a++)
- {
- aTextArray[a] *= fRelative;
- }
- }
- }
- }
-
- proccessMetaTextAction(
- pA->GetPoint(),
- pA->GetText(),
- nTextIndex,
- nTextLength,
- aTextArray,
- rTargetHolders.Current(),
- rPropertyHolders.Current());
- }
-
- break;
- }
- case META_TEXTRECT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- // OSL_FAIL("META_TEXTRECT_ACTION requested (!)");
- const MetaTextRectAction* pA = (const MetaTextRectAction*)pAction;
- const Rectangle& rRectangle = pA->GetRect();
- const sal_uInt32 nStringLength(pA->GetText().Len());
-
- if(!rRectangle.IsEmpty() && 0 != nStringLength)
- {
- // The problem with this action is that it describes unlayouted text
- // and the layout capabilities are in EditEngine/Outliner in SVX. The
- // same problem is true for VCL which internally has implementations
- // to layout text in this case. There exists even a call
- // OutputDevice::AddTextRectActions(...) to create the needed actions
- // as 'sub-content' of a Metafile. Unfortunately i do not have an
- // OutputDevice here since this interpreter tries to work without
- // VCL AFAP.
- // Since AddTextRectActions is the only way as long as we do not have
- // a simple text layouter available, i will try to add it to the
- // TextLayouterDevice isloation.
- drawinglayer::primitive2d::TextLayouterDevice aTextLayouterDevice;
- aTextLayouterDevice.setFont(rPropertyHolders.Current().getFont());
- GDIMetaFile aGDIMetaFile;
-
- aTextLayouterDevice.addTextRectActions(
- rRectangle, pA->GetText(), pA->GetStyle(), aGDIMetaFile);
-
- if(aGDIMetaFile.GetActionSize())
- {
- // cerate sub-content
- drawinglayer::primitive2d::Primitive2DSequence xSubContent;
- {
- rTargetHolders.Push();
- // #i# for sub-Mteafile contents, do start with new, default render state
- rPropertyHolders.PushDefault();
- interpretMetafile(aGDIMetaFile, rTargetHolders, rPropertyHolders, rViewInformation);
- xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
- rPropertyHolders.Pop();
- rTargetHolders.Pop();
- }
-
- if(xSubContent.hasElements())
- {
- // add with transformation
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::TransformPrimitive2D(
- rPropertyHolders.Current().getTransformation(),
- xSubContent));
- }
- }
- }
-
- break;
- }
- case META_BMP_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaBmpAction* pA = (const MetaBmpAction*)pAction;
- const BitmapEx aBitmapEx(pA->GetBitmap());
-
- createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
-
- break;
- }
- case META_BMPSCALE_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*)pAction;
- const Bitmap aBitmapEx(pA->GetBitmap());
-
- createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
-
- break;
- }
- case META_BMPSCALEPART_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*)pAction;
- const Bitmap& rBitmap = pA->GetBitmap();
-
- if(!rBitmap.IsEmpty())
- {
- Bitmap aCroppedBitmap(rBitmap);
- const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
-
- if(!aCropRectangle.IsEmpty())
- {
- aCroppedBitmap.Crop(aCropRectangle);
- }
-
- const BitmapEx aCroppedBitmapEx(aCroppedBitmap);
- createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_BMPEX_ACTION :
- {
- /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */
- const MetaBmpExAction* pA = (const MetaBmpExAction*)pAction;
- const BitmapEx& rBitmapEx = pA->GetBitmapEx();
-
- createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
-
- break;
- }
- case META_BMPEXSCALE_ACTION :
- {
- /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */
- const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*)pAction;
- const BitmapEx& rBitmapEx = pA->GetBitmapEx();
-
- createBitmapExPrimitive(rBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
-
- break;
- }
- case META_BMPEXSCALEPART_ACTION :
- {
- /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */
- const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*)pAction;
- const BitmapEx& rBitmapEx = pA->GetBitmapEx();
-
- if(!rBitmapEx.IsEmpty())
- {
- BitmapEx aCroppedBitmapEx(rBitmapEx);
- const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
-
- if(!aCropRectangle.IsEmpty())
- {
- aCroppedBitmapEx.Crop(aCropRectangle);
- }
-
- createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_MASK_ACTION :
- {
- /** CHECKED, WORKS WELL: Simply same as META_BMP_ACTION */
- const MetaMaskAction* pA = (const MetaMaskAction*)pAction;
- const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
-
- createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), rTargetHolders.Current(), rPropertyHolders.Current());
-
- break;
- }
- case META_MASKSCALE_ACTION :
- {
- /** CHECKED, WORKS WELL: Simply same as META_BMPSCALE_ACTION */
- const MetaMaskScaleAction* pA = (const MetaMaskScaleAction*)pAction;
- const BitmapEx aBitmapEx(createMaskBmpEx(pA->GetBitmap(), pA->GetColor()));
-
- createBitmapExPrimitive(aBitmapEx, pA->GetPoint(), pA->GetSize(), rTargetHolders.Current(), rPropertyHolders.Current());
-
- break;
- }
- case META_MASKSCALEPART_ACTION :
- {
- /** CHECKED, WORKS WELL: Simply same as META_BMPSCALEPART_ACTION */
- const MetaMaskScalePartAction* pA = (const MetaMaskScalePartAction*)pAction;
- const Bitmap& rBitmap = pA->GetBitmap();
-
- if(!rBitmap.IsEmpty())
- {
- Bitmap aCroppedBitmap(rBitmap);
- const Rectangle aCropRectangle(pA->GetSrcPoint(), pA->GetSrcSize());
-
- if(!aCropRectangle.IsEmpty())
- {
- aCroppedBitmap.Crop(aCropRectangle);
- }
-
- const BitmapEx aCroppedBitmapEx(createMaskBmpEx(aCroppedBitmap, pA->GetColor()));
- createBitmapExPrimitive(aCroppedBitmapEx, pA->GetDestPoint(), pA->GetDestSize(), rTargetHolders.Current(), rPropertyHolders.Current());
- }
-
- break;
- }
- case META_GRADIENT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaGradientAction* pA = (const MetaGradientAction*)pAction;
- const Rectangle& rRectangle = pA->GetRect();
-
- if(!rRectangle.IsEmpty())
- {
- basegfx::B2DRange aRange(rRectangle.Left(), rRectangle.Top(), rRectangle.Right(), rRectangle.Bottom());
-
- if(!aRange.isEmpty())
- {
- const Gradient& rGradient = pA->GetGradient();
- const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
- basegfx::B2DPolyPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
-
- if(aAttribute.getStartColor() == aAttribute.getEndColor())
- {
- // not really a gradient. Create filled rectangle
- createFillPrimitive(
- aOutline,
- rTargetHolders.Current(),
- rPropertyHolders.Current());
- }
- else
- {
- // really a gradient
- aRange.transform(rPropertyHolders.Current().getTransformation());
- drawinglayer::primitive2d::Primitive2DSequence xGradient(1);
-
- if(rPropertyHolders.Current().isRasterOpInvert())
- {
- // use a special version of FillGradientPrimitive2D which creates
- // non-overlapping geometry on decomposition to makethe old XOR
- // paint 'trick' work.
- xGradient[0] = drawinglayer::primitive2d::Primitive2DReference(
- new drawinglayer::primitive2d::NonOverlappingFillGradientPrimitive2D(
- aRange,
- aAttribute));
- }
- else
- {
- xGradient[0] = drawinglayer::primitive2d::Primitive2DReference(
- new drawinglayer::primitive2d::FillGradientPrimitive2D(
- aRange,
- aAttribute));
- }
-
- // #i112300# clip against polygon representing the rectangle from
- // the action. This is implicitely done using a temp Clipping in VCL
- // when a MetaGradientAction is executed
- aOutline.transform(rPropertyHolders.Current().getTransformation());
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::MaskPrimitive2D(
- aOutline,
- xGradient));
- }
- }
- }
-
- break;
- }
- case META_HATCH_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaHatchAction* pA = (const MetaHatchAction*)pAction;
- basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
-
- if(aOutline.count())
- {
- const Hatch& rHatch = pA->GetHatch();
- const drawinglayer::attribute::FillHatchAttribute aAttribute(createFillHatchAttribute(rHatch));
-
- aOutline.transform(rPropertyHolders.Current().getTransformation());
-
- const basegfx::B2DRange aObjectRange(aOutline.getB2DRange());
- const drawinglayer::primitive2d::Primitive2DReference aFillHatch(
- new drawinglayer::primitive2d::FillHatchPrimitive2D(
- aObjectRange,
- basegfx::BColor(),
- aAttribute));
-
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::MaskPrimitive2D(
- aOutline,
- drawinglayer::primitive2d::Primitive2DSequence(&aFillHatch, 1)));
- }
-
- break;
- }
- case META_WALLPAPER_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaWallpaperAction* pA = (const MetaWallpaperAction*)pAction;
- Rectangle aWallpaperRectangle(pA->GetRect());
-
- if(!aWallpaperRectangle.IsEmpty())
- {
- const Wallpaper& rWallpaper = pA->GetWallpaper();
- const WallpaperStyle eWallpaperStyle(rWallpaper.GetStyle());
- basegfx::B2DRange aWallpaperRange(
- aWallpaperRectangle.Left(), aWallpaperRectangle.Top(),
- aWallpaperRectangle.Right(), aWallpaperRectangle.Bottom());
-
- if(WALLPAPER_NULL != eWallpaperStyle)
- {
- if(rWallpaper.IsBitmap())
- {
- // create bitmap background. Caution: This
- // also will create gradient/color background(s)
- // when the bitmap is transparent or not tiled
- CreateAndAppendBitmapWallpaper(
- aWallpaperRange,
- rWallpaper,
- rTargetHolders.Current(),
- rPropertyHolders.Current());
- }
- else if(rWallpaper.IsGradient())
- {
- // create gradient background
- rTargetHolders.Current().append(
- CreateGradientWallpaper(
- aWallpaperRange,
- rWallpaper.GetGradient(),
- rPropertyHolders.Current()));
- }
- else if(!rWallpaper.GetColor().GetTransparency())
- {
- // create color background
- rTargetHolders.Current().append(
- CreateColorWallpaper(
- aWallpaperRange,
- rWallpaper.GetColor().getBColor(),
- rPropertyHolders.Current()));
- }
- }
- }
-
- break;
- }
- case META_CLIPREGION_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaClipRegionAction* pA = (const MetaClipRegionAction*)pAction;
-
- if(pA->IsClipping())
- {
- // new clipping. Get PolyPolygon and transform with current transformation
- basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(pA->GetRegion()));
-
- aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
- HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
- }
- else
- {
- // end clipping
- const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
-
- HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
- }
-
- break;
- }
- case META_ISECTRECTCLIPREGION_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*)pAction;
- const Rectangle& rRectangle = pA->GetRect();
-
- if(rRectangle.IsEmpty())
- {
- // intersect with empty rectangle will always give empty
- // ClipPolyPolygon; start new clipping with empty PolyPolygon
- const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
-
- HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
- }
- else
- {
- // create transformed ClipRange
- basegfx::B2DRange aClipRange(
- rRectangle.Left(), rRectangle.Top(),
- rRectangle.Right(), rRectangle.Bottom());
-
- aClipRange.transform(rPropertyHolders.Current().getTransformation());
-
- if(rPropertyHolders.Current().getClipPolyPolygonActive())
- {
- if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
- {
- // nothing to do, empty active clipPolyPolygon will stay
- // empty when intersecting
- }
- else
- {
- // AND existing region and new ClipRange
- const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
- rPropertyHolders.Current().getClipPolyPolygon());
- basegfx::B2DPolyPolygon aClippedPolyPolygon;
-
- if(aOriginalPolyPolygon.count())
- {
- aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnRange(
- aOriginalPolyPolygon,
- aClipRange,
- true,
- false);
- }
-
- if(aClippedPolyPolygon != aOriginalPolyPolygon)
- {
- // start new clipping with intersected region
- HandleNewClipRegion(
- aClippedPolyPolygon,
- rTargetHolders,
- rPropertyHolders);
- }
- }
- }
- else
- {
- // start new clipping with ClipRange
- const basegfx::B2DPolyPolygon aNewClipPolyPolygon(
- basegfx::tools::createPolygonFromRect(aClipRange));
-
- HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
- }
- }
-
- break;
- }
- case META_ISECTREGIONCLIPREGION_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*)pAction;
- const Region& rNewRegion = pA->GetRegion();
-
- if(rNewRegion.IsEmpty())
- {
- // intersect with empty region will always give empty
- // region; start new clipping with empty PolyPolygon
- const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
-
- HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
- }
- else
- {
- // get new ClipPolyPolygon, transform it with current transformation
- basegfx::B2DPolyPolygon aNewClipPolyPolygon(getB2DPolyPolygonFromRegion(rNewRegion));
- aNewClipPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
-
- if(rPropertyHolders.Current().getClipPolyPolygonActive())
- {
- if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
- {
- // nothing to do, empty active clipPolyPolygon will stay empty
- // when intersecting with any region
- }
- else
- {
- // AND existing and new region
- const basegfx::B2DPolyPolygon aOriginalPolyPolygon(
- rPropertyHolders.Current().getClipPolyPolygon());
- basegfx::B2DPolyPolygon aClippedPolyPolygon;
-
- if(aOriginalPolyPolygon.count())
- {
- aClippedPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
- aOriginalPolyPolygon, aNewClipPolyPolygon, true, false);
- }
-
- if(aClippedPolyPolygon != aOriginalPolyPolygon)
- {
- // start new clipping with intersected ClipPolyPolygon
- HandleNewClipRegion(aClippedPolyPolygon, rTargetHolders, rPropertyHolders);
- }
- }
- }
- else
- {
- // start new clipping with new ClipPolyPolygon
- HandleNewClipRegion(aNewClipPolyPolygon, rTargetHolders, rPropertyHolders);
- }
- }
-
- break;
- }
- case META_MOVECLIPREGION_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*)pAction;
-
- if(rPropertyHolders.Current().getClipPolyPolygonActive())
- {
- if(0 == rPropertyHolders.Current().getClipPolyPolygon().count())
- {
- // nothing to do
- }
- else
- {
- const sal_Int32 nHor(pA->GetHorzMove());
- const sal_Int32 nVer(pA->GetVertMove());
-
- if(0 != nHor || 0 != nVer)
- {
- // prepare translation, add current transformation
- basegfx::B2DVector aVector(pA->GetHorzMove(), pA->GetVertMove());
- aVector *= rPropertyHolders.Current().getTransformation();
- basegfx::B2DHomMatrix aTransform(
- basegfx::tools::createTranslateB2DHomMatrix(aVector));
-
- // transform existing region
- basegfx::B2DPolyPolygon aClipPolyPolygon(
- rPropertyHolders.Current().getClipPolyPolygon());
-
- aClipPolyPolygon.transform(aTransform);
- HandleNewClipRegion(aClipPolyPolygon, rTargetHolders, rPropertyHolders);
- }
- }
- }
-
- break;
- }
- case META_LINECOLOR_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaLineColorAction* pA = (const MetaLineColorAction*)pAction;
- const bool bActive(pA->IsSetting());
-
- rPropertyHolders.Current().setLineColorActive(bActive);
- if(bActive)
- rPropertyHolders.Current().setLineColor(pA->GetColor().getBColor());
-
- break;
- }
- case META_FILLCOLOR_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaFillColorAction* pA = (const MetaFillColorAction*)pAction;
- const bool bActive(pA->IsSetting());
-
- rPropertyHolders.Current().setFillColorActive(bActive);
- if(bActive)
- rPropertyHolders.Current().setFillColor(pA->GetColor().getBColor());
-
- break;
- }
- case META_TEXTCOLOR_ACTION :
- {
- /** SIMPLE, DONE */
- const MetaTextColorAction* pA = (const MetaTextColorAction*)pAction;
- const bool bActivate(COL_TRANSPARENT != pA->GetColor().GetColor());
-
- rPropertyHolders.Current().setTextColorActive(bActivate);
- rPropertyHolders.Current().setTextColor(pA->GetColor().getBColor());
-
- break;
- }
- case META_TEXTFILLCOLOR_ACTION :
- {
- /** SIMPLE, DONE */
- const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*)pAction;
- const bool bWithColorArgument(pA->IsSetting());
-
- if(bWithColorArgument)
- {
- // emulate OutputDevice::SetTextFillColor(...) WITH argument
- const Color& rFontFillColor = pA->GetColor();
- rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
- rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor());
- }
- else
- {
- // emulate SetFillColor() <- NO argument (!)
- rPropertyHolders.Current().setTextFillColorActive(false);
- }
-
- break;
- }
- case META_TEXTALIGN_ACTION :
- {
- /** SIMPLE, DONE */
- const MetaTextAlignAction* pA = (const MetaTextAlignAction*)pAction;
- const TextAlign aNewTextAlign = pA->GetTextAlign();
-
- // TextAlign is applied to the current font (as in
- // OutputDevice::SetTextAlign which would be used when
- // playing the Metafile)
- if(rPropertyHolders.Current().getFont().GetAlign() != aNewTextAlign)
- {
- Font aNewFont(rPropertyHolders.Current().getFont());
- aNewFont.SetAlign(aNewTextAlign);
- rPropertyHolders.Current().setFont(aNewFont);
- }
-
- break;
- }
- case META_MAPMODE_ACTION :
- {
- /** CHECKED, WORKS WELL */
- // the most necessary MapMode to be interpreted is MAP_RELATIVE,
- // but also the others may occur. Even not yet supported ones
- // may need to be added here later
- const MetaMapModeAction* pA = (const MetaMapModeAction*)pAction;
- const MapMode& rMapMode = pA->GetMapMode();
- basegfx::B2DHomMatrix aMapping;
-
- if(MAP_RELATIVE == rMapMode.GetMapUnit())
- {
- aMapping = getTransformFromMapMode(rMapMode);
- }
- else
- {
- switch(rMapMode.GetMapUnit())
- {
- case MAP_100TH_MM :
- {
- if(MAP_TWIP == rPropertyHolders.Current().getMapUnit())
- {
- // MAP_TWIP -> MAP_100TH_MM
- const double fTwipTo100thMm(127.0 / 72.0);
- aMapping.scale(fTwipTo100thMm, fTwipTo100thMm);
- }
- break;
- }
- case MAP_TWIP :
- {
- if(MAP_100TH_MM == rPropertyHolders.Current().getMapUnit())
- {
- // MAP_100TH_MM -> MAP_TWIP
- const double f100thMmToTwip(72.0 / 127.0);
- aMapping.scale(f100thMmToTwip, f100thMmToTwip);
- }
- break;
- }
- default :
- {
- OSL_FAIL("interpretMetafile: META_MAPMODE_ACTION with unsupported MapUnit (!)");
- break;
- }
- }
-
- aMapping = getTransformFromMapMode(rMapMode) * aMapping;
- rPropertyHolders.Current().setMapUnit(rMapMode.GetMapUnit());
- }
-
- if(!aMapping.isIdentity())
- {
- aMapping = aMapping * rPropertyHolders.Current().getTransformation();
- rPropertyHolders.Current().setTransformation(aMapping);
- }
-
- break;
- }
- case META_FONT_ACTION :
- {
- /** SIMPLE, DONE */
- const MetaFontAction* pA = (const MetaFontAction*)pAction;
- rPropertyHolders.Current().setFont(pA->GetFont());
- Size aFontSize(pA->GetFont().GetSize());
-
- if(0 == aFontSize.Height())
- {
- // this should not happen but i got Metafiles where this was the
- // case. A height needs to be guessed (similar to OutputDevice::ImplNewFont())
- Font aCorrectedFont(pA->GetFont());
-
- // guess 16 pixel (as in VCL)
- aFontSize = Size(0, 16);
-
- // convert to target MapUnit if not pixels
- aFontSize = Application::GetDefaultDevice()->LogicToLogic(
- aFontSize, MAP_PIXEL, rPropertyHolders.Current().getMapUnit());
-
- aCorrectedFont.SetSize(aFontSize);
- rPropertyHolders.Current().setFont(aCorrectedFont);
- }
-
- // older Metafiles have no META_TEXTCOLOR_ACTION which defines
- // the FontColor now, so use the Font's color when not transparent
- const Color& rFontColor = pA->GetFont().GetColor();
- const bool bActivate(COL_TRANSPARENT != rFontColor.GetColor());
-
- if(bActivate)
- {
- rPropertyHolders.Current().setTextColor(rFontColor.getBColor());
- }
-
- // caution: do NOT decativate here on transparet, see
- // OutputDevice::SetFont(..) for more info
- // rPropertyHolders.Current().setTextColorActive(bActivate);
-
- // for fill color emulate a MetaTextFillColorAction with !transparent as bool,
- // see OutputDevice::SetFont(..) the if(mpMetaFile) case
- if(bActivate)
- {
- const Color& rFontFillColor = pA->GetFont().GetFillColor();
- rPropertyHolders.Current().setTextFillColor(rFontFillColor.getBColor());
- rPropertyHolders.Current().setTextFillColorActive(COL_TRANSPARENT != rFontFillColor.GetColor());
- }
- else
- {
- rPropertyHolders.Current().setTextFillColorActive(false);
- }
-
- break;
- }
- case META_PUSH_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaPushAction* pA = (const MetaPushAction*)pAction;
- rPropertyHolders.Push(pA->GetFlags());
-
- break;
- }
- case META_POP_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const bool bRegionMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_CLIPREGION);
- const bool bRasterOpMayChange(rPropertyHolders.Current().getPushFlags() & PUSH_RASTEROP);
-
- if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
- {
- // end evtl. clipping
- const basegfx::B2DPolyPolygon aEmptyPolyPolygon;
-
- HandleNewClipRegion(aEmptyPolyPolygon, rTargetHolders, rPropertyHolders);
- }
-
- if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
- {
- // end evtl. RasterOp
- HandleNewRasterOp(ROP_OVERPAINT, rTargetHolders, rPropertyHolders);
- }
-
- rPropertyHolders.Pop();
-
- if(bRasterOpMayChange && rPropertyHolders.Current().isRasterOpActive())
- {
- // start evtl. RasterOp
- HandleNewRasterOp(rPropertyHolders.Current().getRasterOp(), rTargetHolders, rPropertyHolders);
- }
-
- if(bRegionMayChange && rPropertyHolders.Current().getClipPolyPolygonActive())
- {
- // start evtl. clipping
- HandleNewClipRegion(
- rPropertyHolders.Current().getClipPolyPolygon(), rTargetHolders, rPropertyHolders);
- }
-
- break;
- }
- case META_RASTEROP_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaRasterOpAction* pA = (const MetaRasterOpAction*)pAction;
- const RasterOp aRasterOp = pA->GetRasterOp();
-
- HandleNewRasterOp(aRasterOp, rTargetHolders, rPropertyHolders);
-
- break;
- }
- case META_TRANSPARENT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaTransparentAction* pA = (const MetaTransparentAction*)pAction;
- const basegfx::B2DPolyPolygon aOutline(pA->GetPolyPolygon().getB2DPolyPolygon());
-
- if(aOutline.count())
- {
- const sal_uInt16 nTransparence(pA->GetTransparence());
-
- if(0 == nTransparence)
- {
- // not transparent
- createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- }
- else if(nTransparence >= 100)
- {
- // fully or more than transparent
- }
- else
- {
- // transparent. Create new target
- rTargetHolders.Push();
-
- // create primitives there and get them
- createHairlineAndFillPrimitive(aOutline, rTargetHolders.Current(), rPropertyHolders.Current());
- const drawinglayer::primitive2d::Primitive2DSequence aSubContent(
- rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current()));
-
- // back to old target
- rTargetHolders.Pop();
-
- if(aSubContent.hasElements())
- {
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
- aSubContent,
- nTransparence * 0.01));
- }
- }
- }
-
- break;
- }
- case META_EPS_ACTION :
- {
- /** CHECKED, WORKS WELL */
- // To support this action, i have added a EpsPrimitive2D which will
- // by default decompose to the Metafile replacement data. To support
- // this EPS on screen, the renderer visualizing this has to support
- // that primitive and visualize the Eps file (e.g. printing)
- const MetaEPSAction* pA = (const MetaEPSAction*)pAction;
- const Rectangle aRectangle(pA->GetPoint(), pA->GetSize());
-
- if(!aRectangle.IsEmpty())
- {
- // create object transform
- basegfx::B2DHomMatrix aObjectTransform;
-
- aObjectTransform.set(0, 0, aRectangle.GetWidth());
- aObjectTransform.set(1, 1, aRectangle.GetHeight());
- aObjectTransform.set(0, 2, aRectangle.Left());
- aObjectTransform.set(1, 2, aRectangle.Top());
-
- // add current transformation
- aObjectTransform = rPropertyHolders.Current().getTransformation() * aObjectTransform;
-
- // embed using EpsPrimitive
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::EpsPrimitive2D(
- aObjectTransform,
- pA->GetLink(),
- pA->GetSubstitute()));
- }
-
- break;
- }
- case META_REFPOINT_ACTION :
- {
- /** SIMPLE, DONE */
- // only used for hatch and line pattern offsets, pretty much no longer
- // supported today
- // const MetaRefPointAction* pA = (const MetaRefPointAction*)pAction;
- break;
- }
- case META_TEXTLINECOLOR_ACTION :
- {
- /** SIMPLE, DONE */
- const MetaTextLineColorAction* pA = (const MetaTextLineColorAction*)pAction;
- const bool bActive(pA->IsSetting());
-
- rPropertyHolders.Current().setTextLineColorActive(bActive);
- if(bActive)
- rPropertyHolders.Current().setTextLineColor(pA->GetColor().getBColor());
-
- break;
- }
- case META_TEXTLINE_ACTION :
- {
- /** CHECKED, WORKS WELL */
- // actually creates overline, underline and strikeouts, so
- // these should be isolated from TextDecoratedPortionPrimitive2D
- // to own primitives. Done, available now.
- //
- // This Metaaction seems not to be used (was not used in any
- // checked files). It's used in combination with the current
- // Font.
- const MetaTextLineAction* pA = (const MetaTextLineAction*)pAction;
-
- proccessMetaTextLineAction(
- *pA,
- rTargetHolders.Current(),
- rPropertyHolders.Current());
-
- break;
- }
- case META_FLOATTRANSPARENT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*)pAction;
- const Rectangle aTargetRectangle(pA->GetPoint(), pA->GetSize());
-
- if(!aTargetRectangle.IsEmpty())
- {
- const GDIMetaFile& rContent = pA->GetGDIMetaFile();
-
- if(rContent.GetActionSize())
- {
- // create the sub-content with no embedding specific to the
- // sub-metafile, this seems not to be used.
- drawinglayer::primitive2d::Primitive2DSequence xSubContent;
- {
- rTargetHolders.Push();
- // #i# for sub-Mteafile contents, do start with new, default render state
- rPropertyHolders.PushDefault();
- interpretMetafile(rContent, rTargetHolders, rPropertyHolders, rViewInformation);
- xSubContent = rTargetHolders.Current().getPrimitive2DSequence(rPropertyHolders.Current());
- rPropertyHolders.Pop();
- rTargetHolders.Pop();
- }
-
- if(xSubContent.hasElements())
- {
- // check if gradient is a real gradient
- const Gradient& rGradient = pA->GetGradient();
- const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
-
- if(aAttribute.getStartColor() == aAttribute.getEndColor())
- {
- // not really a gradient; create UnifiedTransparencePrimitive2D
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
- xSubContent,
- aAttribute.getStartColor().luminance()));
- }
- else
- {
- // really a gradient. Create gradient sub-content (with correct scaling)
- basegfx::B2DRange aRange(
- aTargetRectangle.Left(), aTargetRectangle.Top(),
- aTargetRectangle.Right(), aTargetRectangle.Bottom());
- aRange.transform(rPropertyHolders.Current().getTransformation());
-
- // prepare gradient for transparent content
- const drawinglayer::primitive2d::Primitive2DReference xTransparence(
- new drawinglayer::primitive2d::FillGradientPrimitive2D(
- aRange,
- aAttribute));
-
- // create transparence primitive
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::TransparencePrimitive2D(
- xSubContent,
- drawinglayer::primitive2d::Primitive2DSequence(&xTransparence, 1)));
- }
- }
- }
- }
-
- break;
- }
- case META_GRADIENTEX_ACTION :
- {
- /** SIMPLE, DONE */
- // This is only a data holder which is interpreted inside comment actions,
- // see META_COMMENT_ACTION for more info
- // const MetaGradientExAction* pA = (const MetaGradientExAction*)pAction;
- break;
- }
- case META_LAYOUTMODE_ACTION :
- {
- /** SIMPLE, DONE */
- const MetaLayoutModeAction* pA = (const MetaLayoutModeAction*)pAction;
- rPropertyHolders.Current().setLayoutMode(pA->GetLayoutMode());
- break;
- }
- case META_TEXTLANGUAGE_ACTION :
- {
- /** SIMPLE, DONE */
- const MetaTextLanguageAction* pA = (const MetaTextLanguageAction*)pAction;
- rPropertyHolders.Current().setLanguageType(pA->GetTextLanguage());
- break;
- }
- case META_OVERLINECOLOR_ACTION :
- {
- /** SIMPLE, DONE */
- const MetaOverlineColorAction* pA = (const MetaOverlineColorAction*)pAction;
- const bool bActive(pA->IsSetting());
-
- rPropertyHolders.Current().setOverlineColorActive(bActive);
- if(bActive)
- rPropertyHolders.Current().setOverlineColor(pA->GetColor().getBColor());
-
- break;
- }
- case META_RENDERGRAPHIC_ACTION :
- {
- const MetaRenderGraphicAction* pA = (const MetaRenderGraphicAction*)pAction;
- const Rectangle aRectangle(pA->GetPoint(), pA->GetSize());
-
- if(!aRectangle.IsEmpty())
- {
- // create object transform
- basegfx::B2DHomMatrix aObjectTransform;
-
- aObjectTransform.set(0, 0, aRectangle.GetWidth());
- aObjectTransform.set(1, 1, aRectangle.GetHeight());
- aObjectTransform.set(0, 2, aRectangle.Left());
- aObjectTransform.set(1, 2, aRectangle.Top());
-
- // add current transformation
- aObjectTransform = rPropertyHolders.Current().getTransformation() * aObjectTransform;
-
- // embed using EpsPrimitive
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::RenderGraphicPrimitive2D(
- pA->GetRenderGraphic(),
- aObjectTransform ) );
- }
-
- break;
- }
- case META_COMMENT_ACTION :
- {
- /** CHECKED, WORKS WELL */
- // I already implemented
- // XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END
- // XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END,
- // but opted to remove these again; it works well without them
- // and makes the code less dependent from those Metafile Add-Ons
- const MetaCommentAction* pA = (const MetaCommentAction*)pAction;
-
- if(COMPARE_EQUAL == pA->GetComment().CompareIgnoreCaseToAscii("XGRAD_SEQ_BEGIN"))
- {
- // XGRAD_SEQ_BEGIN, XGRAD_SEQ_END should be supported since the
- // pure recorded paint of the gradients uses the XOR paint functionality
- // ('trick'). This is (and will be) broblematic with AntAliasing, so it's
- // better to use this info
- const MetaGradientExAction* pMetaGradientExAction = 0;
- bool bDone(false);
- sal_uInt32 b(nAction + 1);
-
- for(; !bDone && b < nCount; b++)
- {
- pAction = rMetaFile.GetAction(b);
-
- if(META_GRADIENTEX_ACTION == pAction->GetType())
- {
- pMetaGradientExAction = (const MetaGradientExAction*)pAction;
- }
- else if(META_COMMENT_ACTION == pAction->GetType())
- {
- if(COMPARE_EQUAL == ((const MetaCommentAction*)pAction)->GetComment().CompareIgnoreCaseToAscii("XGRAD_SEQ_END"))
- {
- bDone = true;
- }
- }
- }
-
- if(bDone && pMetaGradientExAction)
- {
- // consume actions and skip forward
- nAction = b - 1;
-
- // get geometry data
- basegfx::B2DPolyPolygon aPolyPolygon(pMetaGradientExAction->GetPolyPolygon().getB2DPolyPolygon());
-
- if(aPolyPolygon.count())
- {
- // transform geometry
- aPolyPolygon.transform(rPropertyHolders.Current().getTransformation());
-
- // get and check if gradient is a real gradient
- const Gradient& rGradient = pMetaGradientExAction->GetGradient();
- const drawinglayer::attribute::FillGradientAttribute aAttribute(createFillGradientAttribute(rGradient));
-
- if(aAttribute.getStartColor() == aAttribute.getEndColor())
- {
- // not really a gradient
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(
- aPolyPolygon,
- aAttribute.getStartColor()));
- }
- else
- {
- // really a gradient
- rTargetHolders.Current().append(
- new drawinglayer::primitive2d::PolyPolygonGradientPrimitive2D(
- aPolyPolygon,
- aAttribute));
- }
- }
- }
- }
-
- break;
- }
- default:
- {
- OSL_FAIL("Unknown MetaFile Action (!)");
- break;
- }
- }
- }
- }
-} // end of anonymous namespace
-
-//////////////////////////////////////////////////////////////////////////////
-
-namespace drawinglayer
-{
- namespace primitive2d
- {
- Primitive2DSequence MetafilePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
- {
- // prepare target and porperties; each will have one default entry
- TargetHolders aTargetHolders;
- PropertyHolders aPropertyHolders;
-
- // set target MapUnit at Properties
- aPropertyHolders.Current().setMapUnit(getMetaFile().GetPrefMapMode().GetMapUnit());
-
- // interpret the Metafile
- interpretMetafile(getMetaFile(), aTargetHolders, aPropertyHolders, rViewInformation);
-
- // get the content. There should be ony one target, as in the start condition,
- // but iterating will be the right thing to do when some push/pop is not closed
- Primitive2DSequence xRetval;
-
- while(aTargetHolders.size() > 1)
- {
- appendPrimitive2DSequenceToPrimitive2DSequence(xRetval,
- aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
- aTargetHolders.Pop();
- }
-
- appendPrimitive2DSequenceToPrimitive2DSequence(xRetval,
- aTargetHolders.Current().getPrimitive2DSequence(aPropertyHolders.Current()));
-
- if(xRetval.hasElements())
- {
- // get target size
- const Rectangle aMtfTarget(getMetaFile().GetPrefMapMode().GetOrigin(), getMetaFile().GetPrefSize());
-
- // create transformation
- basegfx::B2DHomMatrix aAdaptedTransform;
-
- aAdaptedTransform.translate(-aMtfTarget.Left(), -aMtfTarget.Top());
- aAdaptedTransform.scale(
- aMtfTarget.getWidth() ? 1.0 / aMtfTarget.getWidth() : 1.0,
- aMtfTarget.getHeight() ? 1.0 / aMtfTarget.getHeight() : 1.0);
- aAdaptedTransform = getTransform() * aAdaptedTransform;
-
- // embed to target transformation
- const Primitive2DReference aEmbeddedTransform(
- new TransformPrimitive2D(
- aAdaptedTransform,
- xRetval));
-
- xRetval = Primitive2DSequence(&aEmbeddedTransform, 1);
- }
-
- return xRetval;
- }
-
- MetafilePrimitive2D::MetafilePrimitive2D(
- const basegfx::B2DHomMatrix& rMetaFileTransform,
- const GDIMetaFile& rMetaFile)
- : BufferedDecompositionPrimitive2D(),
- maMetaFileTransform(rMetaFileTransform),
- maMetaFile(rMetaFile)
- {
- }
-
- bool MetafilePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
- {
- if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
- {
- const MetafilePrimitive2D& rCompare = (MetafilePrimitive2D&)rPrimitive;
-
- return (getTransform() == rCompare.getTransform()
- && getMetaFile() == rCompare.getMetaFile());
- }
-
- return false;
- }
-
- basegfx::B2DRange MetafilePrimitive2D::getB2DRange(const geometry::ViewInformation2D& /*rViewInformation*/) const
- {
- // use own implementation to quickly answer the getB2DRange question. The
- // MetafilePrimitive2D assumes that all geometry is inside of the shape. If
- // this is not the case (i have already seen some wrong Metafiles) it should
- // be embedded to a MaskPrimitive2D
- basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
- aRetval.transform(getTransform());
-
- return aRetval;
- }
-
- // provide unique ID
- ImplPrimitrive2DIDBlock(MetafilePrimitive2D, PRIMITIVE2D_ID_METAFILEPRIMITIVE2D)
-
- } // end of namespace primitive2d
-} // end of namespace drawinglayer
-
-//////////////////////////////////////////////////////////////////////////////
-// eof
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */