summaryrefslogtreecommitdiff
path: root/drawinglayer/source/processor2d
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer/source/processor2d')
-rw-r--r--drawinglayer/source/processor2d/baseprocessor2d.cxx91
-rw-r--r--drawinglayer/source/processor2d/canvasprocessor.cxx2218
-rw-r--r--drawinglayer/source/processor2d/contourextractor2d.cxx203
-rw-r--r--drawinglayer/source/processor2d/helperchartrenderer.cxx155
-rw-r--r--drawinglayer/source/processor2d/helperchartrenderer.hxx60
-rw-r--r--drawinglayer/source/processor2d/helperwrongspellrenderer.cxx96
-rw-r--r--drawinglayer/source/processor2d/helperwrongspellrenderer.hxx65
-rw-r--r--drawinglayer/source/processor2d/hittestprocessor2d.cxx605
-rw-r--r--drawinglayer/source/processor2d/linegeometryextractor2d.cxx144
-rw-r--r--drawinglayer/source/processor2d/makefile.mk58
-rw-r--r--drawinglayer/source/processor2d/textaspolygonextractor2d.cxx247
-rw-r--r--drawinglayer/source/processor2d/vclhelperbitmaprender.cxx272
-rw-r--r--drawinglayer/source/processor2d/vclhelperbitmaprender.hxx66
-rw-r--r--drawinglayer/source/processor2d/vclhelperbitmaptransform.cxx431
-rw-r--r--drawinglayer/source/processor2d/vclhelperbitmaptransform.hxx60
-rw-r--r--drawinglayer/source/processor2d/vclhelperbufferdevice.cxx182
-rw-r--r--drawinglayer/source/processor2d/vclhelperbufferdevice.hxx70
-rw-r--r--drawinglayer/source/processor2d/vclhelpergradient.cxx285
-rw-r--r--drawinglayer/source/processor2d/vclhelpergradient.hxx62
-rw-r--r--drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx2030
-rw-r--r--drawinglayer/source/processor2d/vclpixelprocessor2d.cxx613
-rw-r--r--drawinglayer/source/processor2d/vclprocessor2d.cxx1492
22 files changed, 9505 insertions, 0 deletions
diff --git a/drawinglayer/source/processor2d/baseprocessor2d.cxx b/drawinglayer/source/processor2d/baseprocessor2d.cxx
new file mode 100644
index 000000000000..ffa58ada0d03
--- /dev/null
+++ b/drawinglayer/source/processor2d/baseprocessor2d.cxx
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * 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/processor2d/baseprocessor2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ void BaseProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& /*rCandidate*/)
+ {
+ }
+
+ BaseProcessor2D::BaseProcessor2D(const geometry::ViewInformation2D& rViewInformation)
+ : maViewInformation2D(rViewInformation)
+ {
+ }
+
+ BaseProcessor2D::~BaseProcessor2D()
+ {
+ }
+
+ void BaseProcessor2D::process(const primitive2d::Primitive2DSequence& rSource)
+ {
+ if(rSource.hasElements())
+ {
+ const sal_Int32 nCount(rSource.getLength());
+
+ for(sal_Int32 a(0L); a < nCount; a++)
+ {
+ // get reference
+ const primitive2d::Primitive2DReference xReference(rSource[a]);
+
+ if(xReference.is())
+ {
+ // try to cast to BasePrimitive2D implementation
+ const primitive2d::BasePrimitive2D* pBasePrimitive = dynamic_cast< const primitive2d::BasePrimitive2D* >(xReference.get());
+
+ if(pBasePrimitive)
+ {
+ // it is a BasePrimitive2D implementation, use local processor
+ processBasePrimitive2D(*pBasePrimitive);
+ }
+ else
+ {
+ // unknown implementation, use UNO API call instead and process recursively
+ const uno::Sequence< beans::PropertyValue >& rViewParameters(getViewInformation2D().getViewInformationSequence());
+ process(xReference->getDecomposition(rViewParameters));
+ }
+ }
+ }
+ }
+ }
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/canvasprocessor.cxx b/drawinglayer/source/processor2d/canvasprocessor.cxx
new file mode 100644
index 000000000000..e20f1a417dcc
--- /dev/null
+++ b/drawinglayer/source/processor2d/canvasprocessor.cxx
@@ -0,0 +1,2218 @@
+/*************************************************************************
+ *
+ * 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/processor2d/canvasprocessor.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <com/sun/star/rendering/XCanvas.hpp>
+#include <vcl/canvastools.hxx>
+#include <basegfx/tools/canvastools.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <canvas/canvastools.hxx>
+#include <svl/ctloptions.hxx>
+#include <vcl/svapp.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+#include <com/sun/star/rendering/XBitmapCanvas.hpp>
+#include <cppcanvas/vclfactory.hxx>
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <com/sun/star/rendering/TextDirection.hpp>
+#include <vclhelperbitmaptransform.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <basegfx/tuple/b2i64tuple.hxx>
+#include <basegfx/range/b2irange.hxx>
+#include <com/sun/star/rendering/XIntegerReadOnlyBitmap.hpp>
+#include <com/sun/star/rendering/CompositeOperation.hpp>
+#include <com/sun/star/rendering/StrokeAttributes.hpp>
+#include <com/sun/star/rendering/PathJoinType.hpp>
+#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
+#include <com/sun/star/rendering/TexturingMode.hpp>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <vclhelperbufferdevice.hxx>
+#include <drawinglayer/primitive2d/chartprimitive2d.hxx>
+#include <helperchartrenderer.hxx>
+#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
+#include <helperwrongspellrenderer.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+// AW: Adding the canvas example from THB here to extract stuff later
+/*
+ // TODO(Q3): share impCreateEmptyBitmapWithPattern() and other
+ // helper methods with vclprocessor.cxx
+ Bitmap impCreateEmptyBitmapWithPattern(Bitmap aSource, const Size& aTargetSizePixel)
+ {
+ Bitmap aRetval;
+ BitmapReadAccess* pReadAccess = aSource.AcquireReadAccess();
+
+ if(pReadAccess)
+ {
+ if(aSource.GetBitCount() <= 8)
+ {
+ BitmapPalette aPalette(pReadAccess->GetPalette());
+ aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount(), &aPalette);
+ }
+ else
+ {
+ aRetval = Bitmap(aTargetSizePixel, aSource.GetBitCount());
+ }
+
+ delete pReadAccess;
+ }
+
+ return aRetval;
+ }
+
+ Bitmap impModifyBitmap(const basegfx::BColorModifier& rModifier, const Bitmap& rSource)
+ {
+ Bitmap aRetval(rSource);
+
+ switch(rModifier.getMode())
+ {
+ case basegfx::BCOLORMODIFYMODE_REPLACE :
+ {
+ aRetval = impCreateEmptyBitmapWithPattern(aRetval, Size(1L, 1L));
+ aRetval.Erase(Color(rModifier.getBColor()));
+ break;
+ }
+
+ default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE
+ {
+ BitmapWriteAccess* pContent = aRetval.AcquireWriteAccess();
+
+ if(pContent)
+ {
+ for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
+ {
+ for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
+ {
+ const Color aColor = pContent->GetPixel(y, x);
+ const basegfx::BColor aBColor(rModifier.getModifiedColor(aColor.getBColor()));
+ pContent->SetPixel(y, x, BitmapColor(Color(aBColor)));
+ }
+ }
+
+ delete pContent;
+ }
+
+ break;
+ }
+ }
+
+ return aRetval;
+ }
+
+ Bitmap impModifyBitmap(const basegfx::BColorModifierStack& rBColorModifierStack, const Bitmap& rSource)
+ {
+ Bitmap aRetval(rSource);
+
+ for(sal_uInt32 a(rBColorModifierStack.count()); a; )
+ {
+ const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a);
+ aRetval = impModifyBitmap(rModifier, aRetval);
+ }
+
+ return aRetval;
+ }
+
+ sal_uInt32 impCalcGradientSteps(sal_uInt32 nSteps, const basegfx::B2DRange& rRange, sal_uInt32 nMaxDist)
+ {
+ if(nSteps == 0L)
+ nSteps = (sal_uInt32)(rRange.getWidth() + rRange.getHeight()) / 8;
+
+ if(nSteps < 2L)
+ {
+ nSteps = 2L;
+ }
+
+ if(nSteps > nMaxDist)
+ {
+ nSteps = nMaxDist;
+ }
+
+ return nSteps;
+ }
+
+ void canvasProcessor::impDrawGradientSimple(
+ const basegfx::B2DPolyPolygon& rTargetForm,
+ const ::std::vector< basegfx::B2DHomMatrix >& rMatrices,
+ const ::std::vector< basegfx::BColor >& rColors,
+ const basegfx::B2DPolygon& rUnitPolygon)
+ {
+ uno::Reference< rendering::XPolyPolygon2D > xPoly(
+ basegfx::unotools::xPolyPolygonFromB2DPolygon(
+ mxCanvas->getDevice(),
+ rUnitPolygon));
+ uno::Reference< rendering::XPolyPolygon2D > xTargetPoly(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ rTargetForm));
+
+ for(sal_uInt32 a(0L); a < rColors.size(); a++)
+ {
+ // set correct color
+ const basegfx::BColor aFillColor(rColors[a]);
+
+ maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+ mxCanvas->getDevice(),
+ aFillColor);
+
+ if(a)
+ {
+ if(a - 1L < rMatrices.size())
+ {
+ canvas::tools::setRenderStateTransform( maRenderState,
+ rMatrices[a - 1L] );
+ mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState);
+ }
+ }
+ else
+ {
+ canvas::tools::setRenderStateTransform( maRenderState,
+ basegfx::B2DHomMatrix() );
+ mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState);
+ }
+ }
+ }
+
+ void canvasProcessor::impDrawGradientComplex(
+ const basegfx::B2DPolyPolygon& rTargetForm,
+ const ::std::vector< basegfx::B2DHomMatrix >& rMatrices,
+ const ::std::vector< basegfx::BColor >& rColors,
+ const basegfx::B2DPolygon& rUnitPolygon)
+ {
+ uno::Reference< rendering::XPolyPolygon2D > xPoly(
+ basegfx::unotools::xPolyPolygonFromB2DPolygon(
+ mxCanvas->getDevice(),
+ rUnitPolygon));
+ uno::Reference< rendering::XPolyPolygon2D > xTargetPoly(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ rTargetForm));
+
+ maRenderState.Clip = xTargetPoly;
+
+ // draw gradient PolyPolygons
+ for(std::size_t a = 0L; a < rMatrices.size(); a++)
+ {
+ // set correct color
+ if(rColors.size() > a)
+ {
+ const basegfx::BColor aFillColor(rColors[a]);
+
+ maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+ mxCanvas->getDevice(),
+ aFillColor);
+ }
+
+ canvas::tools::setRenderStateTransform( maRenderState,
+ rMatrices[a] );
+
+ if(a)
+ mxCanvas->fillPolyPolygon(xPoly,maViewState,maRenderState);
+ else
+ mxCanvas->fillPolyPolygon(xTargetPoly,maViewState,maRenderState);
+ }
+
+ maRenderState.Clip.clear();
+ }
+
+ void canvasProcessor::impDrawGradient(
+ const basegfx::B2DPolyPolygon& rTargetForm,
+ ::drawinglayer::primitive::GradientStyle eGradientStyle,
+ sal_uInt32 nSteps,
+ const basegfx::BColor& rStart,
+ const basegfx::BColor& rEnd,
+ double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple)
+ {
+ fprintf(stderr,"impDrawGradient\n");
+
+ basegfx::B2DPolyPolygon aTmp(rTargetForm);
+ aTmp.transform( maWorldToView );
+ const basegfx::B2DRange aOutlineRangePixel(basegfx::tools::getRange(aTmp));
+ const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(rTargetForm));
+
+ fprintf(stderr,"impDrawGradient: #%d\n",nSteps);
+
+ if( // step count is infinite, can use native canvas
+ // gradients here
+ nSteps == 0 ||
+ // step count is sufficiently high, such that no
+ // discernible difference should be visible.
+ nSteps > 64 )
+ {
+ uno::Reference< rendering::XParametricPolyPolygon2DFactory > xFactory(
+ mxCanvas->getDevice()->getParametricPolyPolygonFactory() );
+
+ if( xFactory.is() )
+ {
+ fprintf(stderr,"native gradient #1\n");
+
+ basegfx::B2DHomMatrix aTextureTransformation;
+ rendering::Texture aTexture;
+
+ aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
+ aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
+ aTexture.Alpha = 1.0;
+
+
+ // setup start/end color values
+ // ----------------------------
+
+ const uno::Sequence< double > aStartColor(
+ basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(),
+ rStart ));
+ const uno::Sequence< double > aEndColor(
+ basegfx::unotools::colorToDoubleSequence( mxCanvas->getDevice(),
+ rEnd ));
+
+ // Setup texture transformation
+ // ----------------------------
+
+ const basegfx::B2DRange& rBounds(
+ basegfx::tools::getRange( rTargetForm ));
+
+ // setup rotation angle. VCL rotates
+ // counter-clockwise, while canvas transformation
+ // rotates clockwise
+ //fAngle = -fAngle;
+
+ switch(eGradientStyle)
+ {
+ case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
+ // FALLTHROUGH intended
+ case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
+ {
+ // standard orientation for VCL linear
+ // gradient is vertical, thus, rotate 90
+ // degrees
+ fAngle += M_PI/2.0;
+
+ // shrink texture, to account for border
+ // (only in x direction, linear gradient
+ // is constant in y direction, anyway)
+ aTextureTransformation.scale(
+ basegfx::pruneScaleValue(1.0 - fBorder),
+ 1.0 );
+
+ double fBorderX(0.0);
+
+ // determine type of gradient (and necessary
+ // transformation matrix, should it be emulated by a
+ // generic gradient)
+ switch(eGradientStyle)
+ {
+ case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
+ // linear gradients don't respect
+ // offsets (they are implicitely
+ // assumed to be 50%). linear
+ // gradients don't have border on
+ // both sides, only on the
+ // startColor side. Gradient is
+ // invariant in y direction: leave
+ // y offset alone.
+ fBorderX = fBorder;
+ aTexture.Gradient = xFactory->createLinearHorizontalGradient( aStartColor,
+ aEndColor );
+ break;
+
+ case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
+ // axial gradients have border on
+ // both sides. Gradient is
+ // invariant in y direction: leave
+ // y offset alone.
+ fBorderX = fBorder * .5;
+ aTexture.Gradient = xFactory->createAxialHorizontalGradient( aStartColor,
+ aEndColor );
+ break;
+ }
+
+ // apply border offset values
+ aTextureTransformation.translate( fBorderX,
+ 0.0 );
+
+ // rotate texture according to gradient rotation
+ aTextureTransformation.translate( -0.5, -0.5 );
+ aTextureTransformation.rotate( fAngle );
+
+ // to let the first strip of a rotated
+ // gradient start at the _edge_ of the
+ // bound rect (and not, due to rotation,
+ // slightly inside), slightly enlarge the
+ // gradient:
+ //
+ // y/2 sin(transparence) + x/2 cos(transparence)
+ //
+ // (values to change are not actual
+ // gradient scales, but original bound
+ // rect dimensions. Since we still want
+ // the border setting to apply after that,
+ // we multiply with that as above for
+ // nScaleX)
+ const double nScale(
+ basegfx::pruneScaleValue(
+ fabs( rBounds.getHeight()*sin(fAngle) ) +
+ fabs( rBounds.getWidth()*cos(fAngle) )));
+
+ aTextureTransformation.scale( nScale, nScale );
+
+ // translate back origin to center of
+ // primitive
+ aTextureTransformation.translate( 0.5*rBounds.getWidth(),
+ 0.5*rBounds.getHeight() );
+ break;
+ }
+
+ case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL:
+ // FALLTHROUGH intended
+ case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL:
+ // FALLTHROUGH intended
+ case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE:
+ // FALLTHROUGH intended
+ case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
+ {
+ fprintf(stderr,"native gradient #2\n");
+
+ // determine scale factors for the gradient (must
+ // be scaled up from [0,1]x[0,1] rect to object
+ // bounds). Will potentially changed in switch
+ // statement below.
+ // Respect border value, while doing so, the VCL
+ // gradient's border will effectively shrink the
+ // resulting gradient.
+ double nScaleX( rBounds.getWidth() * (1.0 - fBorder) );
+ double nScaleY( rBounds.getHeight()* (1.0 - fBorder) );
+
+ // determine offset values. Since the
+ // border is divided half-by-half to both
+ // sides of the gradient, divide
+ // translation offset by an additional
+ // factor of 2. Also respect offset here,
+ // but since VCL gradients have their
+ // center at [0,0] for zero offset, but
+ // canvas gradients have their top, left
+ // edge aligned with the primitive, and
+ // offset of 50% effectively must yield
+ // zero shift. Both values will
+ // potentially be adapted in switch
+ // statement below.
+ double nOffsetX( rBounds.getWidth() *
+ (2.0 * fOffsetX - 1.0 + fBorder)*.5 );
+ double nOffsetY( rBounds.getHeight() *
+ (2.0 * fOffsetY - 1.0 + fBorder)*.5 );
+
+ // determine type of gradient (and necessary
+ // transformation matrix, should it be emulated by a
+ // generic gradient)
+ switch(eGradientStyle)
+ {
+ case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL:
+ {
+ // create isotrophic scaling
+ if( nScaleX > nScaleY )
+ {
+ nOffsetY -= (nScaleX - nScaleY) * 0.5;
+ nScaleY = nScaleX;
+ }
+ else
+ {
+ nOffsetX -= (nScaleY - nScaleX) * 0.5;
+ nScaleX = nScaleY;
+ }
+
+ // enlarge gradient to match bound rect diagonal
+ aTextureTransformation.translate( -0.5, -0.5 );
+ const double nScale( hypot(rBounds.getWidth(),
+ rBounds.getHeight()) / nScaleX );
+ aTextureTransformation.scale( nScale, nScale );
+ aTextureTransformation.translate( 0.5, 0.5 );
+
+ aTexture.Gradient = xFactory->createEllipticalGradient(
+ aEndColor,
+ aStartColor,
+ cssgeom::RealRectangle2D(0.0,0.0,
+ 1.0,1.0) );
+ }
+ break;
+
+ case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL:
+ {
+ // enlarge gradient slightly
+ aTextureTransformation.translate( -0.5, -0.5 );
+ const double nSqrt2( sqrt(2.0) );
+ aTextureTransformation.scale( nSqrt2,nSqrt2 );
+ aTextureTransformation.translate( 0.5, 0.5 );
+
+ aTexture.Gradient = xFactory->createEllipticalGradient(
+ aEndColor,
+ aStartColor,
+ cssgeom::RealRectangle2D( rBounds.getMinX(),
+ rBounds.getMinY(),
+ rBounds.getMaxX(),
+ rBounds.getMaxY() ));
+ }
+ break;
+
+ case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE:
+ {
+ // create isotrophic scaling
+ if( nScaleX > nScaleY )
+ {
+ nOffsetY -= (nScaleX - nScaleY) * 0.5;
+ nScaleY = nScaleX;
+ }
+ else
+ {
+ nOffsetX -= (nScaleY - nScaleX) * 0.5;
+ nScaleX = nScaleY;
+ }
+
+ aTexture.Gradient = xFactory->createRectangularGradient(
+ aEndColor,
+ aStartColor,
+ cssgeom::RealRectangle2D(0.0,0.0,
+ 1.0,1.0));
+ }
+ break;
+
+ case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
+ {
+ aTexture.Gradient = xFactory->createRectangularGradient(
+ aEndColor,
+ aStartColor,
+ cssgeom::RealRectangle2D( rBounds.getMinX(),
+ rBounds.getMinY(),
+ rBounds.getMaxX(),
+ rBounds.getMaxY() ));
+ }
+ break;
+ }
+
+ nScaleX = basegfx::pruneScaleValue( nScaleX );
+ nScaleY = basegfx::pruneScaleValue( nScaleY );
+
+ aTextureTransformation.scale( nScaleX, nScaleY );
+
+ // rotate texture according to gradient rotation
+ aTextureTransformation.translate( -0.5*nScaleX, -0.5*nScaleY );
+ aTextureTransformation.rotate( fAngle );
+ aTextureTransformation.translate( 0.5*nScaleX, 0.5*nScaleY );
+
+ aTextureTransformation.translate( nOffsetX, nOffsetY );
+ }
+ break;
+
+ default:
+ OSL_ENSURE( false,
+ "canvasProcessor::impDrawGradient(): Unexpected gradient type" );
+ break;
+ }
+
+ // As the texture coordinate space is relative to
+ // the polygon coordinate space (NOT to the
+ // polygon itself), move gradient to the start of
+ // the actual polygon. If we skip this, the
+ // gradient will always display at the origin, and
+ // not within the polygon bound (which might be
+ // miles away from the origin).
+ aTextureTransformation.translate( rBounds.getMinX(),
+ rBounds.getMinY() );
+
+ basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
+ aTextureTransformation );
+ uno::Sequence< rendering::Texture > aSeq(1);
+ aSeq[0] = aTexture;
+
+ mxCanvas->fillTexturedPolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ rTargetForm),
+ maViewState,
+ maRenderState,
+ aSeq );
+
+ // done, using native gradients
+ return;
+ }
+ }
+ else
+ {
+ // make sure steps is not too high/low
+ nSteps = impCalcGradientSteps(nSteps,
+ aOutlineRangePixel,
+ sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5));
+
+
+ ::std::vector< basegfx::B2DHomMatrix > aMatrices;
+ ::std::vector< basegfx::BColor > aColors;
+ basegfx::B2DPolygon aUnitPolygon;
+
+ if( drawinglayer::primitive::GRADIENTSTYLE_RADIAL == eGradientStyle ||
+ drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL == eGradientStyle)
+ {
+ const basegfx::B2DPoint aCircleCenter(0.5, 0.5);
+ aUnitPolygon = basegfx::tools::createPolygonFromEllipse(aCircleCenter, 0.5, 0.5);
+ aUnitPolygon = basegfx::tools::adaptiveSubdivideByAngle(aUnitPolygon);
+ }
+ else
+ {
+ aUnitPolygon = basegfx::tools::createUnitPolygon();
+ }
+
+ // create geometries
+ switch(eGradientStyle)
+ {
+ case ::drawinglayer::primitive::GRADIENTSTYLE_LINEAR:
+ {
+ ::drawinglayer::primitive::geoTexSvxGradientLinear aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case ::drawinglayer::primitive::GRADIENTSTYLE_AXIAL:
+ {
+ ::drawinglayer::primitive::geoTexSvxGradientAxial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case ::drawinglayer::primitive::GRADIENTSTYLE_RADIAL:
+ {
+ ::drawinglayer::primitive::geoTexSvxGradientRadial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetY);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case ::drawinglayer::primitive::GRADIENTSTYLE_ELLIPTICAL:
+ {
+ ::drawinglayer::primitive::geoTexSvxGradientElliptical aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case ::drawinglayer::primitive::GRADIENTSTYLE_SQUARE:
+ {
+ ::drawinglayer::primitive::geoTexSvxGradientSquare aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case ::drawinglayer::primitive::GRADIENTSTYLE_RECT:
+ {
+ ::drawinglayer::primitive::geoTexSvxGradientRect aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ }
+
+ // paint them with mask using the XOR method
+ if(aMatrices.size())
+ {
+ if(bSimple)
+ {
+ impDrawGradientSimple(rTargetForm, aMatrices, aColors, aUnitPolygon);
+ }
+ else
+ {
+ impDrawGradientComplex(rTargetForm, aMatrices, aColors, aUnitPolygon);
+ }
+ }
+ }
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////
+ // rendering support
+
+ // directdraw of text simple portion
+ void canvasProcessor::impRender_STXP(const textSimplePortionPrimitive& rTextCandidate)
+ {
+ const fontAttributes& rFontAttrs( rTextCandidate.getFontAttribute() );
+ rendering::FontRequest aFontRequest;
+
+ aFontRequest.FontDescription.FamilyName = rFontAttrs.maFamilyName;
+ aFontRequest.FontDescription.StyleName = rFontAttrs.maStyleName;
+ aFontRequest.FontDescription.IsSymbolFont = rFontAttrs.mbSymbol ? util::TriState_YES : util::TriState_NO;
+ aFontRequest.FontDescription.IsVertical = rFontAttrs.mbVertical ? util::TriState_YES : util::TriState_NO;
+
+ // TODO(F2): improve vclenum->panose conversion
+ aFontRequest.FontDescription.FontDescription.Weight =
+ rFontAttrs.mnWeight;
+ aFontRequest.FontDescription.FontDescription.Letterform =
+ rFontAttrs.mbItalic ? 9 : 0;
+
+ // font matrix should only be used for glyph rotations etc.
+ css::geometry::Matrix2D aFontMatrix;
+ canvas::tools::setIdentityMatrix2D( aFontMatrix );
+
+ uno::Reference<rendering::XCanvasFont> xFont(
+ mxCanvas->createFont( aFontRequest,
+ uno::Sequence< beans::PropertyValue >(),
+ aFontMatrix ));
+
+ if( !xFont.is() )
+ return;
+
+ uno::Reference<rendering::XTextLayout> xLayout(
+ xFont->createTextLayout(
+ rendering::StringContext( rTextCandidate.getText(),
+ 0,
+ rTextCandidate.getText().Len() ),
+ // TODO(F3): Is this sufficient?
+ rendering::TextDirection::WEAK_LEFT_TO_RIGHT,
+ 0 ));
+ if( !xLayout.is() )
+ return;
+
+ xLayout->applyLogicalAdvancements(
+ uno::Sequence<double>(&rTextCandidate.getDXArray()[0],
+ rTextCandidate.getDXArray().size() ));
+
+ const basegfx::BColor aRGBColor(
+ maBColorModifierStack.getModifiedColor(
+ rTextCandidate.getFontColor()));
+
+ maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+ mxCanvas->getDevice(),
+ aRGBColor);
+
+ // get render parameters and paint
+ mxCanvas->drawTextLayout( xLayout,
+ maViewState,
+ maRenderState );
+ }
+
+ // direct draw of hairline
+ void canvasProcessor::impRender_POHL(const polygonHairlinePrimitive& rPolygonCandidate)
+ {
+ const basegfx::BColor aRGBColor(
+ maBColorModifierStack.getModifiedColor(
+ rPolygonCandidate.getBColor()));
+
+ maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+ mxCanvas->getDevice(),
+ aRGBColor);
+
+ mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolygon(
+ mxCanvas->getDevice(),
+ rPolygonCandidate.getB2DPolygon()),
+ maViewState,
+ maRenderState );
+ }
+
+ // direct draw of transformed BitmapEx primitive
+ void canvasProcessor::impRender_BMPR(const bitmapPrimitive& rBitmapCandidate)
+ {
+ BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx());
+
+ if(maBColorModifierStack.count())
+ {
+ // TODO(Q3): Share common bmp modification code with
+ // vclprocessor.cxx
+ Bitmap aChangedBitmap(impModifyBitmap(maBColorModifierStack, aBitmapEx.GetBitmap()));
+
+ if(aBitmapEx.IsTransparent())
+ {
+ if(aBitmapEx.IsAlpha())
+ aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetAlpha());
+ else
+ aBitmapEx = BitmapEx(aChangedBitmap, aBitmapEx.GetMask());
+ }
+ else
+ aBitmapEx = BitmapEx(aChangedBitmap);
+ }
+
+ mxCanvas->drawBitmap(
+ vcl::unotools::xBitmapFromBitmapEx( mxCanvas->getDevice(),
+ aBitmapEx ),
+ maViewState,
+ maRenderState);
+ }
+
+ void canvasProcessor::impRender_PPLB(const polyPolygonBitmapPrimitive& rPolyBitmapCandidate )
+ {
+ const fillBitmapAttribute& rFillBmpAttr( rPolyBitmapCandidate.getFillBitmap() );
+ const basegfx::B2DPolyPolygon& rPoly( rPolyBitmapCandidate.getB2DPolyPolygon() );
+
+ // TODO(Q3): Share common bmp modification code with
+ // vclprocessor.cxx
+ Bitmap aChangedBitmap(
+ impModifyBitmap(maBColorModifierStack,
+ rFillBmpAttr.getBitmap()));
+
+ rendering::Texture aTexture;
+ const basegfx::B2DVector aBmpSize( rFillBmpAttr.getSize() );
+
+ const basegfx::B2DRange& rBounds(
+ basegfx::tools::getRange( rPoly ));
+
+ basegfx::B2DHomMatrix aScale;
+ aScale.scale( aBmpSize.getX() * rBounds.getWidth(),
+ aBmpSize.getY() * rBounds.getHeight() );
+
+ basegfx::unotools::affineMatrixFromHomMatrix(
+ aTexture.AffineTransform,
+ aScale );
+
+ aTexture.Alpha = 1.0;
+ aTexture.Bitmap =
+ ::vcl::unotools::xBitmapFromBitmapEx(
+ mxCanvas->getDevice(),
+ aChangedBitmap );
+ aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
+ aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
+
+ uno::Sequence< rendering::Texture > aSeq(1);
+ aSeq[0] = aTexture;
+
+ mxCanvas->fillTexturedPolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ rPoly),
+ maViewState,
+ maRenderState,
+ aSeq );
+ }
+
+ // direct draw of gradient
+ void canvasProcessor::impRender_PPLG(const polyPolygonGradientPrimitive& rPolygonCandidate)
+ {
+ const fillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
+ basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
+ basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+
+ if(aStartColor == aEndColor)
+ {
+ // no gradient at all, draw as polygon
+
+ maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+ mxCanvas->getDevice(),
+ aStartColor);
+
+ mxCanvas->drawPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ aLocalPolyPolygon),
+ maViewState,
+ maRenderState );
+ }
+ else
+ {
+ // TODO(F3): if rGradient.getSteps() > 0, render
+ // gradient manually!
+ impDrawGradient(
+ aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(),
+ aStartColor, aEndColor, rGradient.getBorder(),
+ -rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false);
+ }
+ }
+
+ // direct draw of PolyPolygon with color
+ void canvasProcessor::impRender_PPLC(const polyPolygonColorPrimitive& rPolygonCandidate)
+ {
+ const basegfx::BColor aRGBColor(
+ maBColorModifierStack.getModifiedColor(
+ rPolygonCandidate.getBColor()));
+
+ maRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+ mxCanvas->getDevice(),
+ aRGBColor);
+
+ mxCanvas->fillPolyPolygon( basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ rPolygonCandidate.getB2DPolyPolygon()),
+ maViewState,
+ maRenderState );
+ }
+
+ // direct draw of MetaFile
+ void canvasProcessor::impRender_META(const metafilePrimitive& rMetaCandidate)
+ {
+ // get metafile (copy it)
+ GDIMetaFile aMetaFile;
+
+ // TODO(Q3): Share common metafile modification code with
+ // vclprocessor.cxx
+ if(maBColorModifierStack.count())
+ {
+ const basegfx::BColor aRGBBaseColor(0, 0, 0);
+ const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
+ aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
+ }
+ else
+ {
+ aMetaFile = rMetaCandidate.getMetaFile();
+ }
+
+ cppcanvas::BitmapCanvasSharedPtr pCanvas(
+ cppcanvas::VCLFactory::getInstance().createCanvas(
+ uno::Reference<rendering::XBitmapCanvas>(
+ mxCanvas,
+ uno::UNO_QUERY_THROW) ));
+ cppcanvas::RendererSharedPtr pMtfRenderer(
+ cppcanvas::VCLFactory::getInstance().createRenderer(
+ pCanvas,
+ aMetaFile,
+ cppcanvas::Renderer::Parameters() ));
+ if( pMtfRenderer )
+ {
+ pCanvas->setTransformation(maWorldToView);
+ pMtfRenderer->setTransformation(rMetaCandidate.getTransform());
+ pMtfRenderer->draw();
+ }
+ }
+
+ // mask group. Set mask polygon as clip
+ void canvasProcessor::impRender_MASK(const maskPrimitive& rMaskCandidate)
+ {
+ const primitiveVector& rSubList = rMaskCandidate.getPrimitiveVector();
+
+ if(!rSubList.empty())
+ {
+ // TODO(F3): cannot use state-global renderstate, when recursing!
+ maRenderState.Clip =
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ rMaskCandidate.getMask());
+
+ // paint to it
+ process(rSubList);
+
+ maRenderState.Clip.clear();
+ }
+ }
+
+ // modified color group. Force output to unified color.
+ void canvasProcessor::impRender_MCOL(const modifiedColorPrimitive& rModifiedCandidate)
+ {
+ const primitiveVector& rSubList = rModifiedCandidate.getPrimitiveVector();
+
+ if(!rSubList.empty())
+ {
+ maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
+ process(rModifiedCandidate.getPrimitiveVector());
+ maBColorModifierStack.pop();
+ }
+ }
+
+ // sub-transparence group. Draw to bitmap device first.
+ void canvasProcessor::impRender_TRPR(const transparencePrimitive& rTransCandidate)
+ {
+ const primitiveVector& rSubList = rTransCandidate.getPrimitiveVector();
+
+ if(!rSubList.empty())
+ {
+ basegfx::B2DRange aRange(
+ get2DRangeFromVector(rSubList,
+ getViewInformation()));
+ aRange.transform(maWorldToView);
+ const basegfx::B2I64Tuple& rSize(
+ canvas::tools::spritePixelAreaFromB2DRange(aRange).getRange());
+ uno::Reference< rendering::XCanvas > xBitmap(
+ mxCanvas->getDevice()->createCompatibleAlphaBitmap(
+ css::geometry::IntegerSize2D(rSize.getX(),
+ rSize.getY())),
+ uno::UNO_QUERY_THROW);
+
+ // remember last worldToView and add pixel offset
+ basegfx::B2DHomMatrix aLastWorldToView(maWorldToView);
+ basegfx::B2DHomMatrix aPixelOffset;
+ aPixelOffset.translate(aRange.getMinX(),
+ aRange.getMinY());
+ setWorldToView(aPixelOffset * maWorldToView);
+
+ // remember last canvas, set bitmap as target
+ uno::Reference< rendering::XCanvas > xLastCanvas( mxCanvas );
+ mxCanvas = xBitmap;
+
+ // paint content to it
+ process(rSubList);
+
+ // TODO(F3): render transparent list to transparence
+ // channel. Note that the OutDev implementation has a
+ // shortcoming, in that nested transparency groups
+ // don't work - transparence is not combined properly.
+
+ // process(rTransCandidate.getTransparenceList());
+
+ // back to old OutDev and worldToView
+ mxCanvas = xLastCanvas;
+ setWorldToView(aLastWorldToView);
+
+ // DUMMY: add transparence modulation value to DeviceColor
+ // TODO(F3): color management
+ canvas::tools::setDeviceColor( maRenderState,
+ 1.0, 1.0, 1.0, 0.5 );
+ // finally, draw bitmap
+ mxCanvas->drawBitmapModulated(
+ uno::Reference< rendering::XBitmap >(
+ xBitmap,
+ uno::UNO_QUERY_THROW),
+ maViewState,
+ maRenderState );
+ }
+ }
+
+ // transform group.
+ void canvasProcessor::impRender_TRN2(const transformPrimitive& rTransformCandidate)
+ {
+ // remember current transformation
+ basegfx::B2DHomMatrix aLastWorldToView(maWorldToView);
+
+ // create new transformations
+ setWorldToView(maWorldToView * rTransformCandidate.getTransformation());
+
+ // let break down
+ process(rTransformCandidate.getPrimitiveVector());
+
+ // restore transformations
+ setWorldToView(aLastWorldToView);
+ }
+
+ // marker
+ void canvasProcessor::impRender_MARK(const markerPrimitive& rMarkCandidate)
+ {
+ const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rMarkCandidate.getRGBColor()));
+
+ canvas::tools::initRenderState(maMarkerRenderState);
+ maMarkerRenderState.DeviceColor = basegfx::unotools::colorToDoubleSequence(
+ mxCanvas->getDevice(),
+ aRGBColor);
+
+ // Markers are special objects - their position is
+ // determined by the view transformation, but their size
+ // is always the same
+ const basegfx::B2DPoint aViewPos(maWorldToView * rMarkCandidate.getPosition());
+
+ uno::Reference< rendering::XPolyPolygon2D > xMarkerPoly;
+ uno::Reference< rendering::XPolyPolygon2D > xHighlightMarkerPoly;
+ switch(rMarkCandidate.getStyle())
+ {
+ default:
+ case MARKERSTYLE_POINT:
+ mxCanvas->drawPoint( basegfx::unotools::point2DFromB2DPoint(aViewPos),
+ maMarkerViewState,
+ maMarkerRenderState );
+ return;
+
+ case MARKERSTYLE_CROSS:
+ if( !mxCrossMarkerPoly.is() )
+ {
+ basegfx::B2DPolyPolygon aPoly;
+ basegfx::tools::importFromSvgD(
+ aPoly,
+ rtl::OUString::createFromAscii(
+ "m-1 0 h2 m0 -1 v2" ));
+ mxCrossMarkerPoly =
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ aPoly );
+ }
+ xMarkerPoly = mxCrossMarkerPoly;
+ break;
+
+ case MARKERSTYLE_GLUEPOINT :
+ if( !mxGluePointPoly.is() )
+ {
+ basegfx::B2DPolyPolygon aPoly;
+ basegfx::tools::importFromSvgD(
+ aPoly,
+ rtl::OUString::createFromAscii(
+ "m-2 -3 l5 5 m-3 -2 l5 5 m-3 2 l5 -5 m-2 3 l5 -5" ));
+ mxGluePointPoly =
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ aPoly );
+ }
+ if( !mxGluePointHighlightPoly.is() )
+ {
+ basegfx::B2DPolyPolygon aPoly;
+ basegfx::tools::importFromSvgD(
+ aPoly,
+ rtl::OUString::createFromAscii(
+ "m-2 -2 l4 4 m-2 2 l4 -4" ));
+ mxGluePointHighlightPoly =
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(),
+ aPoly );
+ }
+ xMarkerPoly = mxGluePointPoly;
+ xHighlightMarkerPoly = mxGluePointHighlightPoly;
+ break;
+ }
+
+ basegfx::B2DRange aRange;
+ rMarkCandidate.getRealtiveViewRange(aRange);
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
+
+ basegfx::B2DHomMatrix aTranslate;
+ aTranslate.translate(aViewPos.getX()+aCenter.getX(),
+ aViewPos.getY()+aCenter.getY());
+
+ canvas::tools::setRenderStateTransform( maMarkerRenderState,
+ aTranslate );
+
+
+ mxCanvas->drawPolyPolygon( xMarkerPoly,
+ maMarkerViewState,
+ maMarkerRenderState );
+ if( xHighlightMarkerPoly.is() )
+ {
+ // TODO(F3): color management
+ canvas::tools::setDeviceColor(maMarkerRenderState,
+ 0.0, 0.0, 1.0, 1.0);
+ mxCanvas->drawPolyPolygon( xMarkerPoly,
+ maMarkerViewState,
+ maMarkerRenderState );
+ }
+ }
+
+ void canvasProcessor::setWorldToView(const basegfx::B2DHomMatrix& rMat)
+ {
+ maWorldToView = rMat;
+ canvas::tools::setViewStateTransform(maViewState,
+ maWorldToView);
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // internal processing support
+
+ void canvasProcessor::process(const primitiveVector& rSource)
+ {
+ primitiveVector::const_iterator aCurr = rSource.begin();
+ const primitiveVector::const_iterator aEnd = rSource.end();
+ while( aCurr != aEnd )
+ {
+ const referencedPrimitive& rCandidate = *aCurr;
+
+ switch(rCandidate.getID())
+ {
+ case CreatePrimitiveID('S', 'T', 'X', 'P'):
+ {
+ // directdraw of text simple portion
+ impRender_STXP(static_cast< const textSimplePortionPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('P', 'O', 'H', 'L'):
+ {
+ // direct draw of hairline
+ impRender_POHL(static_cast< const polygonHairlinePrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('B', 'M', 'P', 'R'):
+ {
+ // direct draw of transformed BitmapEx primitive
+ impRender_BMPR(static_cast< const bitmapPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('F', 'B', 'M', 'P'):
+ {
+ OSL_ENSURE(false,"fillBitmapPrimitive not yet implemented");
+ break;
+ }
+
+ case CreatePrimitiveID('P', 'P', 'L', 'B'):
+ {
+ // direct draw of polygon with bitmap fill
+ impRender_PPLB(static_cast< const polyPolygonBitmapPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('P', 'P', 'L', 'G'):
+ {
+ // direct draw of gradient
+ impRender_PPLG(static_cast< const polyPolygonGradientPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('P', 'P', 'L', 'C'):
+ {
+ // direct draw of PolyPolygon with color
+ impRender_PPLC(static_cast< const polyPolygonColorPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('M', 'E', 'T', 'A'):
+ {
+ // direct draw of MetaFile
+ impRender_META(static_cast< const metafilePrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('M', 'A', 'S', 'K'):
+ {
+ // mask group. Force output to VDev and create mask from given mask
+ impRender_MASK(static_cast< const maskPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('M', 'C', 'O', 'L'):
+ {
+ // modified color group. Force output to unified color.
+ impRender_MCOL(static_cast< const modifiedColorPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('T', 'R', 'P', 'R'):
+ {
+ // sub-transparence group. Draw to VDev first.
+ impRender_TRPR(static_cast< const transparencePrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('T', 'R', 'N', '2'):
+ {
+ // transform group.
+ impRender_TRN2(static_cast< const transformPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('M', 'A', 'R', 'K'):
+ {
+ // marker
+ impRender_MARK(static_cast< const markerPrimitive& >(rCandidate.getBasePrimitive()));
+ break;
+ }
+
+ case CreatePrimitiveID('A', 'N', 'S', 'W'):
+ case CreatePrimitiveID('A', 'N', 'B', 'L'):
+ case CreatePrimitiveID('A', 'N', 'I', 'N'):
+ {
+ // check timing, but do not accept
+ const animatedSwitchPrimitive& rAnimatedCandidate(static_cast< const animatedSwitchPrimitive& >(rCandidate.getBasePrimitive()));
+ const ::drawinglayer::animation::animationEntryList& rAnimationList = rAnimatedCandidate.getAnimationList();
+ const double fNewTime(rAnimationList.getNextEventTime(getViewInformation().getViewTime()));
+
+ // let break down
+ process(rAnimatedCandidate.getDecomposition(getViewInformation()));
+
+ break;
+ }
+
+ default:
+ {
+ // let break down
+ process(rCandidate.getBasePrimitive().getDecomposition(getViewInformation()));
+ }
+ }
+
+ ++aCurr;
+ }
+ }
+
+ canvasProcessor::canvasProcessor( const ::drawinglayer::geometry::viewInformation& rViewInformation,
+ const uno::Reference<rendering::XCanvas>& rCanvas ) :
+ processor(rViewInformation),
+ mxCanvas( rCanvas ),
+ mxCrossMarkerPoly(),
+ mxGluePointPoly(),
+ mxGluePointHighlightPoly(),
+ maBColorModifierStack(),
+ maWorldToView(),
+ maViewState(),
+ maRenderState(),
+ maMarkerViewState(),
+ maMarkerRenderState()
+ {
+ canvas::tools::initViewState(maViewState);
+ canvas::tools::initRenderState(maRenderState);
+ canvas::tools::initViewState(maMarkerViewState);
+ canvas::tools::initRenderState(maMarkerRenderState);
+
+ maWorldToView = maViewInformation.getViewTransformation();
+
+ canvas::tools::setViewStateTransform(maViewState,
+ maWorldToView);
+ }
+
+ canvasProcessor::~canvasProcessor()
+ {}
+*/
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ //////////////////////////////////////////////////////////////////////////////
+ // single primitive renderers
+
+ void canvasProcessor2D::impRenderMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate)
+ {
+ const primitive2d::Primitive2DSequence& rChildren = rMaskCandidate.getChildren();
+ static bool bUseMaskBitmapMethod(true);
+
+ if(rChildren.hasElements())
+ {
+ basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
+
+ if(!aMask.count())
+ {
+ // no mask, no clipping. recursively paint content
+ process(rChildren);
+ }
+ else
+ {
+ // there are principally two methods for implementing the mask primitive. One
+ // is to set a clip polygon at the canvas, the other is to create and use a
+ // transparence-using XBitmap for content and draw the mask as transparence. Both have their
+ // advantages and disadvantages, so here are both with a bool allowing simple
+ // change
+ if(bUseMaskBitmapMethod)
+ {
+ // get logic range of transparent part, clip with ViewRange
+ basegfx::B2DRange aLogicRange(aMask.getB2DRange());
+
+ if(!getViewInformation2D().getViewport().isEmpty())
+ {
+ aLogicRange.intersect(getViewInformation2D().getViewport());
+ }
+
+ if(!aLogicRange.isEmpty())
+ {
+ // get discrete range of transparent part
+ basegfx::B2DRange aDiscreteRange(aLogicRange);
+ aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
+
+ // expand to next covering discrete values (pixel bounds)
+ aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY())));
+ aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY())));
+
+ // use VCL-based buffer device
+ impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false);
+
+ if(aBufferDevice.isVisible())
+ {
+ // remember current OutDev, Canvas and ViewInformation
+ OutputDevice* pLastOutputDevice = mpOutputDevice;
+ uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas);
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // prepare discrete offset for XBitmap, do not forget that the buffer bitmap
+ // may be truncated to discrete visible pixels
+ const basegfx::B2DHomMatrix aDiscreteOffset(basegfx::tools::createTranslateB2DHomMatrix(
+ aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0,
+ aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0));
+
+ // create new local ViewInformation2D with new transformation
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation(),
+ aDiscreteOffset * getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // set OutDev and Canvas to content target
+ mpOutputDevice = &aBufferDevice.getContent();
+ mxCanvas = mpOutputDevice->GetCanvas();
+ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+
+ // if ViewState transform is changed, the clipping polygon needs to be adapted, too
+ const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon);
+
+ if(maClipPolyPolygon.count())
+ {
+ maClipPolyPolygon.transform(aDiscreteOffset);
+ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+ }
+
+ // paint content
+ process(rChildren);
+
+ // draw mask
+ const basegfx::BColor aBlack(0.0, 0.0, 0.0);
+ maRenderState.DeviceColor = aBlack.colorToDoubleSequence(mxCanvas->getDevice());
+
+ if(getOptionsDrawinglayer().IsAntiAliasing())
+ {
+ // with AA, use 8bit AlphaMask to get nice borders
+ VirtualDevice& rTransparence = aBufferDevice.getTransparence();
+ rTransparence.GetCanvas()->fillPolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask),
+ maViewState, maRenderState);
+ }
+ else
+ {
+ // No AA, use 1bit mask
+ VirtualDevice& rMask = aBufferDevice.getMask();
+ rMask.GetCanvas()->fillPolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), aMask),
+ maViewState, maRenderState);
+ }
+
+ // back to old color stack, OutDev, Canvas and ViewTransform
+ mpOutputDevice = pLastOutputDevice;
+ mxCanvas = xLastCanvas;
+ updateViewInformation(aLastViewInformation2D);
+ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+
+ // restore clipping polygon
+ maClipPolyPolygon = aOldClipPolyPolygon;
+
+ if(maClipPolyPolygon.count())
+ {
+ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+ }
+
+ // dump buffer to outdev
+ aBufferDevice.paint();
+ }
+ }
+ }
+ else
+ {
+ // transform new mask polygon to view coordinates for processing. All masks
+ // are processed in view coordinates and clipped against each other evtl. to
+ // create multi-clips
+ aMask.transform(getViewInformation2D().getObjectTransformation());
+
+ // remember last current clip polygon
+ const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
+
+ if(maClipPolyPolygon.count())
+ {
+ // there is already a clip polygon set; build clipped union of
+ // current mask polygon and new one
+ maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(aMask, maClipPolyPolygon, false, false);
+ }
+ else
+ {
+ // use mask directly
+ maClipPolyPolygon = aMask;
+ }
+
+ // set at ViewState
+ if(maClipPolyPolygon.count())
+ {
+ // set new as clip polygon
+ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+ }
+ else
+ {
+ // empty, reset
+ maViewState.Clip.clear();
+ }
+
+ // paint content
+ process(rChildren);
+
+ // restore local current to rescued clip polygon
+ maClipPolyPolygon = aLastClipPolyPolygon;
+
+ // set at ViewState
+ if(maClipPolyPolygon.count())
+ {
+ // set new as clip polygon
+ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+ }
+ else
+ {
+ // empty, reset
+ maViewState.Clip.clear();
+ }
+ }
+ }
+ }
+ }
+
+ void canvasProcessor2D::impRenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate)
+ {
+ GDIMetaFile aMetaFile;
+
+ if(maBColorModifierStack.count())
+ {
+ const basegfx::BColor aRGBBaseColor(0, 0, 0);
+ const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
+ aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
+ }
+ else
+ {
+ aMetaFile = rMetaCandidate.getMetaFile();
+ }
+
+ cppcanvas::BitmapCanvasSharedPtr pCanvas(cppcanvas::VCLFactory::getInstance().createCanvas(
+ uno::Reference<rendering::XBitmapCanvas>(mxCanvas, uno::UNO_QUERY_THROW)));
+ cppcanvas::RendererSharedPtr pMtfRenderer(cppcanvas::VCLFactory::getInstance().createRenderer(
+ pCanvas, aMetaFile, cppcanvas::Renderer::Parameters()));
+
+ if(pMtfRenderer)
+ {
+ pCanvas->setTransformation(getViewInformation2D().getObjectToViewTransformation());
+ pMtfRenderer->setTransformation(rMetaCandidate.getTransform());
+ pMtfRenderer->draw();
+ }
+ }
+
+ void canvasProcessor2D::impRenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
+ {
+ if(rTextCandidate.getTextLength())
+ {
+ double fShearX(0.0);
+ {
+ const basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectToViewTransformation() * rTextCandidate.getTextTransform());
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate;
+ aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+ }
+
+ if(!basegfx::fTools::equalZero(fShearX))
+ {
+ // text is sheared. As long as the canvas renderers do not support this,
+ // use the decomposed primitive
+ process(rTextCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ else
+ {
+ const attribute::FontAttribute& rFontAttr(rTextCandidate.getFontAttribute());
+ rendering::FontRequest aFontRequest;
+
+ aFontRequest.FontDescription.FamilyName = rFontAttr.getFamilyName();
+ aFontRequest.FontDescription.StyleName = rFontAttr.getStyleName();
+ aFontRequest.FontDescription.IsSymbolFont = rFontAttr.getSymbol() ? util::TriState_YES : util::TriState_NO;
+ aFontRequest.FontDescription.IsVertical = rFontAttr.getVertical() ? util::TriState_YES : util::TriState_NO;
+ // TODO(F2): improve vclenum->panose conversion
+ aFontRequest.FontDescription.FontDescription.Weight = static_cast< sal_uInt8 >(rFontAttr.getWeight());
+ aFontRequest.FontDescription.FontDescription.Letterform = rFontAttr.getItalic() ? 9 : 0;
+
+ // init CellSize to 1.0, else a default font height will be used
+ aFontRequest.CellSize = 1.0;
+ aFontRequest.Locale = rTextCandidate.getLocale();
+
+ // font matrix should only be used for glyph rotations etc.
+ com::sun::star::geometry::Matrix2D aFontMatrix;
+ canvas::tools::setIdentityMatrix2D(aFontMatrix);
+
+ uno::Reference<rendering::XCanvasFont> xFont(mxCanvas->createFont(
+ aFontRequest, uno::Sequence< beans::PropertyValue >(), aFontMatrix));
+
+ if(xFont.is())
+ {
+ // got a font, now try to get a TextLayout
+ const rendering::StringContext aStringContext(
+ rTextCandidate.getText(), rTextCandidate.getTextPosition(), rTextCandidate.getTextLength());
+ uno::Reference<rendering::XTextLayout> xLayout(xFont->createTextLayout(
+ aStringContext, com::sun::star::rendering::TextDirection::WEAK_LEFT_TO_RIGHT, 0));
+
+ if(xLayout.is())
+ {
+ // got a text layout, apply DXArray if given
+ const ::std::vector< double >& rDXArray = rTextCandidate.getDXArray();
+ const sal_uInt32 nDXCount(rDXArray.size());
+
+ if(nDXCount)
+ {
+ // DXArray does not need to be adapted to getTextPosition/getTextLength,
+ // it is already provided correctly
+ const uno::Sequence< double > aDXSequence(&rDXArray[0], nDXCount);
+ xLayout->applyLogicalAdvancements(aDXSequence);
+ }
+
+ // set text color
+ const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor()));
+ maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice());
+
+ // set text transformation
+ canvas::tools::setRenderStateTransform(maRenderState,
+ getViewInformation2D().getObjectTransformation() * rTextCandidate.getTextTransform());
+
+ // paint
+ mxCanvas->drawTextLayout(xLayout, maViewState, maRenderState);
+ }
+ }
+ }
+ }
+ }
+
+ void canvasProcessor2D::impRenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
+ {
+ // apply possible color modification to BitmapEx
+ BitmapEx aModifiedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rBitmapCandidate.getBitmapEx()));
+
+ if(aModifiedBitmapEx.IsEmpty())
+ {
+ // replace with color filled polygon
+ const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
+ const basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
+
+ maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice());
+ canvas::tools::setRenderStateTransform(maRenderState,
+ getViewInformation2D().getObjectTransformation() * rBitmapCandidate.getTransform());
+
+ mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState);
+ }
+ else
+ {
+ // adapt object's transformation to the correct scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ const Size aSizePixel(aModifiedBitmapEx.GetSizePixel());
+
+ if(0 != aSizePixel.Width() && 0 != aSizePixel.Height())
+ {
+ rBitmapCandidate.getTransform().decompose(aScale, aTranslate, fRotate, fShearX);
+ const basegfx::B2DHomMatrix aNewMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale.getX() / aSizePixel.Width(), aScale.getY() / aSizePixel.Height(),
+ fShearX, fRotate, aTranslate.getX(), aTranslate.getY()));
+
+ canvas::tools::setRenderStateTransform(maRenderState,
+ getViewInformation2D().getObjectTransformation() * aNewMatrix);
+
+ mxCanvas->drawBitmap(
+ vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aModifiedBitmapEx),
+ maViewState, maRenderState);
+ }
+ }
+ }
+
+ void canvasProcessor2D::impRenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransparenceCandidate)
+ {
+ const primitive2d::Primitive2DSequence& rChildren = rTransparenceCandidate.getChildren();
+ const primitive2d::Primitive2DSequence& rTransparence = rTransparenceCandidate.getTransparence();
+
+ if(rChildren.hasElements() && rTransparence.hasElements())
+ {
+ // get logic range of transparent part and clip with ViewRange
+ basegfx::B2DRange aLogicRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rChildren, getViewInformation2D()));
+
+ if(!getViewInformation2D().getViewport().isEmpty())
+ {
+ aLogicRange.intersect(getViewInformation2D().getViewport());
+ }
+
+ if(!aLogicRange.isEmpty())
+ {
+ // get discrete range of transparent part
+ basegfx::B2DRange aDiscreteRange(aLogicRange);
+ aDiscreteRange.transform(getViewInformation2D().getObjectToViewTransformation());
+
+ // expand to next covering discrete values (pixel bounds)
+ aDiscreteRange.expand(basegfx::B2DTuple(floor(aDiscreteRange.getMinX()), floor(aDiscreteRange.getMinY())));
+ aDiscreteRange.expand(basegfx::B2DTuple(ceil(aDiscreteRange.getMaxX()), ceil(aDiscreteRange.getMaxY())));
+
+ // use VCL-based buffer device
+ impBufferDevice aBufferDevice(*mpOutputDevice, aDiscreteRange, false);
+
+ if(aBufferDevice.isVisible())
+ {
+ // remember current OutDev, Canvas and ViewInformation
+ OutputDevice* pLastOutputDevice = mpOutputDevice;
+ uno::Reference< rendering::XCanvas > xLastCanvas(mxCanvas);
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // prepare discrete offset for XBitmap, do not forget that the buffer bitmap
+ // may be truncated to discrete visible pixels
+ const basegfx::B2DHomMatrix aDiscreteOffset(basegfx::tools::createTranslateB2DHomMatrix(
+ aDiscreteRange.getMinX() > 0.0 ? -aDiscreteRange.getMinX() : 0.0,
+ aDiscreteRange.getMinY() > 0.0 ? -aDiscreteRange.getMinY() : 0.0));
+
+ // create new local ViewInformation2D with new transformation
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation(),
+ aDiscreteOffset * getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // set OutDev and Canvas to content target
+ mpOutputDevice = &aBufferDevice.getContent();
+ mxCanvas = mpOutputDevice->GetCanvas();
+ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+
+ // if ViewState transform is changed, the clipping polygon needs to be adapted, too
+ const basegfx::B2DPolyPolygon aOldClipPolyPolygon(maClipPolyPolygon);
+
+ if(maClipPolyPolygon.count())
+ {
+ maClipPolyPolygon.transform(aDiscreteOffset);
+ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+ }
+
+ // paint content
+ process(rChildren);
+
+ // set to mask
+ mpOutputDevice = &aBufferDevice.getTransparence();
+ mxCanvas = mpOutputDevice->GetCanvas();
+ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+
+ // when painting transparence masks, reset the color stack
+ basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
+ maBColorModifierStack = basegfx::BColorModifierStack();
+
+ // paint mask to it (always with transparence intensities, evtl. with AA)
+ process(rTransparence);
+
+ // back to old color stack, OutDev, Canvas and ViewTransform
+ maBColorModifierStack = aLastBColorModifierStack;
+ mpOutputDevice = pLastOutputDevice;
+ mxCanvas = xLastCanvas;
+ updateViewInformation(aLastViewInformation2D);
+ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+
+ // restore clipping polygon
+ maClipPolyPolygon = aOldClipPolyPolygon;
+
+ if(maClipPolyPolygon.count())
+ {
+ maViewState.Clip = basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), maClipPolyPolygon);
+ }
+
+ // dump buffer to outdev
+ aBufferDevice.paint();
+ }
+ }
+ }
+ }
+
+ void canvasProcessor2D::impRenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive)
+ {
+ // support direct fat line geometry. This moves the decomposition to the canvas.
+ // As long as our canvases are used (which also use basegfx tooling) this makes
+ // no difference, but potentially canvases may better support this
+ static bool bSupportFatLineDirectly(true);
+ bool bOutputDone(false);
+
+ if(bSupportFatLineDirectly)
+ {
+ const attribute::LineAttribute& rLineAttribute = rPolygonStrokePrimitive.getLineAttribute();
+ const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokePrimitive.getStrokeAttribute();
+
+ if(0.0 < rLineAttribute.getWidth() || 0 != rStrokeAttribute.getDotDashArray().size())
+ {
+ rendering::StrokeAttributes aStrokeAttribute;
+
+ aStrokeAttribute.StrokeWidth = rLineAttribute.getWidth();
+ aStrokeAttribute.MiterLimit = 15.0; // degrees; maybe here (15.0 * F_PI180) is needed, not clear in the documentation
+ const ::std::vector< double >& rDotDashArray = rStrokeAttribute.getDotDashArray();
+
+ if(rDotDashArray.size())
+ {
+ aStrokeAttribute.DashArray = uno::Sequence< double >(&rDotDashArray[0], rDotDashArray.size());
+ }
+
+ switch(rLineAttribute.getLineJoin())
+ {
+ default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
+ aStrokeAttribute.JoinType = rendering::PathJoinType::NONE;
+ break;
+ case basegfx::B2DLINEJOIN_BEVEL:
+ aStrokeAttribute.JoinType = rendering::PathJoinType::BEVEL;
+ break;
+ case basegfx::B2DLINEJOIN_MITER:
+ aStrokeAttribute.JoinType = rendering::PathJoinType::MITER;
+ break;
+ case basegfx::B2DLINEJOIN_ROUND:
+ aStrokeAttribute.JoinType = rendering::PathJoinType::ROUND;
+ break;
+ }
+
+ const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
+ maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice());
+ canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
+
+ mxCanvas->strokePolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonStrokePrimitive.getB2DPolygon()),
+ maViewState, maRenderState, aStrokeAttribute);
+
+ bOutputDone = true;
+ }
+ }
+
+ if(!bOutputDone)
+ {
+ // process decomposition
+ process(rPolygonStrokePrimitive.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+
+ void canvasProcessor2D::impRenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapPrimitive2D)
+ {
+ // support tiled fills directly when tiling is on
+ static bool bSupportFillBitmapDirectly(true);
+ bool bOutputDone(false);
+
+ if(bSupportFillBitmapDirectly)
+ {
+ const attribute::FillBitmapAttribute& rFillBitmapAttribute = rFillBitmapPrimitive2D.getFillBitmap();
+
+ if(rFillBitmapAttribute.getTiling())
+ {
+ // apply possible color modification to Bitmap
+ const BitmapEx aChangedBitmapEx(impModifyBitmapEx(maBColorModifierStack, rFillBitmapAttribute.getBitmapEx()));
+
+ if(aChangedBitmapEx.IsEmpty())
+ {
+ // replace with color filled polygon
+ const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
+ const basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
+
+ maRenderState.DeviceColor = aModifiedColor.colorToDoubleSequence(mxCanvas->getDevice());
+ canvas::tools::setRenderStateTransform(maRenderState,
+ getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation());
+
+ mxCanvas->fillPolyPolygon(basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
+ mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aPolygon)), maViewState, maRenderState);
+ }
+ else
+ {
+ const Size aSizePixel(aChangedBitmapEx.GetSizePixel());
+
+ if(0 != aSizePixel.Width() && 0 != aSizePixel.Height())
+ {
+ // create texture matrix from texture to object (where object is unit square here),
+ // so use values directly
+ const basegfx::B2DHomMatrix aTextureMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
+ rFillBitmapAttribute.getSize().getX(), rFillBitmapAttribute.getSize().getY(),
+ rFillBitmapAttribute.getTopLeft().getX(), rFillBitmapAttribute.getTopLeft().getY()));
+
+ // create and fill texture
+ rendering::Texture aTexture;
+
+ basegfx::unotools::affineMatrixFromHomMatrix(aTexture.AffineTransform, aTextureMatrix);
+ aTexture.Alpha = 1.0;
+ aTexture.Bitmap = vcl::unotools::xBitmapFromBitmapEx(mxCanvas->getDevice(), aChangedBitmapEx);
+ aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
+ aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
+
+ // canvas needs a polygon to fill, create unit rectangle polygon
+ const basegfx::B2DPolygon aOutlineRectangle(basegfx::tools::createUnitPolygon());
+
+ // set primitive's transformation as render state transform
+ canvas::tools::setRenderStateTransform(maRenderState,
+ getViewInformation2D().getObjectTransformation() * rFillBitmapPrimitive2D.getTransformation());
+
+ // put texture into a uno sequence for handover
+ uno::Sequence< rendering::Texture > aSeq(1);
+ aSeq[0] = aTexture;
+
+ // draw textured rectangle
+ mxCanvas->fillTexturedPolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), basegfx::B2DPolyPolygon(aOutlineRectangle)),
+ maViewState, maRenderState, aSeq);
+ }
+ }
+
+ bOutputDone = true;
+ }
+ }
+
+ if(!bOutputDone)
+ {
+ // process decomposition
+ process(rFillBitmapPrimitive2D.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+
+ void canvasProcessor2D::impRenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate)
+ {
+ if(0.0 == rUniTransparenceCandidate.getTransparence())
+ {
+ // not transparent at all, directly use content
+ process(rUniTransparenceCandidate.getChildren());
+ }
+ else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
+ {
+ const primitive2d::Primitive2DSequence rChildren = rUniTransparenceCandidate.getChildren();
+
+ if(rChildren.hasElements())
+ {
+ bool bOutputDone(false);
+
+ // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
+ // use the fillPolyPolygon method with correctly set transparence. This is a often used
+ // case, so detectiong it is valuable
+ if(1 == rChildren.getLength())
+ {
+ const primitive2d::Primitive2DReference xReference(rChildren[0]);
+ const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
+
+ if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
+ {
+ // direct draw of PolyPolygon with color and transparence
+ const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
+
+ // add transparence modulation value to DeviceColor
+ uno::Sequence< double > aColor(4);
+
+ aColor[0] = aPolygonColor.getRed();
+ aColor[1] = aPolygonColor.getGreen();
+ aColor[2] = aPolygonColor.getBlue();
+ aColor[3] = 1.0 - rUniTransparenceCandidate.getTransparence();
+ maRenderState.DeviceColor = aColor;
+
+ canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
+ mxCanvas->fillPolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), pPoPoColor->getB2DPolyPolygon()),
+ maViewState, maRenderState);
+ bOutputDone = true;
+ }
+ }
+
+ if(!bOutputDone)
+ {
+ // process decomposition. This will be decomposed to an TransparencePrimitive2D
+ // with the same child context and a single polygon for transparent context. This could be
+ // directly handled here with known VCL-buffer technology, but would only
+ // make a small difference compared to directly rendering the TransparencePrimitive2D
+ // using impRenderTransparencePrimitive2D above.
+ process(rUniTransparenceCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // internal processing support
+
+ void canvasProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+ {
+ switch(rCandidate.getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
+ {
+ // direct draw of hairline
+ const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
+ const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
+
+ maRenderState.DeviceColor = aHairlineColor.colorToDoubleSequence(mxCanvas->getDevice());
+ canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
+ mxCanvas->drawPolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolygon()),
+ maViewState, maRenderState);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
+ {
+ // direct draw of PolyPolygon with color
+ const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate = static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate);
+ const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
+
+ maRenderState.DeviceColor = aPolygonColor.colorToDoubleSequence(mxCanvas->getDevice());
+ canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
+ mxCanvas->fillPolyPolygon(
+ basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(mxCanvas->getDevice(), rPolygonCandidate.getB2DPolyPolygon()),
+ maViewState, maRenderState);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
+ {
+ // modified color group. Force output to unified color.
+ const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate = static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate);
+
+ if(rModifiedCandidate.getChildren().hasElements())
+ {
+ maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
+ process(rModifiedCandidate.getChildren());
+ maBColorModifierStack.pop();
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ {
+ // mask group
+ impRenderMaskPrimitive2D(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
+ {
+ // transform group. Remember current ViewInformation2D
+ const primitive2d::TransformPrimitive2D& rTransformCandidate = static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate);
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // create new local ViewInformation2D with new transformation
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
+ getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // set at canvas
+ canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
+
+ // proccess content
+ process(rTransformCandidate.getChildren());
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation2D);
+
+ // restore at canvas
+ canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
+
+ break;
+ }
+ case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
+ {
+ // new XDrawPage for ViewInformation2D
+ const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate = static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate);
+
+ // remember current transformation and ViewInformation
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // create new local ViewInformation2D
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation(),
+ getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ rPagePreviewCandidate.getXDrawPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // proccess decomposed content
+ process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D()));
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation2D);
+ break;
+ }
+ case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
+ {
+ // MetaFile primitive
+ impRenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+ {
+ // PointArray primitive
+ const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate = static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate);
+
+ // set point color
+ const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor()));
+ maRenderState.DeviceColor = aRGBColor.colorToDoubleSequence(mxCanvas->getDevice());
+ canvas::tools::setRenderStateTransform(maRenderState, getViewInformation2D().getObjectTransformation());
+
+ const std::vector< basegfx::B2DPoint >& rPointVector = rPointArrayCandidate.getPositions();
+ const sal_uInt32 nPointCount(rPointVector.size());
+
+ for(sal_uInt32 a(0); a < nPointCount; a++)
+ {
+ const basegfx::B2DPoint& rPoint = rPointVector[a];
+ mxCanvas->drawPoint(basegfx::unotools::point2DFromB2DPoint(rPoint), maViewState, maRenderState);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
+ {
+ // TextSimplePortion primitive
+ impRenderTextSimplePortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
+ {
+ // Bitmap primitive
+ impRenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
+ {
+ // Transparence primitive
+ impRenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
+ {
+ // PolygonStrokePrimitive
+ impRenderPolygonStrokePrimitive2D(static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D :
+ {
+ // FillBitmapPrimitive2D
+ impRenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
+ {
+ // UnifiedTransparencePrimitive2D
+ impRenderUnifiedTransparencePrimitive2D(static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_CHARTPRIMITIVE2D :
+ {
+ // chart primitive in canvas renderer; restore original DrawMode during call
+ // since the evtl. used ChartPrettyPainter will use the MapMode
+ const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate);
+ mpOutputDevice->Push(PUSH_MAPMODE);
+ mpOutputDevice->SetMapMode(maOriginalMapMode);
+
+ if(!renderChartPrimitive2D(
+ rChartPrimitive,
+ *mpOutputDevice,
+ getViewInformation2D()))
+ {
+ // fallback to decomposition (MetaFile)
+ process(rChartPrimitive.get2DDecomposition(getViewInformation2D()));
+ }
+
+ mpOutputDevice->Pop();
+ break;
+ }
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+ {
+ // wrong spell primitive. Handled directly here using VCL since VCL has a nice and
+ // very direct waveline painting which is needed for this. If VCL is to be avoided,
+ // this can be removed anytime and the decomposition may be used
+ const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate);
+
+ if(!renderWrongSpellPrimitive2D(
+ rWrongSpellPrimitive,
+ *mpOutputDevice,
+ getViewInformation2D().getObjectToViewTransformation(),
+ maBColorModifierStack))
+ {
+ // fallback to decomposition (MetaFile)
+ process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D()));
+ }
+
+ break;
+ }
+
+ // nice to have:
+ //
+ // case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
+ // - support FormControls more direct eventually, not sure if this is needed
+ // with the canvas renderer. The decomposition provides a bitmap representation
+ // of the control which will work
+ //
+
+ default :
+ {
+ // process recursively
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+
+ break;
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // process support
+
+ canvasProcessor2D::canvasProcessor2D(
+ const geometry::ViewInformation2D& rViewInformation,
+ OutputDevice& rOutDev)
+ : BaseProcessor2D(rViewInformation),
+ maOriginalMapMode(rOutDev.GetMapMode()),
+ mpOutputDevice(&rOutDev),
+ mxCanvas(rOutDev.GetCanvas()),
+ maViewState(),
+ maRenderState(),
+ maBColorModifierStack(),
+ maDrawinglayerOpt(),
+ maClipPolyPolygon(),
+ meLang(LANGUAGE_SYSTEM)
+ {
+ const SvtCTLOptions aSvtCTLOptions;
+
+ canvas::tools::initViewState(maViewState);
+ canvas::tools::initRenderState(maRenderState);
+ canvas::tools::setViewStateTransform(maViewState, getViewInformation2D().getViewTransformation());
+
+ // set digit language, derived from SvtCTLOptions to have the correct
+ // number display for arabic/hindi numerals
+ if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals())
+ {
+ meLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
+ }
+ else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals())
+ {
+ meLang = LANGUAGE_ENGLISH;
+ }
+ else
+ {
+ meLang = (LanguageType)Application::GetSettings().GetLanguage();
+ }
+
+ rOutDev.SetDigitLanguage(meLang);
+
+ // prepare output directly to pixels
+ mpOutputDevice->Push(PUSH_MAPMODE);
+ mpOutputDevice->SetMapMode();
+
+ // react on AntiAliasing settings
+ if(getOptionsDrawinglayer().IsAntiAliasing())
+ {
+ mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW);
+ }
+ else
+ {
+ mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
+ }
+ }
+
+ canvasProcessor2D::~canvasProcessor2D()
+ {
+ // restore MapMode
+ mpOutputDevice->Pop();
+
+ // restore AntiAliasing
+ mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
+ }
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/contourextractor2d.cxx b/drawinglayer/source/processor2d/contourextractor2d.cxx
new file mode 100644
index 000000000000..d87b13551e1a
--- /dev/null
+++ b/drawinglayer/source/processor2d/contourextractor2d.cxx
@@ -0,0 +1,203 @@
+/*************************************************************************
+ *
+ * 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/processor2d/contourextractor2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ ContourExtractor2D::ContourExtractor2D(const geometry::ViewInformation2D& rViewInformation)
+ : BaseProcessor2D(rViewInformation),
+ maExtractedContour()
+ {
+ }
+
+ ContourExtractor2D::~ContourExtractor2D()
+ {
+ }
+
+ void ContourExtractor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+ {
+ switch(rCandidate.getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
+ {
+ // extract hairline in world coordinates
+ const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate));
+ basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon());
+ aLocalPolygon.transform(getViewInformation2D().getObjectTransformation());
+
+ if(aLocalPolygon.isClosed())
+ {
+ // line polygons need to be represented as open polygons to differentiate them
+ // from filled polygons
+ basegfx::tools::openWithGeometryChange(aLocalPolygon);
+ }
+
+ maExtractedContour.push_back(basegfx::B2DPolyPolygon(aLocalPolygon));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
+ {
+ // extract fill in world coordinates
+ const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+ aLocalPolyPolygon.transform(getViewInformation2D().getObjectTransformation());
+ maExtractedContour.push_back(aLocalPolyPolygon);
+ break;
+ }
+ case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
+ {
+ // extract BoundRect from bitmaps in world coordinates
+ const primitive2d::BitmapPrimitive2D& rBitmapCandidate(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
+ basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectTransformation() * rBitmapCandidate.getTransform());
+ basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
+ aPolygon.transform(aLocalTransform);
+ maExtractedContour.push_back(basegfx::B2DPolyPolygon(aPolygon));
+ break;
+ }
+ case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
+ {
+ // extract BoundRect from MetaFiles in world coordinates
+ const primitive2d::MetafilePrimitive2D& rMetaCandidate(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate));
+ basegfx::B2DHomMatrix aLocalTransform(getViewInformation2D().getObjectTransformation() * rMetaCandidate.getTransform());
+ basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
+ aPolygon.transform(aLocalTransform);
+ maExtractedContour.push_back(basegfx::B2DPolyPolygon(aPolygon));
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
+ {
+ // sub-transparence group. Look at children
+ const primitive2d::TransparencePrimitive2D& rTransCandidate(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate));
+ process(rTransCandidate.getChildren());
+ break;
+ }
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ {
+ // extract mask in world coordinates, ignore content
+ const primitive2d::MaskPrimitive2D& rMaskCandidate(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
+ basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
+ aMask.transform(getViewInformation2D().getObjectTransformation());
+ maExtractedContour.push_back(basegfx::B2DPolyPolygon(aMask));
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
+ {
+ // remember current ViewInformation2D
+ const primitive2d::TransformPrimitive2D& rTransformCandidate(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // create new local ViewInformation2D
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
+ getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // proccess content
+ process(rTransformCandidate.getChildren());
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation2D);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_SCENEPRIMITIVE2D :
+ {
+ // 2D Scene primitive containing 3D stuff; extract 2D contour in world coordinates
+ const primitive2d::ScenePrimitive2D& rScenePrimitive2DCandidate(static_cast< const primitive2d::ScenePrimitive2D& >(rCandidate));
+ const primitive2d::Primitive2DSequence xExtracted2DSceneGeometry(rScenePrimitive2DCandidate.getGeometry2D());
+ const primitive2d::Primitive2DSequence xExtracted2DSceneShadow(rScenePrimitive2DCandidate.getShadow2D(getViewInformation2D()));
+
+ // proccess content
+ if(xExtracted2DSceneGeometry.hasElements())
+ {
+ process(xExtracted2DSceneGeometry);
+ }
+
+ // proccess content
+ if(xExtracted2DSceneShadow.hasElements())
+ {
+ process(xExtracted2DSceneShadow);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+ case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
+ case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+ {
+ // ignorable primitives
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
+ case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
+ {
+ // primitives who's BoundRect will be added in world coordinates
+ basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+ aRange.transform(getViewInformation2D().getObjectTransformation());
+ maExtractedContour.push_back(basegfx::B2DPolyPolygon(basegfx::tools::createPolygonFromRect(aRange)));
+ break;
+ }
+ default :
+ {
+ // process recursively
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ break;
+ }
+ }
+ }
+
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/helperchartrenderer.cxx b/drawinglayer/source/processor2d/helperchartrenderer.cxx
new file mode 100644
index 000000000000..43af1f9f2f85
--- /dev/null
+++ b/drawinglayer/source/processor2d/helperchartrenderer.cxx
@@ -0,0 +1,155 @@
+/*************************************************************************
+ *
+ * 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 <helperchartrenderer.hxx>
+#include <drawinglayer/primitive2d/chartprimitive2d.hxx>
+#include <svtools/chartprettypainter.hxx>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ bool renderChartPrimitive2D(
+ const primitive2d::ChartPrimitive2D& rChartCandidate,
+ OutputDevice& rOutputDevice,
+ const geometry::ViewInformation2D& rViewInformation2D)
+ {
+ bool bChartRendered(false);
+
+ // code from chart PrettyPrinter
+ try
+ {
+ uno::Reference< lang::XMultiServiceFactory > xFact( rChartCandidate.getChartModel(), uno::UNO_QUERY );
+ OSL_ENSURE( xFact.is(), "Chart cannot be painted pretty!\n" );
+
+ if( xFact.is() )
+ {
+ uno::Reference< lang::XUnoTunnel > xChartRenderer( xFact->createInstance(
+ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.chart2.ChartRenderer" ) ) ), uno::UNO_QUERY );
+ OSL_ENSURE( xChartRenderer.is(), "Chart cannot be painted pretty!\n" );
+
+ if( xChartRenderer.is() )
+ {
+ ChartPrettyPainter* pPrettyPainter = reinterpret_cast<ChartPrettyPainter*>(
+ xChartRenderer->getSomething( ChartPrettyPainter::getUnoTunnelId() ));
+
+ if( pPrettyPainter )
+ {
+ // create logic object range; do NOT use ObjectTransformation for this
+ // (rViewInformation2D.getObjectTransformation()), only the logic object
+ // size is wanted
+ basegfx::B2DRange aObjectRange(0.0, 0.0, 1.0, 1.0);
+ aObjectRange.transform(rChartCandidate.getTransformation());
+ const Rectangle aRectangle(
+ (sal_Int32)aObjectRange.getMinX(), (sal_Int32)aObjectRange.getMinY(),
+ (sal_Int32)aObjectRange.getMaxX(), (sal_Int32)aObjectRange.getMaxY());
+
+ // #i101811#
+ if(rViewInformation2D.getObjectTransformation().isIdentity())
+ {
+ // no embedding in another transfromation, just paint with existing
+ // MapMode. This is just a shortcut; using the below code will also
+ // work; it has just a neutral ObjectTransformation
+ bChartRendered = pPrettyPainter->DoPaint(&rOutputDevice, aRectangle);
+ }
+ else
+ {
+ // rViewInformation2D.getObjectTransformation() is used and
+ // needs to be expressed in the MapMode for the PrettyPainter;
+ // else it would call ChartModelHelper::setPageSize(...) with the
+ // changed size what really will change the chart model and leads
+ // to re-layouts and re-formattings
+ const MapMode aOldMapMode(rOutputDevice.GetMapMode());
+ basegfx::B2DVector aVTScale, aScale, aTranslate;
+ double fRotate, fShearX;
+
+ // get basic scaling with current MapMode (aVTScale), containing
+ // mapping for set MapUnit (e.g. for 100th mm, the basic scale is
+ // not 1.0, 1.0). This is needed since this scale is included in
+ // the ObjectToView Transformation and needs to be removed (see
+ // correction below) to re-create a MapMode
+ rOutputDevice.SetMapMode(aOldMapMode.GetMapUnit());
+ rOutputDevice.GetViewTransformation().decompose(aVTScale, aTranslate, fRotate, fShearX);
+
+ // get complete ObjectToView Transformation scale and translate from current
+ // transformation chain (combined view and object transform)
+ rViewInformation2D.getObjectToViewTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // assert when shear and/or rotation is used
+ OSL_ENSURE(basegfx::fTools::equalZero(fRotate), "Chart PrettyPrinting with unsupportable rotation (!)");
+ OSL_ENSURE(basegfx::fTools::equalZero(fShearX), "Chart PrettyPrinting with unsupportable shear (!)");
+
+ // clean scale and translate from basic scaling (DPI, etc...)
+ // since this will implicitely be part of the to-be-created MapMode
+ const basegfx::B2DTuple aBasicCleaner(
+ basegfx::fTools::equalZero(aVTScale.getX()) ? 1.0 : 1.0 / aVTScale.getX(),
+ basegfx::fTools::equalZero(aVTScale.getY()) ? 1.0 : 1.0 / aVTScale.getY());
+ aScale *= aBasicCleaner;
+ aTranslate *= aBasicCleaner;
+
+ // for MapMode, take scale out of translation
+ const basegfx::B2DTuple aScaleRemover(
+ basegfx::fTools::equalZero(aScale.getX()) ? 1.0 : 1.0 / aScale.getX(),
+ basegfx::fTools::equalZero(aScale.getY()) ? 1.0 : 1.0 / aScale.getY());
+ aTranslate *= aScaleRemover;
+
+ // build new MapMode
+ const MapMode aNewMapMode(aOldMapMode.GetMapUnit(),
+ Point(basegfx::fround(aTranslate.getX()), basegfx::fround(aTranslate.getY())),
+ Fraction(aScale.getX()), Fraction(aScale.getY()));
+
+ // use, paint, restore
+ rOutputDevice.SetMapMode(aNewMapMode);
+ bChartRendered = pPrettyPainter->DoPaint(&rOutputDevice, aRectangle);
+ rOutputDevice.SetMapMode(aOldMapMode);
+ }
+ }
+ }
+ }
+ }
+ catch( uno::Exception& e )
+ {
+ (void)e;
+ DBG_ERROR( "Chart cannot be painted pretty!" );
+ }
+
+ return bChartRendered;
+ }
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/helperchartrenderer.hxx b/drawinglayer/source/processor2d/helperchartrenderer.hxx
new file mode 100644
index 000000000000..b93eeebaee4e
--- /dev/null
+++ b/drawinglayer/source/processor2d/helperchartrenderer.hxx
@@ -0,0 +1,60 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERCHARTRENDER_HXX
+#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERCHARTRENDER_HXX
+
+#include <sal/types.h>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+class OutputDevice;
+
+namespace drawinglayer { namespace primitive2d { class ChartPrimitive2D; }}
+namespace drawinglayer { namespace geometry { class ViewInformation2D; }}
+
+//////////////////////////////////////////////////////////////////////////////
+// support chart PrettyPrinter usage from primitives
+
+namespace drawinglayer
+{
+ // #i101811#
+ // Added current ViewInformation2D to take evtl. changed
+ // ObjectTransformation into account
+ bool renderChartPrimitive2D(
+ const primitive2d::ChartPrimitive2D& rChartCandidate,
+ OutputDevice& rOutputDevice,
+ const geometry::ViewInformation2D& rViewInformation2D);
+
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERCHARTRENDER_HXX
+
+// eof
diff --git a/drawinglayer/source/processor2d/helperwrongspellrenderer.cxx b/drawinglayer/source/processor2d/helperwrongspellrenderer.cxx
new file mode 100644
index 000000000000..a678a3fa12b9
--- /dev/null
+++ b/drawinglayer/source/processor2d/helperwrongspellrenderer.cxx
@@ -0,0 +1,96 @@
+/*************************************************************************
+ *
+ * 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 <helperwrongspellrenderer.hxx>
+#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
+#include <tools/gen.hxx>
+#include <vcl/outdev.hxx>
+#include <basegfx/color/bcolormodifier.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ bool renderWrongSpellPrimitive2D(
+ const primitive2d::WrongSpellPrimitive2D& rWrongSpellCandidate,
+ OutputDevice& rOutputDevice,
+ const basegfx::B2DHomMatrix& rObjectToViewTransformation,
+ const basegfx::BColorModifierStack& rBColorModifierStack)
+ {
+ const basegfx::B2DHomMatrix aLocalTransform(rObjectToViewTransformation * rWrongSpellCandidate.getTransformation());
+ const basegfx::B2DVector aFontVectorPixel(aLocalTransform * basegfx::B2DVector(0.0, 1.0));
+ const sal_uInt32 nFontPixelHeight(basegfx::fround(aFontVectorPixel.getLength()));
+
+ static const sal_uInt32 nMinimumFontHeight(5); // #define WRONG_SHOW_MIN 5
+ static const sal_uInt32 nSmallFontHeight(11); // #define WRONG_SHOW_SMALL 11
+ static const sal_uInt32 nMediumFontHeight(15); // #define WRONG_SHOW_MEDIUM 15
+
+ if(nFontPixelHeight > nMinimumFontHeight)
+ {
+ const basegfx::B2DPoint aStart(aLocalTransform * basegfx::B2DPoint(rWrongSpellCandidate.getStart(), 0.0));
+ const basegfx::B2DPoint aStop(aLocalTransform * basegfx::B2DPoint(rWrongSpellCandidate.getStop(), 0.0));
+ const Point aVclStart(basegfx::fround(aStart.getX()), basegfx::fround(aStart.getY()));
+ const Point aVclStop(basegfx::fround(aStop.getX()), basegfx::fround(aStop.getY()));
+ sal_uInt16 nWaveStyle(WAVE_FLAT);
+
+ if(nFontPixelHeight > nMediumFontHeight)
+ {
+ nWaveStyle = WAVE_NORMAL;
+ }
+ else if(nFontPixelHeight > nSmallFontHeight)
+ {
+ nWaveStyle = WAVE_SMALL;
+ }
+
+ // #i101075# draw it. Do not forget to use the evtl. offsetted origin of the target device,
+ // e.g. when used with mask/transparence buffer device
+ const Point aOrigin(rOutputDevice.GetMapMode().GetOrigin());
+
+ const basegfx::BColor aProcessedColor(rBColorModifierStack.getModifiedColor(rWrongSpellCandidate.getColor()));
+ const bool bMapModeEnabledState(rOutputDevice.IsMapModeEnabled());
+
+ rOutputDevice.EnableMapMode(false);
+ rOutputDevice.SetLineColor(Color(aProcessedColor));
+ rOutputDevice.SetFillColor();
+ rOutputDevice.DrawWaveLine(aOrigin + aVclStart, aOrigin + aVclStop, nWaveStyle);
+ rOutputDevice.EnableMapMode(bMapModeEnabledState);
+ }
+
+ // cannot really go wrong
+ return true;
+ }
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/helperwrongspellrenderer.hxx b/drawinglayer/source/processor2d/helperwrongspellrenderer.hxx
new file mode 100644
index 000000000000..1f669775b866
--- /dev/null
+++ b/drawinglayer/source/processor2d/helperwrongspellrenderer.hxx
@@ -0,0 +1,65 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERWRONGSPELLRENDER_HXX
+#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERWRONGSPELLRENDER_HXX
+
+#include <sal/types.h>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+class OutputDevice;
+
+namespace drawinglayer { namespace primitive2d {
+ class WrongSpellPrimitive2D;
+}}
+
+namespace basegfx {
+ class B2DHomMatrix;
+ class BColorModifierStack;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// support WrongSpell rendreing using VCL from primitives due to VCLs nice
+// and fast solution with wavelines
+
+namespace drawinglayer
+{
+ bool renderWrongSpellPrimitive2D(
+ const primitive2d::WrongSpellPrimitive2D& rWrongSpellCandidate,
+ OutputDevice& rOutputDevice,
+ const basegfx::B2DHomMatrix& rObjectToViewTransformation,
+ const basegfx::BColorModifierStack& rBColorModifierStack);
+
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_HELPERWRONGSPELLRENDER_HXX
+
+// eof
diff --git a/drawinglayer/source/processor2d/hittestprocessor2d.cxx b/drawinglayer/source/processor2d/hittestprocessor2d.cxx
new file mode 100644
index 000000000000..aaafa42ec44e
--- /dev/null
+++ b/drawinglayer/source/processor2d/hittestprocessor2d.cxx
@@ -0,0 +1,605 @@
+/*************************************************************************
+ *
+ * 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/processor2d/hittestprocessor2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
+#include <drawinglayer/processor3d/cutfindprocessor3d.hxx>
+#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ HitTestProcessor2D::HitTestProcessor2D(const geometry::ViewInformation2D& rViewInformation,
+ const basegfx::B2DPoint& rLogicHitPosition,
+ double fLogicHitTolerance,
+ bool bHitTextOnly)
+ : BaseProcessor2D(rViewInformation),
+ maDiscreteHitPosition(),
+ mfDiscreteHitTolerance(0.0),
+ mbHit(false),
+ mbHitToleranceUsed(false),
+ mbUseInvisiblePrimitiveContent(true),
+ mbHitTextOnly(bHitTextOnly)
+ {
+ // init hit tolerance
+ mfDiscreteHitTolerance = fLogicHitTolerance;
+
+ if(basegfx::fTools::less(mfDiscreteHitTolerance, 0.0))
+ {
+ // ensure input parameter for hit tolerance is >= 0.0
+ mfDiscreteHitTolerance = 0.0;
+ }
+ else if(basegfx::fTools::more(mfDiscreteHitTolerance, 0.0))
+ {
+ // generate discrete hit tolerance
+ mfDiscreteHitTolerance = (getViewInformation2D().getObjectToViewTransformation()
+ * basegfx::B2DVector(mfDiscreteHitTolerance, 0.0)).getLength();
+ }
+
+ // gererate discrete hit position
+ maDiscreteHitPosition = getViewInformation2D().getObjectToViewTransformation() * rLogicHitPosition;
+
+ // check if HitTolerance is used
+ mbHitToleranceUsed = basegfx::fTools::more(getDiscreteHitTolerance(), 0.0);
+ }
+
+ HitTestProcessor2D::~HitTestProcessor2D()
+ {
+ }
+
+ bool HitTestProcessor2D::checkHairlineHitWithTolerance(
+ const basegfx::B2DPolygon& rPolygon,
+ double fDiscreteHitTolerance)
+ {
+ basegfx::B2DPolygon aLocalPolygon(rPolygon);
+ aLocalPolygon.transform(getViewInformation2D().getObjectToViewTransformation());
+
+ // get discrete range
+ basegfx::B2DRange aPolygonRange(aLocalPolygon.getB2DRange());
+
+ if(basegfx::fTools::more(fDiscreteHitTolerance, 0.0))
+ {
+ aPolygonRange.grow(fDiscreteHitTolerance);
+ }
+
+ // do rough range test first
+ if(aPolygonRange.isInside(getDiscreteHitPosition()))
+ {
+ // check if a polygon edge is hit
+ return basegfx::tools::isInEpsilonRange(
+ aLocalPolygon,
+ getDiscreteHitPosition(),
+ fDiscreteHitTolerance);
+ }
+
+ return false;
+ }
+
+ bool HitTestProcessor2D::checkFillHitWithTolerance(
+ const basegfx::B2DPolyPolygon& rPolyPolygon,
+ double fDiscreteHitTolerance)
+ {
+ bool bRetval(false);
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon);
+ aLocalPolyPolygon.transform(getViewInformation2D().getObjectToViewTransformation());
+
+ // get discrete range
+ basegfx::B2DRange aPolygonRange(aLocalPolyPolygon.getB2DRange());
+ const bool bDiscreteHitToleranceUsed(basegfx::fTools::more(fDiscreteHitTolerance, 0.0));
+
+ if(bDiscreteHitToleranceUsed)
+ {
+ aPolygonRange.grow(fDiscreteHitTolerance);
+ }
+
+ // do rough range test first
+ if(aPolygonRange.isInside(getDiscreteHitPosition()))
+ {
+ // if a HitTolerance is given, check for polygon edge hit in epsilon first
+ if(bDiscreteHitToleranceUsed &&
+ basegfx::tools::isInEpsilonRange(
+ aLocalPolyPolygon,
+ getDiscreteHitPosition(),
+ fDiscreteHitTolerance))
+ {
+ bRetval = true;
+ }
+
+ // check for hit in filled polyPolygon
+ if(!bRetval && basegfx::tools::isInside(
+ aLocalPolyPolygon,
+ getDiscreteHitPosition(),
+ true))
+ {
+ bRetval = true;
+ }
+ }
+
+ return bRetval;
+ }
+
+ void HitTestProcessor2D::check3DHit(const primitive2d::ScenePrimitive2D& rCandidate)
+ {
+ // calculate relative point in unified 2D scene
+ const basegfx::B2DPoint aLogicHitPosition(getViewInformation2D().getInverseObjectToViewTransformation() * getDiscreteHitPosition());
+
+ // use bitmap check in ScenePrimitive2D
+ bool bTryFastResult(false);
+
+ if(rCandidate.tryToCheckLastVisualisationDirectHit(aLogicHitPosition, bTryFastResult))
+ {
+ mbHit = bTryFastResult;
+ }
+ else
+ {
+ basegfx::B2DHomMatrix aInverseSceneTransform(rCandidate.getObjectTransformation());
+ aInverseSceneTransform.invert();
+ const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * aLogicHitPosition);
+
+ // check if test point is inside scene's unified area at all
+ if(aRelativePoint.getX() >= 0.0 && aRelativePoint.getX() <= 1.0
+ && aRelativePoint.getY() >= 0.0 && aRelativePoint.getY() <= 1.0)
+ {
+ // get 3D view information
+ const geometry::ViewInformation3D& rObjectViewInformation3D = rCandidate.getViewInformation3D();
+
+ // create HitPoint Front and Back, transform to object coordinates
+ basegfx::B3DHomMatrix aViewToObject(rObjectViewInformation3D.getObjectToView());
+ aViewToObject.invert();
+ const basegfx::B3DPoint aFront(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 0.0));
+ const basegfx::B3DPoint aBack(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 1.0));
+
+ if(!aFront.equal(aBack))
+ {
+ const primitive3d::Primitive3DSequence& rPrimitives = rCandidate.getChildren3D();
+
+ if(rPrimitives.hasElements())
+ {
+ // make BoundVolume empty and overlapping test for speedup
+ const basegfx::B3DRange aObjectRange(
+ drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(
+ rPrimitives, rObjectViewInformation3D));
+
+ if(!aObjectRange.isEmpty())
+ {
+ const basegfx::B3DRange aFrontBackRange(aFront, aBack);
+
+ if(aObjectRange.overlaps(aFrontBackRange))
+ {
+ // bound volumes hit, geometric cut tests needed
+ drawinglayer::processor3d::CutFindProcessor aCutFindProcessor(
+ rObjectViewInformation3D,
+ aFront,
+ aBack,
+ true);
+ aCutFindProcessor.process(rPrimitives);
+
+ mbHit = (0 != aCutFindProcessor.getCutPoints().size());
+ }
+ }
+ }
+ }
+ }
+
+ // This is needed to check hit with 3D shadows, too. HitTest is without shadow
+ // to keep compatible with previous versions. Keeping here as reference
+ //
+ // if(!getHit())
+ // {
+ // // if scene has shadow, check hit with shadow, too
+ // const primitive2d::Primitive2DSequence xExtracted2DSceneShadow(rCandidate.getShadow2D(getViewInformation2D()));
+ //
+ // if(xExtracted2DSceneShadow.hasElements())
+ // {
+ // // proccess extracted 2D content
+ // process(xExtracted2DSceneShadow);
+ // }
+ // }
+
+ if(!getHit())
+ {
+ // empty 3D scene; Check for border hit
+ basegfx::B2DPolygon aOutline(basegfx::tools::createUnitPolygon());
+ aOutline.transform(rCandidate.getObjectTransformation());
+
+ mbHit = checkHairlineHitWithTolerance(aOutline, getDiscreteHitTolerance());
+ }
+
+ // This is what the previous version did. Keeping it here for reference
+ //
+ // // 2D Scene primitive containing 3D stuff; extract 2D contour in world coordinates
+ // // This may be refined later to an own 3D HitTest renderer which processes the 3D
+ // // geometry directly
+ // const primitive2d::ScenePrimitive2D& rScenePrimitive2DCandidate(static_cast< const primitive2d::ScenePrimitive2D& >(rCandidate));
+ // const primitive2d::Primitive2DSequence xExtracted2DSceneGeometry(rScenePrimitive2DCandidate.getGeometry2D());
+ // const primitive2d::Primitive2DSequence xExtracted2DSceneShadow(rScenePrimitive2DCandidate.getShadow2D(getViewInformation2D()));
+ //
+ // if(xExtracted2DSceneGeometry.hasElements() || xExtracted2DSceneShadow.hasElements())
+ // {
+ // // proccess extracted 2D content
+ // process(xExtracted2DSceneGeometry);
+ // process(xExtracted2DSceneShadow);
+ // }
+ // else
+ // {
+ // // empty 3D scene; Check for border hit
+ // const basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+ // if(!aRange.isEmpty())
+ // {
+ // const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
+ // mbHit = checkHairlineHitWithTolerance(aOutline, getDiscreteHitTolerance());
+ // }
+ // }
+ }
+ }
+
+ void HitTestProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+ {
+ if(getHit())
+ {
+ // stop processing as soon as a hit was recognized
+ return;
+ }
+
+ switch(rCandidate.getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
+ {
+ // remember current ViewInformation2D
+ const primitive2d::TransformPrimitive2D& rTransformCandidate(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // create new local ViewInformation2D containing transformation
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
+ getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // proccess child content recursively
+ process(rTransformCandidate.getChildren());
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation2D);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ // create hairline in discrete coordinates
+ const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate));
+
+ // use hairline test
+ mbHit = checkHairlineHitWithTolerance(rPolygonCandidate.getB2DPolygon(), getDiscreteHitTolerance());
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONMARKERPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ // handle marker like hairline; no need to decompose in dashes
+ const primitive2d::PolygonMarkerPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonMarkerPrimitive2D& >(rCandidate));
+
+ // use hairline test
+ mbHit = checkHairlineHitWithTolerance(rPolygonCandidate.getB2DPolygon(), getDiscreteHitTolerance());
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ // handle stroke evtl. directly; no need to decompose to filled polygon outlines
+ const primitive2d::PolygonStrokePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate));
+ const attribute::LineAttribute& rLineAttribute = rPolygonCandidate.getLineAttribute();
+
+ if(basegfx::fTools::more(rLineAttribute.getWidth(), 0.0))
+ {
+ if(basegfx::B2DLINEJOIN_MITER == rLineAttribute.getLineJoin())
+ {
+ // if line is mitered, use decomposition since mitered line
+ // geometry may use more space than the geometry grown by half line width
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ else
+ {
+ // for all other B2DLINEJOIN_* do a hairline HitTest with expanded tolerance
+ const basegfx::B2DVector aDiscreteHalfLineVector(getViewInformation2D().getObjectToViewTransformation()
+ * basegfx::B2DVector(rLineAttribute.getWidth() * 0.5, 0.0));
+ mbHit = checkHairlineHitWithTolerance(
+ rPolygonCandidate.getB2DPolygon(),
+ getDiscreteHitTolerance() + aDiscreteHalfLineVector.getLength());
+ }
+ }
+ else
+ {
+ // hairline; fallback to hairline test. Do not decompose
+ // since this may decompose the hairline to dashes
+ mbHit = checkHairlineHitWithTolerance(rPolygonCandidate.getB2DPolygon(), getDiscreteHitTolerance());
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONWAVEPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ // do not use decompose; just handle like a line with width
+ const primitive2d::PolygonWavePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonWavePrimitive2D& >(rCandidate));
+ double fLogicHitTolerance(0.0);
+
+ // if WaveHeight, grow by it
+ if(basegfx::fTools::more(rPolygonCandidate.getWaveHeight(), 0.0))
+ {
+ fLogicHitTolerance += rPolygonCandidate.getWaveHeight();
+ }
+
+ // if line width, grow by it
+ if(basegfx::fTools::more(rPolygonCandidate.getLineAttribute().getWidth(), 0.0))
+ {
+ fLogicHitTolerance += rPolygonCandidate.getLineAttribute().getWidth() * 0.5;
+ }
+
+ const basegfx::B2DVector aDiscreteHalfLineVector(getViewInformation2D().getObjectToViewTransformation()
+ * basegfx::B2DVector(fLogicHitTolerance, 0.0));
+
+ mbHit = checkHairlineHitWithTolerance(
+ rPolygonCandidate.getB2DPolygon(),
+ getDiscreteHitTolerance() + aDiscreteHalfLineVector.getLength());
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ // create filled polyPolygon in discrete coordinates
+ const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
+
+ // use fill hit test
+ mbHit = checkFillHitWithTolerance(rPolygonCandidate.getB2DPolyPolygon(), getDiscreteHitTolerance());
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
+ {
+ // sub-transparence group
+ const primitive2d::TransparencePrimitive2D& rTransCandidate(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate));
+
+ // Currently the transparence content is not taken into account; only
+ // the children are recursively checked for hit. This may be refined for
+ // parts where the content is completely transparent if needed.
+ process(rTransCandidate.getChildren());
+
+ break;
+ }
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ {
+ // create mask in discrete coordinates; only recursively continue
+ // with content when HitTest position is inside the mask
+ const primitive2d::MaskPrimitive2D& rMaskCandidate(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
+
+ // use fill hit test
+ if(checkFillHitWithTolerance(rMaskCandidate.getMask(), getDiscreteHitTolerance()))
+ {
+ // recursively HitTest children
+ process(rMaskCandidate.getChildren());
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_SCENEPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ const primitive2d::ScenePrimitive2D& rScenePrimitive2D(
+ static_cast< const primitive2d::ScenePrimitive2D& >(rCandidate));
+ check3DHit(rScenePrimitive2D);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+ case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
+ case PRIMITIVE2D_ID_GRIDPRIMITIVE2D :
+ case PRIMITIVE2D_ID_HELPLINEPRIMITIVE2D :
+ {
+ // ignorable primitives
+ break;
+ }
+ case PRIMITIVE2D_ID_SHADOWPRIMITIVE2D :
+ {
+ // Ignore shadows; we do not want to have shadows hittable.
+ // Remove this one to make shadows hittable on demand.
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
+ case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
+ {
+ // for text use the BoundRect of the primitive itself
+ const basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+
+ if(!aRange.isEmpty())
+ {
+ const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
+ mbHit = checkFillHitWithTolerance(basegfx::B2DPolyPolygon(aOutline), getDiscreteHitTolerance());
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ // The recently added BitmapEx::GetTransparency() makes it easy to extend
+ // the BitmapPrimitive2D HitTest to take the contained BotmapEx and it's
+ // transparency into account
+ const basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+
+ if(!aRange.isEmpty())
+ {
+ const primitive2d::BitmapPrimitive2D& rBitmapCandidate(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
+ const BitmapEx& rBitmapEx = rBitmapCandidate.getBitmapEx();
+ const Size& rSizePixel(rBitmapEx.GetSizePixel());
+
+ if(rSizePixel.Width() && rSizePixel.Height())
+ {
+ basegfx::B2DHomMatrix aBackTransform(
+ getViewInformation2D().getObjectToViewTransformation() *
+ rBitmapCandidate.getTransform());
+ aBackTransform.invert();
+
+ const basegfx::B2DPoint aRelativePoint(aBackTransform * getDiscreteHitPosition());
+ const basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
+
+ if(aUnitRange.isInside(aRelativePoint))
+ {
+ const sal_Int32 nX(basegfx::fround(aRelativePoint.getX() * rSizePixel.Width()));
+ const sal_Int32 nY(basegfx::fround(aRelativePoint.getY() * rSizePixel.Height()));
+
+ mbHit = (0xff != rBitmapEx.GetTransparency(nX, nY));
+ }
+ }
+ else
+ {
+ // fallback to standard HitTest
+ const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
+ mbHit = checkFillHitWithTolerance(basegfx::B2DPolyPolygon(aOutline), getDiscreteHitTolerance());
+ }
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
+ case PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D :
+ case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D :
+ case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ // Class of primitives for which just the BoundRect of the primitive itself
+ // will be used for HitTest currently.
+ //
+ // This may be refined in the future, e.g:
+ // - For Bitamps, the mask and/or transparence information may be used
+ // - For MetaFiles, the MetaFile content may be used
+ const basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+
+ if(!aRange.isEmpty())
+ {
+ const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(aRange));
+ mbHit = checkFillHitWithTolerance(basegfx::B2DPolyPolygon(aOutline), getDiscreteHitTolerance());
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D :
+ {
+ // HiddenGeometryPrimitive2D; the default decomposition would return an empty seqence,
+ // so force this primitive to process it's children directly if the switch is set
+ // (which is the default). Else, ignore invisible content
+ const primitive2d::HiddenGeometryPrimitive2D& rHiddenGeometry(static_cast< const primitive2d::HiddenGeometryPrimitive2D& >(rCandidate));
+ const primitive2d::Primitive2DSequence& rChildren = rHiddenGeometry.getChildren();
+
+ if(rChildren.hasElements())
+ {
+ if(getUseInvisiblePrimitiveContent())
+ {
+ process(rChildren);
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+ {
+ if(!getHitTextOnly())
+ {
+ const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
+ const std::vector< basegfx::B2DPoint >& rPositions = rPointArrayCandidate.getPositions();
+ const sal_uInt32 nCount(rPositions.size());
+
+ for(sal_uInt32 a(0); !getHit() && a < nCount; a++)
+ {
+ const basegfx::B2DPoint aPosition(getViewInformation2D().getObjectToViewTransformation() * rPositions[a]);
+ const basegfx::B2DVector aDistance(aPosition - getDiscreteHitPosition());
+
+ if(aDistance.getLength() <= getDiscreteHitTolerance())
+ {
+ mbHit = true;
+ }
+ }
+ }
+
+ break;
+ }
+ default :
+ {
+ // process recursively
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+
+ break;
+ }
+ }
+ }
+
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/linegeometryextractor2d.cxx b/drawinglayer/source/processor2d/linegeometryextractor2d.cxx
new file mode 100644
index 000000000000..be3601dd0024
--- /dev/null
+++ b/drawinglayer/source/processor2d/linegeometryextractor2d.cxx
@@ -0,0 +1,144 @@
+/*************************************************************************
+ *
+ * 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/processor2d/linegeometryextractor2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ LineGeometryExtractor2D::LineGeometryExtractor2D(const geometry::ViewInformation2D& rViewInformation)
+ : BaseProcessor2D(rViewInformation),
+ maExtractedHairlines(),
+ maExtractedLineFills(),
+ mbInLineGeometry(false)
+ {
+ }
+
+ LineGeometryExtractor2D::~LineGeometryExtractor2D()
+ {
+ }
+
+ void LineGeometryExtractor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+ {
+ switch(rCandidate.getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
+ {
+ // enter a line geometry group (with or without LineEnds)
+ bool bOldState(mbInLineGeometry);
+ mbInLineGeometry = true;
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ mbInLineGeometry = bOldState;
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
+ {
+ if(mbInLineGeometry)
+ {
+ // extract hairline line geometry in world coordinates
+ const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate));
+ basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon());
+ aLocalPolygon.transform(getViewInformation2D().getObjectTransformation());
+ maExtractedHairlines.push_back(aLocalPolygon);
+ }
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
+ {
+ if(mbInLineGeometry)
+ {
+ // extract filled line geometry (line with width)
+ const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+ aLocalPolyPolygon.transform(getViewInformation2D().getObjectTransformation());
+ maExtractedLineFills.push_back(aLocalPolyPolygon);
+ }
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
+ {
+ // remember current transformation and ViewInformation
+ const primitive2d::TransformPrimitive2D& rTransformCandidate(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // create new transformations for CurrentTransformation and for local ViewInformation2D
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
+ getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // proccess content
+ process(rTransformCandidate.getChildren());
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation2D);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_SCENEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+ case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
+ case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+ case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
+ case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ {
+ // ignorable primitives
+ break;
+ }
+ default :
+ {
+ // process recursively
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ break;
+ }
+ }
+ }
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/makefile.mk b/drawinglayer/source/processor2d/makefile.mk
new file mode 100644
index 000000000000..ec7b8aef647b
--- /dev/null
+++ b/drawinglayer/source/processor2d/makefile.mk
@@ -0,0 +1,58 @@
+#*************************************************************************
+#
+# 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.
+#
+#*************************************************************************
+
+PRJ=..$/..
+PRJNAME=drawinglayer
+TARGET=processor2d
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings ----------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Files -------------------------------------
+
+SLOFILES= \
+ $(SLO)$/baseprocessor2d.obj \
+ $(SLO)$/vclhelpergradient.obj \
+ $(SLO)$/vclhelperbitmaptransform.obj \
+ $(SLO)$/vclhelperbitmaprender.obj \
+ $(SLO)$/vclhelperbufferdevice.obj \
+ $(SLO)$/vclprocessor2d.obj \
+ $(SLO)$/helperchartrenderer.obj \
+ $(SLO)$/helperwrongspellrenderer.obj \
+ $(SLO)$/vclpixelprocessor2d.obj \
+ $(SLO)$/vclmetafileprocessor2d.obj \
+ $(SLO)$/contourextractor2d.obj \
+ $(SLO)$/linegeometryextractor2d.obj \
+ $(SLO)$/canvasprocessor.obj \
+ $(SLO)$/hittestprocessor2d.obj \
+ $(SLO)$/textaspolygonextractor2d.obj
+
+# --- Targets ----------------------------------
+
+.INCLUDE : target.mk
diff --git a/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx b/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx
new file mode 100644
index 000000000000..b9ad83373923
--- /dev/null
+++ b/drawinglayer/source/processor2d/textaspolygonextractor2d.cxx
@@ -0,0 +1,247 @@
+/*************************************************************************
+ *
+ * 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/processor2d/textaspolygonextractor2d.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ void TextAsPolygonExtractor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+ {
+ switch(rCandidate.getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
+ {
+ // TextDecoratedPortionPrimitive2D can produce the following primitives
+ // when being decomposed:
+ //
+ // - TextSimplePortionPrimitive2D
+ // - PolygonWavePrimitive2D
+ // - PolygonStrokePrimitive2D
+ // - PolygonStrokePrimitive2D
+ // - PolyPolygonColorPrimitive2D
+ // - PolyPolygonHairlinePrimitive2D
+ // - PolygonHairlinePrimitive2D
+ // - ShadowPrimitive2D
+ // - ModifiedColorPrimitive2D
+ // - TransformPrimitive2D
+ // - TextEffectPrimitive2D
+ // - ModifiedColorPrimitive2D
+ // - TransformPrimitive2D
+ // - GroupPrimitive2D
+
+ // encapsulate with flag and use decomposition
+ mnInText++;
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ mnInText--;
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
+ {
+ // TextSimplePortionPrimitive2D can produce the following primitives
+ // when being decomposed:
+ //
+ // - PolyPolygonColorPrimitive2D
+ // - TextEffectPrimitive2D
+ // - ModifiedColorPrimitive2D
+ // - TransformPrimitive2D
+ // - GroupPrimitive2D
+
+ // encapsulate with flag and use decomposition
+ mnInText++;
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ mnInText--;
+
+ break;
+ }
+
+ // as can be seen from the TextSimplePortionPrimitive2D and the
+ // TextDecoratedPortionPrimitive2D, inside of the mnInText marks
+ // the following primitives can occurr containing geometry data
+ // from text decomposition:
+ //
+ // - PolyPolygonColorPrimitive2D
+ // - PolygonHairlinePrimitive2D
+ // - PolyPolygonHairlinePrimitive2D (for convenience)
+ //
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
+ {
+ if(mnInText)
+ {
+ const primitive2d::PolyPolygonColorPrimitive2D& rPoPoCoCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
+ basegfx::B2DPolyPolygon aPolyPolygon(rPoPoCoCandidate.getB2DPolyPolygon());
+
+ if(aPolyPolygon.count())
+ {
+ // transform the PolyPolygon
+ aPolyPolygon.transform(getViewInformation2D().getObjectToViewTransformation());
+
+ // get evtl. corrected color
+ const basegfx::BColor aColor(maBColorModifierStack.getModifiedColor(rPoPoCoCandidate.getBColor()));
+
+ // add to result vector
+ maTarget.push_back(TextAsPolygonDataNode(aPolyPolygon, aColor, true));
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
+ {
+ if(mnInText)
+ {
+ const primitive2d::PolygonHairlinePrimitive2D& rPoHaCandidate(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate));
+ basegfx::B2DPolygon aPolygon(rPoHaCandidate.getB2DPolygon());
+
+ if(aPolygon.count())
+ {
+ // transform the Polygon
+ aPolygon.transform(getViewInformation2D().getObjectToViewTransformation());
+
+ // get evtl. corrected color
+ const basegfx::BColor aColor(maBColorModifierStack.getModifiedColor(rPoHaCandidate.getBColor()));
+
+ // add to result vector
+ maTarget.push_back(TextAsPolygonDataNode(basegfx::B2DPolyPolygon(aPolygon), aColor, false));
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONHAIRLINEPRIMITIVE2D :
+ {
+ if(mnInText)
+ {
+ const primitive2d::PolyPolygonHairlinePrimitive2D& rPoPoHaCandidate(static_cast< const primitive2d::PolyPolygonHairlinePrimitive2D& >(rCandidate));
+ basegfx::B2DPolyPolygon aPolyPolygon(rPoPoHaCandidate.getB2DPolyPolygon());
+
+ if(aPolyPolygon.count())
+ {
+ // transform the Polygon
+ aPolyPolygon.transform(getViewInformation2D().getObjectToViewTransformation());
+
+ // get evtl. corrected color
+ const basegfx::BColor aColor(maBColorModifierStack.getModifiedColor(rPoPoHaCandidate.getBColor()));
+
+ // add to result vector
+ maTarget.push_back(TextAsPolygonDataNode(aPolyPolygon, aColor, false));
+ }
+ }
+
+ break;
+ }
+
+ // usage of color modification stack is needed
+ case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
+ {
+ const primitive2d::ModifiedColorPrimitive2D& rModifiedColorCandidate(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
+
+ if(rModifiedColorCandidate.getChildren().hasElements())
+ {
+ maBColorModifierStack.push(rModifiedColorCandidate.getColorModifier());
+ process(rModifiedColorCandidate.getChildren());
+ maBColorModifierStack.pop();
+ }
+
+ break;
+ }
+
+ // usage of transformation stack is needed
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
+ {
+ // remember current transformation and ViewInformation
+ const primitive2d::TransformPrimitive2D& rTransformCandidate(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // create new transformations for CurrentTransformation and for local ViewInformation2D
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
+ getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // proccess content
+ process(rTransformCandidate.getChildren());
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation2D);
+
+ break;
+ }
+
+ // ignorable primitives
+ case PRIMITIVE2D_ID_SCENEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+ case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
+ case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+ case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
+ case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ {
+ break;
+ }
+
+ default :
+ {
+ // process recursively
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ break;
+ }
+ }
+ }
+
+ TextAsPolygonExtractor2D::TextAsPolygonExtractor2D(const geometry::ViewInformation2D& rViewInformation)
+ : BaseProcessor2D(rViewInformation),
+ maTarget(),
+ maBColorModifierStack(),
+ mnInText(0)
+ {
+ }
+
+ TextAsPolygonExtractor2D::~TextAsPolygonExtractor2D()
+ {
+ }
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx b/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx
new file mode 100644
index 000000000000..db61e0721ef0
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx
@@ -0,0 +1,272 @@
+/*************************************************************************
+ *
+ * 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 <vclhelperbitmaprender.hxx>
+#include <svtools/grfmgr.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <vcl/outdev.hxx>
+#include <vclhelperbitmaptransform.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// support for different kinds of bitmap rendering using vcl
+
+namespace drawinglayer
+{
+ void RenderBitmapPrimitive2D_GraphicManager(
+ OutputDevice& rOutDev,
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DHomMatrix& rTransform)
+ {
+ // prepare attributes
+ GraphicAttr aAttributes;
+
+ // decompose matrix to check for shear, rotate and mirroring
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // mirror flags
+ aAttributes.SetMirrorFlags(
+ (basegfx::fTools::less(aScale.getX(), 0.0) ? BMP_MIRROR_HORZ : 0)|
+ (basegfx::fTools::less(aScale.getY(), 0.0) ? BMP_MIRROR_VERT : 0));
+
+ // rotation
+ if(!basegfx::fTools::equalZero(fRotate))
+ {
+ double fRotation(fmod(3600.0 - (fRotate * (10.0 / F_PI180)), 3600.0));
+ aAttributes.SetRotation((sal_uInt16)(fRotation));
+ }
+
+ // prepare Bitmap
+ basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
+
+ if(basegfx::fTools::equalZero(fRotate))
+ {
+ aOutlineRange.transform(rTransform);
+ }
+ else
+ {
+ // if rotated, create the unrotated output rectangle for the GraphicManager paint
+ const basegfx::B2DHomMatrix aSimpleObjectMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
+ fabs(aScale.getX()), fabs(aScale.getY()),
+ aTranslate.getX(), aTranslate.getY()));
+
+ aOutlineRange.transform(aSimpleObjectMatrix);
+ }
+
+ // prepare dest coor
+ const Rectangle aDestRectPixel(
+ basegfx::fround(aOutlineRange.getMinX()), basegfx::fround(aOutlineRange.getMinY()),
+ basegfx::fround(aOutlineRange.getMaxX()), basegfx::fround(aOutlineRange.getMaxY()));
+
+ // paint it using GraphicManager
+ Graphic aGraphic(rBitmapEx);
+ GraphicObject aGraphicObject(aGraphic);
+ aGraphicObject.Draw(&rOutDev, aDestRectPixel.TopLeft(), aDestRectPixel.GetSize(), &aAttributes);
+ }
+
+ void RenderBitmapPrimitive2D_BitmapEx(
+ OutputDevice& rOutDev,
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DHomMatrix& rTransform)
+ {
+ // only translate and scale, use vcl's DrawBitmapEx().
+ BitmapEx aContent(rBitmapEx);
+
+ // prepare dest coor. Necessary to expand since vcl's DrawBitmapEx draws one pix less
+ basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
+ aOutlineRange.transform(rTransform);
+ const Rectangle aDestRectPixel(
+ basegfx::fround(aOutlineRange.getMinX()), basegfx::fround(aOutlineRange.getMinY()),
+ basegfx::fround(aOutlineRange.getMaxX()), basegfx::fround(aOutlineRange.getMaxY()));
+
+ // decompose matrix to check for shear, rotate and mirroring
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ // Check mirroring.
+ sal_uInt32 nMirrorFlags(BMP_MIRROR_NONE);
+
+ if(basegfx::fTools::less(aScale.getX(), 0.0))
+ {
+ nMirrorFlags |= BMP_MIRROR_HORZ;
+ }
+
+ if(basegfx::fTools::less(aScale.getY(), 0.0))
+ {
+ nMirrorFlags |= BMP_MIRROR_VERT;
+ }
+
+ if(BMP_MIRROR_NONE != nMirrorFlags)
+ {
+ aContent.Mirror(nMirrorFlags);
+ }
+
+ // draw bitmap
+ rOutDev.DrawBitmapEx(aDestRectPixel.TopLeft(), aDestRectPixel.GetSize(), aContent);
+ }
+
+ void RenderBitmapPrimitive2D_self(
+ OutputDevice& rOutDev,
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DHomMatrix& rTransform)
+ {
+ // process self with free transformation (containing shear and rotate). Get dest rect in pixels.
+ basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
+ aOutlineRange.transform(rTransform);
+ const Rectangle aDestRectLogic(
+ basegfx::fround(aOutlineRange.getMinX()), basegfx::fround(aOutlineRange.getMinY()),
+ basegfx::fround(aOutlineRange.getMaxX()), basegfx::fround(aOutlineRange.getMaxY()));
+ const Rectangle aDestRectPixel(rOutDev.LogicToPixel(aDestRectLogic));
+
+ // #i96708# check if Metafile is recorded
+ const GDIMetaFile* pMetaFile = rOutDev.GetConnectMetaFile();
+ const bool bRecordToMetaFile(pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+
+ // intersect with output pixel size, but only
+ // when not recording to metafile
+ const Rectangle aOutputRectPixel(Point(), rOutDev.GetOutputSizePixel());
+ Rectangle aCroppedRectPixel(bRecordToMetaFile ? aDestRectPixel : aDestRectPixel.GetIntersection(aOutputRectPixel));
+
+ if(!aCroppedRectPixel.IsEmpty())
+ {
+ // as maximum for destination, orientate at SourceSizePixel, but
+ // take a rotation of 45 degrees (sqrt(2)) as maximum expansion into account
+ const Size aSourceSizePixel(rBitmapEx.GetSizePixel());
+ const double fMaximumArea(
+ (double)aSourceSizePixel.getWidth() *
+ (double)aSourceSizePixel.getHeight() *
+ 1.4142136); // 1.4142136 taken as sqrt(2.0)
+
+ // test if discrete view size (pixel) maybe too big and limit it
+ const double fArea(aCroppedRectPixel.getWidth() * aCroppedRectPixel.getHeight());
+ const bool bNeedToReduce(fArea > fMaximumArea);
+ double fReduceFactor(1.0);
+
+ if(bNeedToReduce)
+ {
+ fReduceFactor = sqrt(fMaximumArea / fArea);
+ aCroppedRectPixel.setWidth(basegfx::fround(aCroppedRectPixel.getWidth() * fReduceFactor));
+ aCroppedRectPixel.setHeight(basegfx::fround(aCroppedRectPixel.getHeight() * fReduceFactor));
+ }
+
+ // build transform from pixel in aDestination to pixel in rBitmapEx
+ // from relative in aCroppedRectPixel to relative in aDestRectPixel
+ // No need to take bNeedToReduce into account, TopLeft is unchanged
+ basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(
+ aCroppedRectPixel.Left() - aDestRectPixel.Left(),
+ aCroppedRectPixel.Top() - aDestRectPixel.Top()));
+
+ // from relative in aDestRectPixel to absolute Logic. Here it
+ // is essential to adapt to reduce factor (if used)
+ double fAdaptedDRPWidth((double)aDestRectPixel.getWidth());
+ double fAdaptedDRPHeight((double)aDestRectPixel.getHeight());
+
+ if(bNeedToReduce)
+ {
+ fAdaptedDRPWidth *= fReduceFactor;
+ fAdaptedDRPHeight *= fReduceFactor;
+ }
+
+ aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix(
+ aDestRectLogic.getWidth() / fAdaptedDRPWidth, aDestRectLogic.getHeight() / fAdaptedDRPHeight,
+ aDestRectLogic.Left(), aDestRectLogic.Top())
+ * aTransform;
+
+ // from absolute in Logic to unified object coordinates (0.0 .. 1.0 in x and y)
+ basegfx::B2DHomMatrix aInvBitmapTransform(rTransform);
+ aInvBitmapTransform.invert();
+ aTransform = aInvBitmapTransform * aTransform;
+
+ // from unit object coordinates to rBitmapEx pixel coordintes
+ aTransform.scale(aSourceSizePixel.getWidth() - 1L, aSourceSizePixel.getHeight() - 1L);
+
+ // create bitmap using source, destination and linear back-transformation
+ BitmapEx aDestination = impTransformBitmapEx(rBitmapEx, aCroppedRectPixel, aTransform);
+
+ // paint
+ if(bNeedToReduce)
+ {
+ // paint in target size
+ const double fFactor(1.0 / fReduceFactor);
+ const Size aDestSizePixel(
+ basegfx::fround(aCroppedRectPixel.getWidth() * fFactor),
+ basegfx::fround(aCroppedRectPixel.getHeight() * fFactor));
+
+ if(bRecordToMetaFile)
+ {
+ rOutDev.DrawBitmapEx(
+ rOutDev.PixelToLogic(aCroppedRectPixel.TopLeft()),
+ rOutDev.PixelToLogic(aDestSizePixel),
+ aDestination);
+ }
+ else
+ {
+ const bool bWasEnabled(rOutDev.IsMapModeEnabled());
+ rOutDev.EnableMapMode(false);
+
+ rOutDev.DrawBitmapEx(
+ aCroppedRectPixel.TopLeft(),
+ aDestSizePixel,
+ aDestination);
+
+ rOutDev.EnableMapMode(bWasEnabled);
+ }
+ }
+ else
+ {
+ if(bRecordToMetaFile)
+ {
+ rOutDev.DrawBitmapEx(
+ rOutDev.PixelToLogic(aCroppedRectPixel.TopLeft()),
+ aDestination);
+ }
+ else
+ {
+ const bool bWasEnabled(rOutDev.IsMapModeEnabled());
+ rOutDev.EnableMapMode(false);
+
+ rOutDev.DrawBitmapEx(
+ aCroppedRectPixel.TopLeft(),
+ aDestination);
+
+ rOutDev.EnableMapMode(bWasEnabled);
+ }
+ }
+ }
+ }
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/vclhelperbitmaprender.hxx b/drawinglayer/source/processor2d/vclhelperbitmaprender.hxx
new file mode 100644
index 000000000000..915e40427aeb
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclhelperbitmaprender.hxx
@@ -0,0 +1,66 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPRENDER_HXX
+#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPRENDER_HXX
+
+#include <sal/types.h>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+class OutputDevice;
+class BitmapEx;
+namespace basegfx { class B2DHomMatrix; }
+
+//////////////////////////////////////////////////////////////////////////////
+// support methods for vcl direct gradient renderering
+
+namespace drawinglayer
+{
+ void RenderBitmapPrimitive2D_GraphicManager(
+ OutputDevice& rOutDev,
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DHomMatrix& rTransform);
+
+ void RenderBitmapPrimitive2D_BitmapEx(
+ OutputDevice& rOutDev,
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DHomMatrix& rTransform);
+
+ void RenderBitmapPrimitive2D_self(
+ OutputDevice& rOutDev,
+ const BitmapEx& rBitmapEx,
+ const basegfx::B2DHomMatrix& rTransform);
+
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPRENDER_HXX
+
+// eof
diff --git a/drawinglayer/source/processor2d/vclhelperbitmaptransform.cxx b/drawinglayer/source/processor2d/vclhelperbitmaptransform.cxx
new file mode 100644
index 000000000000..ce81fb73ed6f
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclhelperbitmaptransform.cxx
@@ -0,0 +1,431 @@
+/*************************************************************************
+ *
+ * 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 <vclhelperbitmaptransform.hxx>
+#include <vcl/bmpacc.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <basegfx/color/bcolormodifier.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// support for rendering Bitmap and BitmapEx contents
+
+namespace drawinglayer
+{
+ namespace
+ {
+ void impSmoothPoint(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
+ {
+ double fDeltaX(rSource.getX() - nIntX);
+ double fDeltaY(rSource.getY() - nIntY);
+ sal_Int32 nIndX(0L);
+ sal_Int32 nIndY(0L);
+
+ if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
+ {
+ nIndX++;
+ }
+ else if(fDeltaX < 0.0 && nIntX >= 1L)
+ {
+ fDeltaX = -fDeltaX;
+ nIndX--;
+ }
+
+ if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
+ {
+ nIndY++;
+ }
+ else if(fDeltaY < 0.0 && nIntY >= 1L)
+ {
+ fDeltaY = -fDeltaY;
+ nIndY--;
+ }
+
+ if(nIndX || nIndY)
+ {
+ const double fColorToReal(1.0 / 255.0);
+ double fR(rValue.GetRed() * fColorToReal);
+ double fG(rValue.GetGreen() * fColorToReal);
+ double fB(rValue.GetBlue() * fColorToReal);
+ double fRBottom(0.0), fGBottom(0.0), fBBottom(0.0);
+
+ if(nIndX)
+ {
+ const double fMulA(fDeltaX * fColorToReal);
+ double fMulB(1.0 - fDeltaX);
+ const BitmapColor aTopPartner(rRead.GetColor(nIntY, nIntX + nIndX));
+
+ fR = (fR * fMulB) + (aTopPartner.GetRed() * fMulA);
+ fG = (fG * fMulB) + (aTopPartner.GetGreen() * fMulA);
+ fB = (fB * fMulB) + (aTopPartner.GetBlue() * fMulA);
+
+ if(nIndY)
+ {
+ fMulB *= fColorToReal;
+ const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
+ const BitmapColor aBottomPartner(rRead.GetColor(nIntY + nIndY, nIntX + nIndX));
+
+ fRBottom = (aBottom.GetRed() * fMulB) + (aBottomPartner.GetRed() * fMulA);
+ fGBottom = (aBottom.GetGreen() * fMulB) + (aBottomPartner.GetGreen() * fMulA);
+ fBBottom = (aBottom.GetBlue() * fMulB) + (aBottomPartner.GetBlue() * fMulA);
+ }
+ }
+
+ if(nIndY)
+ {
+ if(!nIndX)
+ {
+ const BitmapColor aBottom(rRead.GetColor(nIntY + nIndY, nIntX));
+
+ fRBottom = aBottom.GetRed() * fColorToReal;
+ fGBottom = aBottom.GetGreen() * fColorToReal;
+ fBBottom = aBottom.GetBlue() * fColorToReal;
+ }
+
+ const double fMulB(1.0 - fDeltaY);
+
+ fR = (fR * fMulB) + (fRBottom * fDeltaY);
+ fG = (fG * fMulB) + (fGBottom * fDeltaY);
+ fB = (fB * fMulB) + (fBBottom * fDeltaY);
+ }
+
+ rValue.SetRed((sal_uInt8)(fR * 255.0));
+ rValue.SetGreen((sal_uInt8)(fG * 255.0));
+ rValue.SetBlue((sal_uInt8)(fB * 255.0));
+ }
+ }
+
+ void impSmoothIndex(BitmapColor& rValue, const basegfx::B2DPoint& rSource, sal_Int32 nIntX, sal_Int32 nIntY, BitmapReadAccess& rRead)
+ {
+ double fDeltaX(rSource.getX() - nIntX);
+ double fDeltaY(rSource.getY() - nIntY);
+ sal_Int32 nIndX(0L);
+ sal_Int32 nIndY(0L);
+
+ if(fDeltaX > 0.0 && nIntX + 1L < rRead.Width())
+ {
+ nIndX++;
+ }
+ else if(fDeltaX < 0.0 && nIntX >= 1L)
+ {
+ fDeltaX = -fDeltaX;
+ nIndX--;
+ }
+
+ if(fDeltaY > 0.0 && nIntY + 1L < rRead.Height())
+ {
+ nIndY++;
+ }
+ else if(fDeltaY < 0.0 && nIntY >= 1L)
+ {
+ fDeltaY = -fDeltaY;
+ nIndY--;
+ }
+
+ if(nIndX || nIndY)
+ {
+ const double fColorToReal(1.0 / 255.0);
+ double fVal(rValue.GetIndex() * fColorToReal);
+ double fValBottom(0.0);
+
+ if(nIndX)
+ {
+ const double fMulA(fDeltaX * fColorToReal);
+ double fMulB(1.0 - fDeltaX);
+ const BitmapColor aTopPartner(rRead.GetPixel(nIntY, nIntX + nIndX));
+
+ fVal = (fVal * fMulB) + (aTopPartner.GetIndex() * fMulA);
+
+ if(nIndY)
+ {
+ fMulB *= fColorToReal;
+ const BitmapColor aBottom(rRead.GetPixel(nIntY + nIndY, nIntX));
+ const BitmapColor aBottomPartner(rRead.GetPixel(nIntY + nIndY, nIntX + nIndX));
+
+ fValBottom = (aBottom.GetIndex() * fMulB) + (aBottomPartner.GetIndex() * fMulA);
+ }
+ }
+
+ if(nIndY)
+ {
+ if(!nIndX)
+ {
+ const BitmapColor aBottom(rRead.GetPixel(nIntY + nIndY, nIntX));
+
+ fValBottom = aBottom.GetIndex() * fColorToReal;
+ }
+
+ const double fMulB(1.0 - fDeltaY);
+
+ fVal = (fVal * fMulB) + (fValBottom * fDeltaY);
+ }
+
+ rValue.SetIndex((sal_uInt8)(fVal * 255.0));
+ }
+ }
+
+ void impTransformBitmap(const Bitmap& rSource, Bitmap& rDestination, const basegfx::B2DHomMatrix& rTransform, bool bSmooth)
+ {
+ BitmapWriteAccess* pWrite = rDestination.AcquireWriteAccess();
+
+ if(pWrite)
+ {
+ const Size aContentSizePixel(rSource.GetSizePixel());
+ BitmapReadAccess* pRead = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
+
+ if(pRead)
+ {
+ const Size aDestinationSizePixel(rDestination.GetSizePixel());
+ bool bWorkWithIndex(rDestination.GetBitCount() <= 8);
+ BitmapColor aOutside(pRead->GetBestMatchingColor(BitmapColor(0xff, 0xff, 0xff)));
+
+ for(sal_Int32 y(0L); y < aDestinationSizePixel.getHeight(); y++)
+ {
+ for(sal_Int32 x(0L); x < aDestinationSizePixel.getWidth(); x++)
+ {
+ const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
+ const sal_Int32 nIntX(basegfx::fround(aSourceCoor.getX()));
+
+ if(nIntX >= 0L && nIntX < aContentSizePixel.getWidth())
+ {
+ const sal_Int32 nIntY(basegfx::fround(aSourceCoor.getY()));
+
+ if(nIntY >= 0L && nIntY < aContentSizePixel.getHeight())
+ {
+ if(bWorkWithIndex)
+ {
+ BitmapColor aValue(pRead->GetPixel(nIntY, nIntX));
+
+ if(bSmooth)
+ {
+ impSmoothIndex(aValue, aSourceCoor, nIntX, nIntY, *pRead);
+ }
+
+ pWrite->SetPixel(y, x, aValue);
+ }
+ else
+ {
+ BitmapColor aValue(pRead->GetColor(nIntY, nIntX));
+
+ if(bSmooth)
+ {
+ impSmoothPoint(aValue, aSourceCoor, nIntX, nIntY, *pRead);
+ }
+
+ pWrite->SetPixel(y, x, aValue.IsIndex() ? aValue : pWrite->GetBestMatchingColor(aValue));
+ }
+
+ continue;
+ }
+ }
+
+ // here are outside pixels. Complete mask
+ if(bWorkWithIndex)
+ {
+ pWrite->SetPixel(y, x, aOutside);
+ }
+ }
+ }
+
+ delete pRead;
+ }
+
+ delete pWrite;
+ }
+ }
+
+ Bitmap impCreateEmptyBitmapWithPattern(const Bitmap& rSource, const Size& aTargetSizePixel)
+ {
+ Bitmap aRetval;
+ BitmapReadAccess* pReadAccess = (const_cast< Bitmap& >(rSource)).AcquireReadAccess();
+
+ if(pReadAccess)
+ {
+ if(rSource.GetBitCount() <= 8)
+ {
+ BitmapPalette aPalette(pReadAccess->GetPalette());
+ aRetval = Bitmap(aTargetSizePixel, rSource.GetBitCount(), &aPalette);
+ }
+ else
+ {
+ aRetval = Bitmap(aTargetSizePixel, rSource.GetBitCount());
+ }
+
+ delete pReadAccess;
+ }
+
+ return aRetval;
+ }
+ } // end of anonymous namespace
+} // end of namespace drawinglayer
+
+namespace drawinglayer
+{
+ BitmapEx impTransformBitmapEx(
+ const BitmapEx& rSource,
+ const Rectangle& rCroppedRectPixel,
+ const basegfx::B2DHomMatrix& rTransform)
+ {
+ // force destination to 24 bit, we want to smooth output
+ const Size aDestinationSize(rCroppedRectPixel.GetSize());
+ Bitmap aDestination(impCreateEmptyBitmapWithPattern(rSource.GetBitmap(), aDestinationSize));
+ static bool bDoSmoothAtAll(true);
+ impTransformBitmap(rSource.GetBitmap(), aDestination, rTransform, bDoSmoothAtAll);
+
+ // create mask
+ if(rSource.IsTransparent())
+ {
+ if(rSource.IsAlpha())
+ {
+ Bitmap aAlpha(impCreateEmptyBitmapWithPattern(rSource.GetAlpha().GetBitmap(), aDestinationSize));
+ impTransformBitmap(rSource.GetAlpha().GetBitmap(), aAlpha, rTransform, bDoSmoothAtAll);
+ return BitmapEx(aDestination, AlphaMask(aAlpha));
+ }
+ else
+ {
+ Bitmap aMask(impCreateEmptyBitmapWithPattern(rSource.GetMask(), aDestinationSize));
+ impTransformBitmap(rSource.GetMask(), aMask, rTransform, false);
+ return BitmapEx(aDestination, aMask);
+ }
+ }
+
+ return BitmapEx(aDestination);
+ }
+
+ BitmapEx impModifyBitmapEx(
+ const basegfx::BColorModifierStack& rBColorModifierStack,
+ const BitmapEx& rSource)
+ {
+ Bitmap aChangedBitmap(rSource.GetBitmap());
+ bool bDone(false);
+
+ for(sal_uInt32 a(rBColorModifierStack.count()); a && !bDone; )
+ {
+ const basegfx::BColorModifier& rModifier = rBColorModifierStack.getBColorModifier(--a);
+
+ switch(rModifier.getMode())
+ {
+ case basegfx::BCOLORMODIFYMODE_REPLACE :
+ {
+ // complete replace
+ if(rSource.IsTransparent())
+ {
+ // clear bitmap with dest color
+ if(aChangedBitmap.GetBitCount() <= 8)
+ {
+ // do NOT use erase; for e.g. 8bit Bitmaps, the nearest color to the given
+ // erase color is determined and used -> this may be different from what is
+ // wanted here. Better create a new bitmap with the needed color explicitely
+ BitmapReadAccess* pReadAccess = aChangedBitmap.AcquireReadAccess();
+ OSL_ENSURE(pReadAccess, "Got no Bitmap ReadAccess ?!?");
+
+ if(pReadAccess)
+ {
+ BitmapPalette aNewPalette(pReadAccess->GetPalette());
+ aNewPalette[0] = BitmapColor(Color(rModifier.getBColor()));
+ aChangedBitmap = Bitmap(
+ aChangedBitmap.GetSizePixel(),
+ aChangedBitmap.GetBitCount(),
+ &aNewPalette);
+ delete pReadAccess;
+ }
+ }
+ else
+ {
+ aChangedBitmap.Erase(Color(rModifier.getBColor()));
+ }
+ }
+ else
+ {
+ // erase bitmap, caller will know to paint direct
+ aChangedBitmap.SetEmpty();
+ }
+
+ bDone = true;
+ break;
+ }
+
+ default : // BCOLORMODIFYMODE_INTERPOLATE, BCOLORMODIFYMODE_GRAY, BCOLORMODIFYMODE_BLACKANDWHITE
+ {
+ BitmapWriteAccess* pContent = aChangedBitmap.AcquireWriteAccess();
+
+ if(pContent)
+ {
+ const double fConvertColor(1.0 / 255.0);
+
+ for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
+ {
+ for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
+ {
+ const BitmapColor aBMCol(pContent->GetColor(y, x));
+ const basegfx::BColor aBSource(
+ (double)aBMCol.GetRed() * fConvertColor,
+ (double)aBMCol.GetGreen() * fConvertColor,
+ (double)aBMCol.GetBlue() * fConvertColor);
+ const basegfx::BColor aBDest(rModifier.getModifiedColor(aBSource));
+
+ pContent->SetPixel(y, x, BitmapColor(Color(aBDest)));
+ }
+ }
+
+ delete pContent;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if(aChangedBitmap.IsEmpty())
+ {
+ return BitmapEx();
+ }
+ else
+ {
+ if(rSource.IsTransparent())
+ {
+ if(rSource.IsAlpha())
+ {
+ return BitmapEx(aChangedBitmap, rSource.GetAlpha());
+ }
+ else
+ {
+ return BitmapEx(aChangedBitmap, rSource.GetMask());
+ }
+ }
+ else
+ {
+ return BitmapEx(aChangedBitmap);
+ }
+ }
+ }
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/vclhelperbitmaptransform.hxx b/drawinglayer/source/processor2d/vclhelperbitmaptransform.hxx
new file mode 100644
index 000000000000..7a3df9e4fb06
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclhelperbitmaptransform.hxx
@@ -0,0 +1,60 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPTRANSFORM_HXX
+#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPTRANSFORM_HXX
+
+#include <vcl/bitmapex.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+namespace basegfx {
+ class B2DHomMatrix;
+ class BColorModifierStack;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// support methods for vcl direct gradient renderering
+
+namespace drawinglayer
+{
+ BitmapEx impTransformBitmapEx(
+ const BitmapEx& rSource,
+ const Rectangle& rCroppedRectPixel,
+ const basegfx::B2DHomMatrix& rTransform);
+
+ BitmapEx impModifyBitmapEx(
+ const basegfx::BColorModifierStack& rBColorModifierStack,
+ const BitmapEx& rSource);
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBITMAPTRANSFORM_HXX
+
+// eof
diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
new file mode 100644
index 000000000000..87b33b16c53d
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
@@ -0,0 +1,182 @@
+/*************************************************************************
+ *
+ * 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 <vclhelperbufferdevice.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <vcl/bitmapex.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <tools/stream.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// support for rendering Bitmap and BitmapEx contents
+
+namespace drawinglayer
+{
+ impBufferDevice::impBufferDevice(
+ OutputDevice& rOutDev,
+ const basegfx::B2DRange& rRange,
+ bool bAddOffsetToMapping)
+ : mrOutDev(rOutDev),
+ maContent(rOutDev),
+ mpMask(0L),
+ mpAlpha(0L)
+ {
+ basegfx::B2DRange aRangePixel(rRange);
+ aRangePixel.transform(rOutDev.GetViewTransformation());
+ const Rectangle aRectPixel(
+ (sal_Int32)floor(aRangePixel.getMinX()), (sal_Int32)floor(aRangePixel.getMinY()),
+ (sal_Int32)ceil(aRangePixel.getMaxX()), (sal_Int32)ceil(aRangePixel.getMaxY()));
+ const Point aEmptyPoint;
+ maDestPixel = Rectangle(aEmptyPoint, rOutDev.GetOutputSizePixel());
+ maDestPixel.Intersection(aRectPixel);
+
+ if(isVisible())
+ {
+ maContent.SetOutputSizePixel(maDestPixel.GetSize(), false);
+
+ // #i93485# assert when copying from window to VDev is used
+ OSL_ENSURE(rOutDev.GetOutDevType() != OUTDEV_WINDOW,
+ "impBufferDevice render helper: Copying from Window to VDev, this should be avoided (!)");
+
+ const bool bWasEnabledSrc(rOutDev.IsMapModeEnabled());
+ rOutDev.EnableMapMode(false);
+ maContent.DrawOutDev(aEmptyPoint, maDestPixel.GetSize(), maDestPixel.TopLeft(), maDestPixel.GetSize(), rOutDev);
+ rOutDev.EnableMapMode(bWasEnabledSrc);
+
+ MapMode aNewMapMode(rOutDev.GetMapMode());
+
+ if(bAddOffsetToMapping)
+ {
+ const Point aLogicTopLeft(rOutDev.PixelToLogic(maDestPixel.TopLeft()));
+ aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y()));
+ }
+
+ maContent.SetMapMode(aNewMapMode);
+
+ // copy AA flag for new target
+ maContent.SetAntialiasing(mrOutDev.GetAntialiasing());
+ }
+ }
+
+ impBufferDevice::~impBufferDevice()
+ {
+ delete mpMask;
+ delete mpAlpha;
+ }
+
+ void impBufferDevice::paint(double fTrans)
+ {
+ const Point aEmptyPoint;
+ const Size aSizePixel(maContent.GetOutputSizePixel());
+ const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled());
+ static bool bDoSaveForVisualControl(false);
+
+ mrOutDev.EnableMapMode(false);
+ maContent.EnableMapMode(false);
+ Bitmap aContent(maContent.GetBitmap(aEmptyPoint, aSizePixel));
+
+ if(bDoSaveForVisualControl)
+ {
+ SvFileStream aNew((const String&)String(ByteString( "c:\\content.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC);
+ aNew << aContent;
+ }
+
+ if(mpAlpha)
+ {
+ mpAlpha->EnableMapMode(false);
+ const AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));
+
+ if(bDoSaveForVisualControl)
+ {
+ SvFileStream aNew((const String&)String(ByteString( "c:\\transparence.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC);
+ aNew << aAlphaMask.GetBitmap();
+ }
+
+ mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
+ }
+ else if(mpMask)
+ {
+ mpMask->EnableMapMode(false);
+ const Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel));
+
+ if(bDoSaveForVisualControl)
+ {
+ SvFileStream aNew((const String&)String(ByteString( "c:\\mask.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC);
+ aNew << aMask;
+ }
+
+ mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
+ }
+ else if(0.0 != fTrans)
+ {
+ sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0));
+ const AlphaMask aAlphaMask(aSizePixel, &nMaskValue);
+ mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
+ }
+ else
+ {
+ mrOutDev.DrawBitmap(maDestPixel.TopLeft(), aContent);
+ }
+
+ mrOutDev.EnableMapMode(bWasEnabledDst);
+ }
+
+ VirtualDevice& impBufferDevice::getMask()
+ {
+ if(!mpMask)
+ {
+ mpMask = new VirtualDevice(mrOutDev, 1);
+ mpMask->SetOutputSizePixel(maDestPixel.GetSize(), true);
+ mpMask->SetMapMode(maContent.GetMapMode());
+
+ // do NOT copy AA flag for mask!
+ }
+
+ return *mpMask;
+ }
+
+ VirtualDevice& impBufferDevice::getTransparence()
+ {
+ if(!mpAlpha)
+ {
+ mpAlpha = new VirtualDevice();
+ mpAlpha->SetOutputSizePixel(maDestPixel.GetSize(), true);
+ mpAlpha->SetMapMode(maContent.GetMapMode());
+
+ // copy AA flag for new target; masking needs to be smooth
+ mpAlpha->SetAntialiasing(maContent.GetAntialiasing());
+ }
+
+ return *mpAlpha;
+ }
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
new file mode 100644
index 000000000000..857b673e36ad
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
@@ -0,0 +1,70 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBUFFERDEVICE_HXX
+#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBUFFERDEVICE_HXX
+
+#include <vcl/virdev.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+namespace basegfx { class B2DRange; }
+
+//////////////////////////////////////////////////////////////////////////////
+// support methods for vcl direct gradient renderering
+
+namespace drawinglayer
+{
+ class impBufferDevice
+ {
+ OutputDevice& mrOutDev;
+ VirtualDevice maContent;
+ VirtualDevice* mpMask;
+ VirtualDevice* mpAlpha;
+ Rectangle maDestPixel;
+
+ public:
+ impBufferDevice(
+ OutputDevice& rOutDev,
+ const basegfx::B2DRange& rRange,
+ bool bAddOffsetToMapping);
+ ~impBufferDevice();
+
+ void paint(double fTrans = 0.0);
+ bool isVisible() const { return !maDestPixel.IsEmpty(); }
+ VirtualDevice& getContent() { return maContent; }
+ VirtualDevice& getMask();
+ VirtualDevice& getTransparence();
+ };
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERBUFFERDEVICE_HXX
+
+// eof
diff --git a/drawinglayer/source/processor2d/vclhelpergradient.cxx b/drawinglayer/source/processor2d/vclhelpergradient.cxx
new file mode 100644
index 000000000000..6c318dbcedc9
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclhelpergradient.cxx
@@ -0,0 +1,285 @@
+/*************************************************************************
+ *
+ * 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 <vclhelpergradient.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <vcl/outdev.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/texture/texture.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// support methods for vcl direct gradient renderering
+
+namespace drawinglayer
+{
+ namespace
+ {
+ sal_uInt32 impCalcGradientSteps(OutputDevice& rOutDev, sal_uInt32 nSteps, const basegfx::B2DRange& rRange, sal_uInt32 nMaxDist)
+ {
+ if(nSteps == 0L)
+ {
+ const Size aSize(rOutDev.LogicToPixel(Size(basegfx::fround(rRange.getWidth()), basegfx::fround(rRange.getHeight()))));
+ nSteps = (aSize.getWidth() + aSize.getHeight()) >> 3L;
+ }
+
+ if(nSteps < 2L)
+ {
+ nSteps = 2L;
+ }
+
+ if(nSteps > nMaxDist)
+ {
+ nSteps = nMaxDist;
+ }
+
+ return nSteps;
+ }
+
+ void impDrawGradientToOutDevSimple(
+ OutputDevice& rOutDev,
+ const basegfx::B2DPolyPolygon& rTargetForm,
+ const ::std::vector< basegfx::B2DHomMatrix >& rMatrices,
+ const ::std::vector< basegfx::BColor >& rColors,
+ const basegfx::B2DPolygon& rUnitPolygon)
+ {
+ rOutDev.SetLineColor();
+
+ for(sal_uInt32 a(0L); a < rColors.size(); a++)
+ {
+ // set correct color
+ const basegfx::BColor aFillColor(rColors[a]);
+ rOutDev.SetFillColor(Color(aFillColor));
+
+ if(a)
+ {
+ if(a - 1L < static_cast< sal_uInt32 >(rMatrices.size()))
+ {
+ basegfx::B2DPolygon aNewPoly(rUnitPolygon);
+ aNewPoly.transform(rMatrices[a - 1L]);
+ rOutDev.DrawPolygon(aNewPoly);
+ }
+ }
+ else
+ {
+ rOutDev.DrawPolyPolygon(rTargetForm);
+ }
+ }
+ }
+
+ void impDrawGradientToOutDevComplex(
+ OutputDevice& rOutDev,
+ const basegfx::B2DPolyPolygon& rTargetForm,
+ const ::std::vector< basegfx::B2DHomMatrix >& rMatrices,
+ const ::std::vector< basegfx::BColor >& rColors,
+ const basegfx::B2DPolygon& rUnitPolygon)
+ {
+ PolyPolygon aVclTargetForm(rTargetForm);
+ ::std::vector< Polygon > aVclPolygons;
+ sal_uInt32 a;
+
+ // remember and set to XOR
+ rOutDev.SetLineColor();
+ rOutDev.Push(PUSH_RASTEROP);
+ rOutDev.SetRasterOp(ROP_XOR);
+
+ // draw gradient PolyPolygons
+ for(a = 0L; a < rMatrices.size(); a++)
+ {
+ // create polygon and remember
+ basegfx::B2DPolygon aNewPoly(rUnitPolygon);
+ aNewPoly.transform(rMatrices[a]);
+ aVclPolygons.push_back(Polygon(aNewPoly));
+
+ // set correct color
+ if(rColors.size() > a)
+ {
+ const basegfx::BColor aFillColor(rColors[a]);
+ rOutDev.SetFillColor(Color(aFillColor));
+ }
+
+ // create vcl PolyPolygon and draw it
+ if(a)
+ {
+ PolyPolygon aVclPolyPoly(aVclPolygons[a - 1L]);
+ aVclPolyPoly.Insert(aVclPolygons[a]);
+ rOutDev.DrawPolyPolygon(aVclPolyPoly);
+ }
+ else
+ {
+ PolyPolygon aVclPolyPoly(aVclTargetForm);
+ aVclPolyPoly.Insert(aVclPolygons[0L]);
+ rOutDev.DrawPolyPolygon(aVclPolyPoly);
+ }
+ }
+
+ // draw last poly in last color
+ if(rColors.size())
+ {
+ const basegfx::BColor aFillColor(rColors[rColors.size() - 1L]);
+ rOutDev.SetFillColor(Color(aFillColor));
+ rOutDev.DrawPolygon(aVclPolygons[aVclPolygons.size() - 1L]);
+ }
+
+ // draw object form in black and go back to XOR
+ rOutDev.SetFillColor(COL_BLACK);
+ rOutDev.SetRasterOp(ROP_0);
+ rOutDev.DrawPolyPolygon(aVclTargetForm);
+ rOutDev.SetRasterOp(ROP_XOR);
+
+ // draw gradient PolyPolygons again
+ for(a = 0L; a < rMatrices.size(); a++)
+ {
+ // set correct color
+ if(rColors.size() > a)
+ {
+ const basegfx::BColor aFillColor(rColors[a]);
+ rOutDev.SetFillColor(Color(aFillColor));
+ }
+
+ // create vcl PolyPolygon and draw it
+ if(a)
+ {
+ PolyPolygon aVclPolyPoly(aVclPolygons[a - 1L]);
+ aVclPolyPoly.Insert(aVclPolygons[a]);
+ rOutDev.DrawPolyPolygon(aVclPolyPoly);
+ }
+ else
+ {
+ PolyPolygon aVclPolyPoly(aVclTargetForm);
+ aVclPolyPoly.Insert(aVclPolygons[0L]);
+ rOutDev.DrawPolyPolygon(aVclPolyPoly);
+ }
+ }
+
+ // draw last poly in last color
+ if(rColors.size())
+ {
+ const basegfx::BColor aFillColor(rColors[rColors.size() - 1L]);
+ rOutDev.SetFillColor(Color(aFillColor));
+ rOutDev.DrawPolygon(aVclPolygons[aVclPolygons.size() - 1L]);
+ }
+
+ // reset drawmode
+ rOutDev.Pop();
+ }
+ } // end of anonymous namespace
+} // end of namespace drawinglayer
+
+namespace drawinglayer
+{
+ void impDrawGradientToOutDev(
+ OutputDevice& rOutDev,
+ const basegfx::B2DPolyPolygon& rTargetForm,
+ attribute::GradientStyle eGradientStyle,
+ sal_uInt32 nSteps,
+ const basegfx::BColor& rStart,
+ const basegfx::BColor& rEnd,
+ double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple)
+ {
+ const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(rTargetForm));
+ ::std::vector< basegfx::B2DHomMatrix > aMatrices;
+ ::std::vector< basegfx::BColor > aColors;
+ basegfx::B2DPolygon aUnitPolygon;
+
+ // make sure steps is not too high/low
+ nSteps = impCalcGradientSteps(rOutDev, nSteps, aOutlineRange, sal_uInt32((rStart.getMaximumDistance(rEnd) * 127.5) + 0.5));
+
+ // create geometries
+ switch(eGradientStyle)
+ {
+ case attribute::GRADIENTSTYLE_LINEAR:
+ {
+ texture::GeoTexSvxGradientLinear aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ aUnitPolygon = basegfx::tools::createUnitPolygon();
+ break;
+ }
+ case attribute::GRADIENTSTYLE_AXIAL:
+ {
+ texture::GeoTexSvxGradientAxial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(-1, -1, 1, 1));
+ break;
+ }
+ case attribute::GRADIENTSTYLE_RADIAL:
+ {
+ texture::GeoTexSvxGradientRadial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetY);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ aUnitPolygon = basegfx::tools::createPolygonFromCircle(basegfx::B2DPoint(0,0), 1);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_ELLIPTICAL:
+ {
+ texture::GeoTexSvxGradientElliptical aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ aUnitPolygon = basegfx::tools::createPolygonFromCircle(basegfx::B2DPoint(0,0), 1);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_SQUARE:
+ {
+ texture::GeoTexSvxGradientSquare aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(-1, -1, 1, 1));
+ break;
+ }
+ case attribute::GRADIENTSTYLE_RECT:
+ {
+ texture::GeoTexSvxGradientRect aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ aUnitPolygon = basegfx::tools::createPolygonFromRect(basegfx::B2DRange(-1, -1, 1, 1));
+ break;
+ }
+ }
+
+ // paint them with mask using the XOR method
+ if(aMatrices.size())
+ {
+ if(bSimple)
+ {
+ impDrawGradientToOutDevSimple(rOutDev, rTargetForm, aMatrices, aColors, aUnitPolygon);
+ }
+ else
+ {
+ impDrawGradientToOutDevComplex(rOutDev, rTargetForm, aMatrices, aColors, aUnitPolygon);
+ }
+ }
+ }
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/vclhelpergradient.hxx b/drawinglayer/source/processor2d/vclhelpergradient.hxx
new file mode 100644
index 000000000000..d02b20d54e4e
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclhelpergradient.hxx
@@ -0,0 +1,62 @@
+/*************************************************************************
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERGRADIENT_HXX
+#define INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERGRADIENT_HXX
+
+#include <sal/types.h>
+#include <drawinglayer/attribute/fillgradientattribute.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// predefines
+
+class OutputDevice;
+namespace basegfx {
+ class B2DPolyPolygon;
+ class BColor;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// support methods for vcl direct gradient renderering
+
+namespace drawinglayer
+{
+ void impDrawGradientToOutDev(
+ OutputDevice& rOutDev,
+ const basegfx::B2DPolyPolygon& rTargetForm,
+ attribute::GradientStyle eGradientStyle,
+ sal_uInt32 nSteps,
+ const basegfx::BColor& rStart,
+ const basegfx::BColor& rEnd,
+ double fBorder, double fAngle, double fOffsetX, double fOffsetY, bool bSimple);
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+#endif // INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLHELPERGRADIENT_HXX
+
+// eof
diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
new file mode 100644
index 000000000000..263cdeede4f8
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -0,0 +1,2030 @@
+/*************************************************************************
+ *
+ * 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/processor2d/vclmetafileprocessor2d.hxx>
+#include <tools/gen.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/gradient.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <drawinglayer/processor2d/vclpixelprocessor2d.hxx>
+#include <tools/stream.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <vcl/graphictools.hxx>
+#include <vcl/metaact.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
+#include <comphelper/processfactory.hxx>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/i18n/CharacterIteratorMode.hdl>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
+#include <helperchartrenderer.hxx>
+#include <drawinglayer/primitive2d/epsprimitive2d.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// for PDFExtOutDevData Graphic support
+
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <toolkit/helper/formpdfexport.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// for Control printing
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+//////////////////////////////////////////////////////////////////////////////
+// for current chart PrettyPrinting support
+
+#include <drawinglayer/primitive2d/chartprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// for StructureTagPrimitive support in sd's unomodel.cxx
+
+#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+// #112245# definition for maximum allowed point count due to Metafile target.
+// To be on the safe side with the old tools polygon, use slightly less then
+// the theoretical maximum (bad experiences with tools polygon)
+
+#define MAX_POLYGON_POINT_COUNT_METAFILE (0x0000fff0)
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+ // #112245# helper to split line polygon in half
+ void splitLinePolygon(
+ const basegfx::B2DPolygon& rBasePolygon,
+ basegfx::B2DPolygon& o_aLeft,
+ basegfx::B2DPolygon& o_aRight)
+ {
+ const sal_uInt32 nCount(rBasePolygon.count());
+
+ if(nCount)
+ {
+ const sal_uInt32 nHalfCount((nCount - 1) >> 1);
+
+ o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
+ o_aLeft.setClosed(false);
+
+ o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
+ o_aRight.setClosed(false);
+
+ if(rBasePolygon.isClosed())
+ {
+ o_aRight.append(rBasePolygon.getB2DPoint(0));
+
+ if(rBasePolygon.areControlPointsUsed())
+ {
+ o_aRight.setControlPoints(
+ o_aRight.count() - 1,
+ rBasePolygon.getPrevControlPoint(0),
+ rBasePolygon.getNextControlPoint(0));
+ }
+ }
+ }
+ else
+ {
+ o_aLeft.clear();
+ o_aRight.clear();
+ }
+ }
+
+ // #112245# helper to evtl. split filled polygons to maximum metafile point count
+ bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
+ {
+ bool bRetval(false);
+ const sal_uInt32 nPolyCount(rPolyPolygon.count());
+
+ if(nPolyCount)
+ {
+ basegfx::B2DPolyPolygon aSplitted;
+
+ for(sal_uInt32 a(0); a < nPolyCount; a++)
+ {
+ const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
+ const sal_uInt32 nPointCount(aCandidate.count());
+ bool bNeedToSplit(false);
+
+ if(aCandidate.areControlPointsUsed())
+ {
+ // compare with the maximum for bezier curved polygons
+ bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L);
+ }
+ else
+ {
+ // compare with the maximum for simple point polygons
+ bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
+ }
+
+ if(bNeedToSplit)
+ {
+ // need to split the partial polygon
+ const basegfx::B2DRange aRange(aCandidate.getB2DRange());
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
+
+ if(aRange.getWidth() > aRange.getHeight())
+ {
+ // clip in left and right
+ const basegfx::B2DPolyPolygon aLeft(
+ basegfx::tools::clipPolygonOnParallelAxis(
+ aCandidate,
+ false,
+ true,
+ aCenter.getX(),
+ false));
+ const basegfx::B2DPolyPolygon aRight(
+ basegfx::tools::clipPolygonOnParallelAxis(
+ aCandidate,
+ false,
+ false,
+ aCenter.getX(),
+ false));
+
+ aSplitted.append(aLeft);
+ aSplitted.append(aRight);
+ }
+ else
+ {
+ // clip in top and bottom
+ const basegfx::B2DPolyPolygon aTop(
+ basegfx::tools::clipPolygonOnParallelAxis(
+ aCandidate,
+ true,
+ true,
+ aCenter.getY(),
+ false));
+ const basegfx::B2DPolyPolygon aBottom(
+ basegfx::tools::clipPolygonOnParallelAxis(
+ aCandidate,
+ true,
+ false,
+ aCenter.getY(),
+ false));
+
+ aSplitted.append(aTop);
+ aSplitted.append(aBottom);
+ }
+ }
+ else
+ {
+ aSplitted.append(aCandidate);
+ }
+ }
+
+ if(aSplitted.count() != nPolyCount)
+ {
+ rPolyPolygon = aSplitted;
+ }
+ }
+
+ return bRetval;
+ }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
+ const primitive2d::Primitive2DSequence& rContent,
+ GDIMetaFile& o_rContentMetafile)
+ {
+ // Prepare VDev, MetaFile and connections
+ OutputDevice* pLastOutputDevice = mpOutputDevice;
+ GDIMetaFile* pLastMetafile = mpMetaFile;
+ basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
+
+ // transform primitive range with current transformation (e.g shadow offset)
+ aPrimitiveRange.transform(maCurrentTransformation);
+
+ const Rectangle aPrimitiveRectangle(
+ basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
+ basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
+ VirtualDevice aContentVDev;
+ MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
+
+ mpOutputDevice = &aContentVDev;
+ mpMetaFile = &o_rContentMetafile;
+ aContentVDev.EnableOutput(false);
+ aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode());
+ o_rContentMetafile.Record(&aContentVDev);
+ aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor());
+ aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor());
+ aContentVDev.SetFont(pLastOutputDevice->GetFont());
+ aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode());
+ aContentVDev.SetSettings(pLastOutputDevice->GetSettings());
+ aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint());
+
+ // dump to MetaFile
+ process(rContent);
+
+ // cleanups
+ o_rContentMetafile.Stop();
+ o_rContentMetafile.WindStart();
+ aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
+ o_rContentMetafile.SetPrefMapMode(aNewMapMode);
+ o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
+ mpOutputDevice = pLastOutputDevice;
+ mpMetaFile = pLastMetafile;
+
+ return aPrimitiveRectangle;
+ }
+
+ void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
+ Gradient& o_rVCLGradient,
+ const attribute::FillGradientAttribute& rFiGrAtt,
+ bool bIsTransparenceGradient)
+ {
+ if(bIsTransparenceGradient)
+ {
+ // it's about transparence channel intensities (black/white), do not use color modifier
+ o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
+ o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
+ }
+ else
+ {
+ // use color modifier to influence start/end color of gradient
+ o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
+ o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
+ }
+
+ o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
+ o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0));
+ o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0));
+ o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0));
+ o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
+
+ // defaults for intensity; those were computed into the start/end colors already
+ o_rVCLGradient.SetStartIntensity(100);
+ o_rVCLGradient.SetEndIntensity(100);
+
+ switch(rFiGrAtt.getStyle())
+ {
+ default : // attribute::GRADIENTSTYLE_LINEAR :
+ {
+ o_rVCLGradient.SetStyle(GRADIENT_LINEAR);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_AXIAL :
+ {
+ o_rVCLGradient.SetStyle(GRADIENT_AXIAL);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_RADIAL :
+ {
+ o_rVCLGradient.SetStyle(GRADIENT_RADIAL);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_ELLIPTICAL :
+ {
+ o_rVCLGradient.SetStyle(GRADIENT_ELLIPTICAL);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_SQUARE :
+ {
+ o_rVCLGradient.SetStyle(GRADIENT_SQUARE);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_RECT :
+ {
+ o_rVCLGradient.SetStyle(GRADIENT_RECT);
+ break;
+ }
+ }
+ }
+
+ void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
+ {
+ if(pSvtGraphicFill && !mnSvtGraphicFillCount)
+ {
+ SvMemoryStream aMemStm;
+
+ aMemStm << *pSvtGraphicFill;
+ mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const BYTE* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
+ mnSvtGraphicFillCount++;
+ }
+ }
+
+ void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
+ {
+ if(pSvtGraphicFill && mnSvtGraphicFillCount)
+ {
+ mnSvtGraphicFillCount--;
+ mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
+ delete pSvtGraphicFill;
+ }
+ }
+
+ SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
+ const basegfx::B2DPolygon& rB2DPolygon,
+ const basegfx::BColor* pColor,
+ const attribute::LineAttribute* pLineAttribute,
+ const attribute::StrokeAttribute* pStrokeAttribute,
+ const attribute::LineStartEndAttribute* pStart,
+ const attribute::LineStartEndAttribute* pEnd)
+ {
+ SvtGraphicStroke* pRetval = 0;
+
+ if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
+ {
+ basegfx::BColor aStrokeColor;
+ basegfx::B2DPolyPolygon aStartArrow;
+ basegfx::B2DPolyPolygon aEndArrow;
+
+ if(pColor)
+ {
+ aStrokeColor = *pColor;
+ }
+ else if(pLineAttribute)
+ {
+ aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
+ }
+
+ // It IS needed to record the stroke color at all in the metafile,
+ // SvtGraphicStroke has NO entry for stroke color(!)
+ mpOutputDevice->SetLineColor(Color(aStrokeColor));
+
+ if(!rB2DPolygon.isClosed())
+ {
+ double fPolyLength(0.0);
+
+ if(pStart && pStart->isActive())
+ {
+ fPolyLength = basegfx::tools::getLength(rB2DPolygon);
+
+ aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
+ rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
+ fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0);
+ }
+
+ if(pEnd && pEnd->isActive())
+ {
+ if(basegfx::fTools::equalZero(fPolyLength))
+ {
+ fPolyLength = basegfx::tools::getLength(rB2DPolygon);
+ }
+
+ aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
+ rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(),
+ fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0);
+ }
+ }
+
+ SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
+ double fLineWidth(0.0);
+ double fMiterLength(0.0);
+ SvtGraphicStroke::DashArray aDashArray;
+
+ if(pLineAttribute)
+ {
+ // pre-fill fLineWidth
+ fLineWidth = pLineAttribute->getWidth();
+
+ // pre-fill fMiterLength
+ fMiterLength = fLineWidth;
+
+ // get Join
+ switch(pLineAttribute->getLineJoin())
+ {
+ default : // basegfx::B2DLINEJOIN_NONE :
+ {
+ eJoin = SvtGraphicStroke::joinNone;
+ break;
+ }
+ case basegfx::B2DLINEJOIN_BEVEL :
+ {
+ eJoin = SvtGraphicStroke::joinBevel;
+ break;
+ }
+ case basegfx::B2DLINEJOIN_MIDDLE :
+ case basegfx::B2DLINEJOIN_MITER :
+ {
+ eJoin = SvtGraphicStroke::joinMiter;
+ // ATM 15 degrees is assumed
+ fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0));
+ break;
+ }
+ case basegfx::B2DLINEJOIN_ROUND :
+ {
+ eJoin = SvtGraphicStroke::joinRound;
+ break;
+ }
+ }
+ }
+
+ if(pStrokeAttribute)
+ {
+ // copy dash array
+ aDashArray = pStrokeAttribute->getDotDashArray();
+ }
+
+ // #i101734# apply current object transformation to created geometry.
+ // This is a partial fix. When a object transformation is used which
+ // e.g. contains a scaleX != scaleY, an unproportional scaling would
+ // have to be applied to the evtl. existing fat line. The current
+ // concept of PDF export and SvtGraphicStroke usage does simply not
+ // allow handling such definitions. The only clean way would be to
+ // add the transformation to SvtGraphicStroke and to handle it there
+ basegfx::B2DPolygon aB2DPolygon(rB2DPolygon);
+
+ aB2DPolygon.transform(maCurrentTransformation);
+ aStartArrow.transform(maCurrentTransformation);
+ aEndArrow.transform(maCurrentTransformation);
+
+ pRetval = new SvtGraphicStroke(
+ Polygon(aB2DPolygon),
+ PolyPolygon(aStartArrow),
+ PolyPolygon(aEndArrow),
+ mfCurrentUnifiedTransparence,
+ fLineWidth,
+ SvtGraphicStroke::capButt,
+ eJoin,
+ fMiterLength,
+ aDashArray);
+ }
+
+ return pRetval;
+ }
+
+ void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
+ {
+ if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
+ {
+ SvMemoryStream aMemStm;
+
+ aMemStm << *pSvtGraphicStroke;
+ mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const BYTE* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
+ mnSvtGraphicStrokeCount++;
+ }
+ }
+
+ void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
+ {
+ if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
+ {
+ mnSvtGraphicStrokeCount--;
+ mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
+ delete pSvtGraphicStroke;
+ }
+ }
+
+ // init static break iterator
+ uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator;
+
+ VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
+ : VclProcessor2D(rViewInformation, rOutDev),
+ mpMetaFile(rOutDev.GetConnectMetaFile()),
+ mnSvtGraphicFillCount(0),
+ mnSvtGraphicStrokeCount(0),
+ mfCurrentUnifiedTransparence(0.0),
+ mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData()))
+ {
+ OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
+ // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
+ // but only to ObjectTransformation. Do not change MapMode of destination.
+ maCurrentTransformation = rViewInformation.getObjectTransformation();
+ }
+
+ VclMetafileProcessor2D::~VclMetafileProcessor2D()
+ {
+ // MapMode was not changed, no restore necessary
+ }
+
+ /***********************************************************************************************
+
+ Support of MetaCommentActions in the VclMetafileProcessor2D
+ Found MetaCommentActions and how they are supported:
+
+ XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
+
+ Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
+ It is used in various exporters/importers to have direct access to the gradient before it
+ is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
+ the Metafile to SdrObject import creates it's gradient objects.
+ Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
+ map it back to the corresponding tools PolyPolygon and the Gradient and just call
+ OutputDevice::DrawGradient which creates the necessary compatible actions.
+
+ XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
+
+ Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
+ inside GDIMetaFile::Rotate, nothing to take care of here.
+ The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
+ with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
+ XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
+ to the comment action. A closing end token is created in the destructor.
+ Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
+ SdrRectObj.
+ The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
+ of filled objects, even simple colored polygons. It is added as extra information; the
+ Metafile actions between the two tokens are interpreted as output generated from those
+ fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
+ actions.
+ Even for XFillTransparenceItem it is used, thus it may need to be supported in
+ UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon.
+ Implemented for:
+ PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D,
+ PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
+ PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
+ PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
+ and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence
+
+ XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
+
+ Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
+ is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
+ contained path accordingly.
+ The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and
+ only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
+ would hinder to make use of PolyPolygon strokes. I will need to add support at:
+ PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
+ PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
+ PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
+ This can be done hierarchical, too.
+ Okay, base implementation done based on those three primitives.
+
+ FIELD_SEQ_BEGIN, FIELD_SEQ_END
+
+ Used from slideshow for URLs, created from diverse SvxField implementations inside
+ createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
+ inside ImpEditEngine::Paint.
+ Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps
+ text primitives (but is not limited to that). It contains the field type if special actions for the
+ support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
+ needed, it may be supported there.
+ FIELD_SEQ_BEGIN;PageField
+ FIELD_SEQ_END
+ Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
+
+ XTEXT
+
+ XTEXT_EOC(i) end of character
+ XTEXT_EOW(i) end of word
+ XTEXT_EOS(i) end of sentence
+
+ this three are with index and are created with the help of a i18n::XBreakIterator in
+ ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
+ data structure for holding those TEXT infos.
+ Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
+ primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
+ that this creations do not need to be done for all paints all the time. This would be
+ expensive since the BreakIterator and it's usage is expensive and for each paint also the
+ whole character stops would need to be created.
+ Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
+
+ XTEXT_EOL() end of line
+ XTEXT_EOP() end of paragraph
+
+ First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
+ i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
+ namely:
+ - TextHierarchyLinePrimitive2D: Encapsulates single line
+ - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
+ - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
+ Those are now supported in hierarchy. This means the MetaFile renderer will support them
+ by using them, reculrively using their content and adding MetaFile comments as needed.
+ This also means that when another text layouter will be used it will be necessary to
+ create/support the same HierarchyPrimitives to support users.
+ To transport the information using this hierarchy is best suited to all future needs;
+ the slideshow will be able to profit from it directly when using primitives; all other
+ renderers not interested in the text structure will just ignore the encapsulations.
+
+ XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
+ Supported now by the TextHierarchyBlockPrimitive2D.
+
+ EPSReplacementGraphic:
+ Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
+ hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
+ used to export the original again (if exists).
+ Not necessary to support with MetaFuleRenderer.
+
+ XTEXT_SCROLLRECT, XTEXT_PAINTRECT
+ Currently used to get extra MetaFile infos using GraphicExporter which again uses
+ SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
+ the rectangle data is added directly by the GraphicsExporter as comment. Does not need
+ to be adapted at once.
+ When adapting later, the only user - the diashow - should directly use the provided
+ Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
+
+ PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
+ VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
+ a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
+ was explicitely created for the printer already again to some default maximum
+ bitmap sizes.
+ Nothing to do here for the primitive renderer.
+
+ Support for vcl::PDFExtOutDevData:
+ PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
+ the OutDev. When set, some extra data is written there. Trying simple PDF export and
+ watching if i get those infos.
+ Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
+ the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
+ if i get a PDFExtOutDevData at the target output device.
+ Indeed, i get one. Checking what all may be done when that extra-device-info is there.
+
+ All in all i have to talk to SJ. I will need to emulate some of those actions, but
+ i need to discuss which ones.
+ In the future, all those infos would be taken from the primitive sequence anyways,
+ thus these extensions would potentially be temporary, too.
+ Discussed with SJ, added the necessary support and tested it. Details follow.
+
+ - In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
+ Added in primitive MetaFile renderer.
+ Checking URL: Indeed, current version exports it, but it is missing in primitive
+ CWS version. Adding support.
+ Okay, URLs work. Checked, Done.
+
+ - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
+ target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
+ This may be added in primitive MetaFile renderer.
+ Adding support...
+ OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
+ svxform. Have to talk to FS if this has to be like that. Especially since
+ ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
+ Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
+ that stuff to somewhere else, maybe tools or svtools ?!? We will see...
+ Moved to toolkit, so i have to link against it. I tried VCL first, but it did
+ not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name
+ may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
+ the lowest move,ment plave is toolkit.
+ Checked form control export, it works well. Done.
+
+ - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
+ generated. I will need to check what happens here with primitives.
+ To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
+ Added support, but feature is broken in main version, so i cannot test at all.
+ Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
+ SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
+ as intended, the original file is exported. Works, Done.
+
+
+
+
+ To be done:
+
+ - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
+
+
+
+ ****************************************************************************************************/
+
+ void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+ {
+ switch(rCandidate.getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+ {
+ // directdraw of wrong spell primitive
+ // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
+ break;
+ }
+ case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
+ {
+ const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate);
+ bool bUsingPDFExtOutDevData(false);
+ basegfx::B2DVector aTranslate, aScale;
+ static bool bSuppressPDFExtOutDevDataSupport(false);
+
+ if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
+ {
+ // emulate data handling from UnoControlPDFExportContact, original see
+ // svtools/source/graphic/grfmgr.cxx
+ const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
+
+ if(rGraphic.IsLink())
+ {
+ const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
+
+ if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
+ {
+ const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
+ double fRotate, fShearX;
+ rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) )
+ {
+ bUsingPDFExtOutDevData = true;
+ mpPDFExtOutDevData->BeginGroup();
+ }
+ }
+ }
+ }
+
+ // process recursively and add MetaFile comment
+ process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D()));
+
+ if(bUsingPDFExtOutDevData)
+ {
+ // emulate data handling from UnoControlPDFExportContact, original see
+ // svtools/source/graphic/grfmgr.cxx
+ const basegfx::B2DRange aCurrentRange(
+ aTranslate.getX(), aTranslate.getY(),
+ aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
+ const Rectangle aCurrentRect(
+ sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
+ sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
+ const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
+ Rectangle aCropRect;
+
+ if(rAttr.IsCropped())
+ {
+ // calculate scalings between real image size and logic object size. This
+ // is necessary since the crop values are relative to original bitmap size
+ double fFactorX(1.0);
+ double fFactorY(1.0);
+
+ {
+ const MapMode aMapMode100thmm(MAP_100TH_MM);
+ const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic(
+ rGraphicPrimitive.getGraphicObject().GetPrefSize(),
+ rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
+ const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
+ const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
+
+ if(!basegfx::fTools::equalZero(fDivX))
+ {
+ fFactorX = aScale.getX() / fDivX;
+ }
+
+ if(!basegfx::fTools::equalZero(fDivY))
+ {
+ fFactorY = aScale.getY() / fDivY;
+ }
+ }
+
+ // calculate crop range and rect
+ basegfx::B2DRange aCropRange;
+ aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
+ aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
+
+ aCropRect = Rectangle(
+ sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
+ sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
+ }
+
+ mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
+ rAttr.GetTransparency(),
+ aCurrentRect,
+ aCropRect);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
+ {
+ const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
+ const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
+ bool bIsPrintableControl(false);
+
+ // find out if control is printable
+ if(rXControl.is())
+ {
+ try
+ {
+ uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is()
+ ? xModelProperties->getPropertySetInfo()
+ : uno::Reference< beans::XPropertySetInfo >());
+ const ::rtl::OUString sPrintablePropertyName(RTL_CONSTASCII_USTRINGPARAM("Printable"));
+
+ if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
+ {
+ OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
+ }
+ }
+ catch(const uno::Exception&)
+ {
+ OSL_ENSURE(false, "VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
+ }
+ }
+
+ // PDF export and printing only for printable controls
+ if(bIsPrintableControl)
+ {
+ const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
+ bool bDoProcessRecursively(true);
+
+ if(bPDFExport)
+ {
+ // PDF export. Emulate data handling from UnoControlPDFExportContact
+ // I have now moved describePDFControl to toolkit, thus i can implement the PDF
+ // form control support now as follows
+ ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl;
+ ::toolkitform::describePDFControl(rXControl, pPDFControl);
+
+ if(pPDFControl.get())
+ {
+ // still need to fill in the location (is a class Rectangle)
+ const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
+ const Rectangle aRectLogic(
+ (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()),
+ (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY()));
+ pPDFControl->Location = aRectLogic;
+
+ Size aFontSize(pPDFControl->TextFont.GetSize());
+ aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode());
+ pPDFControl->TextFont.SetSize(aFontSize);
+
+ mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
+ mpPDFExtOutDevData->CreateControl(*pPDFControl.get());
+ mpPDFExtOutDevData->EndStructureElement();
+
+ // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
+ // do not process recursively
+ bDoProcessRecursively = false;
+ }
+ else
+ {
+ // PDF export did not work, try simple output.
+ // Fallback to printer output by not setting bDoProcessRecursively
+ // to false.
+ }
+ }
+
+ // #i93169# used flag the wrong way; true means that nothing was done yet
+ if(bDoProcessRecursively)
+ {
+ // printer output
+ try
+ {
+ // remember old graphics and create new
+ uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
+ const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
+ const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
+
+ if(xNewGraphics.is())
+ {
+ // link graphics and view
+ xControlView->setGraphics(xNewGraphics);
+
+ // get position
+ const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
+ const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
+
+ // draw it
+ xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
+ bDoProcessRecursively = false;
+
+ // restore original graphics
+ xControlView->setGraphics(xOriginalGraphics);
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ OSL_ENSURE(false, "VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
+ }
+ }
+
+ // process recursively if not done yet to export as decomposition (bitmap)
+ if(bDoProcessRecursively)
+ {
+ process(rControlPrimitive.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
+ {
+ // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
+ // thus do the MetafileAction embedding stuff but just handle recursively.
+ const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate);
+ static const ByteString aCommentStringCommon("FIELD_SEQ_BEGIN");
+ static const ByteString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
+ static const ByteString aCommentStringEnd("FIELD_SEQ_END");
+
+ switch(rFieldPrimitive.getType())
+ {
+ default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
+ {
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
+ break;
+ }
+ case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
+ {
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
+ break;
+ }
+ case drawinglayer::primitive2d::FIELD_TYPE_URL :
+ {
+ const rtl::OUString& rURL = rFieldPrimitive.getString();
+ const String aOldString(rURL);
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const BYTE* >(aOldString.GetBuffer()), 2 * aOldString.Len()));
+ break;
+ }
+ }
+
+ // process recursively
+ const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D());
+ process(rContent);
+
+ // for the end comment the type is not relevant yet, they are all the same. Just add.
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
+
+ if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
+ {
+ // emulate data handling from ImpEditEngine::Paint
+ const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
+ const Rectangle aRectLogic(
+ (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
+ (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
+ vcl::PDFExtOutDevBookmarkEntry aBookmark;
+ aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
+ aBookmark.aBookmark = rFieldPrimitive.getString();
+ std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
+ rBookmarks.push_back( aBookmark );
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
+ {
+ const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate);
+ static const ByteString aCommentString("XTEXT_EOL");
+
+ // process recursively and add MetaFile comment
+ process(rLinePrimitive.get2DDecomposition(getViewInformation2D()));
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
+ {
+ // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
+ // "XTEXT_EOC" is used, use here, too.
+ const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate);
+ static const ByteString aCommentString("XTEXT_EOC");
+
+ // process recursively and add MetaFile comment
+ process(rBulletPrimitive.get2DDecomposition(getViewInformation2D()));
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
+ {
+ const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate);
+ static const ByteString aCommentString("XTEXT_EOP");
+
+ if(mpPDFExtOutDevData)
+ {
+ // emulate data handling from ImpEditEngine::Paint
+ mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
+ }
+
+ // process recursively and add MetaFile comment
+ process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D()));
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+ if(mpPDFExtOutDevData)
+ {
+ // emulate data handling from ImpEditEngine::Paint
+ mpPDFExtOutDevData->EndStructureElement();
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
+ {
+ const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate);
+ static const ByteString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
+ static const ByteString aCommentStringB("XTEXT_PAINTSHAPE_END");
+
+ // add MetaFile comment, process recursively and add MetaFile comment
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
+ process(rBlockPrimitive.get2DDecomposition(getViewInformation2D()));
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
+ case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
+ {
+ // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
+ const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate);
+ // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate);
+
+ // Adapt evtl. used special DrawMode
+ const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+ adaptTextToFillDrawMode();
+
+ // directdraw of text simple portion; use default processing
+ RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
+
+ // restore DrawMode
+ mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+
+ // #i101169# if(pTextDecoratedCandidate)
+ {
+ // support for TEXT_ MetaFile actions only for decorated texts
+ if(!mxBreakIterator.is())
+ {
+ uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
+ mxBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), uno::UNO_QUERY);
+ }
+
+ if(mxBreakIterator.is())
+ {
+ const rtl::OUString& rTxt = rTextCandidate.getText();
+ const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
+
+ if(nTextLength)
+ {
+ const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale();
+ const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
+
+ sal_Int32 nDone;
+ sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
+ ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
+ sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
+ static const ByteString aCommentStringA("XTEXT_EOC");
+ static const ByteString aCommentStringB("XTEXT_EOW");
+ static const ByteString aCommentStringC("XTEXT_EOS");
+
+ for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
+ {
+ // create the entries for the respective break positions
+ if(i == nNextCellBreak)
+ {
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
+ nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
+ }
+ if(i == nNextWordBoundary.endPos)
+ {
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
+ nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
+ }
+ if(i == nNextSentenceBreak)
+ {
+ mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
+ nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
+ }
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
+ {
+ const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
+ const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
+
+ if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+ {
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. If there are more, split the polygon in half and call recursively
+ basegfx::B2DPolygon aLeft, aRight;
+ splitLinePolygon(rBasePolygon, aLeft, aRight);
+ const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor());
+ const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor());
+
+ processBasePrimitive2D(aPLeft);
+ processBasePrimitive2D(aPRight);
+ }
+ else
+ {
+ // direct draw of hairline; use default processing
+ // support SvtGraphicStroke MetaCommentAction
+ const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
+ SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+ rHairlinePrimitive.getB2DPolygon(),
+ &aLineColor,
+ 0, 0, 0, 0);
+
+ impStartSvtGraphicStroke(pSvtGraphicStroke);
+ RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
+ impEndSvtGraphicStroke(pSvtGraphicStroke);
+ }
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
+ {
+ const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
+ const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
+
+ if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+ {
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. If there are more, split the polygon in half and call recursively
+ basegfx::B2DPolygon aLeft, aRight;
+ splitLinePolygon(rBasePolygon, aLeft, aRight);
+ const primitive2d::PolygonStrokePrimitive2D aPLeft(
+ aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
+ const primitive2d::PolygonStrokePrimitive2D aPRight(
+ aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
+
+ processBasePrimitive2D(aPLeft);
+ processBasePrimitive2D(aPRight);
+ }
+ else
+ {
+ // support SvtGraphicStroke MetaCommentAction
+ SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+ rBasePolygon, 0,
+ &rStrokePrimitive.getLineAttribute(),
+ &rStrokePrimitive.getStrokeAttribute(),
+ 0, 0);
+
+ impStartSvtGraphicStroke(pSvtGraphicStroke);
+ const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
+
+ // create MetaPolyLineActions, but without LINE_DASH
+ if(basegfx::fTools::more(rLine.getWidth(), 0.0))
+ {
+ const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
+ basegfx::B2DPolyPolygon aHairLinePolyPolygon;
+
+ if(0.0 == rStroke.getFullDotDashLen())
+ {
+ aHairLinePolyPolygon.append(rBasePolygon);
+ }
+ else
+ {
+ basegfx::tools::applyLineDashing(
+ rBasePolygon, rStroke.getDotDashArray(),
+ &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen());
+ }
+
+ const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
+ mpOutputDevice->SetLineColor(Color(aHairlineColor));
+ mpOutputDevice->SetFillColor();
+ aHairLinePolyPolygon.transform(maCurrentTransformation);
+
+ // #i113922# LineWidth needs to be transformed, too
+ const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(rLine.getWidth(), 0.0));
+ const double fDiscreteLineWidth(aDiscreteUnit.getLength());
+
+ LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fDiscreteLineWidth));
+ aLineInfo.SetLineJoin(rLine.getLineJoin());
+
+ for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
+ {
+ const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
+
+ if(aCandidate.count() > 1)
+ {
+ const Polygon aToolsPolygon(aCandidate);
+
+ mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
+ }
+ }
+ }
+ else
+ {
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+
+ impEndSvtGraphicStroke(pSvtGraphicStroke);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
+ {
+ const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate);
+ const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
+
+ if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+ {
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. If there are more, split the polygon in half and call recursively
+ basegfx::B2DPolygon aLeft, aRight;
+ splitLinePolygon(rBasePolygon, aLeft, aRight);
+ const attribute::LineStartEndAttribute aEmpty;
+ const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft(
+ aLeft,
+ rStrokeArrowPrimitive.getLineAttribute(),
+ rStrokeArrowPrimitive.getStrokeAttribute(),
+ rStrokeArrowPrimitive.getStart(),
+ aEmpty);
+ const primitive2d::PolygonStrokeArrowPrimitive2D aPRight(
+ aRight,
+ rStrokeArrowPrimitive.getLineAttribute(),
+ rStrokeArrowPrimitive.getStrokeAttribute(),
+ aEmpty,
+ rStrokeArrowPrimitive.getEnd());
+
+ processBasePrimitive2D(aPLeft);
+ processBasePrimitive2D(aPRight);
+ }
+ else
+ {
+ // support SvtGraphicStroke MetaCommentAction
+ SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+ rBasePolygon, 0,
+ &rStrokeArrowPrimitive.getLineAttribute(),
+ &rStrokeArrowPrimitive.getStrokeAttribute(),
+ &rStrokeArrowPrimitive.getStart(),
+ &rStrokeArrowPrimitive.getEnd());
+
+ impStartSvtGraphicStroke(pSvtGraphicStroke);
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ impEndSvtGraphicStroke(pSvtGraphicStroke);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
+ {
+ // direct draw of transformed BitmapEx primitive; use default processing
+ RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D :
+ {
+ // need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
+ const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate);
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
+
+ if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+ {
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. If there are more use the splitted polygon and call recursively
+ const primitive2d::PolyPolygonBitmapPrimitive2D aSplitted(
+ aLocalPolyPolygon,
+ rBitmapCandidate.getFillBitmap());
+
+ processBasePrimitive2D(aSplitted);
+ }
+ else
+ {
+ SvtGraphicFill* pSvtGraphicFill = 0;
+
+ if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ {
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+ // calculate transformation. Get real object size, all values in FillBitmapAttribute
+ // are relative to the unified object
+ const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap();
+ const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon));
+ const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange());
+
+ // get absolute values
+ const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize);
+ const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize);
+
+ // the scaling needs scale from pixel to logic coordinate system
+ const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx();
+ Size aBmpSizePixel(rBitmapEx.GetSizePixel());
+
+ if(!aBmpSizePixel.Width())
+ {
+ aBmpSizePixel.Width() = 1;
+ }
+
+ if(!aBmpSizePixel.Height())
+ {
+ aBmpSizePixel.Height() = 1;
+ }
+
+ // setup transformation like in impgrfll
+ SvtGraphicFill::Transform aTransform;
+
+ // scale values are divided by bitmap pixel sizes
+ aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width();
+ aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height();
+
+ // translates are absolute
+ aTransform.matrix[2] = aFillBitmapTopLeft.getX();
+ aTransform.matrix[5] = aFillBitmapTopLeft.getY();
+
+ // setup fill graphic like in impgrfll
+ Graphic aFillGraphic = Graphic(rBitmapEx);
+ aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL));
+ aFillGraphic.SetPrefSize(aBmpSizePixel);
+
+ pSvtGraphicFill = new SvtGraphicFill(
+ PolyPolygon(aLocalPolyPolygon),
+ Color(),
+ 0.0,
+ SvtGraphicFill::fillEvenOdd,
+ SvtGraphicFill::fillTexture,
+ aTransform,
+ rFillBitmapAttribute.getTiling(),
+ SvtGraphicFill::hatchSingle,
+ Color(),
+ SvtGraphicFill::gradientLinear,
+ Color(),
+ Color(),
+ 0,
+ aFillGraphic);
+ }
+
+ // Do use decomposition; encapsulate with SvtGraphicFill
+ impStartSvtGraphicFill(pSvtGraphicFill);
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ impEndSvtGraphicFill(pSvtGraphicFill);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
+ {
+ // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
+ const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate);
+ const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
+
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. Split polygon until there are less than that
+ while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+ ;
+
+ if(rFillHatchAttribute.isFillBackground())
+ {
+ // with fixing #i111954# (see below) the possible background
+ // fill of a hatched object was lost.Generate a background fill
+ // primitive and render it
+ const primitive2d::Primitive2DReference xBackground(
+ new primitive2d::PolyPolygonColorPrimitive2D(
+ aLocalPolyPolygon,
+ rHatchCandidate.getBackgroundColor()));
+
+ process(primitive2d::Primitive2DSequence(&xBackground, 1));
+ }
+
+ SvtGraphicFill* pSvtGraphicFill = 0;
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ {
+ // re-create a VCL hatch as base data
+ SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
+
+ switch(rFillHatchAttribute.getStyle())
+ {
+ default: // attribute::HATCHSTYLE_SINGLE :
+ {
+ eHatch = SvtGraphicFill::hatchSingle;
+ break;
+ }
+ case attribute::HATCHSTYLE_DOUBLE :
+ {
+ eHatch = SvtGraphicFill::hatchDouble;
+ break;
+ }
+ case attribute::HATCHSTYLE_TRIPLE :
+ {
+ eHatch = SvtGraphicFill::hatchTriple;
+ break;
+ }
+ }
+
+ SvtGraphicFill::Transform aTransform;
+
+ // scale
+ aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
+ aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
+
+ // rotate (was never correct in impgrfll anyways, use correct angle now)
+ aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
+ aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
+ aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
+ aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
+
+ pSvtGraphicFill = new SvtGraphicFill(
+ PolyPolygon(aLocalPolyPolygon),
+ Color(),
+ 0.0,
+ SvtGraphicFill::fillEvenOdd,
+ SvtGraphicFill::fillHatch,
+ aTransform,
+ false,
+ eHatch,
+ Color(rFillHatchAttribute.getColor()),
+ SvtGraphicFill::gradientLinear,
+ Color(),
+ Color(),
+ 0,
+ Graphic());
+ }
+
+ // Do use decomposition; encapsulate with SvtGraphicFill
+ impStartSvtGraphicFill(pSvtGraphicFill);
+
+ // #i111954# do NOT use decomposition, but use direct VCL-command
+ // process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ const PolyPolygon aToolsPolyPolygon(aLocalPolyPolygon);
+ const HatchStyle aHatchStyle(
+ attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE :
+ attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE :
+ HATCH_TRIPLE);
+
+ mpOutputDevice->DrawHatch(aToolsPolyPolygon,
+ Hatch(aHatchStyle,
+ Color(rFillHatchAttribute.getColor()),
+ basegfx::fround(rFillHatchAttribute.getDistance()),
+ basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
+
+ impEndSvtGraphicFill(pSvtGraphicFill);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
+ {
+ const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
+
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. Split polygon until there are less than that
+ while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+ ;
+
+ // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
+ // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
+ // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
+ Gradient aVCLGradient;
+ impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ // #i82145# ATM VCL printing of gradients using curved shapes does not work,
+ // i submitted the bug with the given ID to THB. When that task is fixed it is
+ // necessary to again remove this subdivision since it decreases possible
+ // printing quality (not even resolution-dependent for now). THB will tell
+ // me when that task is fixed in the master
+ const PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon));
+
+ // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
+ SvtGraphicFill* pSvtGraphicFill = 0;
+
+ if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ {
+ // setup gradient stuff like in like in impgrfll
+ SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear);
+
+ switch(aVCLGradient.GetStyle())
+ {
+ default : // GRADIENT_LINEAR:
+ case GRADIENT_AXIAL:
+ eGrad = SvtGraphicFill::gradientLinear;
+ break;
+ case GRADIENT_RADIAL:
+ case GRADIENT_ELLIPTICAL:
+ eGrad = SvtGraphicFill::gradientRadial;
+ break;
+ case GRADIENT_SQUARE:
+ case GRADIENT_RECT:
+ eGrad = SvtGraphicFill::gradientRectangular;
+ break;
+ }
+
+ pSvtGraphicFill = new SvtGraphicFill(
+ aToolsPolyPolygon,
+ Color(),
+ 0.0,
+ SvtGraphicFill::fillEvenOdd,
+ SvtGraphicFill::fillGradient,
+ SvtGraphicFill::Transform(),
+ false,
+ SvtGraphicFill::hatchSingle,
+ Color(),
+ eGrad,
+ aVCLGradient.GetStartColor(),
+ aVCLGradient.GetEndColor(),
+ aVCLGradient.GetSteps(),
+ Graphic());
+ }
+
+ // call VCL directly; encapsulate with SvtGraphicFill
+ impStartSvtGraphicFill(pSvtGraphicFill);
+ mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
+ impEndSvtGraphicFill(pSvtGraphicFill);
+
+ // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above
+ // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate));
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
+ {
+ const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. Split polygon until there are less than that
+ while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+ ;
+
+ const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
+ SvtGraphicFill* pSvtGraphicFill = 0;
+
+ if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ {
+ // setup simple color fill stuff like in impgrfll
+ pSvtGraphicFill = new SvtGraphicFill(
+ PolyPolygon(aLocalPolyPolygon),
+ Color(aPolygonColor),
+ 0.0,
+ SvtGraphicFill::fillEvenOdd,
+ SvtGraphicFill::fillSolid,
+ SvtGraphicFill::Transform(),
+ false,
+ SvtGraphicFill::hatchSingle,
+ Color(),
+ SvtGraphicFill::gradientLinear,
+ Color(),
+ Color(),
+ 0,
+ Graphic());
+ }
+
+ // set line and fill color
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
+
+ // call VCL directly; encapsulate with SvtGraphicFill
+ impStartSvtGraphicFill(pSvtGraphicFill);
+ mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
+ impEndSvtGraphicFill(pSvtGraphicFill);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
+ {
+ // direct draw of MetaFile, use default pocessing
+ RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ {
+ // mask group. Special handling for MetaFiles.
+ const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate);
+
+ if(rMaskCandidate.getChildren().hasElements())
+ {
+ basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
+
+ if(aMask.count())
+ {
+ // prepare new mask polygon and rescue current one
+ aMask.transform(maCurrentTransformation);
+ const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
+
+ if(maClipPolyPolygon.count())
+ {
+ // there is already a clip polygon set; build clipped union of
+ // current mask polygon and new one
+ maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
+ aMask,
+ maClipPolyPolygon,
+ true, // #i106516# we want the inside of aMask, not the outside
+ false);
+ }
+ else
+ {
+ // use mask directly
+ maClipPolyPolygon = aMask;
+ }
+
+ if(maClipPolyPolygon.count())
+ {
+ // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
+ // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
+ // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
+ mpOutputDevice->Push(PUSH_CLIPREGION);
+ //mpOutputDevice->SetClipRegion(Region(PolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(maClipPolyPolygon))));
+ mpOutputDevice->SetClipRegion(Region(PolyPolygon(maClipPolyPolygon)));
+ }
+
+ // recursively paint content
+ process(rMaskCandidate.getChildren());
+
+ if(maClipPolyPolygon.count())
+ {
+ // restore VCL clip region
+ mpOutputDevice->Pop();
+ }
+
+ // restore to rescued clip polygon
+ maClipPolyPolygon = aLastClipPolyPolygon;
+ }
+ else
+ {
+ // no mask, no clipping. recursively paint content
+ process(rMaskCandidate.getChildren());
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
+ {
+ // modified color group. Force output to unified color. Use default pocessing.
+ RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D :
+ {
+ // HiddenGeometryPrimitive2D; to rebuilt the old MetaFile creation, it is necessary to
+ // not ignore them (as it was thought), but to add a MetaFile entry for them.
+ basegfx::B2DRange aInvisibleRange(rCandidate.getB2DRange(getViewInformation2D()));
+
+ if(!aInvisibleRange.isEmpty())
+ {
+ aInvisibleRange.transform(maCurrentTransformation);
+ const Rectangle aRectLogic(
+ (sal_Int32)floor(aInvisibleRange.getMinX()), (sal_Int32)floor(aInvisibleRange.getMinY()),
+ (sal_Int32)ceil(aInvisibleRange.getMaxX()), (sal_Int32)ceil(aInvisibleRange.getMaxY()));
+
+ mpOutputDevice->SetFillColor();
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->DrawRect(aRectLogic);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
+ {
+ // for metafile: Need to examine what the pure vcl version is doing here actually
+ // - uses DrawTransparent with metafile for content and a gradient
+ // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by
+ // checking the content for single PolyPolygonColorPrimitive2D
+ const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
+ const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren();
+
+ if(rContent.hasElements())
+ {
+ if(0.0 == rUniTransparenceCandidate.getTransparence())
+ {
+ // not transparent at all, use content
+ process(rUniTransparenceCandidate.getChildren());
+ }
+ else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
+ {
+ // try to identify a single PolyPolygonColorPrimitive2D in the
+ // content part of the transparence primitive
+ const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0;
+ static bool bForceToMetafile(false);
+
+ if(!bForceToMetafile && 1 == rContent.getLength())
+ {
+ const primitive2d::Primitive2DReference xReference(rContent[0]);
+ pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
+ }
+
+ // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
+ // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D.
+ // Check also for correct ID to exclude derived implementations
+ if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
+ {
+ // single transparent PolyPolygon identified, use directly
+ const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
+
+ // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+ // per polygon. Split polygon until there are less than that
+ while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+ ;
+
+ // now transform
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
+ SvtGraphicFill* pSvtGraphicFill = 0;
+
+ if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+ {
+ // setup simple color with transparence fill stuff like in impgrfll
+ pSvtGraphicFill = new SvtGraphicFill(
+ PolyPolygon(aLocalPolyPolygon),
+ Color(aPolygonColor),
+ rUniTransparenceCandidate.getTransparence(),
+ SvtGraphicFill::fillEvenOdd,
+ SvtGraphicFill::fillSolid,
+ SvtGraphicFill::Transform(),
+ false,
+ SvtGraphicFill::hatchSingle,
+ Color(),
+ SvtGraphicFill::gradientLinear,
+ Color(),
+ Color(),
+ 0,
+ Graphic());
+ }
+
+ // set line and fill color
+ const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0));
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
+
+ // call VCL directly; encapsulate with SvtGraphicFill
+ impStartSvtGraphicFill(pSvtGraphicFill);
+ mpOutputDevice->DrawTransparent(
+ PolyPolygon(aLocalPolyPolygon),
+ nTransPercentVcl);
+ impEndSvtGraphicFill(pSvtGraphicFill);
+ }
+ else
+ {
+ // svae old mfCurrentUnifiedTransparence and set new one
+ // so that contained SvtGraphicStroke may use the current one
+ const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
+ // #i105377# paint the content metafile opaque as the transparency gets
+ // split of into the gradient below
+ // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
+ mfCurrentUnifiedTransparence = 0;
+
+ // various content, create content-metafile
+ GDIMetaFile aContentMetafile;
+ const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
+
+ // restore mfCurrentUnifiedTransparence; it may have been used
+ // while processing the sub-content in impDumpToMetaFile
+ mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
+
+ // create uniform VCL gradient for uniform transparency
+ Gradient aVCLGradient;
+ const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0));
+ const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
+
+ aVCLGradient.SetStyle(GRADIENT_LINEAR);
+ aVCLGradient.SetStartColor(aTransColor);
+ aVCLGradient.SetEndColor(aTransColor);
+ aVCLGradient.SetAngle(0);
+ aVCLGradient.SetBorder(0);
+ aVCLGradient.SetOfsX(0);
+ aVCLGradient.SetOfsY(0);
+ aVCLGradient.SetStartIntensity(100);
+ aVCLGradient.SetEndIntensity(100);
+ aVCLGradient.SetSteps(2);
+
+ // render it to VCL
+ mpOutputDevice->DrawTransparent(
+ aContentMetafile, aPrimitiveRectangle.TopLeft(),
+ aPrimitiveRectangle.GetSize(), aVCLGradient);
+ }
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
+ {
+ // for metafile: Need to examine what the pure vcl version is doing here actually
+ // - uses DrawTransparent with metafile for content and a gradient
+ // i can detect this here with checking the gradient part for a single
+ // FillGradientPrimitive2D and reconstruct the gradient.
+ // If that detection goes wrong, i have to create an transparence-blended bitmap. Eventually
+ // do that in stripes, else RenderTransparencePrimitive2D may just be used
+ const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate);
+ const primitive2d::Primitive2DSequence rContent = rTransparenceCandidate.getChildren();
+ const primitive2d::Primitive2DSequence rTransparence = rTransparenceCandidate.getTransparence();
+
+ if(rContent.hasElements() && rTransparence.hasElements())
+ {
+ // try to identify a single FillGradientPrimitive2D in the
+ // transparence part of the primitive
+ const primitive2d::FillGradientPrimitive2D* pFiGradient = 0;
+ static bool bForceToBigTransparentVDev(false);
+
+ if(!bForceToBigTransparentVDev && 1 == rTransparence.getLength())
+ {
+ const primitive2d::Primitive2DReference xReference(rTransparence[0]);
+ pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get());
+ }
+
+ // Check also for correct ID to exclude derived implementations
+ if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID())
+ {
+ // various content, create content-metafile
+ GDIMetaFile aContentMetafile;
+ const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
+
+ // re-create a VCL-gradient from FillGradientPrimitive2D
+ Gradient aVCLGradient;
+ impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true);
+
+ // render it to VCL
+ mpOutputDevice->DrawTransparent(
+ aContentMetafile, aPrimitiveRectangle.TopLeft(),
+ aPrimitiveRectangle.GetSize(), aVCLGradient);
+ }
+ else
+ {
+ // sub-transparence group. Draw to VDev first.
+ // this may get refined to tiling when resolution is too big here
+
+ // need to avoid switching off MapMode stuff here; maybe need another
+ // tooling class, cannot just do the same as with the pixel renderer.
+ // Need to experiment...
+
+ // Okay, basic implementation finished and tested. The DPI stuff was hard
+ // and not easy to find out that it's needed.
+ // Since this will not yet happen normally (as long as noone constructs
+ // transparence primitives with non-trivial transparence content) i will for now not
+ // refine to tiling here.
+
+ basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
+ aViewRange.transform(maCurrentTransformation);
+ const Rectangle aRectLogic(
+ (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
+ (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
+ const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
+ const Size aSizePixel(aRectPixel.GetSize());
+ const Point aEmptyPoint;
+ VirtualDevice aBufferDevice;
+
+ if(aBufferDevice.SetOutputSizePixel(aSizePixel))
+ {
+ // create and set MapModes for target devices
+ MapMode aNewMapMode(mpOutputDevice->GetMapMode());
+ aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
+ aBufferDevice.SetMapMode(aNewMapMode);
+
+ // prepare view transformation for target renderers
+ // ATTENTION! Need to apply another scaling because of the potential DPI differences
+ // between Printer and VDev (mpOutputDevice and aBufferDevice here).
+ // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used.
+ basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation());
+ const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH));
+ const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH));
+ const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth());
+ const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight());
+
+ if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0))
+ {
+ aViewTransform.scale(fDPIXChange, fDPIYChange);
+ }
+
+ // create view information and pixel renderer. Reuse known ViewInformation
+ // except new transformation and range
+ const geometry::ViewInformation2D aViewInfo(
+ getViewInformation2D().getObjectTransformation(),
+ aViewTransform,
+ aViewRange,
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+
+ VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice);
+
+ // draw content using pixel renderer
+ aBufferProcessor.process(rContent);
+ const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
+
+ // draw transparence using pixel renderer
+ aBufferDevice.Erase();
+ aBufferProcessor.process(rTransparence);
+ const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
+
+#ifdef DBG_UTIL
+ static bool bDoSaveForVisualControl(false);
+ if(bDoSaveForVisualControl)
+ {
+ SvFileStream aNew(String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC);
+ aNew << aBmContent;
+ }
+#endif
+
+ // paint
+ mpOutputDevice->DrawBitmapEx(
+ aRectLogic.TopLeft(),
+ aRectLogic.GetSize(),
+ BitmapEx(aBmContent, aBmAlpha));
+ }
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
+ {
+ // use default transform group pocessing
+ RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
+ {
+ // new XDrawPage for ViewInformation2D
+ RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
+ {
+ // use default marker array pocessing
+ RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+ {
+ // use default point array pocessing
+ RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_CHARTPRIMITIVE2D :
+ {
+ // ChartPrimitive2D
+ const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate);
+
+ if(!renderChartPrimitive2D(
+ rChartPrimitive,
+ *mpOutputDevice,
+ getViewInformation2D()))
+ {
+ // fallback to decomposition (MetaFile)
+ process(rChartPrimitive.get2DDecomposition(getViewInformation2D()));
+ }
+ break;
+ }
+ case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D :
+ {
+ // structured tag primitive
+ const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate);
+ const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
+ const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement);
+
+ if(mpPDFExtOutDevData && bTagUsed)
+ {
+ // write start tag
+ mpPDFExtOutDevData->BeginStructureElement(rTagElement);
+ }
+
+ // proccess childs normally
+ process(rStructureTagCandidate.getChildren());
+
+ if(mpPDFExtOutDevData && bTagUsed)
+ {
+ // write end tag
+ mpPDFExtOutDevData->EndStructureElement();
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
+ {
+ RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
+ break;
+ }
+ default :
+ {
+ // process recursively
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ break;
+ }
+ }
+ }
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
new file mode 100644
index 000000000000..6a280fcad95e
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -0,0 +1,613 @@
+/*************************************************************************
+ *
+ * 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/processor2d/vclpixelprocessor2d.hxx>
+#include <vcl/outdev.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
+#include <drawinglayer/primitive2d/chartprimitive2d.hxx>
+#include <helperchartrenderer.hxx>
+#include <helperwrongspellrenderer.hxx>
+#include <drawinglayer/primitive2d/fillhatchprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <vcl/hatch.hxx>
+#include <tools/diagnose_ex.h>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <drawinglayer/primitive2d/invertprimitive2d.hxx>
+#include <cstdio>
+#include <drawinglayer/primitive2d/backgroundcolorprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/primitive2d/epsprimitive2d.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/window.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
+ : VclProcessor2D(rViewInformation, rOutDev),
+ maOriginalMapMode(rOutDev.GetMapMode())
+ {
+ // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels
+ maCurrentTransformation = rViewInformation.getObjectToViewTransformation();
+
+ // prepare output directly to pixels
+ mpOutputDevice->Push(PUSH_MAPMODE);
+ mpOutputDevice->SetMapMode();
+
+ // react on AntiAliasing settings
+ if(getOptionsDrawinglayer().IsAntiAliasing())
+ {
+ mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() | ANTIALIASING_ENABLE_B2DDRAW);
+ }
+ else
+ {
+ mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
+ }
+ }
+
+ VclPixelProcessor2D::~VclPixelProcessor2D()
+ {
+ // restore MapMode
+ mpOutputDevice->Pop();
+
+ // restore AntiAliasing
+ mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
+ }
+
+ void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+ {
+ switch(rCandidate.getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+ {
+ // directdraw of wrong spell primitive; added test possibility to check wrong spell decompose
+ static bool bHandleWrongSpellDirectly(true);
+
+ if(bHandleWrongSpellDirectly)
+ {
+ const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive = static_cast< const primitive2d::WrongSpellPrimitive2D& >(rCandidate);
+
+ if(!renderWrongSpellPrimitive2D(
+ rWrongSpellPrimitive,
+ *mpOutputDevice,
+ maCurrentTransformation,
+ maBColorModifierStack))
+ {
+ // fallback to decomposition (MetaFile)
+ process(rWrongSpellPrimitive.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+ else
+ {
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
+ {
+ // directdraw of text simple portion; added test possibility to check text decompose
+ static bool bForceSimpleTextDecomposition(false);
+
+ // Adapt evtl. used special DrawMode
+ const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+ adaptTextToFillDrawMode();
+
+ if(!bForceSimpleTextDecomposition && getOptionsDrawinglayer().IsRenderSimpleTextDirect())
+ {
+ RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
+ }
+ else
+ {
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+
+ // restore DrawMode
+ mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
+ {
+ // directdraw of text simple portion; added test possibility to check text decompose
+ static bool bForceComplexTextDecomposition(false);
+
+ // Adapt evtl. used special DrawMode
+ const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+ adaptTextToFillDrawMode();
+
+ if(!bForceComplexTextDecomposition && getOptionsDrawinglayer().IsRenderDecoratedTextDirect())
+ {
+ RenderTextSimpleOrDecoratedPortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
+ }
+ else
+ {
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+
+ // restore DrawMode
+ mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
+ {
+ // direct draw of hairline
+ RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), true);
+ break;
+ }
+ case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
+ {
+ // direct draw of transformed BitmapEx primitive
+ RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_FILLBITMAPPRIMITIVE2D :
+ {
+ // direct draw of fillBitmapPrimitive
+ RenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
+ {
+ // direct draw of gradient
+ RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D :
+ {
+ // direct draw of bitmap
+ RenderPolyPolygonBitmapPrimitive2D(static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
+ {
+ // direct draw of PolyPolygon with color
+ RenderPolyPolygonColorPrimitive2D(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
+ {
+ // #i98289#
+ const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete());
+ const sal_uInt16 nOldAntiAliase(mpOutputDevice->GetAntialiasing());
+
+ if(bForceLineSnap)
+ {
+ mpOutputDevice->SetAntialiasing(nOldAntiAliase | ANTIALIASING_PIXELSNAPHAIRLINE);
+ }
+
+ static bool bTestMetaFilePrimitiveDecomposition(true);
+ if(bTestMetaFilePrimitiveDecomposition)
+ {
+ // use new Metafile decomposition
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ else
+ {
+ // direct draw of MetaFile
+ RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate));
+ }
+
+ if(bForceLineSnap)
+ {
+ mpOutputDevice->SetAntialiasing(nOldAntiAliase);
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+ {
+ // mask group.
+ RenderMaskPrimitive2DPixel(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
+ {
+ // modified color group. Force output to unified color.
+ RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
+ {
+ // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
+ // use the faster OutputDevice::DrawTransparent method
+ const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
+ const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren();
+
+ if(rContent.hasElements())
+ {
+ if(0.0 == rUniTransparenceCandidate.getTransparence())
+ {
+ // not transparent at all, use content
+ process(rUniTransparenceCandidate.getChildren());
+ }
+ else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
+ {
+ bool bDrawTransparentUsed(false);
+
+ // since DEV300 m33 DrawTransparent is supported in VCL (for some targets
+ // natively), so i am now enabling this shortcut
+ static bool bAllowUsingDrawTransparent(true);
+
+ if(bAllowUsingDrawTransparent && 1 == rContent.getLength())
+ {
+ const primitive2d::Primitive2DReference xReference(rContent[0]);
+ const primitive2d::BasePrimitive2D* pBasePrimitive = dynamic_cast< const primitive2d::BasePrimitive2D* >(xReference.get());
+
+ if(pBasePrimitive)
+ {
+ switch(pBasePrimitive->getPrimitive2DID())
+ {
+ case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
+ {
+ // single transparent PolyPolygon identified, use directly
+ const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = static_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(pBasePrimitive);
+ OSL_ENSURE(pPoPoColor, "OOps, PrimitiveID and PrimitiveType do not match (!)");
+ const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
+
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ mpOutputDevice->DrawTransparent(aLocalPolyPolygon, rUniTransparenceCandidate.getTransparence());
+ bDrawTransparentUsed = true;
+ break;
+ }
+ // #i# need to wait for #i101378# which is in CWS vcl112 to directly paint transparent hairlines
+ //case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
+ //{
+ // // single transparent PolygonHairlinePrimitive2D identified, use directly
+ // const primitive2d::PolygonHairlinePrimitive2D* pPoHair = static_cast< const primitive2d::PolygonHairlinePrimitive2D* >(pBasePrimitive);
+ // OSL_ENSURE(pPoHair, "OOps, PrimitiveID and PrimitiveType do not match (!)");
+ // break;
+ //}
+ }
+ }
+ }
+
+ if(!bDrawTransparentUsed)
+ {
+ // unified sub-transparence. Draw to VDev first.
+ RenderUnifiedTransparencePrimitive2D(rUniTransparenceCandidate);
+ }
+ }
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
+ {
+ // sub-transparence group. Draw to VDev first.
+ RenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
+ {
+ // transform group.
+ RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
+ {
+ // new XDrawPage for ViewInformation2D
+ RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
+ {
+ // marker array
+ RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+ {
+ // point array
+ RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
+ break;
+ }
+ case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
+ {
+ // control primitive
+ const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
+ const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
+
+ try
+ {
+ // remember old graphics and create new
+ uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
+ const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
+ const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
+
+ if(xNewGraphics.is())
+ {
+ // link graphics and view
+ xControlView->setGraphics(xNewGraphics);
+
+ // get position
+ const basegfx::B2DHomMatrix aObjectToPixel(maCurrentTransformation * rControlPrimitive.getTransform());
+ const basegfx::B2DPoint aTopLeftPixel(aObjectToPixel * basegfx::B2DPoint(0.0, 0.0));
+
+ // find out if the control is already visualized as a VCL-ChildWindow. If yes,
+ // it does not need to be painted at all.
+ uno::Reference< awt::XWindow2 > xControlWindow(rXControl, uno::UNO_QUERY_THROW);
+ const bool bControlIsVisibleAsChildWindow(rXControl->getPeer().is() && xControlWindow->isVisible());
+
+ if(!bControlIsVisibleAsChildWindow)
+ {
+ // draw it. Do not forget to use the evtl. offsetted origin of the target device,
+ // e.g. when used with mask/transparence buffer device
+ const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin());
+ xControlView->draw(
+ aOrigin.X() + basegfx::fround(aTopLeftPixel.getX()),
+ aOrigin.Y() + basegfx::fround(aTopLeftPixel.getY()));
+ }
+
+ // restore original graphics
+ xControlView->setGraphics(xOriginalGraphics);
+ }
+ }
+ catch(const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION();
+
+ // process recursively and use the decomposition as Bitmap
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+
+ break;
+ }
+ case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
+ {
+ // the stroke primitive may be decomposed to filled polygons. To keep
+ // evtl. set DrawModes aka DRAWMODE_BLACKLINE, DRAWMODE_GRAYLINE,
+ // DRAWMODE_GHOSTEDLINE, DRAWMODE_WHITELINE or DRAWMODE_SETTINGSLINE
+ // working, these need to be copied to the corresponding fill modes
+ const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+ adaptLineToFillDrawMode();
+
+ // polygon stroke primitive
+ static bool bSuppressFatToHairlineCorrection(false);
+
+ if(bSuppressFatToHairlineCorrection)
+ {
+ // remeber that we enter a PolygonStrokePrimitive2D decomposition,
+ // used for AA thick line drawing
+ mnPolygonStrokePrimitive2D++;
+
+ // with AA there is no need to handle thin lines special
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+
+ // leave PolygonStrokePrimitive2D
+ mnPolygonStrokePrimitive2D--;
+ }
+ else
+ {
+ // Lines with 1 and 2 pixel width without AA need special treatment since their vsiualisation
+ // as filled polygons is geometrically corret but looks wrong since polygon filling avoids
+ // the right and bottom pixels. The used method evaluates that and takes the correct action,
+ // including calling recursively with decomposition if line is wide enough
+ const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
+
+ RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive);
+ }
+
+ // restore DrawMode
+ mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+
+ break;
+ }
+ case PRIMITIVE2D_ID_CHARTPRIMITIVE2D :
+ {
+ // chart primitive in pixel renderer; restore original DrawMode during call
+ // since the evtl. used ChartPrettyPainter will use the MapMode
+ const primitive2d::ChartPrimitive2D& rChartPrimitive = static_cast< const primitive2d::ChartPrimitive2D& >(rCandidate);
+ mpOutputDevice->Push(PUSH_MAPMODE);
+ mpOutputDevice->SetMapMode(maOriginalMapMode);
+
+ if(!renderChartPrimitive2D(
+ rChartPrimitive,
+ *mpOutputDevice,
+ getViewInformation2D()))
+ {
+ // fallback to decomposition (MetaFile)
+ process(rChartPrimitive.get2DDecomposition(getViewInformation2D()));
+ }
+
+ mpOutputDevice->Pop();
+ break;
+ }
+ case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D :
+ {
+ static bool bForceIgnoreHatchSmoothing(false);
+
+ if(bForceIgnoreHatchSmoothing || getOptionsDrawinglayer().IsAntiAliasing())
+ {
+ // if AA is used (or ignore smoothing is on), there is no need to smooth
+ // hatch painting, use decomposition
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ else
+ {
+ // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel
+ // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother.
+ // This is wrong in principle, but looks nicer. This could also be done here directly
+ // without VCL usage if needed
+ const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive = static_cast< const primitive2d::FillHatchPrimitive2D& >(rCandidate);
+ const attribute::FillHatchAttribute& rFillHatchAttributes = rFillHatchPrimitive.getFillHatch();
+
+ // create hatch polygon in range size and discrete coordinates
+ basegfx::B2DRange aHatchRange(rFillHatchPrimitive.getObjectRange());
+ aHatchRange.transform(maCurrentTransformation);
+ const basegfx::B2DPolygon aHatchPolygon(basegfx::tools::createPolygonFromRect(aHatchRange));
+
+ if(rFillHatchAttributes.isFillBackground())
+ {
+ // #i111846# background fill is active; draw fill polygon
+ const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
+
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->DrawPolygon(aHatchPolygon);
+ }
+
+ // set hatch line color
+ const basegfx::BColor aHatchColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
+ mpOutputDevice->SetFillColor();
+ mpOutputDevice->SetLineColor(Color(aHatchColor));
+
+ // get hatch style
+ HatchStyle eHatchStyle(HATCH_SINGLE);
+
+ switch(rFillHatchAttributes.getStyle())
+ {
+ default : // HATCHSTYLE_SINGLE
+ {
+ break;
+ }
+ case attribute::HATCHSTYLE_DOUBLE :
+ {
+ eHatchStyle = HATCH_DOUBLE;
+ break;
+ }
+ case attribute::HATCHSTYLE_TRIPLE :
+ {
+ eHatchStyle = HATCH_TRIPLE;
+ break;
+ }
+ }
+
+ // create hatch
+ const basegfx::B2DVector aDiscreteDistance(maCurrentTransformation * basegfx::B2DVector(rFillHatchAttributes.getDistance(), 0.0));
+ const sal_uInt32 nDistance(basegfx::fround(aDiscreteDistance.getLength()));
+ const sal_uInt16 nAngle10((sal_uInt16)basegfx::fround(rFillHatchAttributes.getAngle() / F_PI1800));
+ ::Hatch aVCLHatch(eHatchStyle, Color(rFillHatchAttributes.getColor()), nDistance, nAngle10);
+
+ // draw hatch using VCL
+ mpOutputDevice->DrawHatch(PolyPolygon(Polygon(aHatchPolygon)), aVCLHatch);
+ }
+ break;
+ }
+ case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D :
+ {
+ // #i98404# Handle directly, especially when AA is active
+ const primitive2d::BackgroundColorPrimitive2D& rPrimitive = static_cast< const primitive2d::BackgroundColorPrimitive2D& >(rCandidate);
+ const sal_uInt16 nOriginalAA(mpOutputDevice->GetAntialiasing());
+
+ // switch AA off in all cases
+ mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~ANTIALIASING_ENABLE_B2DDRAW);
+
+ // create color for fill
+ const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor()));
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
+
+ // create rectangle for fill
+ const basegfx::B2DRange& aViewport(getViewInformation2D().getDiscreteViewport());
+ const Rectangle aRectangle(
+ (sal_Int32)floor(aViewport.getMinX()), (sal_Int32)floor(aViewport.getMinY()),
+ (sal_Int32)ceil(aViewport.getMaxX()), (sal_Int32)ceil(aViewport.getMaxY()));
+ mpOutputDevice->DrawRect(aRectangle);
+
+ // restore AA setting
+ mpOutputDevice->SetAntialiasing(nOriginalAA);
+ break;
+ }
+ case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D :
+ {
+ // #i97628#
+ // This primitive means that the content is derived from an active text edit,
+ // not from model data itself. Some renderers need to suppress this content, e.g.
+ // the pixel renderer used for displaying the edit view (like this one). It's
+ // not to be suppressed by the MetaFile renderers, so that the edited text is
+ // part of the MetaFile, e.g. needed for presentation previews.
+ // Action: Ignore here, do nothing.
+ break;
+ }
+ case PRIMITIVE2D_ID_INVERTPRIMITIVE2D :
+ {
+ // invert primitive (currently only used for HighContrast fallback for selection in SW and SC).
+ // Set OutDev to XOR and switch AA off (XOR does not work with AA)
+ mpOutputDevice->Push();
+ mpOutputDevice->SetRasterOp( ROP_XOR );
+ const sal_uInt16 nAntiAliasing(mpOutputDevice->GetAntialiasing());
+ mpOutputDevice->SetAntialiasing(nAntiAliasing & ~ANTIALIASING_ENABLE_B2DDRAW);
+
+ // process content recursively
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+
+ // restore OutDev
+ mpOutputDevice->Pop();
+ mpOutputDevice->SetAntialiasing(nAntiAliasing);
+ break;
+ }
+ case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
+ {
+ RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
+ break;
+ }
+ default :
+ {
+ // process recursively
+ process(rCandidate.get2DDecomposition(getViewInformation2D()));
+ break;
+ }
+ }
+ }
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof
diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx
new file mode 100644
index 000000000000..e49e54fb751c
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx
@@ -0,0 +1,1492 @@
+/*************************************************************************
+ *
+ * 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/processor2d/vclprocessor2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
+#include <tools/debug.hxx>
+#include <vcl/outdev.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <vclhelperbitmaptransform.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <vclhelperbitmaprender.hxx>
+#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx>
+#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <vclhelpergradient.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <vclhelperbufferdevice.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/wrongspellprimitive2d.hxx>
+#include <svl/ctloptions.hxx>
+#include <vcl/svapp.hxx>
+#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/metric.hxx>
+#include <drawinglayer/primitive2d/textenumsprimitive2d.hxx>
+#include <drawinglayer/primitive2d/epsprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// control support
+
+#include <com/sun/star/awt/XWindow2.hpp>
+#include <com/sun/star/awt/PosSize.hpp>
+#include <com/sun/star/awt/XView.hpp>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// for test, can be removed again
+
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/polygon/b2dtrapezoid.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ //////////////////////////////////////////////////////////////////////////////
+ // UNO class usages
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::awt::XView;
+ using ::com::sun::star::awt::XGraphics;
+ using ::com::sun::star::awt::XWindow;
+ using ::com::sun::star::awt::PosSize::POSSIZE;
+
+ //////////////////////////////////////////////////////////////////////////////
+ // rendering support
+
+ // directdraw of text simple portion or decorated portion primitive. When decorated, all the extra
+ // information is translated to VCL parameters and set at the font.
+ // Acceptance is restricted to no shearing and positive scaling in X and Y (no font mirroring
+ // for VCL)
+ void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
+ {
+ // decompose matrix to have position and size of text
+ basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rTextCandidate.getTextTransform());
+ basegfx::B2DVector aFontScaling, aTranslate;
+ double fRotate, fShearX;
+ aLocalTransform.decompose(aFontScaling, aTranslate, fRotate, fShearX);
+ bool bPrimitiveAccepted(false);
+
+ if(basegfx::fTools::equalZero(fShearX))
+ {
+ if(basegfx::fTools::less(aFontScaling.getX(), 0.0) && basegfx::fTools::less(aFontScaling.getY(), 0.0))
+ {
+ // handle special case: If scale is negative in (x,y) (3rd quadrant), it can
+ // be expressed as rotation by PI. Use this since the Font rendering will not
+ // apply the negative scales in any form
+ aFontScaling = basegfx::absolute(aFontScaling);
+ fRotate += F_PI;
+ }
+
+ if(basegfx::fTools::more(aFontScaling.getX(), 0.0) && basegfx::fTools::more(aFontScaling.getY(), 0.0))
+ {
+ // Get the VCL font (use FontHeight as FontWidth)
+ Font aFont(primitive2d::getVclFontFromFontAttribute(
+ rTextCandidate.getFontAttribute(),
+ aFontScaling.getX(),
+ aFontScaling.getY(),
+ fRotate,
+ rTextCandidate.getLocale()));
+
+ // handle additional font attributes
+ const primitive2d::TextDecoratedPortionPrimitive2D* pTCPP =
+ dynamic_cast<const primitive2d::TextDecoratedPortionPrimitive2D*>( &rTextCandidate );
+
+ if( pTCPP != NULL )
+ {
+
+ // set the color of text decorations
+ const basegfx::BColor aTextlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getTextlineColor());
+ mpOutputDevice->SetTextLineColor( Color(aTextlineColor) );
+
+ // set Overline attribute
+ const FontUnderline eFontOverline(primitive2d::mapTextLineToFontUnderline( pTCPP->getFontOverline() ));
+ if( eFontOverline != UNDERLINE_NONE )
+ {
+ aFont.SetOverline( eFontOverline );
+ const basegfx::BColor aOverlineColor = maBColorModifierStack.getModifiedColor(pTCPP->getOverlineColor());
+ mpOutputDevice->SetOverlineColor( Color(aOverlineColor) );
+ if( pTCPP->getWordLineMode() )
+ aFont.SetWordLineMode( true );
+ }
+
+ // set Underline attribute
+ const FontUnderline eFontUnderline(primitive2d::mapTextLineToFontUnderline( pTCPP->getFontUnderline() ));
+ if( eFontUnderline != UNDERLINE_NONE )
+ {
+ aFont.SetUnderline( eFontUnderline );
+ if( pTCPP->getWordLineMode() )
+ aFont.SetWordLineMode( true );
+//TODO: ??? if( pTCPP->getUnderlineAbove() )
+// aFont.SetUnderlineAbove( true );
+ }
+
+ // set Strikeout attribute
+ const FontStrikeout eFontStrikeout(primitive2d::mapTextStrikeoutToFontStrikeout(pTCPP->getTextStrikeout()));
+
+ if( eFontStrikeout != STRIKEOUT_NONE )
+ aFont.SetStrikeout( eFontStrikeout );
+
+ // set EmphasisMark attribute
+ FontEmphasisMark eFontEmphasisMark = EMPHASISMARK_NONE;
+ switch( pTCPP->getTextEmphasisMark() )
+ {
+ default:
+ DBG_WARNING1( "DrawingLayer: Unknown EmphasisMark style (%d)!", pTCPP->getTextEmphasisMark() );
+ // fall through
+ case primitive2d::TEXT_EMPHASISMARK_NONE: eFontEmphasisMark = EMPHASISMARK_NONE; break;
+ case primitive2d::TEXT_EMPHASISMARK_DOT: eFontEmphasisMark = EMPHASISMARK_DOT; break;
+ case primitive2d::TEXT_EMPHASISMARK_CIRCLE: eFontEmphasisMark = EMPHASISMARK_CIRCLE; break;
+ case primitive2d::TEXT_EMPHASISMARK_DISC: eFontEmphasisMark = EMPHASISMARK_DISC; break;
+ case primitive2d::TEXT_EMPHASISMARK_ACCENT: eFontEmphasisMark = EMPHASISMARK_ACCENT; break;
+ }
+
+ if( eFontEmphasisMark != EMPHASISMARK_NONE )
+ {
+ DBG_ASSERT( (pTCPP->getEmphasisMarkAbove() != pTCPP->getEmphasisMarkBelow()),
+ "DrawingLayer: Bad EmphasisMark position!" );
+ if( pTCPP->getEmphasisMarkAbove() )
+ eFontEmphasisMark |= EMPHASISMARK_POS_ABOVE;
+ else
+ eFontEmphasisMark |= EMPHASISMARK_POS_BELOW;
+ aFont.SetEmphasisMark( eFontEmphasisMark );
+ }
+
+ // set Relief attribute
+ FontRelief eFontRelief = RELIEF_NONE;
+ switch( pTCPP->getTextRelief() )
+ {
+ default:
+ DBG_WARNING1( "DrawingLayer: Unknown Relief style (%d)!", pTCPP->getTextRelief() );
+ // fall through
+ case primitive2d::TEXT_RELIEF_NONE: eFontRelief = RELIEF_NONE; break;
+ case primitive2d::TEXT_RELIEF_EMBOSSED: eFontRelief = RELIEF_EMBOSSED; break;
+ case primitive2d::TEXT_RELIEF_ENGRAVED: eFontRelief = RELIEF_ENGRAVED; break;
+ }
+
+ if( eFontRelief != RELIEF_NONE )
+ aFont.SetRelief( eFontRelief );
+
+ // set Shadow attribute
+ if( pTCPP->getShadow() )
+ aFont.SetShadow( true );
+ }
+
+ // create transformed integer DXArray in view coordinate system
+ ::std::vector< sal_Int32 > aTransformedDXArray;
+
+ if(rTextCandidate.getDXArray().size())
+ {
+ aTransformedDXArray.reserve(rTextCandidate.getDXArray().size());
+ const basegfx::B2DVector aPixelVector(maCurrentTransformation * basegfx::B2DVector(1.0, 0.0));
+ const double fPixelVectorFactor(aPixelVector.getLength());
+
+ for(::std::vector< double >::const_iterator aStart(rTextCandidate.getDXArray().begin());
+ aStart != rTextCandidate.getDXArray().end(); aStart++)
+ {
+ aTransformedDXArray.push_back(basegfx::fround((*aStart) * fPixelVectorFactor));
+ }
+ }
+
+ // set parameters and paint text snippet
+ const basegfx::BColor aRGBFontColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor()));
+ const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0));
+ const Point aStartPoint(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY()));
+ const sal_uInt32 nOldLayoutMode(mpOutputDevice->GetLayoutMode());
+
+ if(rTextCandidate.getFontAttribute().getRTL())
+ {
+ sal_uInt32 nRTLLayoutMode(nOldLayoutMode & ~(TEXT_LAYOUT_COMPLEX_DISABLED|TEXT_LAYOUT_BIDI_STRONG));
+ nRTLLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT;
+ mpOutputDevice->SetLayoutMode(nRTLLayoutMode);
+ }
+
+ mpOutputDevice->SetFont(aFont);
+ mpOutputDevice->SetTextColor(Color(aRGBFontColor));
+
+ if(aTransformedDXArray.size())
+ {
+ mpOutputDevice->DrawTextArray(
+ aStartPoint,
+ rTextCandidate.getText(),
+ &(aTransformedDXArray[0]),
+ rTextCandidate.getTextPosition(),
+ rTextCandidate.getTextLength());
+ }
+ else
+ {
+ mpOutputDevice->DrawText(
+ aStartPoint,
+ rTextCandidate.getText(),
+ rTextCandidate.getTextPosition(),
+ rTextCandidate.getTextLength());
+ }
+
+ if(rTextCandidate.getFontAttribute().getRTL())
+ {
+ mpOutputDevice->SetLayoutMode(nOldLayoutMode);
+ }
+
+ bPrimitiveAccepted = true;
+ }
+ }
+
+ if(!bPrimitiveAccepted)
+ {
+ // let break down
+ process(rTextCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+
+ // direct draw of hairline
+ void VclProcessor2D::RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate, bool bPixelBased)
+ {
+ const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
+ mpOutputDevice->SetLineColor(Color(aHairlineColor));
+ mpOutputDevice->SetFillColor();
+
+ basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon());
+ aLocalPolygon.transform(maCurrentTransformation);
+
+ static bool bCheckTrapezoidDecomposition(false);
+ static bool bShowOutlinesThere(false);
+ if(bCheckTrapezoidDecomposition)
+ {
+ // clip against discrete ViewPort
+ const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport();
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(basegfx::tools::clipPolygonOnRange(
+ aLocalPolygon, rDiscreteViewport, true, false));
+
+ if(aLocalPolyPolygon.count())
+ {
+ // subdivide
+ aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(
+ aLocalPolyPolygon, 0.5);
+
+ // trapezoidize
+ static double fLineWidth(2.0);
+ basegfx::B2DTrapezoidVector aB2DTrapezoidVector;
+ basegfx::tools::createLineTrapezoidFromB2DPolyPolygon(aB2DTrapezoidVector, aLocalPolyPolygon, fLineWidth);
+
+ const sal_uInt32 nCount(aB2DTrapezoidVector.size());
+
+ if(nCount)
+ {
+ basegfx::BColor aInvPolygonColor(aHairlineColor);
+ aInvPolygonColor.invert();
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon());
+
+ if(bShowOutlinesThere)
+ {
+ mpOutputDevice->SetFillColor(Color(aHairlineColor));
+ mpOutputDevice->SetLineColor();
+ }
+
+ mpOutputDevice->DrawPolygon(aTempPolygon);
+
+ if(bShowOutlinesThere)
+ {
+ mpOutputDevice->SetFillColor();
+ mpOutputDevice->SetLineColor(Color(aInvPolygonColor));
+ mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if(bPixelBased && getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete())
+ {
+ // #i98289#
+ // when a Hairline is painted and AntiAliasing is on the option SnapHorVerLinesToDiscrete
+ // allows to suppress AntiAliasing for pure horizontal or vertical lines. This is done since
+ // not-AntiAliased such lines look more pleasing to the eye (e.g. 2D chart content). This
+ // NEEDS to be done in discrete coordinates, so only useful for pixel based rendering.
+ aLocalPolygon = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aLocalPolygon);
+ }
+
+ mpOutputDevice->DrawPolyLine(aLocalPolygon, 0.0);
+ }
+ }
+
+ // direct draw of transformed BitmapEx primitive
+ void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
+ {
+ // create local transform
+ basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform());
+ BitmapEx aBitmapEx(rBitmapCandidate.getBitmapEx());
+ bool bPainted(false);
+
+ if(maBColorModifierStack.count())
+ {
+ aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx);
+
+ if(aBitmapEx.IsEmpty())
+ {
+ // color gets completely replaced, get it
+ const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
+ basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
+ aPolygon.transform(aLocalTransform);
+
+ mpOutputDevice->SetFillColor(Color(aModifiedColor));
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->DrawPolygon(aPolygon);
+
+ bPainted = true;
+ }
+ }
+
+ if(!bPainted)
+ {
+ static bool bForceUseOfOwnTransformer(false);
+ static bool bUseGraphicManager(true);
+
+ // decompose matrix to check for shear, rotate and mirroring
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ if(!bForceUseOfOwnTransformer && basegfx::fTools::equalZero(fShearX))
+ {
+ if(!bUseGraphicManager && basegfx::fTools::equalZero(fRotate))
+ {
+ RenderBitmapPrimitive2D_BitmapEx(*mpOutputDevice, aBitmapEx, aLocalTransform);
+ }
+ else
+ {
+ RenderBitmapPrimitive2D_GraphicManager(*mpOutputDevice, aBitmapEx, aLocalTransform);
+ }
+ }
+ else
+ {
+ if(!aBitmapEx.IsTransparent() && (!basegfx::fTools::equalZero(fShearX) || !basegfx::fTools::equalZero(fRotate)))
+ {
+ // parts will be uncovered, extend aBitmapEx with a mask bitmap
+ const Bitmap aContent(aBitmapEx.GetBitmap());
+ aBitmapEx = BitmapEx(aContent, Bitmap(aContent.GetSizePixel(), 1));
+ }
+
+ RenderBitmapPrimitive2D_self(*mpOutputDevice, aBitmapEx, aLocalTransform);
+ }
+ }
+ }
+
+ void VclProcessor2D::RenderFillBitmapPrimitive2D(const primitive2d::FillBitmapPrimitive2D& rFillBitmapCandidate)
+ {
+ const attribute::FillBitmapAttribute& rFillBitmapAttribute(rFillBitmapCandidate.getFillBitmap());
+ bool bPrimitiveAccepted(false);
+
+ if(rFillBitmapAttribute.getTiling())
+ {
+ // decompose matrix to check for shear, rotate and mirroring
+ basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rFillBitmapCandidate.getTransformation());
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ if(basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX))
+ {
+ // no shear or rotate, draw direct in pixel coordinates
+ bPrimitiveAccepted = true;
+ BitmapEx aBitmapEx(rFillBitmapAttribute.getBitmapEx());
+ bool bPainted(false);
+
+ if(maBColorModifierStack.count())
+ {
+ aBitmapEx = impModifyBitmapEx(maBColorModifierStack, aBitmapEx);
+
+ if(aBitmapEx.IsEmpty())
+ {
+ // color gets completely replaced, get it
+ const basegfx::BColor aModifiedColor(maBColorModifierStack.getModifiedColor(basegfx::BColor()));
+ basegfx::B2DPolygon aPolygon(basegfx::tools::createUnitPolygon());
+ aPolygon.transform(aLocalTransform);
+
+ mpOutputDevice->SetFillColor(Color(aModifiedColor));
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->DrawPolygon(aPolygon);
+
+ bPainted = true;
+ }
+ }
+
+ if(!bPainted)
+ {
+ const basegfx::B2DPoint aObjTopLeft(aTranslate.getX(), aTranslate.getY());
+ const basegfx::B2DPoint aObjBottomRight(aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
+ const Point aObjTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjTopLeft.getX(), (sal_Int32)aObjTopLeft.getY())));
+ const Point aObjBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aObjBottomRight.getX(), (sal_Int32)aObjBottomRight.getY())));
+
+ const basegfx::B2DPoint aBmpTopLeft(aLocalTransform * rFillBitmapAttribute.getTopLeft());
+ const basegfx::B2DPoint aBmpBottomRight(aLocalTransform * basegfx::B2DPoint(rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize()));
+ const Point aBmpTL(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpTopLeft.getX(), (sal_Int32)aBmpTopLeft.getY())));
+ const Point aBmpBR(mpOutputDevice->LogicToPixel(Point((sal_Int32)aBmpBottomRight.getX(), (sal_Int32)aBmpBottomRight.getY())));
+
+ sal_Int32 nOWidth(aObjBR.X() - aObjTL.X());
+ sal_Int32 nOHeight(aObjBR.Y() - aObjTL.Y());
+
+ // only do something when object has a size in discrete units
+ if(nOWidth > 0 && nOHeight > 0)
+ {
+ sal_Int32 nBWidth(aBmpBR.X() - aBmpTL.X());
+ sal_Int32 nBHeight(aBmpBR.Y() - aBmpTL.Y());
+
+ // only do something when bitmap fill has a size in discrete units
+ if(nBWidth > 0 && nBHeight > 0)
+ {
+ sal_Int32 nBLeft(aBmpTL.X());
+ sal_Int32 nBTop(aBmpTL.Y());
+
+ if(nBLeft > aObjTL.X())
+ {
+ nBLeft -= ((nBLeft / nBWidth) + 1L) * nBWidth;
+ }
+
+ if(nBLeft + nBWidth <= aObjTL.X())
+ {
+ nBLeft -= (nBLeft / nBWidth) * nBWidth;
+ }
+
+ if(nBTop > aObjTL.Y())
+ {
+ nBTop -= ((nBTop / nBHeight) + 1L) * nBHeight;
+ }
+
+ if(nBTop + nBHeight <= aObjTL.Y())
+ {
+ nBTop -= (nBTop / nBHeight) * nBHeight;
+ }
+
+ // nBWidth, nBHeight is the pixel size of the neede bitmap. To not need to scale it
+ // in vcl many times, create a size-optimized version
+ const Size aNeededBitmapSizePixel(nBWidth, nBHeight);
+
+ if(aNeededBitmapSizePixel != aBitmapEx.GetSizePixel())
+ {
+ aBitmapEx.Scale(aNeededBitmapSizePixel);
+ }
+
+ // prepare OutDev
+ const Point aEmptyPoint(0, 0);
+ const Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel());
+ const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
+ mpOutputDevice->EnableMapMode(false);
+
+ for(sal_Int32 nXPos(nBLeft); nXPos < aObjTL.X() + nOWidth; nXPos += nBWidth)
+ {
+ for(sal_Int32 nYPos(nBTop); nYPos < aObjTL.Y() + nOHeight; nYPos += nBHeight)
+ {
+ const Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel);
+
+ if(aOutRectPixel.IsOver(aVisiblePixel))
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
+ }
+ }
+ }
+
+ // restore OutDev
+ mpOutputDevice->EnableMapMode(bWasEnabled);
+ }
+ }
+ }
+ }
+ }
+
+ if(!bPrimitiveAccepted)
+ {
+ // do not accept, use decomposition
+ process(rFillBitmapCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+
+ // direct draw of gradient
+ void VclProcessor2D::RenderPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate)
+ {
+ const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
+ basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
+ basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+
+ if(aLocalPolyPolygon.count())
+ {
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ if(aStartColor == aEndColor)
+ {
+ // no gradient at all, draw as polygon in AA and non-AA case
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->SetFillColor(Color(aStartColor));
+ mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
+ }
+ else if(getOptionsDrawinglayer().IsAntiAliasing())
+ {
+ // For AA, direct render has to be avoided since it uses XOR maskings which will not
+ // work with AA. Instead, the decompose which uses MaskPrimitive2D with fillings is
+ // used
+ process(rPolygonCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ else
+ {
+ impDrawGradientToOutDev(
+ *mpOutputDevice, aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(),
+ aStartColor, aEndColor, rGradient.getBorder(),
+ rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false);
+ }
+ }
+ }
+
+ // direct draw of bitmap
+ void VclProcessor2D::RenderPolyPolygonBitmapPrimitive2D(const primitive2d::PolyPolygonBitmapPrimitive2D& rPolygonCandidate)
+ {
+ bool bDone(false);
+ const basegfx::B2DPolyPolygon& rPolyPolygon = rPolygonCandidate.getB2DPolyPolygon();
+
+ if(rPolyPolygon.count())
+ {
+ const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPolygonCandidate.getFillBitmap();
+ const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx();
+
+ if(rBitmapEx.IsEmpty())
+ {
+ // empty bitmap, done
+ bDone = true;
+ }
+ else
+ {
+ // try to catch cases where the bitmap will be color-modified to a single
+ // color (e.g. shadow). This would NOT be optimizable with an transparence channel
+ // at the Bitmap which we do not have here. When this should change, this
+ // optimization has to be reworked accordingly.
+ const sal_uInt32 nBColorModifierStackCount(maBColorModifierStack.count());
+
+ if(nBColorModifierStackCount)
+ {
+ const basegfx::BColorModifier& rTopmostModifier = maBColorModifierStack.getBColorModifier(nBColorModifierStackCount - 1);
+
+ if(basegfx::BCOLORMODIFYMODE_REPLACE == rTopmostModifier.getMode())
+ {
+ // the bitmap fill is in unified color, so we can replace it with
+ // a single polygon fill. The form of the fill depends on tiling
+ if(rFillBitmapAttribute.getTiling())
+ {
+ // with tiling, fill the whole PolyPolygon with the modifier color
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolyPolygon);
+
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor()));
+ mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
+ }
+ else
+ {
+ // without tiling, only the area common to the bitmap tile and the
+ // PolyPolygon is filled. Create the bitmap tile area in object
+ // coordinates. For this, the object transformation needs to be created
+ // from the already scaled PolyPolygon. The tile area in object
+ // coordinates wil always be non-rotated, so it's not necessary to
+ // work with a polygon here
+ basegfx::B2DRange aTileRange(rFillBitmapAttribute.getTopLeft(),
+ rFillBitmapAttribute.getTopLeft() + rFillBitmapAttribute.getSize());
+ const basegfx::B2DRange aPolyPolygonRange(rPolyPolygon.getB2DRange());
+ basegfx::B2DHomMatrix aNewObjectTransform;
+
+ aNewObjectTransform.set(0, 0, aPolyPolygonRange.getWidth());
+ aNewObjectTransform.set(1, 1, aPolyPolygonRange.getHeight());
+ aNewObjectTransform.set(0, 2, aPolyPolygonRange.getMinX());
+ aNewObjectTransform.set(1, 2, aPolyPolygonRange.getMinY());
+ aTileRange.transform(aNewObjectTransform);
+
+ // now clip the object polyPolygon against the tile range
+ // to get the common area (OR)
+ basegfx::B2DPolyPolygon aTarget = basegfx::tools::clipPolyPolygonOnRange(rPolyPolygon, aTileRange, true, false);
+
+ if(aTarget.count())
+ {
+ aTarget.transform(maCurrentTransformation);
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->SetFillColor(Color(rTopmostModifier.getBColor()));
+ mpOutputDevice->DrawPolyPolygon(aTarget);
+ }
+ }
+
+ bDone = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ // empty polyPolygon, done
+ bDone = true;
+ }
+
+ if(!bDone)
+ {
+ // use default decomposition
+ process(rPolygonCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+
+ // direct draw of PolyPolygon with color
+ void VclProcessor2D::RenderPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate)
+ {
+ const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
+
+ basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ static bool bCheckTrapezoidDecomposition(false);
+ static bool bShowOutlinesThere(false);
+ if(bCheckTrapezoidDecomposition)
+ {
+ // clip against discrete ViewPort
+ const basegfx::B2DRange& rDiscreteViewport = getViewInformation2D().getDiscreteViewport();
+ aLocalPolyPolygon = basegfx::tools::clipPolyPolygonOnRange(
+ aLocalPolyPolygon, rDiscreteViewport, true, false);
+
+ if(aLocalPolyPolygon.count())
+ {
+ // subdivide
+ aLocalPolyPolygon = basegfx::tools::adaptiveSubdivideByDistance(
+ aLocalPolyPolygon, 0.5);
+
+ // trapezoidize
+ basegfx::B2DTrapezoidVector aB2DTrapezoidVector;
+ basegfx::tools::trapezoidSubdivide(aB2DTrapezoidVector, aLocalPolyPolygon);
+
+ const sal_uInt32 nCount(aB2DTrapezoidVector.size());
+
+ if(nCount)
+ {
+ basegfx::BColor aInvPolygonColor(aPolygonColor);
+ aInvPolygonColor.invert();
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ const basegfx::B2DPolygon aTempPolygon(aB2DTrapezoidVector[a].getB2DPolygon());
+
+ if(bShowOutlinesThere)
+ {
+ mpOutputDevice->SetFillColor(Color(aPolygonColor));
+ mpOutputDevice->SetLineColor();
+ }
+
+ mpOutputDevice->DrawPolygon(aTempPolygon);
+
+ if(bShowOutlinesThere)
+ {
+ mpOutputDevice->SetFillColor();
+ mpOutputDevice->SetLineColor(Color(aInvPolygonColor));
+ mpOutputDevice->DrawPolyLine(aTempPolygon, 0.0);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
+
+ if(mnPolygonStrokePrimitive2D
+ && getOptionsDrawinglayer().IsAntiAliasing()
+ && (mpOutputDevice->GetAntialiasing() & ANTIALIASING_ENABLE_B2DDRAW))
+ {
+ // when AA is on and this filled polygons are the result of stroked line geometry,
+ // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
+ mpOutputDevice->SetFillColor();
+ mpOutputDevice->SetLineColor(Color(aPolygonColor));
+ const sal_uInt32 nCount(aLocalPolyPolygon.count());
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0);
+ }
+ }
+ }
+ }
+
+ // direct draw of MetaFile
+ void VclProcessor2D::RenderMetafilePrimitive2D(const primitive2d::MetafilePrimitive2D& rMetaCandidate)
+ {
+ // decompose matrix to check for shear, rotate and mirroring
+ basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rMetaCandidate.getTransform());
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
+ {
+ // #i102175# handle special case: If scale is negative in (x,y) (3rd quadrant), it can
+ // be expressed as rotation by PI. This needs to be done for Metafiles since
+ // these can be rotated, but not really mirrored
+ aScale = basegfx::absolute(aScale);
+ fRotate += F_PI;
+ }
+
+ // get BoundRect
+ basegfx::B2DRange aOutlineRange(rMetaCandidate.getB2DRange(getViewInformation2D()));
+ aOutlineRange.transform(maCurrentTransformation);
+
+ // Due to the integer MapModes used from VCL aind inside MetaFiles errors of up to three
+ // pixels in size may happen. As long as there is no better way (e.g. convert the MetaFile
+ // to primitives) it is necessary to reduce maximum pixel size by 1 in X and Y and to use
+ // the inner pixel bounds accordingly (ceil resp. floor). This will also be done for logic
+ // units e.g. when creating a new MetaFile, but since much huger value ranges are used
+ // there typically will be okay for this compromize.
+ Rectangle aDestRectView(
+ // !!CAUTION!! Here, ceil and floor are exchanged BY PURPOSE, do NOT copy when
+ // looking for a standard conversion to rectangle (!)
+ (sal_Int32)ceil(aOutlineRange.getMinX()), (sal_Int32)ceil(aOutlineRange.getMinY()),
+ (sal_Int32)floor(aOutlineRange.getMaxX()), (sal_Int32)floor(aOutlineRange.getMaxY()));
+
+ // get metafile (copy it)
+ GDIMetaFile aMetaFile;
+
+ if(maBColorModifierStack.count())
+ {
+ const basegfx::BColor aRGBBaseColor(0, 0, 0);
+ const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(aRGBBaseColor));
+ aMetaFile = rMetaCandidate.getMetaFile().GetMonochromeMtf(Color(aRGBColor));
+ }
+ else
+ {
+ aMetaFile = rMetaCandidate.getMetaFile();
+ }
+
+ // rotation
+ if(!basegfx::fTools::equalZero(fRotate))
+ {
+ // #i103530#
+ // MetaFile::Rotate has no input parameter check, so the parameter needs to be
+ // well-aligned to the old range [0..3600] 10th degrees with inverse orientation
+ sal_Int16 nRotation((sal_Int16)((fRotate / F_PI180) * -10.0));
+
+ while(nRotation < 0)
+ nRotation += 3600;
+
+ while(nRotation >= 3600)
+ nRotation -= 3600;
+
+ aMetaFile.Rotate(nRotation);
+ }
+
+ // Prepare target output size
+ Size aDestSize(aDestRectView.GetSize());
+
+ if(aDestSize.getWidth() && aDestSize.getHeight())
+ {
+ // Get preferred Metafile output size. When it's very equal to the output size, it's probably
+ // a rounding error somewhere, so correct it to get a 1:1 output without single pixel scalings
+ // of the Metafile (esp. for contaned Bitmaps, e.g 3D charts)
+ const Size aPrefSize(mpOutputDevice->LogicToPixel(aMetaFile.GetPrefSize(), aMetaFile.GetPrefMapMode()));
+
+ if(aPrefSize.getWidth() && (aPrefSize.getWidth() - 1 == aDestSize.getWidth() || aPrefSize.getWidth() + 1 == aDestSize.getWidth()))
+ {
+ aDestSize.setWidth(aPrefSize.getWidth());
+ }
+
+ if(aPrefSize.getHeight() && (aPrefSize.getHeight() - 1 == aDestSize.getHeight() || aPrefSize.getHeight() + 1 == aDestSize.getHeight()))
+ {
+ aDestSize.setHeight(aPrefSize.getHeight());
+ }
+
+ // paint it
+ aMetaFile.WindStart();
+ aMetaFile.Play(mpOutputDevice, aDestRectView.TopLeft(), aDestSize);
+ }
+ }
+
+ // mask group. Force output to VDev and create mask from given mask
+ void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive2D& rMaskCandidate)
+ {
+ if(rMaskCandidate.getChildren().hasElements())
+ {
+ basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
+
+ if(aMask.count())
+ {
+ aMask.transform(maCurrentTransformation);
+ const basegfx::B2DRange aRange(basegfx::tools::getRange(aMask));
+ impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
+
+ if(aBufferDevice.isVisible())
+ {
+ // remember last OutDev and set to content
+ OutputDevice* pLastOutputDevice = mpOutputDevice;
+ mpOutputDevice = &aBufferDevice.getContent();
+
+ // paint to it
+ process(rMaskCandidate.getChildren());
+
+ // back to old OutDev
+ mpOutputDevice = pLastOutputDevice;
+
+ // draw mask
+ if(getOptionsDrawinglayer().IsAntiAliasing())
+ {
+ // with AA, use 8bit AlphaMask to get nice borders
+ VirtualDevice& rTransparence = aBufferDevice.getTransparence();
+ rTransparence.SetLineColor();
+ rTransparence.SetFillColor(COL_BLACK);
+ rTransparence.DrawPolyPolygon(aMask);
+
+ // dump buffer to outdev
+ aBufferDevice.paint();
+ }
+ else
+ {
+ // No AA, use 1bit mask
+ VirtualDevice& rMask = aBufferDevice.getMask();
+ rMask.SetLineColor();
+ rMask.SetFillColor(COL_BLACK);
+ rMask.DrawPolyPolygon(aMask);
+
+ // dump buffer to outdev
+ aBufferDevice.paint();
+ }
+ }
+ }
+ }
+ }
+
+ // modified color group. Force output to unified color.
+ void VclProcessor2D::RenderModifiedColorPrimitive2D(const primitive2d::ModifiedColorPrimitive2D& rModifiedCandidate)
+ {
+ if(rModifiedCandidate.getChildren().hasElements())
+ {
+ maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
+ process(rModifiedCandidate.getChildren());
+ maBColorModifierStack.pop();
+ }
+ }
+
+ // unified sub-transparence. Draw to VDev first.
+ void VclProcessor2D::RenderUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rTransCandidate)
+ {
+ static bool bForceToDecomposition(false);
+
+ if(rTransCandidate.getChildren().hasElements())
+ {
+ if(bForceToDecomposition)
+ {
+ // use decomposition
+ process(rTransCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ else
+ {
+ if(0.0 == rTransCandidate.getTransparence())
+ {
+ // no transparence used, so just use the content
+ process(rTransCandidate.getChildren());
+ }
+ else if(rTransCandidate.getTransparence() > 0.0 && rTransCandidate.getTransparence() < 1.0)
+ {
+ // transparence is in visible range
+ basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D()));
+ aRange.transform(maCurrentTransformation);
+ impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
+
+ if(aBufferDevice.isVisible())
+ {
+ // remember last OutDev and set to content
+ OutputDevice* pLastOutputDevice = mpOutputDevice;
+ mpOutputDevice = &aBufferDevice.getContent();
+
+ // paint content to it
+ process(rTransCandidate.getChildren());
+
+ // back to old OutDev
+ mpOutputDevice = pLastOutputDevice;
+
+ // dump buffer to outdev using given transparence
+ aBufferDevice.paint(rTransCandidate.getTransparence());
+ }
+ }
+ }
+ }
+ }
+
+ // sub-transparence group. Draw to VDev first.
+ void VclProcessor2D::RenderTransparencePrimitive2D(const primitive2d::TransparencePrimitive2D& rTransCandidate)
+ {
+ if(rTransCandidate.getChildren().hasElements())
+ {
+ basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D()));
+ aRange.transform(maCurrentTransformation);
+ impBufferDevice aBufferDevice(*mpOutputDevice, aRange, true);
+
+ if(aBufferDevice.isVisible())
+ {
+ // remember last OutDev and set to content
+ OutputDevice* pLastOutputDevice = mpOutputDevice;
+ mpOutputDevice = &aBufferDevice.getContent();
+
+ // paint content to it
+ process(rTransCandidate.getChildren());
+
+ // set to mask
+ mpOutputDevice = &aBufferDevice.getTransparence();
+
+ // when painting transparence masks, reset the color stack
+ basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
+ maBColorModifierStack = basegfx::BColorModifierStack();
+
+ // paint mask to it (always with transparence intensities, evtl. with AA)
+ process(rTransCandidate.getTransparence());
+
+ // back to old color stack
+ maBColorModifierStack = aLastBColorModifierStack;
+
+ // back to old OutDev
+ mpOutputDevice = pLastOutputDevice;
+
+ // dump buffer to outdev
+ aBufferDevice.paint();
+ }
+ }
+ }
+
+ // transform group.
+ void VclProcessor2D::RenderTransformPrimitive2D(const primitive2d::TransformPrimitive2D& rTransformCandidate)
+ {
+ // remember current transformation and ViewInformation
+ const basegfx::B2DHomMatrix aLastCurrentTransformation(maCurrentTransformation);
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // create new transformations for CurrentTransformation
+ // and for local ViewInformation2D
+ maCurrentTransformation = maCurrentTransformation * rTransformCandidate.getTransformation();
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
+ getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ getViewInformation2D().getVisualizedPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // proccess content
+ process(rTransformCandidate.getChildren());
+
+ // restore transformations
+ maCurrentTransformation = aLastCurrentTransformation;
+ updateViewInformation(aLastViewInformation2D);
+ }
+
+ // new XDrawPage for ViewInformation2D
+ void VclProcessor2D::RenderPagePreviewPrimitive2D(const primitive2d::PagePreviewPrimitive2D& rPagePreviewCandidate)
+ {
+ // remember current transformation and ViewInformation
+ const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
+
+ // create new local ViewInformation2D
+ const geometry::ViewInformation2D aViewInformation2D(
+ getViewInformation2D().getObjectTransformation(),
+ getViewInformation2D().getViewTransformation(),
+ getViewInformation2D().getViewport(),
+ rPagePreviewCandidate.getXDrawPage(),
+ getViewInformation2D().getViewTime(),
+ getViewInformation2D().getExtendedInformationSequence());
+ updateViewInformation(aViewInformation2D);
+
+ // proccess decomposed content
+ process(rPagePreviewCandidate.get2DDecomposition(getViewInformation2D()));
+
+ // restore transformations
+ updateViewInformation(aLastViewInformation2D);
+ }
+
+ // marker
+ void VclProcessor2D::RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D& rMarkArrayCandidate)
+ {
+ static bool bCheckCompleteMarkerDecompose(false);
+ if(bCheckCompleteMarkerDecompose)
+ {
+ process(rMarkArrayCandidate.get2DDecomposition(getViewInformation2D()));
+ return;
+ }
+
+ // get data
+ const std::vector< basegfx::B2DPoint >& rPositions = rMarkArrayCandidate.getPositions();
+ const sal_uInt32 nCount(rPositions.size());
+
+ if(nCount && !rMarkArrayCandidate.getMarker().IsEmpty())
+ {
+ // get pixel size
+ const BitmapEx& rMarker(rMarkArrayCandidate.getMarker());
+ const Size aBitmapSize(rMarker.GetSizePixel());
+
+ if(aBitmapSize.Width() && aBitmapSize.Height())
+ {
+ // get discrete half size
+ const basegfx::B2DVector aDiscreteHalfSize(
+ (aBitmapSize.getWidth() - 1.0) * 0.5,
+ (aBitmapSize.getHeight() - 1.0) * 0.5);
+ const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
+
+ // do not forget evtl. moved origin in target device MapMode when
+ // switching it off; it would be missing and lead to wrong positions.
+ // All his could be done using logic sizes and coordinates, too, but
+ // we want a 1:1 bitmap rendering here, so it's more safe and faster
+ // to work with switching off MapMode usage completely.
+ const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin());
+
+ mpOutputDevice->EnableMapMode(false);
+
+ for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++)
+ {
+ const basegfx::B2DPoint aDiscreteTopLeft((maCurrentTransformation * (*aIter)) - aDiscreteHalfSize);
+ const Point aDiscretePoint(basegfx::fround(aDiscreteTopLeft.getX()), basegfx::fround(aDiscreteTopLeft.getY()));
+
+ mpOutputDevice->DrawBitmapEx(aDiscretePoint + aOrigin, rMarker);
+ }
+
+ mpOutputDevice->EnableMapMode(bWasEnabled);
+ }
+ }
+ }
+
+ // point
+ void VclProcessor2D::RenderPointArrayPrimitive2D(const primitive2d::PointArrayPrimitive2D& rPointArrayCandidate)
+ {
+ const std::vector< basegfx::B2DPoint >& rPositions = rPointArrayCandidate.getPositions();
+ const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rPointArrayCandidate.getRGBColor()));
+ const Color aVCLColor(aRGBColor);
+
+ for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++)
+ {
+ const basegfx::B2DPoint aViewPosition(maCurrentTransformation * (*aIter));
+ const Point aPos(basegfx::fround(aViewPosition.getX()), basegfx::fround(aViewPosition.getY()));
+
+ mpOutputDevice->DrawPixel(aPos, aVCLColor);
+ }
+ }
+
+ void VclProcessor2D::RenderPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokeCandidate)
+ {
+ // #i101491# method restructured to clearly use the DrawPolyLine
+ // calls starting from a deined line width
+ const attribute::LineAttribute& rLineAttribute = rPolygonStrokeCandidate.getLineAttribute();
+ const double fLineWidth(rLineAttribute.getWidth());
+ bool bDone(false);
+
+ if(basegfx::fTools::more(fLineWidth, 0.0))
+ {
+ const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(fLineWidth, 0.0));
+ const double fDiscreteLineWidth(aDiscreteUnit.getLength());
+ const attribute::StrokeAttribute& rStrokeAttribute = rPolygonStrokeCandidate.getStrokeAttribute();
+ const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLineAttribute.getColor()));
+ basegfx::B2DPolyPolygon aHairlinePolyPolygon;
+
+ mpOutputDevice->SetLineColor(Color(aHairlineColor));
+ mpOutputDevice->SetFillColor();
+
+ if(0.0 == rStrokeAttribute.getFullDotDashLen())
+ {
+ // no line dashing, just copy
+ aHairlinePolyPolygon.append(rPolygonStrokeCandidate.getB2DPolygon());
+ }
+ else
+ {
+ // else apply LineStyle
+ basegfx::tools::applyLineDashing(rPolygonStrokeCandidate.getB2DPolygon(),
+ rStrokeAttribute.getDotDashArray(),
+ &aHairlinePolyPolygon, 0, rStrokeAttribute.getFullDotDashLen());
+ }
+
+ const sal_uInt32 nCount(aHairlinePolyPolygon.count());
+
+ if(nCount)
+ {
+ const bool bAntiAliased(getOptionsDrawinglayer().IsAntiAliasing());
+ aHairlinePolyPolygon.transform(maCurrentTransformation);
+
+ for(sal_uInt32 a(0); a < nCount; a++)
+ {
+ basegfx::B2DPolygon aCandidate(aHairlinePolyPolygon.getB2DPolygon(a));
+
+ if(bAntiAliased)
+ {
+ if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.0))
+ {
+ // line in range ]0.0 .. 1.0[
+ // paint as simple hairline
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+ bDone = true;
+ }
+ else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.0))
+ {
+ // line in range [1.0 .. 2.0[
+ // paint as 2x2 with dynamic line distance
+ basegfx::B2DHomMatrix aMat;
+ const double fDistance(fDiscreteLineWidth - 1.0);
+ const double fHalfDistance(fDistance * 0.5);
+
+ aMat.set(0, 2, -fHalfDistance);
+ aMat.set(1, 2, -fHalfDistance);
+ aCandidate.transform(aMat);
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, fDistance);
+ aMat.set(1, 2, 0.0);
+ aCandidate.transform(aMat);
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, 0.0);
+ aMat.set(1, 2, fDistance);
+ aCandidate.transform(aMat);
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, -fDistance);
+ aMat.set(1, 2, 0.0);
+ aCandidate.transform(aMat);
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+ bDone = true;
+ }
+ else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 3.0))
+ {
+ // line in range [2.0 .. 3.0]
+ // paint as cross in a 3x3 with dynamic line distance
+ basegfx::B2DHomMatrix aMat;
+ const double fDistance((fDiscreteLineWidth - 1.0) * 0.5);
+
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, -fDistance);
+ aMat.set(1, 2, 0.0);
+ aCandidate.transform(aMat);
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, fDistance);
+ aMat.set(1, 2, -fDistance);
+ aCandidate.transform(aMat);
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, fDistance);
+ aMat.set(1, 2, fDistance);
+ aCandidate.transform(aMat);
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, -fDistance);
+ aMat.set(1, 2, fDistance);
+ aCandidate.transform(aMat);
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+ bDone = true;
+ }
+ else
+ {
+ // #i101491# line width above 3.0
+ }
+ }
+ else
+ {
+ if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 1.5))
+ {
+ // line width below 1.5, draw the basic hairline polygon
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+ bDone = true;
+ }
+ else if(basegfx::fTools::lessOrEqual(fDiscreteLineWidth, 2.5))
+ {
+ // line width is in range ]1.5 .. 2.5], use four hairlines
+ // drawn in a square
+ basegfx::B2DHomMatrix aMat;
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, 1.0);
+ aMat.set(1, 2, 0.0);
+ aCandidate.transform(aMat);
+
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, 0.0);
+ aMat.set(1, 2, 1.0);
+ aCandidate.transform(aMat);
+
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+
+ aMat.set(0, 2, -1.0);
+ aMat.set(1, 2, 0.0);
+ aCandidate.transform(aMat);
+
+ mpOutputDevice->DrawPolyLine(aCandidate, 0.0);
+ bDone = true;
+ }
+ else
+ {
+ // #i101491# line width is above 2.5
+ }
+ }
+
+ if(!bDone && rPolygonStrokeCandidate.getB2DPolygon().count() > 1000)
+ {
+ // #i101491# If the polygon complexity uses more than a given amount, do
+ // use OuputDevice::DrawPolyLine directly; this will avoid buffering all
+ // decompositions in primtives (memory) and fallback to old line painting
+ // for very complex polygons, too
+ mpOutputDevice->DrawPolyLine(aCandidate, fDiscreteLineWidth, rLineAttribute.getLineJoin());
+ bDone = true;
+ }
+ }
+ }
+ }
+
+ if(!bDone)
+ {
+ // remeber that we enter a PolygonStrokePrimitive2D decomposition,
+ // used for AA thick line drawing
+ mnPolygonStrokePrimitive2D++;
+
+ // line width is big enough for standard filled polygon visualisation or zero
+ process(rPolygonStrokeCandidate.get2DDecomposition(getViewInformation2D()));
+
+ // leave PolygonStrokePrimitive2D
+ mnPolygonStrokePrimitive2D--;
+ }
+ }
+
+ void VclProcessor2D::RenderEpsPrimitive2D(const primitive2d::EpsPrimitive2D& rEpsPrimitive2D)
+ {
+ // The new decomposition of Metafiles made it necessary to add an Eps
+ // primitive to handle embedded Eps data. On some devices, this can be
+ // painted directly (mac, printer).
+ // To be able to handle the replacement correctly, i need to handle it myself
+ // since DrawEPS will not be able e.g. to rotate the replacement. To be able
+ // to do that, i added a boolean return to OutputDevice::DrawEPS(..)
+ // to know when EPS was handled directly already.
+ basegfx::B2DRange aRange(0.0, 0.0, 1.0, 1.0);
+ aRange.transform(maCurrentTransformation * rEpsPrimitive2D.getEpsTransform());
+
+ if(!aRange.isEmpty())
+ {
+ const Rectangle aRectangle(
+ (sal_Int32)floor(aRange.getMinX()), (sal_Int32)floor(aRange.getMinY()),
+ (sal_Int32)ceil(aRange.getMaxX()), (sal_Int32)ceil(aRange.getMaxY()));
+
+ if(!aRectangle.IsEmpty())
+ {
+ // try to paint EPS directly without fallback visualisation
+ const bool bEPSPaintedDirectly(mpOutputDevice->DrawEPS(
+ aRectangle.TopLeft(),
+ aRectangle.GetSize(),
+ rEpsPrimitive2D.getGfxLink(),
+ 0));
+
+ if(!bEPSPaintedDirectly)
+ {
+ // use the decomposition which will correctly handle the
+ // fallback visualisation using full transformation (e.g. rotation)
+ process(rEpsPrimitive2D.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+ }
+ }
+
+ void VclProcessor2D::adaptLineToFillDrawMode() const
+ {
+ const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+
+ if(nOriginalDrawMode & (DRAWMODE_BLACKLINE|DRAWMODE_GRAYLINE|DRAWMODE_GHOSTEDLINE|DRAWMODE_WHITELINE|DRAWMODE_SETTINGSLINE))
+ {
+ sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode);
+
+ if(nOriginalDrawMode & DRAWMODE_BLACKLINE)
+ {
+ nAdaptedDrawMode |= DRAWMODE_BLACKFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL;
+ }
+
+ if(nOriginalDrawMode & DRAWMODE_GRAYLINE)
+ {
+ nAdaptedDrawMode |= DRAWMODE_GRAYFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL;
+ }
+
+ if(nOriginalDrawMode & DRAWMODE_GHOSTEDLINE)
+ {
+ nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL;
+ }
+
+ if(nOriginalDrawMode & DRAWMODE_WHITELINE)
+ {
+ nAdaptedDrawMode |= DRAWMODE_WHITEFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL;
+ }
+
+ if(nOriginalDrawMode & DRAWMODE_SETTINGSLINE)
+ {
+ nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL;
+ }
+
+ mpOutputDevice->SetDrawMode(nAdaptedDrawMode);
+ }
+ }
+
+ void VclProcessor2D::adaptTextToFillDrawMode() const
+ {
+ const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+ if(nOriginalDrawMode & (DRAWMODE_BLACKTEXT|DRAWMODE_GRAYTEXT|DRAWMODE_GHOSTEDTEXT|DRAWMODE_WHITETEXT|DRAWMODE_SETTINGSTEXT))
+ {
+ sal_uInt32 nAdaptedDrawMode(nOriginalDrawMode);
+
+ if(nOriginalDrawMode & DRAWMODE_BLACKTEXT)
+ {
+ nAdaptedDrawMode |= DRAWMODE_BLACKFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_BLACKFILL;
+ }
+
+ if(nOriginalDrawMode & DRAWMODE_GRAYTEXT)
+ {
+ nAdaptedDrawMode |= DRAWMODE_GRAYFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_GRAYFILL;
+ }
+
+ if(nOriginalDrawMode & DRAWMODE_GHOSTEDTEXT)
+ {
+ nAdaptedDrawMode |= DRAWMODE_GHOSTEDFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_GHOSTEDFILL;
+ }
+
+ if(nOriginalDrawMode & DRAWMODE_WHITETEXT)
+ {
+ nAdaptedDrawMode |= DRAWMODE_WHITEFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_WHITEFILL;
+ }
+
+ if(nOriginalDrawMode & DRAWMODE_SETTINGSTEXT)
+ {
+ nAdaptedDrawMode |= DRAWMODE_SETTINGSFILL;
+ }
+ else
+ {
+ nAdaptedDrawMode &= ~DRAWMODE_SETTINGSFILL;
+ }
+
+ mpOutputDevice->SetDrawMode(nAdaptedDrawMode);
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // process support
+
+ VclProcessor2D::VclProcessor2D(
+ const geometry::ViewInformation2D& rViewInformation,
+ OutputDevice& rOutDev)
+ : BaseProcessor2D(rViewInformation),
+ mpOutputDevice(&rOutDev),
+ maBColorModifierStack(),
+ maCurrentTransformation(),
+ maDrawinglayerOpt(),
+ mnPolygonStrokePrimitive2D(0)
+ {
+ // set digit language, derived from SvtCTLOptions to have the correct
+ // number display for arabic/hindi numerals
+ const SvtCTLOptions aSvtCTLOptions;
+ LanguageType eLang(LANGUAGE_SYSTEM);
+
+ if(SvtCTLOptions::NUMERALS_HINDI == aSvtCTLOptions.GetCTLTextNumerals())
+ {
+ eLang = LANGUAGE_ARABIC_SAUDI_ARABIA;
+ }
+ else if(SvtCTLOptions::NUMERALS_ARABIC == aSvtCTLOptions.GetCTLTextNumerals())
+ {
+ eLang = LANGUAGE_ENGLISH;
+ }
+ else
+ {
+ eLang = (LanguageType)Application::GetSettings().GetLanguage();
+ }
+
+ rOutDev.SetDigitLanguage(eLang);
+ }
+
+ VclProcessor2D::~VclProcessor2D()
+ {
+ }
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof