summaryrefslogtreecommitdiffstats
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.cxx662
1 files changed, 376 insertions, 286 deletions
diff --git a/drawinglayer/source/processor2d/vclprocessor2d.cxx b/drawinglayer/source/processor2d/vclprocessor2d.cxx
index 9ef220c32cfb..0c5f70bb530b 100644
--- a/drawinglayer/source/processor2d/vclprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclprocessor2d.cxx
@@ -23,9 +23,14 @@
#include "vclhelperbufferdevice.hxx"
#include <cmath>
#include <comphelper/string.hxx>
+#include <comphelper/lok.hxx>
#include <svtools/optionsdrawinglayer.hxx>
#include <tools/debug.hxx>
+#include <tools/fract.hxx>
+#include <utility>
+#include <vcl/glyphitemcache.hxx>
#include <vcl/graph.hxx>
+#include <vcl/kernarray.hxx>
#include <vcl/outdev.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
@@ -90,6 +95,29 @@ sal_uInt32 calculateStepsForSvgGradient(const basegfx::BColor& rColorA,
}
}
+namespace
+{
+/** helper to convert a MapMode to a transformation */
+basegfx::B2DHomMatrix getTransformFromMapMode(const MapMode& rMapMode)
+{
+ basegfx::B2DHomMatrix aMapping;
+ const Fraction aNoScale(1, 1);
+ const Point& rOrigin(rMapMode.GetOrigin());
+
+ if (0 != rOrigin.X() || 0 != rOrigin.Y())
+ {
+ aMapping.translate(rOrigin.X(), rOrigin.Y());
+ }
+
+ if (rMapMode.GetScaleX() != aNoScale || rMapMode.GetScaleY() != aNoScale)
+ {
+ aMapping.scale(double(rMapMode.GetScaleX()), double(rMapMode.GetScaleY()));
+ }
+
+ return aMapping;
+}
+}
+
namespace drawinglayer::processor2d
{
// rendering support
@@ -107,14 +135,14 @@ void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(
basegfx::B2DVector aFontScaling, aTranslate;
double fRotate, fShearX;
aLocalTransform.decompose(aFontScaling, aTranslate, fRotate, fShearX);
+
bool bPrimitiveAccepted(false);
// tdf#95581: Assume tiny shears are rounding artefacts or whatever and can be ignored,
// especially if the effect is less than a pixel.
if (std::abs(aFontScaling.getY() * fShearX) < 1)
{
- if (basegfx::fTools::less(aFontScaling.getX(), 0.0)
- && basegfx::fTools::less(aFontScaling.getY(), 0.0))
+ if (aFontScaling.getX() < 0.0 && aFontScaling.getY() < 0.0)
{
// handle special case: If scale is negative in (x,y) (3rd quadrant), it can
// be expressed as rotation by PI. Use this since the Font rendering will not
@@ -123,25 +151,43 @@ void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(
fRotate += M_PI;
}
- if (basegfx::fTools::more(aFontScaling.getX(), 0.0)
- && basegfx::fTools::more(aFontScaling.getY(), 0.0))
+ if (aFontScaling.getX() > 0.0 && aFontScaling.getY() > 0.0)
{
- // Get the VCL font (use FontHeight as FontWidth)
- vcl::Font aFont(primitive2d::getVclFontFromFontAttribute(
- rTextCandidate.getFontAttribute(), aFontScaling.getX(), aFontScaling.getY(),
- fRotate, rTextCandidate.getLocale()));
+ double fIgnoreRotate, fIgnoreShearX;
+
+ basegfx::B2DVector aFontSize, aTextTranslate;
+ rTextCandidate.getTextTransform().decompose(aFontSize, aTextTranslate, fIgnoreRotate,
+ fIgnoreShearX);
+
+ // tdf#153092 Ideally we don't have to scale the font and dxarray, but we might have
+ // to nevertheless if dealing with non integer sizes
+ const bool bScaleFont(aFontSize.getY() != std::round(aFontSize.getY())
+ || comphelper::LibreOfficeKit::isActive());
+ vcl::Font aFont;
+
+ // Get the VCL font
+ if (!bScaleFont)
+ {
+ aFont = primitive2d::getVclFontFromFontAttribute(
+ rTextCandidate.getFontAttribute(), aFontSize.getX(), aFontSize.getY(), fRotate,
+ rTextCandidate.getLocale());
+ }
+ else
+ {
+ aFont = primitive2d::getVclFontFromFontAttribute(
+ rTextCandidate.getFontAttribute(), aFontScaling.getX(), aFontScaling.getY(),
+ fRotate, rTextCandidate.getLocale());
+ }
// Don't draw fonts without height
- if (aFont.GetFontHeight() <= 0)
+ Size aResultFontSize = aFont.GetFontSize();
+ if (aResultFontSize.Height() <= 0)
return;
// set FillColor Attribute
const Color aFillColor(rTextCandidate.getTextFillColor());
- if (aFillColor != COL_TRANSPARENT)
- {
- aFont.SetFillColor(aFillColor);
- aFont.SetTransparent(false);
- }
+ aFont.SetTransparent(aFillColor.IsTransparent());
+ aFont.SetFillColor(aFillColor);
// handle additional font attributes
const primitive2d::TextDecoratedPortionPrimitive2D* pTCPP = nullptr;
@@ -248,27 +294,27 @@ void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(
aFont.SetShadow(true);
}
- // create transformed integer DXArray in view coordinate system
- std::vector<sal_Int32> aTransformedDXArray;
+ // create integer DXArray
+ KernArray aDXArray;
if (!rTextCandidate.getDXArray().empty())
{
- aTransformedDXArray.reserve(rTextCandidate.getDXArray().size());
- const basegfx::B2DVector aPixelVector(maCurrentTransformation
- * basegfx::B2DVector(1.0, 0.0));
- const double fPixelVectorFactor(aPixelVector.getLength());
-
- for (auto const& elem : rTextCandidate.getDXArray())
+ double fPixelVectorFactor(1.0);
+ if (bScaleFont)
{
- aTransformedDXArray.push_back(basegfx::fround(elem * fPixelVectorFactor));
+ const basegfx::B2DVector aPixelVector(maCurrentTransformation
+ * basegfx::B2DVector(1.0, 0.0));
+ fPixelVectorFactor = aPixelVector.getLength();
}
+
+ aDXArray.reserve(rTextCandidate.getDXArray().size());
+ for (auto const& elem : rTextCandidate.getDXArray())
+ aDXArray.push_back(basegfx::fround(elem * fPixelVectorFactor));
}
// set parameters and paint text snippet
const basegfx::BColor aRGBFontColor(
maBColorModifierStack.getModifiedColor(rTextCandidate.getFontColor()));
- const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0));
- const Point aStartPoint(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY()));
const vcl::text::ComplexTextLayoutFlags nOldLayoutMode(mpOutputDevice->GetLayoutMode());
if (rTextCandidate.getFontAttribute().getRTL())
@@ -280,47 +326,127 @@ void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(
mpOutputDevice->SetLayoutMode(nRTLLayoutMode);
}
- mpOutputDevice->SetFont(aFont);
mpOutputDevice->SetTextColor(Color(aRGBFontColor));
OUString aText(rTextCandidate.getText());
sal_Int32 nPos = rTextCandidate.getTextPosition();
sal_Int32 nLen = rTextCandidate.getTextLength();
+ // this contraption is used in editeng, with format paragraph used to
+ // set a tab with a tab-fill character
if (rTextCandidate.isFilled())
{
- basegfx::B2DVector aOldFontScaling, aOldTranslate;
- double fOldRotate, fOldShearX;
- rTextCandidate.getTextTransform().decompose(aOldFontScaling, aOldTranslate,
- fOldRotate, fOldShearX);
-
- tools::Long nWidthToFill = static_cast<tools::Long>(
- rTextCandidate.getWidthToFill() * aFontScaling.getX() / aOldFontScaling.getX());
+ tools::Long nWidthToFill = rTextCandidate.getWidthToFill();
- tools::Long nWidth = mpOutputDevice->GetTextArray(rTextCandidate.getText(),
- &aTransformedDXArray, 0, 1);
- tools::Long nChars = 2;
+ tools::Long nWidth = basegfx::fround<tools::Long>(
+ mpOutputDevice->GetTextArray(rTextCandidate.getText(), &aDXArray, 0, 1));
+ sal_Int32 nChars = 2;
if (nWidth)
nChars = nWidthToFill / nWidth;
- OUStringBuffer aFilled;
+ OUStringBuffer aFilled(nChars);
comphelper::string::padToLength(aFilled, nChars, aText[0]);
aText = aFilled.makeStringAndClear();
nPos = 0;
nLen = nChars;
- if (!aTransformedDXArray.empty())
+ if (!aDXArray.empty())
{
- sal_Int32 nDX = aTransformedDXArray[0];
- aTransformedDXArray.resize(nLen);
+ sal_Int32 nDX = aDXArray[0];
+ aDXArray.resize(nLen);
for (sal_Int32 i = 1; i < nLen; ++i)
- aTransformedDXArray[i] = aTransformedDXArray[i - 1] + nDX;
+ aDXArray.set(i, aDXArray[i - 1] + nDX);
}
}
- if (!aTransformedDXArray.empty())
+ Point aStartPoint;
+ bool bChangeMapMode(false);
+ if (!bScaleFont)
{
- mpOutputDevice->DrawTextArray(aStartPoint, aText, aTransformedDXArray, nPos, nLen);
+ basegfx::B2DHomMatrix aCombinedTransform(
+ getTransformFromMapMode(mpOutputDevice->GetMapMode())
+ * maCurrentTransformation);
+
+ basegfx::B2DVector aCurrentScaling, aCurrentTranslate;
+ double fCurrentRotate;
+ aCombinedTransform.decompose(aCurrentScaling, aCurrentTranslate, fCurrentRotate,
+ fIgnoreShearX);
+
+ const Point aOrigin(
+ basegfx::fround<tools::Long>(aCurrentTranslate.getX() / aCurrentScaling.getX()),
+ basegfx::fround<tools::Long>(aCurrentTranslate.getY()
+ / aCurrentScaling.getY()));
+
+ Fraction aScaleX(aCurrentScaling.getX());
+ if (!aScaleX.IsValid())
+ {
+ SAL_WARN("drawinglayer", "invalid X Scale");
+ return;
+ }
+
+ Fraction aScaleY(aCurrentScaling.getY());
+ if (!aScaleY.IsValid())
+ {
+ SAL_WARN("drawinglayer", "invalid Y Scale");
+ return;
+ }
+
+ MapMode aMapMode(mpOutputDevice->GetMapMode().GetMapUnit(), aOrigin, aScaleX,
+ aScaleY);
+
+ if (fCurrentRotate)
+ aTextTranslate *= basegfx::utils::createRotateB2DHomMatrix(fCurrentRotate);
+ aStartPoint = Point(basegfx::fround<tools::Long>(aTextTranslate.getX()),
+ basegfx::fround<tools::Long>(aTextTranslate.getY()));
+
+ bChangeMapMode = aMapMode != mpOutputDevice->GetMapMode();
+ if (bChangeMapMode)
+ {
+ mpOutputDevice->Push(vcl::PushFlags::MAPMODE);
+ mpOutputDevice->SetRelativeMapMode(aMapMode);
+ }
+ }
+ else
+ {
+ const basegfx::B2DPoint aPoint(aLocalTransform * basegfx::B2DPoint(0.0, 0.0));
+ double aPointX = aPoint.getX(), aPointY = aPoint.getY();
+
+ // aFont has an integer size; we must scale a bit for precision
+ double nFontScalingFixY = aFontScaling.getY() / aResultFontSize.Height();
+ double nFontScalingFixX = aFontScaling.getX()
+ / (aResultFontSize.Width() ? aResultFontSize.Width()
+ : aResultFontSize.Height());
+
+ if (!rtl_math_approxEqual(nFontScalingFixY, 1.0)
+ || !rtl_math_approxEqual(nFontScalingFixX, 1.0))
+ {
+ MapMode aMapMode = mpOutputDevice->GetMapMode();
+ aMapMode.SetScaleX(aMapMode.GetScaleX() * nFontScalingFixX);
+ aMapMode.SetScaleY(aMapMode.GetScaleY() * nFontScalingFixY);
+
+ mpOutputDevice->Push(vcl::PushFlags::MAPMODE);
+ mpOutputDevice->SetRelativeMapMode(aMapMode);
+ bChangeMapMode = true;
+
+ aPointX /= nFontScalingFixX;
+ aPointY /= nFontScalingFixY;
+ }
+
+ aStartPoint = Point(basegfx::fround<tools::Long>(aPointX),
+ basegfx::fround<tools::Long>(aPointY));
+ }
+
+ // tdf#152990 set the font after the MapMode is (potentially) set so canvas uses the desired
+ // font size
+ mpOutputDevice->SetFont(aFont);
+
+ if (!aDXArray.empty())
+ {
+ const SalLayoutGlyphs* pGlyphs = SalLayoutGlyphsCache::self()->GetLayoutGlyphs(
+ mpOutputDevice, aText, nPos, nLen);
+ mpOutputDevice->DrawTextArray(aStartPoint, aText, aDXArray,
+ rTextCandidate.getKashidaArray(), nPos, nLen,
+ SalLayoutFlags::NONE, pGlyphs);
}
else
{
@@ -332,6 +458,9 @@ void VclProcessor2D::RenderTextSimpleOrDecoratedPortionPrimitive2D(
mpOutputDevice->SetLayoutMode(nOldLayoutMode);
}
+ if (bChangeMapMode)
+ mpOutputDevice->Pop();
+
bPrimitiveAccepted = true;
}
}
@@ -355,8 +484,7 @@ void VclProcessor2D::RenderPolygonHairlinePrimitive2D(
basegfx::B2DPolygon aLocalPolygon(rPolygonCandidate.getB2DPolygon());
aLocalPolygon.transform(maCurrentTransformation);
- if (bPixelBased && SvtOptionsDrawinglayer::IsAntiAliasing()
- && SvtOptionsDrawinglayer::IsSnapHorVerLinesToDiscrete())
+ if (bPixelBased && getViewInformation2D().getPixelSnapHairline())
{
// #i98289#
// when a Hairline is painted and AntiAliasing is on the option SnapHorVerLinesToDiscrete
@@ -372,7 +500,7 @@ void VclProcessor2D::RenderPolygonHairlinePrimitive2D(
// direct draw of transformed BitmapEx primitive
void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
{
- BitmapEx aBitmapEx(VCLUnoHelper::GetBitmap(rBitmapCandidate.getXBitmap()));
+ BitmapEx aBitmapEx(rBitmapCandidate.getBitmap());
const basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation
* rBitmapCandidate.getTransform());
@@ -406,243 +534,224 @@ void VclProcessor2D::RenderBitmapPrimitive2D(const primitive2d::BitmapPrimitive2
void VclProcessor2D::RenderFillGraphicPrimitive2D(
const primitive2d::FillGraphicPrimitive2D& rFillBitmapCandidate)
{
+ bool bPrimitiveAccepted = RenderFillGraphicPrimitive2DImpl(rFillBitmapCandidate);
+
+ if (!bPrimitiveAccepted)
+ {
+ // do not accept, use decomposition
+ process(rFillBitmapCandidate);
+ }
+}
+
+bool VclProcessor2D::RenderFillGraphicPrimitive2DImpl(
+ const primitive2d::FillGraphicPrimitive2D& rFillBitmapCandidate)
+{
const attribute::FillGraphicAttribute& rFillGraphicAttribute(
rFillBitmapCandidate.getFillGraphic());
- bool bPrimitiveAccepted(false);
// #121194# when tiling is used and content is bitmap-based, do direct tiling in the
// renderer on pixel base to ensure tight fitting. Do not do this when
// the fill is rotated or sheared.
- if (rFillGraphicAttribute.getTiling())
- {
- // content is bitmap(ex)
- //
- // for Vector Graphic Data (SVG, EMF+) support, force decomposition when present. This will lead to use
- // the primitive representation of the vector data directly.
- //
- // when graphic is animated, force decomposition to use the correct graphic, else
- // fill style will not be animated
- if (GraphicType::Bitmap == rFillGraphicAttribute.getGraphic().GetType()
- && !rFillGraphicAttribute.getGraphic().getVectorGraphicData()
- && !rFillGraphicAttribute.getGraphic().IsAnimated())
- {
- // 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);
-
- // when nopt rotated/sheared
- if (basegfx::fTools::equalZero(fRotate) && basegfx::fTools::equalZero(fShearX))
- {
- // no shear or rotate, draw direct in pixel coordinates
- bPrimitiveAccepted = true;
+ if (!rFillGraphicAttribute.getTiling())
+ return false;
+
+ // content is bitmap(ex)
+ //
+ // for Vector Graphic Data (SVG, EMF+) support, force decomposition when present. This will lead to use
+ // the primitive representation of the vector data directly.
+ //
+ // when graphic is animated, force decomposition to use the correct graphic, else
+ // fill style will not be animated
+ if (GraphicType::Bitmap != rFillGraphicAttribute.getGraphic().GetType()
+ || rFillGraphicAttribute.getGraphic().getVectorGraphicData()
+ || rFillGraphicAttribute.getGraphic().IsAnimated())
+ return false;
+
+ // 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);
- // transform object range to device coordinates (pixels). Use
- // the device transformation for better accuracy
- basegfx::B2DRange aObjectRange(aTranslate, aTranslate + aScale);
- aObjectRange.transform(mpOutputDevice->GetViewTransformation());
+ // when nopt rotated/sheared
+ if (!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX))
+ return false;
- // extract discrete size of object
- const sal_Int32 nOWidth(basegfx::fround(aObjectRange.getWidth()));
- const sal_Int32 nOHeight(basegfx::fround(aObjectRange.getHeight()));
+ // no shear or rotate, draw direct in pixel coordinates
- // only do something when object has a size in discrete units
- if (nOWidth > 0 && nOHeight > 0)
- {
- // transform graphic range to device coordinates (pixels). Use
- // the device transformation for better accuracy
- basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange());
- aGraphicRange.transform(mpOutputDevice->GetViewTransformation()
- * aLocalTransform);
-
- // extract discrete size of graphic
- // caution: when getting to zero, nothing would be painted; thus, do not allow this
- const sal_Int32 nBWidth(
- std::max(sal_Int32(1), basegfx::fround(aGraphicRange.getWidth())));
- const sal_Int32 nBHeight(
- std::max(sal_Int32(1), basegfx::fround(aGraphicRange.getHeight())));
-
- // only do something when bitmap fill has a size in discrete units
- if (nBWidth > 0 && nBHeight > 0)
- {
- // nBWidth, nBHeight is the pixel size of the needed bitmap. To not need to scale it
- // in vcl many times, create a size-optimized version
- const Size aNeededBitmapSizePixel(nBWidth, nBHeight);
- BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx());
- const bool bPreScaled(nBWidth * nBHeight < (250 * 250));
-
- // ... but only up to a maximum size, else it gets too expensive
- if (bPreScaled)
- {
- // if color depth is below 24bit, expand before scaling for better quality.
- // This is even needed for low colors, else the scale will produce
- // a bitmap in gray or Black/White (!)
- if (isPalettePixelFormat(aBitmapEx.getPixelFormat()))
- {
- aBitmapEx.Convert(BmpConversion::N24Bit);
- }
+ // transform object range to device coordinates (pixels). Use
+ // the device transformation for better accuracy
+ basegfx::B2DRange aObjectRange(aTranslate, aTranslate + aScale);
+ aObjectRange.transform(mpOutputDevice->GetViewTransformation());
- aBitmapEx.Scale(aNeededBitmapSizePixel, BmpScaleFlag::Interpolate);
- }
+ // extract discrete size of object
+ const sal_Int32 nOWidth(basegfx::fround(aObjectRange.getWidth()));
+ const sal_Int32 nOHeight(basegfx::fround(aObjectRange.getHeight()));
- bool bPainted(false);
+ // only do something when object has a size in discrete units
+ if (nOWidth <= 0 || nOHeight <= 0)
+ return true;
- if (maBColorModifierStack.count())
- {
- // when color modifier, apply to bitmap
- aBitmapEx = aBitmapEx.ModifyBitmapEx(maBColorModifierStack);
+ // transform graphic range to device coordinates (pixels). Use
+ // the device transformation for better accuracy
+ basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange());
+ aGraphicRange.transform(mpOutputDevice->GetViewTransformation() * aLocalTransform);
- // impModifyBitmapEx uses empty bitmap as sign to return that
- // the content will be completely replaced to mono color, use shortcut
- if (aBitmapEx.IsEmpty())
- {
- // color gets completely replaced, get it
- const basegfx::BColor aModifiedColor(
- maBColorModifierStack.getModifiedColor(basegfx::BColor()));
- basegfx::B2DPolygon aPolygon(basegfx::utils::createUnitPolygon());
- aPolygon.transform(aLocalTransform);
+ // extract discrete size of graphic
+ // caution: when getting to zero, nothing would be painted; thus, do not allow this
+ const sal_Int32 nBWidth(std::max(sal_Int32(1), basegfx::fround(aGraphicRange.getWidth())));
+ const sal_Int32 nBHeight(std::max(sal_Int32(1), basegfx::fround(aGraphicRange.getHeight())));
- mpOutputDevice->SetFillColor(Color(aModifiedColor));
- mpOutputDevice->SetLineColor();
- mpOutputDevice->DrawPolygon(aPolygon);
+ // nBWidth, nBHeight is the pixel size of the needed bitmap. To not need to scale it
+ // in vcl many times, create a size-optimized version
+ const Size aNeededBitmapSizePixel(nBWidth, nBHeight);
+ BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx());
+ const bool bPreScaled(nBWidth * nBHeight < (250 * 250));
- bPainted = true;
- }
- }
+ // ... but only up to a maximum size, else it gets too expensive
+ if (bPreScaled)
+ {
+ // if color depth is below 24bit, expand before scaling for better quality.
+ // This is even needed for low colors, else the scale will produce
+ // a bitmap in gray or Black/White (!)
+ if (isPalettePixelFormat(aBitmapEx.getPixelFormat()))
+ {
+ aBitmapEx.Convert(BmpConversion::N24Bit);
+ }
- if (!bPainted)
- {
- sal_Int32 nBLeft(basegfx::fround(aGraphicRange.getMinX()));
- sal_Int32 nBTop(basegfx::fround(aGraphicRange.getMinY()));
- const sal_Int32 nOLeft(basegfx::fround(aObjectRange.getMinX()));
- const sal_Int32 nOTop(basegfx::fround(aObjectRange.getMinY()));
- sal_Int32 nPosX(0);
- sal_Int32 nPosY(0);
-
- if (nBLeft > nOLeft)
- {
- const sal_Int32 nDiff((nBLeft / nBWidth) + 1);
+ aBitmapEx.Scale(aNeededBitmapSizePixel, BmpScaleFlag::Interpolate);
+ }
- nPosX -= nDiff;
- nBLeft -= nDiff * nBWidth;
- }
+ if (maBColorModifierStack.count())
+ {
+ // when color modifier, apply to bitmap
+ aBitmapEx = aBitmapEx.ModifyBitmapEx(maBColorModifierStack);
- if (nBLeft + nBWidth <= nOLeft)
- {
- const sal_Int32 nDiff(-nBLeft / nBWidth);
+ // ModifyBitmapEx uses empty bitmap as sign to return that
+ // the content will be completely replaced to mono color, use shortcut
+ if (aBitmapEx.IsEmpty())
+ {
+ // color gets completely replaced, get it
+ const basegfx::BColor aModifiedColor(
+ maBColorModifierStack.getModifiedColor(basegfx::BColor()));
+ basegfx::B2DPolygon aPolygon(basegfx::utils::createUnitPolygon());
+ aPolygon.transform(aLocalTransform);
- nPosX += nDiff;
- nBLeft += nDiff * nBWidth;
- }
+ mpOutputDevice->SetFillColor(Color(aModifiedColor));
+ mpOutputDevice->SetLineColor();
+ mpOutputDevice->DrawPolygon(aPolygon);
- if (nBTop > nOTop)
- {
- const sal_Int32 nDiff((nBTop / nBHeight) + 1);
+ return true;
+ }
+ }
- nPosY -= nDiff;
- nBTop -= nDiff * nBHeight;
- }
+ sal_Int32 nBLeft(basegfx::fround(aGraphicRange.getMinX()));
+ sal_Int32 nBTop(basegfx::fround(aGraphicRange.getMinY()));
+ const sal_Int32 nOLeft(basegfx::fround(aObjectRange.getMinX()));
+ const sal_Int32 nOTop(basegfx::fround(aObjectRange.getMinY()));
+ sal_Int32 nPosX(0);
+ sal_Int32 nPosY(0);
- if (nBTop + nBHeight <= nOTop)
- {
- const sal_Int32 nDiff(-nBTop / nBHeight);
+ if (nBLeft > nOLeft)
+ {
+ const sal_Int32 nDiff((nBLeft / nBWidth) + 1);
- nPosY += nDiff;
- nBTop += nDiff * nBHeight;
- }
+ nPosX -= nDiff;
+ nBLeft -= nDiff * nBWidth;
+ }
- // prepare OutDev
- const Point aEmptyPoint(0, 0);
- const ::tools::Rectangle aVisiblePixel(
- aEmptyPoint, mpOutputDevice->GetOutputSizePixel());
- const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
- mpOutputDevice->EnableMapMode(false);
+ if (nBLeft + nBWidth <= nOLeft)
+ {
+ const sal_Int32 nDiff(-nBLeft / nBWidth);
- // check if offset is used
- const sal_Int32 nOffsetX(
- basegfx::fround(rFillGraphicAttribute.getOffsetX() * nBWidth));
+ nPosX += nDiff;
+ nBLeft += nDiff * nBWidth;
+ }
- if (nOffsetX)
- {
- // offset in X, so iterate over Y first and draw lines
- for (sal_Int32 nYPos(nBTop); nYPos < nOTop + nOHeight;
- nYPos += nBHeight, nPosY++)
- {
- for (sal_Int32 nXPos((nPosY % 2) ? nBLeft - nBWidth + nOffsetX
- : nBLeft);
- nXPos < nOLeft + nOWidth; nXPos += nBWidth)
- {
- const ::tools::Rectangle aOutRectPixel(
- Point(nXPos, nYPos), aNeededBitmapSizePixel);
-
- if (aOutRectPixel.Overlaps(aVisiblePixel))
- {
- if (bPreScaled)
- {
- mpOutputDevice->DrawBitmapEx(
- aOutRectPixel.TopLeft(), aBitmapEx);
- }
- else
- {
- mpOutputDevice->DrawBitmapEx(
- aOutRectPixel.TopLeft(), aNeededBitmapSizePixel,
- aBitmapEx);
- }
- }
- }
- }
- }
- else
- {
- // check if offset is used
- const sal_Int32 nOffsetY(
- basegfx::fround(rFillGraphicAttribute.getOffsetY() * nBHeight));
+ if (nBTop > nOTop)
+ {
+ const sal_Int32 nDiff((nBTop / nBHeight) + 1);
- // possible offset in Y, so iterate over X first and draw columns
- for (sal_Int32 nXPos(nBLeft); nXPos < nOLeft + nOWidth;
- nXPos += nBWidth, nPosX++)
- {
- for (sal_Int32 nYPos((nPosX % 2) ? nBTop - nBHeight + nOffsetY
- : nBTop);
- nYPos < nOTop + nOHeight; nYPos += nBHeight)
- {
- const ::tools::Rectangle aOutRectPixel(
- Point(nXPos, nYPos), aNeededBitmapSizePixel);
-
- if (aOutRectPixel.Overlaps(aVisiblePixel))
- {
- if (bPreScaled)
- {
- mpOutputDevice->DrawBitmapEx(
- aOutRectPixel.TopLeft(), aBitmapEx);
- }
- else
- {
- mpOutputDevice->DrawBitmapEx(
- aOutRectPixel.TopLeft(), aNeededBitmapSizePixel,
- aBitmapEx);
- }
- }
- }
- }
- }
+ nPosY -= nDiff;
+ nBTop -= nDiff * nBHeight;
+ }
- // restore OutDev
- mpOutputDevice->EnableMapMode(bWasEnabled);
- }
+ if (nBTop + nBHeight <= nOTop)
+ {
+ const sal_Int32 nDiff(-nBTop / nBHeight);
+
+ nPosY += nDiff;
+ nBTop += nDiff * nBHeight;
+ }
+
+ // prepare OutDev
+ const Point aEmptyPoint(0, 0);
+ // the visible rect, in pixels
+ const ::tools::Rectangle aVisiblePixel(aEmptyPoint, mpOutputDevice->GetOutputSizePixel());
+ const bool bWasEnabled(mpOutputDevice->IsMapModeEnabled());
+ mpOutputDevice->EnableMapMode(false);
+
+ // check if offset is used
+ const sal_Int32 nOffsetX(basegfx::fround(rFillGraphicAttribute.getOffsetX() * nBWidth));
+
+ if (nOffsetX)
+ {
+ // offset in X, so iterate over Y first and draw lines
+ for (sal_Int32 nYPos(nBTop); nYPos < nOTop + nOHeight; nYPos += nBHeight, nPosY++)
+ {
+ for (sal_Int32 nXPos((nPosY % 2) ? nBLeft - nBWidth + nOffsetX : nBLeft);
+ nXPos < nOLeft + nOWidth; nXPos += nBWidth)
+ {
+ const ::tools::Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel);
+
+ if (aOutRectPixel.Overlaps(aVisiblePixel))
+ {
+ if (bPreScaled)
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
+ }
+ else
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(),
+ aNeededBitmapSizePixel, aBitmapEx);
}
}
}
}
}
-
- if (!bPrimitiveAccepted)
+ else
{
- // do not accept, use decomposition
- process(rFillBitmapCandidate);
+ // check if offset is used
+ const sal_Int32 nOffsetY(basegfx::fround(rFillGraphicAttribute.getOffsetY() * nBHeight));
+
+ // possible offset in Y, so iterate over X first and draw columns
+ for (sal_Int32 nXPos(nBLeft); nXPos < nOLeft + nOWidth; nXPos += nBWidth, nPosX++)
+ {
+ for (sal_Int32 nYPos((nPosX % 2) ? nBTop - nBHeight + nOffsetY : nBTop);
+ nYPos < nOTop + nOHeight; nYPos += nBHeight)
+ {
+ const ::tools::Rectangle aOutRectPixel(Point(nXPos, nYPos), aNeededBitmapSizePixel);
+
+ if (aOutRectPixel.Overlaps(aVisiblePixel))
+ {
+ if (bPreScaled)
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(), aBitmapEx);
+ }
+ else
+ {
+ mpOutputDevice->DrawBitmapEx(aOutRectPixel.TopLeft(),
+ aNeededBitmapSizePixel, aBitmapEx);
+ }
+ }
+ }
+ }
}
+
+ // restore OutDev
+ mpOutputDevice->EnableMapMode(bWasEnabled);
+ return true;
}
// direct draw of Graphic
@@ -774,7 +883,7 @@ void VclProcessor2D::RenderMaskPrimitive2DPixel(const primitive2d::MaskPrimitive
aMask.transform(maCurrentTransformation);
// Unless smooth edges are needed, simply use clipping.
- if (basegfx::utils::isRectangle(aMask) || !SvtOptionsDrawinglayer::IsAntiAliasing())
+ if (basegfx::utils::isRectangle(aMask) || !getViewInformation2D().getUseAntiAliasing())
{
mpOutputDevice->Push(vcl::PushFlags::CLIPREGION);
mpOutputDevice->IntersectClipRegion(vcl::Region(aMask));
@@ -890,7 +999,7 @@ void VclProcessor2D::RenderTransparencePrimitive2D(
process(rTransCandidate.getTransparence());
// back to old color stack
- maBColorModifierStack = aLastBColorModifierStack;
+ maBColorModifierStack = std::move(aLastBColorModifierStack);
// back to old OutDev
mpOutputDevice = pLastOutputDevice;
@@ -910,10 +1019,9 @@ void VclProcessor2D::RenderTransformPrimitive2D(
// create new transformations for CurrentTransformation
// and for local ViewInformation2D
maCurrentTransformation = maCurrentTransformation * rTransformCandidate.getTransformation();
- const geometry::ViewInformation2D aViewInformation2D(
- getViewInformation2D().getObjectTransformation() * rTransformCandidate.getTransformation(),
- getViewInformation2D().getViewTransformation(), getViewInformation2D().getViewport(),
- getViewInformation2D().getVisualizedPage(), getViewInformation2D().getViewTime());
+ geometry::ViewInformation2D aViewInformation2D(getViewInformation2D());
+ aViewInformation2D.setObjectTransformation(getViewInformation2D().getObjectTransformation()
+ * rTransformCandidate.getTransformation());
updateViewInformation(aViewInformation2D);
// process content
@@ -932,10 +1040,8 @@ void VclProcessor2D::RenderPagePreviewPrimitive2D(
const geometry::ViewInformation2D aLastViewInformation2D(getViewInformation2D());
// create new local ViewInformation2D
- const geometry::ViewInformation2D aViewInformation2D(
- getViewInformation2D().getObjectTransformation(),
- getViewInformation2D().getViewTransformation(), getViewInformation2D().getViewport(),
- rPagePreviewCandidate.getXDrawPage(), getViewInformation2D().getViewTime());
+ geometry::ViewInformation2D aViewInformation2D(getViewInformation2D());
+ aViewInformation2D.setVisualizedPage(rPagePreviewCandidate.getXDrawPage());
updateViewInformation(aViewInformation2D);
// process decomposed content
@@ -981,8 +1087,8 @@ void VclProcessor2D::RenderMarkerArrayPrimitive2D(
{
const basegfx::B2DPoint aDiscreteTopLeft((maCurrentTransformation * pos)
- aDiscreteHalfSize);
- const Point aDiscretePoint(basegfx::fround(aDiscreteTopLeft.getX()),
- basegfx::fround(aDiscreteTopLeft.getY()));
+ const Point aDiscretePoint(basegfx::fround<tools::Long>(aDiscreteTopLeft.getX()),
+ basegfx::fround<tools::Long>(aDiscreteTopLeft.getY()));
mpOutputDevice->DrawBitmapEx(aDiscretePoint + aOrigin, rMarker);
}
@@ -1002,8 +1108,8 @@ void VclProcessor2D::RenderPointArrayPrimitive2D(
for (auto const& pos : rPositions)
{
const basegfx::B2DPoint aViewPosition(maCurrentTransformation * pos);
- const Point aPos(basegfx::fround(aViewPosition.getX()),
- basegfx::fround(aViewPosition.getY()));
+ const Point aPos(basegfx::fround<tools::Long>(aViewPosition.getX()),
+ basegfx::fround<tools::Long>(aViewPosition.getY()));
mpOutputDevice->DrawPixel(aPos, aVCLColor);
}
@@ -1018,7 +1124,7 @@ void VclProcessor2D::RenderPolygonStrokePrimitive2D(
const double fLineWidth(rLineAttribute.getWidth());
bool bDone(false);
- if (basegfx::fTools::more(fLineWidth, 0.0))
+ if (fLineWidth > 0.0)
{
const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation
* basegfx::B2DVector(fLineWidth, 0.0));
@@ -1049,7 +1155,7 @@ void VclProcessor2D::RenderPolygonStrokePrimitive2D(
if (nCount)
{
- const bool bAntiAliased(SvtOptionsDrawinglayer::IsAntiAliasing());
+ const bool bAntiAliased(getViewInformation2D().getUseAntiAliasing());
aHairlinePolyPolygon.transform(maCurrentTransformation);
if (bAntiAliased)
@@ -1262,26 +1368,12 @@ void VclProcessor2D::RenderEpsPrimitive2D(const primitive2d::EpsPrimitive2D& rEp
}
}
-void VclProcessor2D::RenderObjectInfoPrimitive2D(
- const primitive2d::ObjectInfoPrimitive2D& rObjectInfoPrimitive2D)
-{
- // remember current ObjectInfoPrimitive2D and set new current one (build a stack - push)
- const primitive2d::ObjectInfoPrimitive2D* pLast(getObjectInfoPrimitive2D());
- mpObjectInfoPrimitive2D = &rObjectInfoPrimitive2D;
-
- // process content
- process(rObjectInfoPrimitive2D.getChildren());
-
- // restore current ObjectInfoPrimitive2D (pop)
- mpObjectInfoPrimitive2D = pLast;
-}
-
void VclProcessor2D::RenderSvgLinearAtomPrimitive2D(
const primitive2d::SvgLinearAtomPrimitive2D& rCandidate)
{
const double fDelta(rCandidate.getOffsetB() - rCandidate.getOffsetA());
- if (!basegfx::fTools::more(fDelta, 0.0))
+ if (fDelta <= 0.0)
return;
const basegfx::BColor aColorA(maBColorModifierStack.getModifiedColor(rCandidate.getColorA()));
@@ -1291,7 +1383,7 @@ void VclProcessor2D::RenderSvgLinearAtomPrimitive2D(
const basegfx::B2DVector aDiscreteVector(
getViewInformation2D().getInverseObjectToViewTransformation()
* basegfx::B2DVector(1.0, 1.0));
- const double fDiscreteUnit(aDiscreteVector.getLength() * (1.0 / 1.414213562373));
+ const double fDiscreteUnit(aDiscreteVector.getLength() * (1.0 / M_SQRT2));
// use color distance and discrete lengths to calculate step count
const sal_uInt32 nSteps(calculateStepsForSvgGradient(aColorA, aColorB, fDelta, fDiscreteUnit));
@@ -1325,7 +1417,7 @@ void VclProcessor2D::RenderSvgRadialAtomPrimitive2D(
{
const double fDeltaScale(rCandidate.getScaleB() - rCandidate.getScaleA());
- if (!basegfx::fTools::more(fDeltaScale, 0.0))
+ if (fDeltaScale <= 0.0)
return;
const basegfx::BColor aColorA(maBColorModifierStack.getModifiedColor(rCandidate.getColorA()));
@@ -1335,7 +1427,7 @@ void VclProcessor2D::RenderSvgRadialAtomPrimitive2D(
const basegfx::B2DVector aDiscreteVector(
getViewInformation2D().getInverseObjectToViewTransformation()
* basegfx::B2DVector(1.0, 1.0));
- const double fDiscreteUnit(aDiscreteVector.getLength() * (1.0 / 1.414213562373));
+ const double fDiscreteUnit(aDiscreteVector.getLength() * (1.0 / M_SQRT2));
// use color distance and discrete lengths to calculate step count
const sal_uInt32 nSteps(
@@ -1476,13 +1568,11 @@ void VclProcessor2D::adaptTextToFillDrawMode() const
// process support
VclProcessor2D::VclProcessor2D(const geometry::ViewInformation2D& rViewInformation,
- OutputDevice& rOutDev,
- const basegfx::BColorModifierStack& rInitStack)
+ OutputDevice& rOutDev, basegfx::BColorModifierStack aInitStack)
: BaseProcessor2D(rViewInformation)
, mpOutputDevice(&rOutDev)
- , maBColorModifierStack(rInitStack)
+ , maBColorModifierStack(std::move(aInitStack))
, mnPolygonStrokePrimitive2D(0)
- , mpObjectInfoPrimitive2D(nullptr)
{
// set digit language, derived from SvtCTLOptions to have the correct
// number display for arabic/hindi numerals