summaryrefslogtreecommitdiff
path: root/drawinglayer/source/processor2d/vclprocessor2d.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer/source/processor2d/vclprocessor2d.cxx')
-rw-r--r--drawinglayer/source/processor2d/vclprocessor2d.cxx1718
1 files changed, 1718 insertions, 0 deletions
diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx
new file mode 100644
index 000000000000..b45f0146f99b
--- /dev/null
+++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx
@@ -0,0 +1,1718 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: vclprocessor2d.cxx,v $
+ *
+ * $Revision: 1.1 $
+ *
+ * last change: $Author: aw $ $Date: 2006-10-19 10:35:37 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library 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 for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_DRAWINGLAYER_PROCESSOR2D_VCLPROCESSOR2D_HXX
+#include <drawinglayer/processor2d/vclprocessor2d.hxx>
+#endif
+
+#ifndef _SV_OUTDEV_HXX
+#include <vcl/outdev.hxx>
+#endif
+
+#ifndef _BGFX_POLYGON_B2DPOLYGON_HXX
+#include <basegfx/polygon/b2dpolygon.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_ATTRIBUTE_FILLATTRIBUTE_HXX
+#include <drawinglayer/attribute/fillattribute.hxx>
+#endif
+
+#ifndef _BGFX_POLYPOLYGON_B2DPOLYGONTOOLS_HXX
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#endif
+
+#ifndef _BGFX_POLYGON_B2DPOLYGONTOOLS_HXX
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_TEXTURE_TEXTURE_HXX
+#include <drawinglayer/texture/texture.hxx>
+#endif
+
+#ifndef _SV_BMPACC_HXX
+#include <vcl/bmpacc.hxx>
+#endif
+
+#ifndef _SV_BITMAPEX_HXX
+#include <vcl/bitmapex.hxx>
+#endif
+
+#ifndef _SV_VIRDEV_HXX
+#include <vcl/virdev.hxx>
+#endif
+
+#ifndef _GRFMGR_HXX
+#include <goodies/grfmgr.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE_TEXTPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_POLYGONPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_BITMAPPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_ATTRIBUTE_SDRFILLBITMAPATTRIBUTE_HXX
+#include <drawinglayer/attribute/sdrfillbitmapattribute.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_FILLBITMAPPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/fillbitmapprimitive2d.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_POLYPOLYGONPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_METAFILEPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#endif
+
+#ifndef _BGFX_TOOLS_CANVASTOOLS_HXX
+#include <basegfx/tools/canvastools.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_MASKPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_ALPHAPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/alphaprimitive2d.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_TRANSFORMPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#endif
+
+#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_MARKERPRIMITIVE2D_HXX
+#include <drawinglayer/primitive2d/markerprimitive2d.hxx>
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+// support methods for vcl direct gradeint 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 < rMatrices.size())
+ {
+ basegfx::B2DPolygon aNewPoly(rUnitPolygon);
+ aNewPoly.transform(rMatrices[a - 1L]);
+ rOutDev.DrawPolygon(Polygon(aNewPoly));
+ }
+ }
+ else
+ {
+ rOutDev.DrawPolyPolygon(PolyPolygon(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();
+ }
+
+ 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;
+
+ if(attribute::GRADIENTSTYLE_RADIAL == eGradientStyle || attribute::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::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0));
+ }
+
+ // 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);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_AXIAL:
+ {
+ texture::GeoTexSvxGradientAxial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_RADIAL:
+ {
+ texture::GeoTexSvxGradientRadial aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetY);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_ELLIPTICAL:
+ {
+ texture::GeoTexSvxGradientElliptical aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_SQUARE:
+ {
+ texture::GeoTexSvxGradientSquare aGradient(aOutlineRange, rStart, rEnd, nSteps, fBorder, fOffsetX, fOffsetX, fAngle);
+ aGradient.appendTransformations(aMatrices);
+ aGradient.appendColors(aColors);
+ break;
+ }
+ case attribute::GRADIENTSTYLE_RECT:
+ {
+ texture::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)
+ {
+ impDrawGradientToOutDevSimple(rOutDev, rTargetForm, aMatrices, aColors, aUnitPolygon);
+ }
+ else
+ {
+ impDrawGradientToOutDevComplex(rOutDev, rTargetForm, aMatrices, aColors, aUnitPolygon);
+ }
+ }
+ }
+ } // end of anonymous namespace
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// 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;
+ }
+
+ 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);
+ }
+
+ } // end of anonymous namespace
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// support class for OutputDevice output with mask
+
+namespace drawinglayer
+{
+ namespace
+ {
+ class impBufferDevice
+ {
+ OutputDevice& mrOutDev;
+ VirtualDevice maContent;
+ VirtualDevice* mpMask;
+ VirtualDevice* mpAlpha;
+ Rectangle maDestPixel;
+
+ public:
+ impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange);
+ ~impBufferDevice();
+
+ void paint(double fTrans = 0.0);
+ bool isVisible() const { return !maDestPixel.IsEmpty(); }
+ VirtualDevice& getContent() { return maContent; }
+ VirtualDevice& getMask();
+ VirtualDevice& getAlpha();
+ };
+
+ impBufferDevice::impBufferDevice(OutputDevice& rOutDev, const basegfx::B2DRange& rRange)
+ : mrOutDev(rOutDev),
+ maContent(rOutDev),
+ mpMask(0L),
+ mpAlpha(0L)
+ {
+ const Rectangle aRectLogic(
+ (sal_Int32)floor(rRange.getMinX()), (sal_Int32)floor(rRange.getMinY()),
+ (sal_Int32)floor(rRange.getMaxX()) + 1L, (sal_Int32)floor(rRange.getMaxY()) + 1L);
+ const Rectangle aRectPixel(rOutDev.LogicToPixel(aRectLogic));
+ const Point aEmptyPoint;
+ maDestPixel = Rectangle(aEmptyPoint, rOutDev.GetOutputSizePixel());
+ maDestPixel.Intersection(aRectPixel);
+
+ if(isVisible())
+ {
+ maContent.SetOutputSizePixel(maDestPixel.GetSize(), false);
+
+ 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());
+ const Point aLogicTopLeft(rOutDev.PixelToLogic(maDestPixel.TopLeft()));
+ aNewMapMode.SetOrigin(Point(-aLogicTopLeft.X(), -aLogicTopLeft.Y()));
+
+ maContent.SetMapMode(aNewMapMode);
+ }
+ }
+
+ impBufferDevice::~impBufferDevice()
+ {
+ delete mpMask;
+ delete mpAlpha;
+ }
+
+ void impBufferDevice::paint(double fTrans)
+ {
+ const Point aEmptyPoint;
+ const Size aSizePixel(maContent.GetOutputSizePixel());
+ const bool bWasEnabledDst(mrOutDev.IsMapModeEnabled());
+
+ mrOutDev.EnableMapMode(false);
+ maContent.EnableMapMode(false);
+ Bitmap aContent(maContent.GetBitmap(aEmptyPoint, aSizePixel));
+
+ if(mpAlpha)
+ {
+ mpAlpha->EnableMapMode(false);
+ AlphaMask aAlphaMask(mpAlpha->GetBitmap(aEmptyPoint, aSizePixel));
+ mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aAlphaMask));
+ }
+ else if(mpMask)
+ {
+ mpMask->EnableMapMode(false);
+ Bitmap aMask(mpMask->GetBitmap(aEmptyPoint, aSizePixel));
+ mrOutDev.DrawBitmapEx(maDestPixel.TopLeft(), BitmapEx(aContent, aMask));
+ }
+ else if(0.0 != fTrans)
+ {
+ sal_uInt8 nMaskValue((sal_uInt8)basegfx::fround(fTrans * 255.0));
+ 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());
+ }
+
+ return *mpMask;
+ }
+
+ VirtualDevice& impBufferDevice::getAlpha()
+ {
+ if(!mpAlpha)
+ {
+ mpAlpha = new VirtualDevice();
+ mpAlpha->SetOutputSizePixel(maDestPixel.GetSize(), true);
+ mpAlpha->SetMapMode(maContent.GetMapMode());
+ }
+
+ return *mpAlpha;
+ }
+ } // end of anonymous namespace
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// support for different kinds of bitmap rendering using vcl
+
+namespace drawinglayer
+{
+ namespace
+ {
+ 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
+ basegfx::B2DHomMatrix aSimpleObjectMatrix;
+
+ aSimpleObjectMatrix.scale(fabs(aScale.getX()), fabs(aScale.getY()));
+ aSimpleObjectMatrix.translate(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));
+
+ // intersect with output pixel size
+ const Rectangle aOutputRectPixel(Point(), rOutDev.GetOutputSizePixel());
+ const Rectangle aCroppedRectPixel(aDestRectPixel.GetIntersection(aOutputRectPixel));
+
+ if(!aCroppedRectPixel.IsEmpty())
+ {
+ // build transform from pixel in aDestination to pixel in rBitmapEx
+ basegfx::B2DHomMatrix aTransform;
+
+ // from relative in aCroppedRectPixel to relative in aDestRectPixel
+ aTransform.translate(aCroppedRectPixel.Left() - aDestRectPixel.Left(), aCroppedRectPixel.Top() - aDestRectPixel.Top());
+
+ // from relative in aDestRectPixel to absolute Logic
+ aTransform.scale((double)aDestRectLogic.getWidth() / (double)aDestRectPixel.getWidth(), (double)aDestRectLogic.getHeight() / (double)aDestRectPixel.getHeight());
+ aTransform.translate(aDestRectLogic.Left(), aDestRectLogic.Top());
+
+ // 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
+ const Size aSourceSizePixel(rBitmapEx.GetSizePixel());
+ aTransform.scale(aSourceSizePixel.getWidth() - 1L, aSourceSizePixel.getHeight() - 1L);
+
+ // create bitmap using source, destination and linear back-transformation
+ BitmapEx aDestination = impTransformBitmapEx(rBitmapEx, aCroppedRectPixel, aTransform);
+
+ // paint
+ const bool bWasEnabled(rOutDev.IsMapModeEnabled());
+ rOutDev.EnableMapMode(false);
+ rOutDev.DrawBitmapEx(aCroppedRectPixel.TopLeft(), aDestination);
+ rOutDev.EnableMapMode(bWasEnabled);
+ }
+ }
+
+ 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
+ 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)
+ {
+ for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
+ {
+ for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
+ {
+ const basegfx::BColor aBColor(rModifier.getModifiedColor(Color(pContent->GetPixel(y, x)).getBColor()));
+ pContent->SetPixel(y, x, BitmapColor(Color(aBColor)));
+ }
+ }
+
+ 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 anonymous namespace
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+ namespace processor2d
+ {
+ //////////////////////////////////////////////////////////////////////////////
+ // rendering support
+
+ // directdraw of text simple portion
+ void VclProcessor2D::RenderTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
+ {
+ // decompose matrix to have position and size of text
+ basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rTextCandidate.getTextTransform());
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+ bool bPrimitiveAccepted(false);
+
+ if(basegfx::fTools::equalZero(fShearX))
+ {
+ if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
+ {
+ // handle special case: If scale is negative in (x,y) (3rd quadrant), it can
+ // be expressed as rotation by PI
+ aScale = basegfx::absolute(aScale);
+ fRotate += (180.0 * F_PI180);
+ }
+
+ if(basegfx::fTools::more(aScale.getX(), 0.0) && basegfx::fTools::more(aScale.getY(), 0.0))
+ {
+ // handle, there is no shear and no mirror
+ bPrimitiveAccepted = true;
+ const Font aFont(getVclFontFromFontAttributes(rTextCandidate.getFontAttributes(), aScale, fRotate));
+ const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0));
+ const Point aStartPoint(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY()));
+
+ // 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(aLocalTransform * basegfx::B2DVector(1.0, 0.0));
+ const double fPixelVectorLength(aPixelVector.getLength());
+
+ for(::std::vector< double >::const_iterator aStart(rTextCandidate.getDXArray().begin()); aStart != rTextCandidate.getDXArray().end(); aStart++)
+ {
+ aTransformedDXArray.push_back(basegfx::fround((*aStart) * fPixelVectorLength));
+ }
+ }
+
+ // set parameters and paint
+ const basegfx::BColor aRGBFontColor(maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor()));
+ mpOutputDevice->SetFont(aFont);
+ mpOutputDevice->SetTextColor(Color(aRGBFontColor));
+ mpOutputDevice->DrawTextArray(aStartPoint, rTextCandidate.getText(), &(aTransformedDXArray[0]));
+ }
+ }
+
+ if(!bPrimitiveAccepted)
+ {
+ // let break down
+ process(rTextCandidate.get2DDecomposition(getViewInformation2D()));
+ }
+ }
+
+ // direct draw of hairline
+ void VclProcessor2D::RenderPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonCandidate)
+ {
+ const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
+ mpOutputDevice->SetLineColor(Color(aHairlineColor));
+ mpOutputDevice->SetFillColor();
+
+ basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon());
+ aLocalPolygon.transform(maCurrentTransformation);
+
+ mpOutputDevice->DrawPolyLine(Polygon(aLocalPolygon));
+ }
+
+ // direct draw of transformed BitmapEx primitive
+ void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
+ {
+ // decompose matrix to check for shear, rotate and mirroring
+ basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform());
+ basegfx::B2DVector aScale, aTranslate;
+ double fRotate, fShearX;
+ aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+ 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::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
+ aPolygon.transform(aLocalTransform);
+
+ mpOutputDevice->SetFillColor(Color(aModifiedColor));
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->DrawPolygon(Polygon(aPolygon));
+
+ bPainted = true;
+ }
+ }
+
+ if(!bPainted)
+ {
+ static bool bForceUseOfOwnTransformer(false);
+ static bool bUseGraphicManager(true);
+
+ if(!bForceUseOfOwnTransformer && basegfx::fTools::equalZero(fShearX))
+ {
+ if(basegfx::fTools::equalZero(fRotate) && !bUseGraphicManager)
+ {
+ 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.getBitmap());
+ 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::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
+ aPolygon.transform(aLocalTransform);
+
+ mpOutputDevice->SetFillColor(Color(aModifiedColor));
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->DrawPolygon(Polygon(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());
+
+ if(nOWidth < 0L)
+ {
+ nOWidth = 1L;
+ }
+
+ if(nOHeight < 0L)
+ {
+ nOHeight = 1L;
+ }
+
+ sal_Int32 nBWidth(aBmpBR.X() - aBmpTL.X());
+ sal_Int32 nBHeight(aBmpBR.Y() - aBmpTL.Y());
+
+ if(nBWidth < 0L)
+ {
+ nBWidth = 1L;
+ }
+
+ if(nBHeight < 0L)
+ {
+ nBHeight = 1L;
+ }
+
+ 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());
+ aLocalPolyPolygon.transform(maCurrentTransformation);
+
+ if(aStartColor == aEndColor)
+ {
+ // no gradient at all, draw as polygon
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->SetFillColor(Color(aStartColor));
+ mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
+ }
+ else
+ {
+ impDrawGradientToOutDev(
+ *mpOutputDevice, aLocalPolyPolygon, rGradient.getStyle(), rGradient.getSteps(),
+ aStartColor, aEndColor, rGradient.getBorder(),
+ -rGradient.getAngle(), rGradient.getOffsetX(), rGradient.getOffsetY(), false);
+ }
+ }
+
+ // 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);
+
+ mpOutputDevice->DrawPolyPolygon(PolyPolygon(aLocalPolyPolygon));
+ }
+
+ // 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);
+
+ // get BoundRect
+ basegfx::B2DRange aOutlineRange(rMetaCandidate.getB2DRange(getViewInformation2D()));
+ aOutlineRange.transform(maCurrentTransformation);
+ const Rectangle aDestRectView(
+ basegfx::fround(aOutlineRange.getMinX()), basegfx::fround(aOutlineRange.getMinY()),
+ basegfx::fround(aOutlineRange.getMaxX()), basegfx::fround(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))
+ {
+ double fRotation((fRotate / F_PI180) * -10.0);
+ aMetaFile.Rotate((sal_uInt16)(fRotation));
+ }
+
+ // paint it
+ aMetaFile.WindStart();
+ aMetaFile.Play(mpOutputDevice, aDestRectView.TopLeft(), aDestRectView.GetSize());
+ }
+
+ // mask group. Force output to VDev and create mask from given mask
+ void VclProcessor2D::RenderMaskPrimitive2D(const primitive2d::MaskPrimitive2D& rMaskCandidate)
+ {
+ if(rMaskCandidate.getChildren().hasElements())
+ {
+ basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
+ aMask.transform(maCurrentTransformation);
+ const basegfx::B2DRange aRange(basegfx::tools::getRange(aMask));
+ impBufferDevice aBufferDevice(*mpOutputDevice, aRange);
+
+ 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
+ VirtualDevice& rMask = aBufferDevice.getMask();
+ rMask.SetLineColor();
+ rMask.SetFillColor(COL_BLACK);
+ rMask.DrawPolyPolygon(PolyPolygon(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();
+ }
+ }
+
+ // sub-transparence group. Draw to VDev first.
+ void VclProcessor2D::RenderAlphaPrimitive2D(const primitive2d::AlphaPrimitive2D& rTransCandidate)
+ {
+ if(rTransCandidate.getChildren().hasElements())
+ {
+ basegfx::B2DRange aRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rTransCandidate.getChildren(), getViewInformation2D()));
+ aRange.transform(maCurrentTransformation);
+ impBufferDevice aBufferDevice(*mpOutputDevice, aRange);
+
+ 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.getAlpha();
+
+ // when painting alpha masks, reset the color stack
+ basegfx::BColorModifierStack aLastBColorModifierStack(maBColorModifierStack);
+ maBColorModifierStack = basegfx::BColorModifierStack();
+
+ // paint mask to it
+ process(rTransCandidate.getAlpha());
+
+ // 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
+ basegfx::B2DHomMatrix aLastCurrentTransformation(maCurrentTransformation);
+
+ // create new transformations
+ maCurrentTransformation = maCurrentTransformation * rTransformCandidate.getTransformation();
+
+ // let break down
+ process(rTransformCandidate.getChildren());
+
+ // restore transformations
+ maCurrentTransformation = aLastCurrentTransformation;
+ }
+
+ // marker
+ void VclProcessor2D::RenderMarkerPrimitive2D(const primitive2d::MarkerPrimitive2D& rMarkCandidate)
+ {
+ const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rMarkCandidate.getRGBColor()));
+ const Color aColor(aRGBColor);
+
+ // evtl. just test markers
+ static bool bForceMarkersToRangeTest(false);
+
+ if(bForceMarkersToRangeTest)
+ {
+ // ATM just test marker range
+ const basegfx::B2DRange aRange(rMarkCandidate.getB2DRange(getViewInformation2D()));
+ basegfx::B2DPolygon aPolygon(basegfx::tools::createPolygonFromRect(aRange));
+ aPolygon.transform(maCurrentTransformation);
+
+ mpOutputDevice->SetFillColor();
+ mpOutputDevice->SetLineColor(aColor);
+ mpOutputDevice->DrawPolygon(Polygon(aPolygon));
+ }
+ else
+ {
+ const basegfx::B2DPoint aViewPosition(maCurrentTransformation * rMarkCandidate.getPosition());
+ Point aPos(basegfx::fround(aViewPosition.getX()), basegfx::fround(aViewPosition.getY()));
+
+ switch(rMarkCandidate.getStyle())
+ {
+ default : // MARKERSTYLE2D_POINT
+ {
+ mpOutputDevice->DrawPixel(aPos, aColor);
+ break;
+ }
+ case primitive2d::MARKERSTYLE2D_CROSS :
+ {
+ basegfx::B2DRange aRange;
+ rMarkCandidate.getRealtiveViewRange(aRange);
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
+
+ aPos = mpOutputDevice->LogicToPixel(aPos);
+ aPos.X() += basegfx::fround(aCenter.getX());
+ aPos.Y() += basegfx::fround(aCenter.getY());
+
+ const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
+ mpOutputDevice->EnableMapMode(false);
+
+ mpOutputDevice->DrawPixel(aPos, aColor);
+ mpOutputDevice->DrawPixel(Point(aPos.X() - 1L, aPos.Y()), aColor);
+ mpOutputDevice->DrawPixel(Point(aPos.X() + 1L, aPos.Y()), aColor);
+ mpOutputDevice->DrawPixel(Point(aPos.X(), aPos.Y() - 1L), aColor);
+ mpOutputDevice->DrawPixel(Point(aPos.X(), aPos.Y() + 1L), aColor);
+
+ mpOutputDevice->EnableMapMode(bWasEnabled);
+ break;
+ }
+ case primitive2d::MARKERSTYLE2D_GLUEPOINT :
+ {
+ basegfx::B2DRange aRange;
+ rMarkCandidate.getRealtiveViewRange(aRange);
+ const basegfx::B2DPoint aCenter(aRange.getCenter());
+
+ aPos = mpOutputDevice->LogicToPixel(aPos);
+ aPos.X() += basegfx::fround(aCenter.getX());
+ aPos.Y() += basegfx::fround(aCenter.getY());
+
+ const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
+ mpOutputDevice->EnableMapMode(false);
+
+ // backpen
+ mpOutputDevice->SetLineColor(aColor);
+ mpOutputDevice->DrawLine(aPos + Point(-2, -3), aPos + Point(+3, +2));
+ mpOutputDevice->DrawLine(aPos + Point(-3, -2), aPos + Point(+2, +3));
+ mpOutputDevice->DrawLine(aPos + Point(-3, +2), aPos + Point(+2, -3));
+ mpOutputDevice->DrawLine(aPos + Point(-2, +3), aPos + Point(+3, -2));
+
+ // frontpen (hard coded)
+ mpOutputDevice->SetLineColor(COL_LIGHTBLUE);
+ mpOutputDevice->DrawLine(aPos + Point(-2, -2), aPos + Point(+2, +2));
+ mpOutputDevice->DrawLine(aPos + Point(-2, +2), aPos + Point(+2, -2));
+
+ mpOutputDevice->EnableMapMode(bWasEnabled);
+ break;
+ }
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ // internal processing support
+
+ void VclProcessor2D::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 getPrimitiveID() call for switch
+ switch(pBasePrimitive->getPrimitiveID())
+ {
+ case Create2DPrimitiveID('2','T','S','i') :
+ {
+ // directdraw of text simple portion
+ RenderTextSimplePortionPrimitive2D(static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','P','H','a') :
+ {
+ // direct draw of hairline
+ RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','B','i','t') :
+ {
+ // direct draw of transformed BitmapEx primitive
+ RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','F','B','i') :
+ {
+ // direct draw of fillBitmapPrimitive
+ RenderFillBitmapPrimitive2D(static_cast< const primitive2d::FillBitmapPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','P','P','G') :
+ {
+ // direct draw of gradient
+ RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','P','P','C') :
+ {
+ // direct draw of PolyPolygon with color
+ RenderPolyPolygonColorPrimitive2D(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','M','e','t') :
+ {
+ // direct draw of MetaFile
+ RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','M','a','s') :
+ {
+ // mask group. Force output to VDev and create mask from given mask
+ RenderMaskPrimitive2D(static_cast< const primitive2d::MaskPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','M','C','o') :
+ {
+ // modified color group. Force output to unified color.
+ RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','A','l','p') :
+ {
+ // sub-transparence group. Draw to VDev first.
+ RenderAlphaPrimitive2D(static_cast< const primitive2d::AlphaPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','T','r','a') :
+ {
+ // transform group.
+ RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ case Create2DPrimitiveID('2','M','a','r') :
+ {
+ // marker
+ RenderMarkerPrimitive2D(static_cast< const primitive2d::MarkerPrimitive2D& >(*pBasePrimitive));
+ break;
+ }
+ default :
+ {
+ // process recursively
+ process(pBasePrimitive->get2DDecomposition(getViewInformation2D()));
+ break;
+ }
+ }
+ }
+ else
+ {
+ // unknown implementation, use UNO API call instead and process recursively
+ com::sun::star::graphic::Primitive2DParameters aPrimitive2DParameters;
+
+ basegfx::unotools::affineMatrixFromHomMatrix(aPrimitive2DParameters.ViewTransformation, getViewInformation2D().getViewTransformation());
+ aPrimitive2DParameters.Viewport = basegfx::unotools::rectangle2DFromB2DRectangle(getViewInformation2D().getViewport());
+ aPrimitive2DParameters.Time = getViewInformation2D().getViewTime();
+
+ process(xReference->getDecomposition(aPrimitive2DParameters));
+ }
+ }
+ }
+ }
+ }
+
+ VclProcessor2D::VclProcessor2D(
+ const geometry::ViewInformation2D& rViewInformation,
+ OutputDevice& rOutDev)
+ : BaseProcessor2D(rViewInformation),
+ mbOutputToRecordingMetaFile(false)
+ {
+ // initialize destination OutDev
+ mpOutputDevice = &rOutDev;
+
+ // check if output is recorded to metafile
+ const GDIMetaFile* pMetaFile = mpOutputDevice->GetConnectMetaFile();
+ mbOutputToRecordingMetaFile = (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
+
+ if(mbOutputToRecordingMetaFile)
+ {
+ // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation,
+ // do not change MapMode of destination
+ }
+ else
+ {
+ // prepare maCurrentTransformation matrix with viewTransformation to go directly to pixels
+ maCurrentTransformation = rViewInformation.getViewTransformation();
+
+ // prepare output to pixels
+ mpOutputDevice->Push(PUSH_MAPMODE);
+ mpOutputDevice->SetMapMode();
+ }
+ }
+
+ VclProcessor2D::~VclProcessor2D()
+ {
+ if(mbOutputToRecordingMetaFile)
+ {
+ }
+ else
+ {
+ // restore MapMode
+ mpOutputDevice->Pop();
+ }
+ }
+ } // end of namespace processor2d
+} // end of namespace drawinglayer
+
+//////////////////////////////////////////////////////////////////////////////
+// eof