blob: 4463625061388412dfc793729f7e3b70ccb21d52 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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
const bool bMirrorX(basegfx::fTools::less(aScale.getX(), 0.0));
const bool bMirrorY(basegfx::fTools::less(aScale.getY(), 0.0));
aAttributes.SetMirrorFlags((bMirrorX ? BMP_MIRROR_HORZ : 0)|(bMirrorY ? 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
// #118824# Caution! When mirrored, adapt transformation accordingly
const basegfx::B2DHomMatrix aSimpleObjectMatrix(
basegfx::tools::createScaleTranslateB2DHomMatrix(
fabs(aScale.getX()),
fabs(aScale.getY()),
bMirrorX ? aTranslate.getX() - fabs(aScale.getX()): aTranslate.getX(),
bMirrorY ? aTranslate.getY() - fabs(aScale.getY()): aTranslate.getY()));
aOutlineRange.transform(aSimpleObjectMatrix);
}
// prepare dest coordinates
const Point aPoint(
basegfx::fround(aOutlineRange.getMinX()),
basegfx::fround(aOutlineRange.getMinY()));
const Size aSize(
basegfx::fround(aOutlineRange.getWidth()),
basegfx::fround(aOutlineRange.getHeight()));
// paint it using GraphicManager
Graphic aGraphic(rBitmapEx);
GraphicObject aGraphicObject(aGraphic);
aGraphicObject.Draw(&rOutDev, aPoint, aSize, &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);
// prepare dest coordinates
const Point aPoint(
basegfx::fround(aOutlineRange.getMinX()),
basegfx::fround(aOutlineRange.getMinY()));
const Size aSize(
basegfx::fround(aOutlineRange.getWidth()),
basegfx::fround(aOutlineRange.getHeight()));
// 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(aPoint, aSize, aContent);
}
void RenderBitmapPrimitive2D_self(
OutputDevice& rOutDev,
const BitmapEx& rBitmapEx,
const basegfx::B2DHomMatrix& rTransform)
{
// process self with free transformation (containing shear and rotate). Get dest rect in pixels.
basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
aOutlineRange.transform(rTransform);
const Rectangle aDestRectLogic(
basegfx::fround(aOutlineRange.getMinX()),
basegfx::fround(aOutlineRange.getMinY()),
basegfx::fround(aOutlineRange.getMaxX()),
basegfx::fround(aOutlineRange.getMaxY()));
const Rectangle aDestRectPixel(rOutDev.LogicToPixel(aDestRectLogic));
// #i96708# check if Metafile is recorded
const GDIMetaFile* pMetaFile = rOutDev.GetConnectMetaFile();
const bool bRecordToMetaFile(pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
// intersect with output pixel size, but only
// when not recording to metafile
const Rectangle aOutputRectPixel(Point(), rOutDev.GetOutputSizePixel());
Rectangle aCroppedRectPixel(bRecordToMetaFile ? aDestRectPixel : aDestRectPixel.GetIntersection(aOutputRectPixel));
if(!aCroppedRectPixel.IsEmpty())
{
// as maximum for destination, orientate at 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