converting the SalGraphics backend from BitmapEx->Bitmap (3)

pass a single SalBitmap in drawTransformedBitmap

Change-Id: Iacb67804e47867f4ab85b394b14f052807925b75
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190498
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
Noel Grandin
2025-09-04 17:06:46 +02:00
parent 7f35303c31
commit aba63efcdb
32 changed files with 316 additions and 282 deletions
@@ -547,7 +547,7 @@ void impBufferDevice::paint(double fTrans)
aSizePixel.Width(), aSizePixel.Height(),
maDestPixel.TopLeft().X(),
maDestPixel.TopLeft().Y()),
BitmapEx(aContent), 1 - fTrans);
aContent, 1 - fTrans);
}
else
{
+42
View File
@@ -183,6 +183,48 @@ public:
sal_Int32 nX,
sal_Int32 nY) const;
/** Create transformed Bitmap
@param fWidth
The target width in pixels
@param fHeight
The target height in pixels
@param rTransformation
The back transformation for each pixel in (0 .. fWidth),(0 .. fHeight) to
local pixel coordinates
*/
[[nodiscard]]
Bitmap TransformBitmap(
double fWidth,
double fHeight,
const basegfx::B2DHomMatrix& rTransformation) const;
/** Create transformed Bitmap
@param rTransformation
The transformation from unit coordinates to the unit range
@param rVisibleRange
The relative visible range in unit coordinates, relative to (0,0,1,1) which
defines the whole target area
@param fMaximumArea
A limitation for the maximum size of pixels to use for the result
The target size of the result bitmap is defined by transforming the given
rTargetRange with the given rTransformation; the area of the result is
linearly scaled to not exceed the given fMaximumArea
@return The transformed bitmap
*/
[[nodiscard]]
SAL_DLLPRIVATE Bitmap getTransformed(
const basegfx::B2DHomMatrix& rTransformation,
const basegfx::B2DRange& rVisibleRange,
double fMaximumArea) const;
/** Convert bitmap format
@param eConversion
+2 -6
View File
@@ -1388,10 +1388,6 @@ public:
@param fAlpha
Optional additional alpha to use for drawing (0 to 1, 1 being no change).
*/
void DrawTransformedBitmapEx(
const basegfx::B2DHomMatrix& rTransformation,
const BitmapEx& rBitmapEx,
double fAlpha = 1.0);
void DrawTransformedBitmapEx(
const basegfx::B2DHomMatrix& rTransformation,
const Bitmap& rBitmap,
@@ -1415,13 +1411,13 @@ protected:
/** Transform and draw a bitmap directly
@param aFullTransform The B2DHomMatrix used for the transformation
@param rBitmapEx Reference to the bitmap to be transformed and drawn
@param rBitmap Reference to the bitmap to be transformed and drawn
@return true if it was able to draw the bitmap, false if not
*/
virtual bool DrawTransformBitmapExDirect(
const basegfx::B2DHomMatrix& aFullTransform,
const BitmapEx& rBitmapEx,
const Bitmap& rBitmap,
double fAlpha = 1.0);
/** Transform and reduce the area that needs to be drawn of the bitmap and return the new
+1 -1
View File
@@ -164,7 +164,7 @@ protected:
const Point& rSrcPtPixel, const Size& rSrcSizePixel) override;
bool DrawTransformBitmapExDirect( const basegfx::B2DHomMatrix& aFullTransform,
const BitmapEx& rBitmapEx, double fAlpha = 1.0) override;
const Bitmap& rBitmap, double fAlpha = 1.0) override;
bool TransformAndReduceBitmapExToTargetRange( const basegfx::B2DHomMatrix& aFullTransform,
basegfx::B2DRange &aVisibleRange, double &fMaximumArea) override;
+2 -2
View File
@@ -37,7 +37,7 @@ Bitmap OutputDeviceTestBitmap::setupDrawTransformedBitmap(vcl::PixelFormat aBitm
aTransform.translate((maVDRectangle.GetWidth() / 2.0) - (aBitmapSize.Width() / 2.0),
(maVDRectangle.GetHeight() / 2.0) - (aBitmapSize.Height() / 2.0));
mpVirtualDevice->DrawTransformedBitmapEx(aTransform, BitmapEx(aBitmap));
mpVirtualDevice->DrawTransformedBitmapEx(aTransform, aBitmap);
return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize());
}
@@ -59,7 +59,7 @@ Bitmap OutputDeviceTestBitmap::setupComplexDrawTransformedBitmap(vcl::PixelForma
aTransform.scale(aBitmapSize.Width() * 2, aBitmapSize.Height() * 2);
aTransform.translate(1, 1);
mpVirtualDevice->DrawTransformedBitmapEx(aTransform, BitmapEx(aBitmap));
mpVirtualDevice->DrawTransformedBitmapEx(aTransform, aBitmap);
return mpVirtualDevice->GetBitmap(maVDRectangle.TopLeft(), maVDRectangle.GetSize());
}
+2 -33
View File
@@ -1699,16 +1699,8 @@ void CairoCommon::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rS
bool CairoCommon::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha,
bool bAntiAlias)
double fAlpha, bool bAntiAlias)
{
if (pAlphaBitmap && pAlphaBitmap->GetBitCount() != 8 && pAlphaBitmap->GetBitCount() != 1)
{
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap alpha depth case: "
<< pAlphaBitmap->GetBitCount());
return false;
}
if (fAlpha != 1.0)
return false;
@@ -1725,26 +1717,6 @@ bool CairoCommon::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const ba
return false;
}
// MM02 try to access buffered MaskHelper
std::shared_ptr<MaskHelper> aMask;
if (nullptr != pAlphaBitmap)
{
tryToUseMaskBuffer(*pAlphaBitmap, aMask);
}
// access cairo_surface_t from MaskHelper
cairo_surface_t* mask(nullptr);
if (aMask)
{
mask = aMask->getSurface(nDestWidth, nDestHeight);
}
if (nullptr != pAlphaBitmap && nullptr == mask)
{
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case");
return false;
}
const Size aSize = rSourceBitmap.GetSize();
cairo_t* cr = getCairoContext(false, bAntiAlias);
clipRegion(cr);
@@ -1765,10 +1737,7 @@ bool CairoCommon::drawTransformedBitmap(const basegfx::B2DPoint& rNull, const ba
cairo_clip(cr);
cairo_set_source_surface(cr, source, 0, 0);
if (mask)
cairo_mask_surface(cr, mask, 0, 0);
else
cairo_paint(cr);
cairo_paint(cr);
releaseCairoContext(cr, false, extents);
+2 -3
View File
@@ -214,10 +214,9 @@ void SvpGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rTR, const SalBitmap&
bool SvpGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha)
const SalBitmap& rSourceBitmap, double fAlpha)
{
return m_rCairoCommon.drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha,
return m_rCairoCommon.drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, fAlpha,
getAntiAlias());
}
+1 -1
View File
@@ -218,7 +218,7 @@ struct VCL_DLLPUBLIC CairoCommon
bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha, bool bAntiAlias);
double fAlpha, bool bAntiAlias);
void drawMask(const SalTwoRect& rTR, const SalBitmap& rSalBitmap, Color nMaskColor,
bool bAntiAlias);
+1 -1
View File
@@ -103,7 +103,7 @@ public:
bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha) override;
double fAlpha) override;
bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
sal_uInt8 nTransparency) override;
+1 -1
View File
@@ -132,7 +132,7 @@ public:
bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha) override;
double fAlpha) override;
bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
sal_uInt8 nTransparency) override;
+1 -1
View File
@@ -344,7 +344,7 @@ public:
bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha) override;
double fAlpha) override;
bool drawAlphaRect(tools::Long nX, tools::Long nY, tools::Long nWidth, tools::Long nHeight,
sal_uInt8 nTransparency) override;
+2 -4
View File
@@ -363,7 +363,6 @@ public:
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap,
double fAlpha,
const OutputDevice& rOutDev );
@@ -521,7 +520,6 @@ protected:
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap,
double fAlpha) = 0;
/// Returns true if the drawTransformedBitmap() call is fast, and so it should
@@ -793,9 +791,9 @@ public:
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha) override
double fAlpha) override
{
return GetImpl()->drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha);
return GetImpl()->drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, fAlpha);
}
bool hasFastDrawTransformedBitmap() const override
-1
View File
@@ -185,7 +185,6 @@ public:
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap,
double fAlpha) = 0;
/// Only currently true for SkiaSalGraphicsImpl
+4 -6
View File
@@ -150,7 +150,7 @@ public:
/** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */
virtual bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha) override;
double fAlpha) override;
virtual bool hasFastDrawTransformedBitmap() const override;
@@ -251,12 +251,10 @@ protected:
void setCanvasScalingAndClipping();
void resetCanvasScalingAndClipping();
static void setCanvasClipRegion(SkCanvas* canvas, const vcl::Region& region);
sk_sp<SkImage> mergeCacheBitmaps(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap,
const Size& targetSize);
sk_sp<SkImage> mergeCacheBitmaps(const SkiaSalBitmap& bitmap, const Size& targetSize);
using DirectImage = SkiaHelper::DirectImage;
static OString makeCachedImageKey(const SkiaSalBitmap& bitmap, const SkiaSalBitmap* alphaBitmap,
const Size& targetSize, DirectImage bitmapType,
DirectImage alphaBitmapType);
static OString makeCachedImageKey(const SkiaSalBitmap& bitmap, const Size& targetSize,
DirectImage bitmapType);
// Skia uses floating point coordinates, so when we use integer coordinates, sometimes
// rounding results in off-by-one errors (down), especially when drawing using GPU,
+1 -1
View File
@@ -50,7 +50,7 @@ public:
void* ImplGethDIB() const { return mpDIB; }
HBITMAP ImplGethDDB() const { return mhDDB; }
std::shared_ptr< Gdiplus::Bitmap > ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource = nullptr) const;
std::shared_ptr< Gdiplus::Bitmap > ImplGetGdiPlusBitmap() const;
static void ImplCreateDIB( const Size& rSize, vcl::PixelFormat ePixelFormat, const BitmapPalette& rPal,
void*& rpDIB, sal_Int32 &rnDIBSize );
-1
View File
@@ -126,7 +126,6 @@ public:
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap,
double fAlpha) override;
virtual bool hasFastDrawTransformedBitmap() const override;
+4 -5
View File
@@ -653,12 +653,11 @@ public:
for (int j = 0; j < 8; ++j)
pWriteAccess->SetPixel(j, i, COL_BLACK);
}
BitmapEx aBitmapEx(aBitmap);
basegfx::B2DHomMatrix aMatrix;
// Draw with no transformation, only alpha change.
aMatrix.scale(16, 16);
device->DrawTransformedBitmapEx(aMatrix, aBitmapEx, 0.5);
BitmapEx result(device->GetBitmap(Point(0, 0), Size(16, 16)));
device->DrawTransformedBitmapEx(aMatrix, aBitmap, 0.5);
Bitmap result(device->GetBitmap(Point(0, 0), Size(16, 16)));
CPPUNIT_ASSERT_EQUAL(COL_GRAY, result.GetPixelColor(0, 0));
CPPUNIT_ASSERT_EQUAL(COL_WHITE, result.GetPixelColor(15, 15));
// Draw rotated and move to the bottom-left corner.
@@ -667,7 +666,7 @@ public:
aMatrix.scale(16, 16);
aMatrix.rotate(M_PI / 2);
aMatrix.translate(8, 8);
device->DrawTransformedBitmapEx(aMatrix, aBitmapEx, 0.5);
device->DrawTransformedBitmapEx(aMatrix, aBitmap, 0.5);
result = device->GetBitmap(Point(0, 0), Size(16, 16));
CPPUNIT_ASSERT_EQUAL(COL_WHITE, result.GetPixelColor(0, 0));
CPPUNIT_ASSERT_EQUAL(COL_GRAY, result.GetPixelColor(0, 15));
@@ -1401,7 +1400,7 @@ public:
bitmap.GetSizePixel().Height()); // draw as 10x10
// Draw a blue bitmap to the device. The bug was that there was no alpha, but OutputDevice::DrawTransformBitmapExDirect()
// supplied a fully opaque alpha done with Erase() on the alpha bitmap, and Skia backend didn't handle such alpha correctly.
device->DrawTransformedBitmapEx(matrix, BitmapEx(bitmap));
device->DrawTransformedBitmapEx(matrix, bitmap);
exportDevice(u"tdf136171.png"_ustr, device);
// The whole virtual device content now should be blue.
CPPUNIT_ASSERT_EQUAL(COL_BLUE, device->GetPixel(Point(0, 0)));
+2 -4
View File
@@ -356,7 +356,6 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapEx)
}
}
}
BitmapEx aBitmapEx(aBitmap);
basegfx::B2DHomMatrix aMatrix;
aMatrix.scale(8, 8);
// Rotate 90 degrees clockwise, so the black part goes to the top right.
@@ -365,7 +364,7 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapEx)
aMtf.Record(pVDev.get());
// Draw the rotated bitmap on the vdev.
pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx);
pVDev->DrawTransformedBitmapEx(aMatrix, aBitmap);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMtf.GetActionSize());
MetaAction* pAction = aMtf.GetAction(0);
CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType());
@@ -420,7 +419,6 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapExFlip)
}
}
}
BitmapEx aBitmapEx(aBitmap);
basegfx::B2DHomMatrix aMatrix;
// Negative y scale: bitmap should be upside down, so the black part goes to the bottom left.
aMatrix.scale(8, -8);
@@ -430,7 +428,7 @@ CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawTransformedBitmapExFlip)
aMtf.Record(pVDev.get());
// Draw the scaled and rotated bitmap on the vdev.
pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx);
pVDev->DrawTransformedBitmapEx(aMatrix, aBitmap);
CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMtf.GetActionSize());
MetaAction* pAction = aMtf.GetAction(0);
CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType());
+1 -1
View File
@@ -149,7 +149,7 @@ void SkiaTest::testDrawShaders()
basegfx::B2DHomMatrix matrix;
matrix.scale(10, 10);
matrix.rotate(M_PI / 4);
device->DrawTransformedBitmapEx(matrix, BitmapEx(bitmap, alpha));
device->DrawTransformedBitmapEx(matrix, Bitmap(bitmap, alpha));
//savePNG("/tmp/a3.png", device);
CPPUNIT_ASSERT_EQUAL(resultRed, device->GetPixel(Point(0, 1)));
CPPUNIT_ASSERT_EQUAL(COL_WHITE, device->GetPixel(Point(1, 0)));
+2 -20
View File
@@ -559,19 +559,6 @@ void QtGraphicsBackend::invert(sal_uInt32 /*nPoints*/, const Point* /*pPtAry*/,
{
}
static QImage getAlphaImage(const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap)
{
assert(rSourceBitmap.GetSize() == rAlphaBitmap.GetSize());
assert(rAlphaBitmap.GetBitCount() == 8 || rAlphaBitmap.GetBitCount() == 1);
QImage aAlphaMask = *static_cast<const QtBitmap*>(&rAlphaBitmap)->GetQImage();
const QImage* pBitmap = static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
QImage aImage = pBitmap->convertToFormat(Qt_DefaultFormat32);
aImage.setAlphaChannel(aAlphaMask);
return aImage;
}
void QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSourceBitmap)
{
drawBitmap(rPosAry, rSourceBitmap);
@@ -580,14 +567,9 @@ void QtGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBitm
bool QtGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha)
const SalBitmap& rSourceBitmap, double fAlpha)
{
QImage aImage;
if (!pAlphaBitmap)
aImage = *static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
else
aImage = getAlphaImage(rSourceBitmap, *pAlphaBitmap);
QImage aImage = *static_cast<const QtBitmap*>(&rSourceBitmap)->GetQImage();
const basegfx::B2DVector aXRel = rX - rNull;
const basegfx::B2DVector aYRel = rY - rNull;
+3 -9
View File
@@ -1216,8 +1216,7 @@ void AquaGraphicsBackend::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBi
bool AquaGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSrcBitmap,
const SalBitmap* pAlphaBmp, double fAlpha)
const SalBitmap& rSrcBitmap, double fAlpha)
{
if (!mrShared.checkContext())
return true;
@@ -1226,14 +1225,9 @@ bool AquaGraphicsBackend::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
return false;
// get the Quartz image
CGImageRef xImage = nullptr;
const Size aSize = rSrcBitmap.GetSize();
if (!pAlphaBmp)
xImage = rSrcBitmap.CreateCroppedImage(0, 0, int(aSize.Width()), int(aSize.Height()));
else
xImage
= rSrcBitmap.CreateWithMask(*pAlphaBmp, 0, 0, int(aSize.Width()), int(aSize.Height()));
CGImageRef xImage
= rSrcBitmap.CreateCroppedImage(0, 0, int(aSize.Width()), int(aSize.Height()));
if (!xImage)
return false;
+17 -86
View File
@@ -1532,17 +1532,11 @@ void SkiaSalGraphicsImpl::invert(sal_uInt32 nPoints, const Point* pPointArray, S
// with the given target size. Result will be possibly cached, unless disabled.
// Especially in raster mode scaling and alpha blending may be expensive if done repeatedly.
sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitmap,
const SkiaSalBitmap* alphaBitmap,
const Size& targetSize)
{
if (alphaBitmap)
assert(bitmap.GetSize() == alphaBitmap->GetSize());
if (targetSize.IsEmpty())
return {};
if (alphaBitmap && alphaBitmap->IsFullyOpaqueAsAlpha())
alphaBitmap = nullptr; // the alpha can be ignored
if (bitmap.PreferSkShader() && (!alphaBitmap || alphaBitmap->PreferSkShader()))
if (bitmap.PreferSkShader())
return {};
// If the bitmap has SkImage that matches the required size, try to use it, even
@@ -1551,48 +1545,18 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
// scale, changing GetImageKey() in the process so we'd have to re-cache, and then we'd need
// to scale again in this function.
bool bitmapReady = false;
bool alphaBitmapReady = false;
if (const sk_sp<SkImage>& image = bitmap.GetSkImage(DirectImage::Yes))
{
assert(!bitmap.PreferSkShader());
if (imageSize(image) == targetSize)
bitmapReady = true;
}
// If the image usable and there's no alpha, then it matches exactly what's wanted.
if (bitmapReady && !alphaBitmap)
// If the image usable, then it matches exactly what's wanted.
if (bitmapReady)
return bitmap.GetSkImage(DirectImage::Yes);
if (alphaBitmap)
{
if (!alphaBitmap->GetAlphaSkImage(DirectImage::Yes)
&& alphaBitmap->GetSkImage(DirectImage::Yes)
&& imageSize(alphaBitmap->GetSkImage(DirectImage::Yes)) == targetSize)
{
// There's a usable non-alpha image, try to convert it to alpha.
assert(!alphaBitmap->PreferSkShader());
const_cast<SkiaSalBitmap*>(alphaBitmap)->TryDirectConvertToAlphaNoScaling();
}
if (const sk_sp<SkImage>& image = alphaBitmap->GetAlphaSkImage(DirectImage::Yes))
{
assert(!alphaBitmap->PreferSkShader());
if (imageSize(image) == targetSize)
alphaBitmapReady = true;
}
}
if (bitmapReady && (!alphaBitmap || alphaBitmapReady))
{
// Try to find a cached image based on the already existing images.
OString key = makeCachedImageKey(bitmap, alphaBitmap, targetSize, DirectImage::Yes,
DirectImage::Yes);
if (sk_sp<SkImage> image = findCachedImage(key))
{
assert(imageSize(image) == targetSize);
return image;
}
}
// Probably not much point in caching of just doing a copy.
if (alphaBitmap == nullptr && targetSize == bitmap.GetSize())
if (targetSize == bitmap.GetSize())
return {};
// Image too small to be worth caching if not scaling.
if (targetSize == bitmap.GetSize() && targetSize.Width() < 100 && targetSize.Height() < 100)
@@ -1616,17 +1580,11 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
// that they are the same size, or that one prefers a shader or doesn't exist
// (i.e. avoid two images of different size).
bitmapReady = bitmap.GetSkImage(DirectImage::Yes) != nullptr;
alphaBitmapReady = alphaBitmap && alphaBitmap->GetAlphaSkImage(DirectImage::Yes) != nullptr;
if (bitmapReady && alphaBitmap && !alphaBitmapReady && !alphaBitmap->PreferSkShader())
bitmapReady = false;
if (alphaBitmapReady && !bitmapReady && bitmap.PreferSkShader())
alphaBitmapReady = false;
DirectImage bitmapType = bitmapReady ? DirectImage::Yes : DirectImage::No;
DirectImage alphaBitmapType = alphaBitmapReady ? DirectImage::Yes : DirectImage::No;
// Try to find a cached result, this time after possible delayed scaling.
OString key = makeCachedImageKey(bitmap, alphaBitmap, targetSize, bitmapType, alphaBitmapType);
OString key = makeCachedImageKey(bitmap, targetSize, bitmapType);
if (sk_sp<SkImage> image = findCachedImage(key))
{
assert(imageSize(image) == targetSize);
@@ -1666,14 +1624,11 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
Size sourceSize;
if (bitmapReady)
sourceSize = imageSize(bitmap.GetSkImage(DirectImage::Yes));
else if (alphaBitmapReady)
sourceSize = imageSize(alphaBitmap->GetAlphaSkImage(DirectImage::Yes));
else
sourceSize = bitmap.GetSize();
// Generate a new result and cache it.
sk_sp<SkSurface> tmpSurface
= createSkSurface(targetSize, alphaBitmap ? kPremul_SkAlphaType : bitmap.alphaType());
sk_sp<SkSurface> tmpSurface = createSkSurface(targetSize, bitmap.alphaType());
if (!tmpSurface)
return nullptr;
SkCanvas* canvas = tmpSurface->getCanvas();
@@ -1690,12 +1645,10 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
if (!isUnitTestRunning()) // unittests want exact pixel values
samplingOptions = makeSamplingOptions(matrix, 1);
}
if (alphaBitmap != nullptr)
if (bitmap.alphaType() == kPremul_SkAlphaType)
{
canvas->clear(SK_ColorTRANSPARENT);
paint.setShader(SkShaders::Blend(
SkBlendMode::kDstIn, bitmap.GetSkShader(samplingOptions, bitmapType),
alphaBitmap->GetAlphaSkShader(samplingOptions, alphaBitmapType)));
paint.setShader(bitmap.GetSkShader(samplingOptions, bitmapType));
canvas->drawPaint(paint);
}
else if (bitmap.PreferSkShader())
@@ -1715,15 +1668,11 @@ sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
return image;
}
OString SkiaSalGraphicsImpl::makeCachedImageKey(const SkiaSalBitmap& bitmap,
const SkiaSalBitmap* alphaBitmap,
const Size& targetSize, DirectImage bitmapType,
DirectImage alphaBitmapType)
OString SkiaSalGraphicsImpl::makeCachedImageKey(const SkiaSalBitmap& bitmap, const Size& targetSize,
DirectImage bitmapType)
{
OString key = OString::number(targetSize.Width()) + "x" + OString::number(targetSize.Height())
+ "_" + bitmap.GetImageKey(bitmapType);
if (alphaBitmap)
key += "_" + alphaBitmap->GetAlphaImageKey(alphaBitmapType);
return key;
}
@@ -1745,7 +1694,7 @@ void SkiaSalGraphicsImpl::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBi
imagePosAry.mnSrcHeight = imagePosAry.mnDestHeight;
imageSize = Size(imagePosAry.mnSrcWidth, imagePosAry.mnSrcHeight);
}
sk_sp<SkImage> image = mergeCacheBitmaps(rSkiaSourceBitmap, nullptr, imageSize * mScaling);
sk_sp<SkImage> image = mergeCacheBitmaps(rSkiaSourceBitmap, imageSize * mScaling);
if (image)
drawImage(imagePosAry, image, mScaling);
else
@@ -1769,7 +1718,7 @@ void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBit
imagePosAry.mnSrcHeight = imagePosAry.mnDestHeight;
imageSize = Size(imagePosAry.mnSrcWidth, imagePosAry.mnSrcHeight);
}
sk_sp<SkImage> image = mergeCacheBitmaps(bitmap, nullptr, imageSize * mScaling);
sk_sp<SkImage> image = mergeCacheBitmaps(bitmap, imageSize * mScaling);
if (image)
drawImage(imagePosAry, image, mScaling, blendMode);
else if (bitmap.PreferSkShader())
@@ -1880,17 +1829,11 @@ bool matrixNeedsHighQuality(const SkMatrix& matrix) { return ::matrixNeedsHighQu
bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha)
const SalBitmap& rSourceBitmap, double fAlpha)
{
assert(dynamic_cast<const SkiaSalBitmap*>(&rSourceBitmap));
assert(!pAlphaBitmap || dynamic_cast<const SkiaSalBitmap*>(pAlphaBitmap));
const SkiaSalBitmap& rSkiaBitmap = static_cast<const SkiaSalBitmap&>(rSourceBitmap);
const SkiaSalBitmap* pSkiaAlphaBitmap = static_cast<const SkiaSalBitmap*>(pAlphaBitmap);
if (pSkiaAlphaBitmap && pSkiaAlphaBitmap->IsFullyOpaqueAsAlpha())
pSkiaAlphaBitmap = nullptr; // the alpha can be ignored
// Setup the image transformation,
// using the rNull, rX, rY points as destinations for the (0,0), (Width,0), (0,Height) source points.
@@ -1909,8 +1852,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
// Pass size * mScaling to mergeCacheBitmaps() so that it prepares the size that will be needed
// after the mScaling-scaling matrix, but otherwise calculate everything else using the VCL coordinates.
Size imageSize(round(aXRel.getLength()), round(aYRel.getLength()));
sk_sp<SkImage> imageToDraw
= mergeCacheBitmaps(rSkiaBitmap, pSkiaAlphaBitmap, imageSize * mScaling);
sk_sp<SkImage> imageToDraw = mergeCacheBitmaps(rSkiaBitmap, imageSize * mScaling);
if (imageToDraw)
{
SkMatrix matrix;
@@ -1968,19 +1910,7 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
SkSamplingOptions samplingOptions;
if (matrixNeedsHighQuality(matrix) || (mScaling != 1 && !isUnitTestRunning()))
samplingOptions = makeSamplingOptions(matrix, mScaling);
if (pSkiaAlphaBitmap)
{
SkPaint paint = makeBitmapPaint();
paint.setShader(SkShaders::Blend(SkBlendMode::kDstIn,
rSkiaBitmap.GetSkShader(samplingOptions),
pSkiaAlphaBitmap->GetAlphaSkShader(samplingOptions)));
if (fAlpha != 1.0)
paint.setShader(
SkShaders::Blend(SkBlendMode::kDstIn, paint.refShader(),
SkShaders::Color(SkColorSetARGB(fAlpha * 255, 0, 0, 0))));
canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint);
}
else if (rSkiaBitmap.PreferSkShader() || fAlpha != 1.0)
if (rSkiaBitmap.PreferSkShader() || fAlpha != 1.0)
{
SkPaint paint = makeBitmapPaint();
paint.setShader(rSkiaBitmap.GetSkShader(samplingOptions));
@@ -1993,7 +1923,8 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
else
{
SkPaint paint = makeBitmapPaint();
canvas->drawImage(rSkiaBitmap.GetSkImage(), 0, 0, samplingOptions, &paint);
paint.setShader(rSkiaBitmap.GetSkShader(samplingOptions));
canvas->drawRect(SkRect::MakeWH(aSize.Width(), aSize.Height()), paint);
}
}
postDraw();
+189
View File
@@ -19,6 +19,7 @@
#include <config_features.h>
#include <rtl/math.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <tools/helpers.hxx>
@@ -2719,4 +2720,192 @@ tools::Polygon Bitmap::GetContour( bool bContourEdgeDetect,
return aRetPoly;
}
static Bitmap impTransformBitmap(
const Bitmap& rSource,
const Size& rDestinationSize,
const basegfx::B2DHomMatrix& rTransform,
bool bSmooth)
{
Bitmap aDestination(rDestinationSize, rSource.getPixelFormat());
BitmapScopedWriteAccess xWrite(aDestination);
if(xWrite)
{
BitmapScopedReadAccess xRead(rSource);
if (xRead)
{
const Size aDestinationSizePixel(aDestination.GetSizePixel());
// tdf#157795 set color to black outside of bitmap bounds
// Due to commit 81994cb2b8b32453a92bcb011830fcb884f22ff3,
// transparent areas are now black instead of white.
// tdf#160831 only set outside color to black for alpha masks
// The outside color still needs to be white for the content
// so only apply the fix for tdf#157795 to the alpha mask.
const BitmapColor aOutside(ColorAlpha, 0xff, 0xff, 0xff, 0x00);
for(tools::Long y(0); y < aDestinationSizePixel.getHeight(); y++)
{
Scanline pScanline = xWrite->GetScanline( y );
for(tools::Long x(0); x < aDestinationSizePixel.getWidth(); x++)
{
const basegfx::B2DPoint aSourceCoor(rTransform * basegfx::B2DPoint(x, y));
if(bSmooth)
{
xWrite->SetPixelOnData(
pScanline,
x,
xRead->GetInterpolatedColorWithFallback(
aSourceCoor.getY(),
aSourceCoor.getX(),
aOutside));
}
else
{
// this version does the correct <= 0.0 checks, so no need
// to do the static_cast< sal_Int32 > self and make an error
xWrite->SetPixelOnData(
pScanline,
x,
xRead->GetColorWithFallback(
aSourceCoor.getY(),
aSourceCoor.getX(),
aOutside));
}
}
}
}
}
xWrite.reset();
rSource.AdaptBitCount(aDestination);
return aDestination;
}
/// Decides if rTransformation needs smoothing or not (e.g. 180 deg rotation doesn't need it).
static bool implTransformNeedsSmooth(const basegfx::B2DHomMatrix& rTransformation)
{
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
rTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
if (aScale != basegfx::B2DVector(1, 1))
{
return true;
}
fRotate = fmod( fRotate, 2 * M_PI );
if (fRotate < 0)
{
fRotate += 2 * M_PI;
}
if (!rtl::math::approxEqual(fRotate, 0)
&& !rtl::math::approxEqual(fRotate, M_PI_2)
&& !rtl::math::approxEqual(fRotate, M_PI)
&& !rtl::math::approxEqual(fRotate, 3 * M_PI_2))
{
return true;
}
if (!rtl::math::approxEqual(fShearX, 0))
{
return true;
}
return false;
}
Bitmap Bitmap::TransformBitmap(
double fWidth,
double fHeight,
const basegfx::B2DHomMatrix& rTransformation) const
{
if(fWidth <= 1 || fHeight <= 1)
return Bitmap();
// force destination to 24 bit, we want to smooth output
const Size aDestinationSize(basegfx::fround<tools::Long>(fWidth), basegfx::fround<tools::Long>(fHeight));
bool bSmooth = implTransformNeedsSmooth(rTransformation);
const Bitmap aDestination(impTransformBitmap(*this, aDestinationSize, rTransformation, bSmooth));
return aDestination;
}
Bitmap Bitmap::getTransformed(
const basegfx::B2DHomMatrix& rTransformation,
const basegfx::B2DRange& rVisibleRange,
double fMaximumArea) const
{
if (IsEmpty())
return Bitmap();
const sal_uInt32 nSourceWidth(GetSizePixel().Width());
const sal_uInt32 nSourceHeight(GetSizePixel().Height());
if (!nSourceWidth || !nSourceHeight)
return Bitmap();
// Get aOutlineRange
basegfx::B2DRange aOutlineRange(0.0, 0.0, 1.0, 1.0);
aOutlineRange.transform(rTransformation);
// create visible range from it by moving from relative to absolute
basegfx::B2DRange aVisibleRange(rVisibleRange);
aVisibleRange.transform(
basegfx::utils::createScaleTranslateB2DHomMatrix(
aOutlineRange.getRange(),
aOutlineRange.getMinimum()));
// get target size (which is visible range's size)
double fWidth(aVisibleRange.getWidth());
double fHeight(aVisibleRange.getHeight());
if (fWidth < 1.0 || fHeight < 1.0)
return Bitmap();
// test if discrete size (pixel) maybe too big and limit it
const double fArea(fWidth * fHeight);
const bool bNeedToReduce(basegfx::fTools::more(fArea, fMaximumArea));
double fReduceFactor(1.0);
if(bNeedToReduce)
{
fReduceFactor = sqrt(fMaximumArea / fArea);
fWidth *= fReduceFactor;
fHeight *= fReduceFactor;
}
// Build complete transform from source pixels to target pixels.
// Start by scaling from source pixel size to unit coordinates
basegfx::B2DHomMatrix aTransform(
basegfx::utils::createScaleB2DHomMatrix(
1.0 / nSourceWidth,
1.0 / nSourceHeight));
// multiply with given transform which leads from unit coordinates inside
// aOutlineRange
aTransform = rTransformation * aTransform;
// subtract top-left of absolute VisibleRange
aTransform.translate(
-aVisibleRange.getMinX(),
-aVisibleRange.getMinY());
// scale to target pixels (if needed)
if(bNeedToReduce)
{
aTransform.scale(fReduceFactor, fReduceFactor);
}
// invert to get transformation from target pixel coordinates to source pixels
aTransform.invert();
// create bitmap using source, destination and linear back-transformation
return TransformBitmap(fWidth, fHeight, aTransform);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+1 -1
View File
@@ -171,7 +171,7 @@ void Printer::ImplPrintTransparent( const Bitmap& rBmp,
bool Printer::DrawTransformBitmapExDirect(
const basegfx::B2DHomMatrix& /*aFullTransform*/,
const BitmapEx& /*rBitmapEx*/,
const Bitmap& /*rBitmap*/,
double /*fAlpha*/)
{
// printers can't draw bitmaps directly
+2 -4
View File
@@ -90,7 +90,6 @@ bool SalGraphics::drawTransformedBitmap(
const basegfx::B2DPoint& /* rX */,
const basegfx::B2DPoint& /* rY */,
const SalBitmap& /* rSourceBitmap */,
const SalBitmap* /* pAlphaBitmap */,
double /* fAlpha */)
{
// here direct support for transformed bitmaps can be implemented
@@ -841,7 +840,6 @@ bool SalGraphics::DrawTransformedBitmap(
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap,
double fAlpha,
const OutputDevice& rOutDev)
{
@@ -859,11 +857,11 @@ bool SalGraphics::DrawTransformedBitmap(
basegfx::B2DPoint aX = aTranslateToMirroredBounds * rX;
basegfx::B2DPoint aY = aTranslateToMirroredBounds * rY;
return drawTransformedBitmap(aNull, aX, aY, rSourceBitmap, pAlphaBitmap, fAlpha);
return drawTransformedBitmap(aNull, aX, aY, rSourceBitmap, fAlpha);
}
}
return drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha);
return drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, fAlpha);
}
bool SalGraphics::HasFastDrawTransformedBitmap() const
+22 -39
View File
@@ -186,7 +186,7 @@ void OutputDevice::DrawDeviceBitmapEx( const Point& rDestPt, const Size& rDestSi
bool OutputDevice::DrawTransformBitmapExDirect(
const basegfx::B2DHomMatrix& aFullTransform,
const BitmapEx& rBitmapEx,
const Bitmap& rBitmap,
double fAlpha)
{
assert(!is_double_buffered_window());
@@ -195,22 +195,13 @@ bool OutputDevice::DrawTransformBitmapExDirect(
const basegfx::B2DPoint aNull(aFullTransform * basegfx::B2DPoint(0.0, 0.0));
const basegfx::B2DPoint aTopX(aFullTransform * basegfx::B2DPoint(1.0, 0.0));
const basegfx::B2DPoint aTopY(aFullTransform * basegfx::B2DPoint(0.0, 1.0));
SalBitmap* pSalSrcBmp = rBitmapEx.GetBitmap().ImplGetSalBitmap().get();
AlphaMask aAlphaBitmap;
if(rBitmapEx.IsAlpha())
{
aAlphaBitmap = rBitmapEx.GetAlphaMask();
}
SalBitmap* pSalAlphaBmp = aAlphaBitmap.GetBitmap().ImplGetSalBitmap().get();
SalBitmap* pSalSrcBmp = rBitmap.ImplGetSalBitmap().get();
return mpGraphics->DrawTransformedBitmap(
aNull,
aTopX,
aTopY,
*pSalSrcBmp,
pSalAlphaBmp,
fAlpha,
*this);
};
@@ -326,21 +317,13 @@ void OutputDevice::DrawTransformedBitmapEx(
const basegfx::B2DHomMatrix& rTransformation,
const Bitmap& rBitmap,
double fAlpha)
{
DrawTransformedBitmapEx(rTransformation, BitmapEx(rBitmap), fAlpha);
}
void OutputDevice::DrawTransformedBitmapEx(
const basegfx::B2DHomMatrix& rTransformation,
const BitmapEx& rBitmapEx,
double fAlpha)
{
assert(!is_double_buffered_window());
if( ImplIsRecordLayout() )
return;
if(rBitmapEx.IsEmpty())
if(rBitmap.IsEmpty())
return;
if( fAlpha == 0.0 )
@@ -378,7 +361,7 @@ void OutputDevice::DrawTransformedBitmapEx(
: nullptr);
#endif
BitmapEx bitmapEx = rBitmapEx;
Bitmap bitmap = rBitmap;
const bool bInvert(RasterOp::Invert == meRasterOp);
const bool bBitmapChangedColor(mnDrawMode & (DrawModeFlags::BlackBitmap | DrawModeFlags::WhiteBitmap | DrawModeFlags::GrayBitmap ));
@@ -393,7 +376,7 @@ void OutputDevice::DrawTransformedBitmapEx(
{
if(bTryDirectPaint)
{
if(DrawTransformBitmapExDirect(aFullTransform, bitmapEx, fAlpha))
if(DrawTransformBitmapExDirect(aFullTransform, bitmap, fAlpha))
{
// we are done
return;
@@ -401,15 +384,15 @@ void OutputDevice::DrawTransformedBitmapEx(
}
// Apply the alpha manually.
sal_uInt8 nTransparency( static_cast<sal_uInt8>( ::basegfx::fround( 255.0*(1.0 - fAlpha) + .5) ) );
AlphaMask aAlpha( bitmapEx.GetSizePixel(), &nTransparency );
if( bitmapEx.IsAlpha())
aAlpha.BlendWith( bitmapEx.GetAlphaMask());
bitmapEx = BitmapEx( bitmapEx.GetBitmap(), aAlpha );
AlphaMask aAlpha( bitmap.GetSizePixel(), &nTransparency );
if( bitmap.HasAlpha())
aAlpha.BlendWith( bitmap.CreateAlphaMask());
bitmap = Bitmap( bitmap.CreateColorBitmap(), aAlpha );
}
// If the backend's implementation is known to not need any optimizations here, pass to it directly.
// With most backends it's more performant to try to simplify to DrawBitmapEx() first.
if(bTryDirectPaint && mpGraphics->HasFastDrawTransformedBitmap() && DrawTransformBitmapExDirect(aFullTransform, bitmapEx))
if(bTryDirectPaint && mpGraphics->HasFastDrawTransformedBitmap() && DrawTransformBitmapExDirect(aFullTransform, bitmap))
return;
// decompose matrix to check rotation and shear
@@ -437,7 +420,7 @@ void OutputDevice::DrawTransformedBitmapEx(
EnableMapMode(false);
}
DrawBitmapEx(aDestPt, aDestSize, Bitmap(bitmapEx));
DrawBitmapEx(aDestPt, aDestSize, bitmap);
if (!bMetafile && comphelper::LibreOfficeKit::isActive() && GetMapMode().GetMapUnit() != MapUnit::MapPixel)
{
EnableMapMode();
@@ -447,7 +430,7 @@ void OutputDevice::DrawTransformedBitmapEx(
}
// Try the backend's implementation before resorting to the slower fallback here.
if(bTryDirectPaint && DrawTransformBitmapExDirect(aFullTransform, bitmapEx))
if(bTryDirectPaint && DrawTransformBitmapExDirect(aFullTransform, bitmap))
return;
// take the fallback when no rotate and shear, but mirror (else we would have done this above)
@@ -461,7 +444,7 @@ void OutputDevice::DrawTransformedBitmapEx(
basegfx::fround<tools::Long>(aScale.getX() + aTranslate.getX()) - aDestPt.X(),
basegfx::fround<tools::Long>(aScale.getY() + aTranslate.getY()) - aDestPt.Y());
DrawBitmapEx(aDestPt, aDestSize, Bitmap(bitmapEx));
DrawBitmapEx(aDestPt, aDestSize, bitmap);
return;
}
@@ -476,8 +459,8 @@ void OutputDevice::DrawTransformedBitmapEx(
// by using a fixed minimum (allow at least, but no need to utilize) for good smoothing and an area
// dependent of original size for good quality when e.g. rotated/sheared. Still, limit to a maximum
// to avoid crashes/resource problems (ca. 1500x3000 here)
const Size& rOriginalSizePixel(bitmapEx.GetSizePixel());
const double fOrigArea(rOriginalSizePixel.Width() * rOriginalSizePixel.Height() * 0.5);
const Size aOriginalSizePixel(bitmap.GetSizePixel());
const double fOrigArea(aOriginalSizePixel.Width() * aOriginalSizePixel.Height() * 0.5);
const double fOrigAreaScaled(fOrigArea * 1.44);
double fMaximumArea(std::clamp(fOrigAreaScaled, 1000000.0, 4500000.0));
@@ -490,20 +473,20 @@ void OutputDevice::DrawTransformedBitmapEx(
if(aVisibleRange.isEmpty())
return;
BitmapEx aTransformed(bitmapEx);
Bitmap aTransformed(bitmap);
// #122923# when the result needs an alpha channel due to being rotated or sheared
// and thus uncovering areas, add these channels so that the own transformer (used
// in getTransformed) also creates a transformed alpha channel
if(!aTransformed.IsAlpha() && (bSheared || bRotated))
if(!aTransformed.HasAlpha() && (bSheared || bRotated))
{
// parts will be uncovered, extend aTransformed with a mask bitmap
const Bitmap aContent(aTransformed.GetBitmap());
const Bitmap aContent(aTransformed.CreateColorBitmap());
AlphaMask aMaskBmp(aContent.GetSizePixel());
aMaskBmp.Erase(0);
aTransformed = BitmapEx(aContent, aMaskBmp);
aTransformed = Bitmap(aContent, aMaskBmp);
}
basegfx::B2DVector aFullScale, aFullTranslate;
@@ -511,9 +494,9 @@ void OutputDevice::DrawTransformedBitmapEx(
aFullTransform.decompose(aFullScale, aFullTranslate, fFullRotate, fFullShearX);
double fSourceRatio = 1.0;
if (rOriginalSizePixel.getHeight() != 0)
if (aOriginalSizePixel.getHeight() != 0)
{
fSourceRatio = rOriginalSizePixel.getWidth() / rOriginalSizePixel.getHeight();
fSourceRatio = aOriginalSizePixel.getWidth() / aOriginalSizePixel.getHeight();
}
double fTargetRatio = 1.0;
if (aFullScale.getY() != 0)
@@ -558,7 +541,7 @@ void OutputDevice::DrawTransformedBitmapEx(
basegfx::fround<tools::Long>(aVisibleRange.getMaxX()) - aDestPt.X(),
basegfx::fround<tools::Long>(aVisibleRange.getMaxY()) - aDestPt.Y());
DrawBitmapEx(aDestPt, aDestSize, Bitmap(aTransformed));
DrawBitmapEx(aDestPt, aDestSize, aTransformed);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
@@ -204,10 +204,9 @@ bool X11CairoSalGraphicsImpl::drawPolyPolygonBezier(sal_uInt32, const sal_uInt32
bool X11CairoSalGraphicsImpl::drawTransformedBitmap(const basegfx::B2DPoint& rNull,
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha)
const SalBitmap& rSourceBitmap, double fAlpha)
{
return mrCairoCommon.drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, pAlphaBitmap, fAlpha,
return mrCairoCommon.drawTransformedBitmap(rNull, rX, rY, rSourceBitmap, fAlpha,
getAntiAlias());
}
@@ -156,7 +156,7 @@ public:
/** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */
bool drawTransformedBitmap(const basegfx::B2DPoint& rNull, const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY, const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap, double fAlpha) override;
double fAlpha) override;
bool supportsOperation(OutDevSupportType eType) const override;
};
+1 -4
View File
@@ -2342,18 +2342,15 @@ bool WinSalGraphicsImpl::drawTransformedBitmap(
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap,
double fAlpha)
{
assert(dynamic_cast<const WinSalBitmap*>(&rSourceBitmap));
assert(!pAlphaBitmap || dynamic_cast<const WinSalBitmap*>(pAlphaBitmap));
if( fAlpha != 1.0 )
return false;
const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSourceBitmap);
const WinSalBitmap* pSalAlpha = static_cast< const WinSalBitmap* >(pAlphaBitmap);
std::shared_ptr< Gdiplus::Bitmap > aARGB(rSalBitmap.ImplGetGdiPlusBitmap(pSalAlpha));
std::shared_ptr< Gdiplus::Bitmap > aARGB(rSalBitmap.ImplGetGdiPlusBitmap());
if(!aARGB)
return false;
-1
View File
@@ -192,7 +192,6 @@ public:
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap,
double fAlpha) override;
virtual bool hasFastDrawTransformedBitmap() const override;
+5 -39
View File
@@ -74,14 +74,11 @@ class SystemDependentData_GdiPlusBitmap : public basegfx::SystemDependentData
{
private:
std::shared_ptr<Gdiplus::Bitmap> mpGdiPlusBitmap;
const WinSalBitmap* mpAssociatedAlpha;
public:
SystemDependentData_GdiPlusBitmap(
const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap,
const WinSalBitmap* pAssociatedAlpha);
const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap);
const WinSalBitmap* getAssociatedAlpha() const { return mpAssociatedAlpha; }
const std::shared_ptr<Gdiplus::Bitmap>& getGdiPlusBitmap() const { return mpGdiPlusBitmap; }
virtual sal_Int64 estimateUsageInBytes() const override;
@@ -90,13 +87,11 @@ public:
}
SystemDependentData_GdiPlusBitmap::SystemDependentData_GdiPlusBitmap(
const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap,
const WinSalBitmap* pAssociatedAlpha)
const std::shared_ptr<Gdiplus::Bitmap>& rGdiPlusBitmap)
: basegfx::SystemDependentData(
Application::GetSystemDependentDataManager(),
basegfx::SDD_Type::SDDType_GdiPlusBitmap),
mpGdiPlusBitmap(rGdiPlusBitmap),
mpAssociatedAlpha(pAssociatedAlpha)
mpGdiPlusBitmap(rGdiPlusBitmap)
{
}
@@ -151,7 +146,7 @@ sal_Int64 SystemDependentData_GdiPlusBitmap::estimateUsageInBytes() const
return nRetval;
}
std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinSalBitmap* pAlphaSource) const
std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap() const
{
std::shared_ptr< Gdiplus::Bitmap > aRetval;
@@ -159,20 +154,6 @@ std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinS
std::shared_ptr<SystemDependentData_GdiPlusBitmap> pSystemDependentData_GdiPlusBitmap(
getSystemDependentData<SystemDependentData_GdiPlusBitmap>(basegfx::SDD_Type::SDDType_GdiPlusBitmap));
if(pSystemDependentData_GdiPlusBitmap)
{
// check data validity
if(pSystemDependentData_GdiPlusBitmap->getAssociatedAlpha() != pAlphaSource
|| 0 == maSize.Width()
|| 0 == maSize.Height())
{
// #122350# if associated alpha with which the GDIPlus was constructed has changed
// it is necessary to remove it from buffer, reset reference to it and reconstruct
// data invalid, forget
pSystemDependentData_GdiPlusBitmap.reset();
}
}
if(pSystemDependentData_GdiPlusBitmap)
{
// use from buffer
@@ -180,24 +161,9 @@ std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinS
}
else if(!maSize.IsEmpty())
{
// create and set data
const WinSalBitmap* pAssociatedAlpha(nullptr);
if(pAlphaSource)
{
aRetval = const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap(*pAlphaSource);
pAssociatedAlpha = pAlphaSource;
}
else
{
aRetval = const_cast< WinSalBitmap* >(this)->ImplCreateGdiPlusBitmap();
pAssociatedAlpha = nullptr;
}
// add to buffering mechanism
addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>(
aRetval,
pAssociatedAlpha);
aRetval);
}
return aRetval;
+1 -2
View File
@@ -79,11 +79,10 @@ bool WinSalGraphics::drawTransformedBitmap(
const basegfx::B2DPoint& rX,
const basegfx::B2DPoint& rY,
const SalBitmap& rSourceBitmap,
const SalBitmap* pAlphaBitmap,
double fAlpha)
{
return mpImpl->drawTransformedBitmap(rNull, rX, rY,
rSourceBitmap, pAlphaBitmap, fAlpha);
rSourceBitmap, fAlpha);
}
bool WinSalGraphics::hasFastDrawTransformedBitmap() const