diff options
Diffstat (limited to 'drawinglayer/source/processor2d/vclhelperbitmaprender.cxx')
-rw-r--r-- | drawinglayer/source/processor2d/vclhelperbitmaprender.cxx | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx b/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx new file mode 100644 index 000000000000..80e34ba27701 --- /dev/null +++ b/drawinglayer/source/processor2d/vclhelperbitmaprender.cxx @@ -0,0 +1,280 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_drawinglayer.hxx" + +#include <vclhelperbitmaprender.hxx> +#include <svtools/grfmgr.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/range/b2drange.hxx> +#include <vcl/outdev.hxx> +#include <vclhelperbitmaptransform.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +////////////////////////////////////////////////////////////////////////////// +// support for different kinds of bitmap rendering using vcl + +namespace drawinglayer +{ + void RenderBitmapPrimitive2D_GraphicManager( + OutputDevice& rOutDev, + const BitmapEx& rBitmapEx, + const basegfx::B2DHomMatrix& rTransform) + { + // prepare attributes + GraphicAttr aAttributes; + + // decompose matrix to check for shear, rotate and mirroring + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + rTransform.decompose(aScale, aTranslate, fRotate, fShearX); + + // mirror flags + aAttributes.SetMirrorFlags( + (basegfx::fTools::less(aScale.getX(), 0.0) ? BMP_MIRROR_HORZ : 0)| + (basegfx::fTools::less(aScale.getY(), 0.0) ? BMP_MIRROR_VERT : 0)); + + // rotation + if(!basegfx::fTools::equalZero(fRotate)) + { + double fRotation(fmod(3600.0 - (fRotate * (10.0 / F_PI180)), 3600.0)); + aAttributes.SetRotation((sal_uInt16)(fRotation)); + } + + // prepare Bitmap + basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0); + + if(basegfx::fTools::equalZero(fRotate)) + { + aOutlineRange.transform(rTransform); + } + else + { + // if rotated, create the unrotated output rectangle for the GraphicManager paint + const basegfx::B2DHomMatrix aSimpleObjectMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix( + fabs(aScale.getX()), fabs(aScale.getY()), + aTranslate.getX(), aTranslate.getY())); + + aOutlineRange.transform(aSimpleObjectMatrix); + } + + // prepare dest coor + const sal_uInt32 nDiscreteWidth(basegfx::fround(aOutlineRange.getMaxX())); + const sal_uInt32 nDiscreteHeight(basegfx::fround(aOutlineRange.getMaxY())); + const Rectangle aDestRectPixel( + basegfx::fround(aOutlineRange.getMinX()), + basegfx::fround(aOutlineRange.getMinY()), + nDiscreteWidth > 0 ? nDiscreteWidth - 1 : 0, + nDiscreteHeight > 0 ? nDiscreteHeight - 1 : 0); + + // 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 sal_uInt32 nDiscreteWidth(basegfx::fround(aOutlineRange.getMaxX())); + const sal_uInt32 nDiscreteHeight(basegfx::fround(aOutlineRange.getMaxY())); + const Rectangle aDestRectPixel( + basegfx::fround(aOutlineRange.getMinX()), + basegfx::fround(aOutlineRange.getMinY()), + nDiscreteWidth > 0 ? nDiscreteWidth - 1 : 0, + nDiscreteHeight > 0 ? nDiscreteHeight - 1 : 0); + + // 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 sal_uInt32 nDiscreteWidth(basegfx::fround(aOutlineRange.getMaxX())); + const sal_uInt32 nDiscreteHeight(basegfx::fround(aOutlineRange.getMaxY())); + const Rectangle aDestRectLogic( + basegfx::fround(aOutlineRange.getMinX()), + basegfx::fround(aOutlineRange.getMinY()), + nDiscreteWidth > 0 ? nDiscreteWidth - 1 : 0, + nDiscreteHeight > 0 ? nDiscreteHeight - 1 : 0); + const Rectangle aDestRectPixel(rOutDev.LogicToPixel(aDestRectLogic)); + + // #i96708# check if Metafile is recorded + const GDIMetaFile* pMetaFile = rOutDev.GetConnectMetaFile(); + const bool bRecordToMetaFile(pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause()); + + // intersect with output pixel size, but only + // when not recording to metafile + const Rectangle aOutputRectPixel(Point(), rOutDev.GetOutputSizePixel()); + Rectangle aCroppedRectPixel(bRecordToMetaFile ? aDestRectPixel : aDestRectPixel.GetIntersection(aOutputRectPixel)); + + if(!aCroppedRectPixel.IsEmpty()) + { + // as maximum for destination, orientate at aOutputRectPixel, but + // take a rotation of 45 degrees (sqrt(2)) as maximum expansion into account + const Size aSourceSizePixel(rBitmapEx.GetSizePixel()); + const double fMaximumArea( + (double)aOutputRectPixel.getWidth() * + (double)aOutputRectPixel.getHeight() * + 1.4142136); // 1.4142136 taken as sqrt(2.0) + + // test if discrete view size (pixel) maybe too big and limit it + const double fArea(aCroppedRectPixel.getWidth() * aCroppedRectPixel.getHeight()); + const bool bNeedToReduce(fArea > fMaximumArea); + double fReduceFactor(1.0); + const Size aDestSizePixel(aCroppedRectPixel.GetSize()); + + if(bNeedToReduce) + { + fReduceFactor = sqrt(fMaximumArea / fArea); + aCroppedRectPixel.setWidth(basegfx::fround(aCroppedRectPixel.getWidth() * fReduceFactor)); + aCroppedRectPixel.setHeight(basegfx::fround(aCroppedRectPixel.getHeight() * fReduceFactor)); + } + + // build transform from pixel in aDestination to pixel in rBitmapEx + // from relative in aCroppedRectPixel to relative in aDestRectPixel + // No need to take bNeedToReduce into account, TopLeft is unchanged + basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix( + aCroppedRectPixel.Left() - aDestRectPixel.Left(), + aCroppedRectPixel.Top() - aDestRectPixel.Top())); + + // from relative in aDestRectPixel to absolute Logic. Here it + // is essential to adapt to reduce factor (if used) + double fAdaptedDRPWidth((double)aDestRectPixel.getWidth()); + double fAdaptedDRPHeight((double)aDestRectPixel.getHeight()); + + if(bNeedToReduce) + { + fAdaptedDRPWidth *= fReduceFactor; + fAdaptedDRPHeight *= fReduceFactor; + } + + aTransform = basegfx::tools::createScaleTranslateB2DHomMatrix( + aDestRectLogic.getWidth() / fAdaptedDRPWidth, aDestRectLogic.getHeight() / fAdaptedDRPHeight, + aDestRectLogic.Left(), aDestRectLogic.Top()) + * aTransform; + + // from absolute in Logic to unified object coordinates (0.0 .. 1.0 in x and y) + basegfx::B2DHomMatrix aInvBitmapTransform(rTransform); + aInvBitmapTransform.invert(); + aTransform = aInvBitmapTransform * aTransform; + + // from unit object coordinates to rBitmapEx pixel coordintes + aTransform.scale(aSourceSizePixel.getWidth() - 1L, aSourceSizePixel.getHeight() - 1L); + + // create bitmap using source, destination and linear back-transformation + BitmapEx aDestination = impTransformBitmapEx(rBitmapEx, aCroppedRectPixel, aTransform); + + // paint + if(bNeedToReduce) + { + // paint in target size + if(bRecordToMetaFile) + { + rOutDev.DrawBitmapEx( + rOutDev.PixelToLogic(aCroppedRectPixel.TopLeft()), + rOutDev.PixelToLogic(aDestSizePixel), + aDestination); + } + else + { + const bool bWasEnabled(rOutDev.IsMapModeEnabled()); + rOutDev.EnableMapMode(false); + + rOutDev.DrawBitmapEx( + aCroppedRectPixel.TopLeft(), + aDestSizePixel, + aDestination); + + rOutDev.EnableMapMode(bWasEnabled); + } + } + else + { + if(bRecordToMetaFile) + { + rOutDev.DrawBitmapEx( + rOutDev.PixelToLogic(aCroppedRectPixel.TopLeft()), + aDestination); + } + else + { + const bool bWasEnabled(rOutDev.IsMapModeEnabled()); + rOutDev.EnableMapMode(false); + + rOutDev.DrawBitmapEx( + aCroppedRectPixel.TopLeft(), + aDestination); + + rOutDev.EnableMapMode(bWasEnabled); + } + } + } + } +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// +// eof |