Files
libreoffice/drawinglayer/source/processor2d/vclprocessor2d.cxx

1839 lines
80 KiB
C++
Raw Normal View History

2006-10-19 09:40:02 +00:00
/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: vclprocessor2d.cxx,v $
*
* $Revision: 1.5 $
2006-10-19 09:40:02 +00:00
*
* last change: $Author: hdu $ $Date: 2007-02-13 08:16:41 $
2006-10-19 09:40:02 +00:00
*
* 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_MARKERARRAYPRIMITIVE2D_HXX
#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
2006-10-19 09:40:02 +00:00
#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)
{
2006-12-13 15:57:09 +00:00
const double fConvertColor(1.0 / 255.0);
2006-10-19 09:40:02 +00:00
for(sal_uInt32 y(0L); y < (sal_uInt32)pContent->Height(); y++)
{
for(sal_uInt32 x(0L); x < (sal_uInt32)pContent->Width(); x++)
{
2006-12-13 15:57:09 +00:00
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)));
2006-10-19 09:40:02 +00:00
}
}
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);
2006-11-28 10:03:58 +00:00
fRotate += F_PI;
2006-10-19 09:40:02 +00:00
}
if(basegfx::fTools::more(aScale.getX(), 0.0) && basegfx::fTools::more(aScale.getY(), 0.0))
{
// prepare everything that is not sheared and mirrored
2006-10-19 09:40:02 +00:00
bPrimitiveAccepted = true;
Font aFont(primitive2d::getVclFontFromFontAttributes(rTextCandidate.getFontAttributes(), aScale, fRotate));
// handle additional font attributes
const primitive2d::TextComplexPortionPrimitive2D* pTCPP =
dynamic_cast<const primitive2d::TextComplexPortionPrimitive2D*>( &rTextCandidate );
if( pTCPP != NULL )
{
// TODO: emulate all text decorations
#if 0
if( pTCPP->getFontUnderline() != primitive2d::FONT_UNDERLINE_NONE )
aFont.SetUnderline( UNDERLINE_SINGLE );
// the compile time assertions make sure that the simple cast
// from primitive2d::FontUnderline to vcl::FontUnderline works
// TODO: test all other primitive2d<->vcl enum mappings
BOOST_STATIC_ASSERT( UNDERLINE_NONE == (FontUnderline)primitive2d::FONT_UNDERLINE_NONE );
BOOST_STATIC_ASSERT( UNDERLINE_SINGLE == (FontUnderline)primitive2d::FONT_UNDERLINE_SINGLE );
BOOST_STATIC_ASSERT( UNDERLINE_BOLDWAVE == (FontUnderline)primitive2d::FONT_UNDERLINE_BOLDWAVE );
FontUnderline eFontUnderline = (FontUnderline)pTCPP->getFontUnderline();
#else
// set Underline attribute
FontUnderline eFontUnderline = UNDERLINE_NONE;
switch( pTCPP->getFontUnderline() )
{
default:
DBG_WARNING1( "DrawingLayer: Unknown underline attribute (%d)!", pTCPP->getFontUnderline() );
// fall through
case primitive2d::FONT_UNDERLINE_NONE: eFontUnderline = UNDERLINE_NONE; break;
case primitive2d::FONT_UNDERLINE_SINGLE: eFontUnderline = UNDERLINE_SINGLE; break;
case primitive2d::FONT_UNDERLINE_DOUBLE: eFontUnderline = UNDERLINE_DOUBLE; break;
case primitive2d::FONT_UNDERLINE_DOTTED: eFontUnderline = UNDERLINE_DOTTED; break;
case primitive2d::FONT_UNDERLINE_DASH: eFontUnderline = UNDERLINE_DASH; break;
case primitive2d::FONT_UNDERLINE_LONGDASH: eFontUnderline = UNDERLINE_LONGDASH; break;
case primitive2d::FONT_UNDERLINE_DASHDOT: eFontUnderline = UNDERLINE_DASHDOT; break;
case primitive2d::FONT_UNDERLINE_DASHDOTDOT:eFontUnderline = UNDERLINE_DASHDOTDOT; break;
case primitive2d::FONT_UNDERLINE_SMALLWAVE: eFontUnderline = UNDERLINE_SMALLWAVE; break;
case primitive2d::FONT_UNDERLINE_WAVE: eFontUnderline = UNDERLINE_WAVE; break;
case primitive2d::FONT_UNDERLINE_DOUBLEWAVE:eFontUnderline = UNDERLINE_DOUBLEWAVE; break;
case primitive2d::FONT_UNDERLINE_BOLD: eFontUnderline = UNDERLINE_BOLD; break;
case primitive2d::FONT_UNDERLINE_BOLDDOTTED:eFontUnderline = UNDERLINE_BOLDDOTTED; break;
case primitive2d::FONT_UNDERLINE_BOLDDASH: eFontUnderline = UNDERLINE_BOLDDASH; break;
case primitive2d::FONT_UNDERLINE_BOLDLONGDASH:eFontUnderline = UNDERLINE_LONGDASH; break;
case primitive2d::FONT_UNDERLINE_BOLDDASHDOT:eFontUnderline = UNDERLINE_BOLDDASHDOT; break;
case primitive2d::FONT_UNDERLINE_BOLDDASHDOTDOT:eFontUnderline = UNDERLINE_BOLDDASHDOT; break;
case primitive2d::FONT_UNDERLINE_BOLDWAVE: eFontUnderline = UNDERLINE_BOLDWAVE; break;
}
#endif
2006-10-19 09:40:02 +00:00
if( eFontUnderline != UNDERLINE_NONE )
{
aFont.SetUnderline( eFontUnderline );
if( pTCPP->getWordLineMode() )
aFont.SetWordLineMode( true );
//TODO: ??? if( pTCPP->getUnderlineAbove() )
// aFont.SetUnderlineAbove( true );
}
2006-10-19 09:40:02 +00:00
// set Strikeout attribute
FontStrikeout eFontStrikeout = STRIKEOUT_NONE;
switch( pTCPP->getFontStrikeout() )
{
default:
DBG_WARNING1( "DrawingLayer: Unknown strikeout attribute (%d)!", pTCPP->getFontUnderline() );
// fall through
case primitive2d::FONT_STRIKEOUT_NONE: eFontStrikeout = STRIKEOUT_NONE; break;
case primitive2d::FONT_STRIKEOUT_SINGLE: eFontStrikeout = STRIKEOUT_SINGLE; break;
case primitive2d::FONT_STRIKEOUT_DOUBLE: eFontStrikeout = STRIKEOUT_DOUBLE; break;
case primitive2d::FONT_STRIKEOUT_BOLD: eFontStrikeout = STRIKEOUT_BOLD; break;
case primitive2d::FONT_STRIKEOUT_SLASH: eFontStrikeout = STRIKEOUT_SLASH; break;
case primitive2d::FONT_STRIKEOUT_X: eFontStrikeout = STRIKEOUT_X; break;
}
2006-10-19 09:40:02 +00:00
if( eFontStrikeout != STRIKEOUT_NONE )
aFont.SetStrikeout( eFontStrikeout );
// set EmphasisMark attribute
FontEmphasisMark eFontEmphasisMark = EMPHASISMARK_NONE;
switch( pTCPP->getFontEmphasisMark() )
2006-10-19 09:40:02 +00:00
{
default:
DBG_WARNING1( "DrawingLayer: Unknown EmphasisMark style (%d)!", pTCPP->getFontEmphasisMark() );
// fall through
case primitive2d::FONT_EMPHASISMARK_NONE: eFontEmphasisMark = EMPHASISMARK_NONE; break;
case primitive2d::FONT_EMPHASISMARK_DOT: eFontEmphasisMark = EMPHASISMARK_DOT; break;
case primitive2d::FONT_EMPHASISMARK_CIRCLE: eFontEmphasisMark = EMPHASISMARK_CIRCLE; break;
case primitive2d::FONT_EMPHASISMARK_DISC: eFontEmphasisMark = EMPHASISMARK_DISC; break;
case primitive2d::FONT_EMPHASISMARK_ACCENT: eFontEmphasisMark = EMPHASISMARK_ACCENT; break;
2006-10-19 09:40:02 +00:00
}
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->getFontRelief() )
{
default:
DBG_WARNING1( "DrawingLayer: Unknown Relief style (%d)!", pTCPP->getFontRelief() );
// fall through
case primitive2d::FONT_RELIEF_NONE: eFontRelief = RELIEF_NONE; break;
case primitive2d::FONT_RELIEF_EMBOSSED: eFontRelief = RELIEF_EMBOSSED; break;
case primitive2d::FONT_RELIEF_ENGRAVED: eFontRelief = RELIEF_ENGRAVED; break;
}
if( eFontRelief != RELIEF_NONE )
aFont.SetRelief( eFontRelief );
// set Shadow attribute
if( pTCPP->getShadow() )
aFont.SetShadow( true );
// set Outline attribute
if( pTCPP->getOutline() )
aFont.SetOutline( true );
2006-10-19 09:40:02 +00:00
}
mpOutputDevice->SetFont(aFont);
}
// 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->SetTextColor(Color(aRGBFontColor));
const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0));
const Point aStartPoint(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY()));
mpOutputDevice->DrawTextArray(aStartPoint, rTextCandidate.getText(),
aTransformedDXArray.size() ? &(aTransformedDXArray[0]) : NULL);
2006-10-19 09:40:02 +00:00
}
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)
{
2006-11-28 10:03:58 +00:00
// create local transform
2006-10-19 09:40:02 +00:00
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::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);
2006-11-28 10:03:58 +00:00
// decompose matrix to check for shear, rotate and mirroring
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
aLocalTransform.decompose(aScale, aTranslate, fRotate, fShearX);
2006-10-19 09:40:02 +00:00
if(!bForceUseOfOwnTransformer && basegfx::fTools::equalZero(fShearX))
{
2006-11-28 10:03:58 +00:00
if(!bUseGraphicManager && basegfx::fTools::equalZero(fRotate))
2006-10-19 09:40:02 +00:00
{
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::RenderMarkerArrayPrimitive2D(const primitive2d::MarkerArrayPrimitive2D& rMarkArrayCandidate)
2006-10-19 09:40:02 +00:00
{
const std::vector< basegfx::B2DPoint >& rPositions = rMarkArrayCandidate.getPositions();
const basegfx::BColor aRGBColor(maBColorModifierStack.getModifiedColor(rMarkArrayCandidate.getRGBColor()));
2006-10-19 09:40:02 +00:00
const Color aColor(aRGBColor);
if(primitive2d::MARKERSTYLE2D_POINT == rMarkArrayCandidate.getStyle())
2006-10-19 09:40:02 +00:00
{
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, aColor);
}
2006-10-19 09:40:02 +00:00
}
else
{
const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
2006-10-19 09:40:02 +00:00
for(std::vector< basegfx::B2DPoint >::const_iterator aIter(rPositions.begin()); aIter != rPositions.end(); aIter++)
2006-10-19 09:40:02 +00:00
{
const basegfx::B2DPoint aViewPosition(maCurrentTransformation * (*aIter));
Point aPos(basegfx::fround(aViewPosition.getX()), basegfx::fround(aViewPosition.getY()));
aPos = mpOutputDevice->LogicToPixel(aPos);
2006-10-19 09:40:02 +00:00
mpOutputDevice->EnableMapMode(false);
2006-10-19 09:40:02 +00:00
switch(rMarkArrayCandidate.getStyle())
2006-10-19 09:40:02 +00:00
{
case primitive2d::MARKERSTYLE2D_CROSS :
{
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);
2006-10-19 09:40:02 +00:00
break;
}
case primitive2d::MARKERSTYLE2D_GLUEPOINT :
{
// 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)
Color aFrontColor(COL_LIGHTBLUE);
const basegfx::BColor aRGBFrontColor(maBColorModifierStack.getModifiedColor(aFrontColor.getBColor()));
aFrontColor = Color(aRGBFrontColor);
mpOutputDevice->SetLineColor(aFrontColor);
mpOutputDevice->DrawLine(aPos + Point(-2, -2), aPos + Point(+2, +2));
mpOutputDevice->DrawLine(aPos + Point(-2, +2), aPos + Point(+2, -2));
break;
}
default : // primitive2d::MARKERSTYLE2D_POINT
{
break;
}
2006-10-19 09:40:02 +00:00
}
mpOutputDevice->EnableMapMode(bWasEnabled);
2006-10-19 09:40:02 +00:00
}
}
}
//////////////////////////////////////////////////////////////////////////////
// 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') :
case Create2DPrimitiveID('2','T','C','o') :
2006-10-19 09:40:02 +00:00
{
// 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 array
RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(*pBasePrimitive));
2006-10-19 09:40:02 +00:00
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