summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2019-10-10 19:03:53 +0200
committerMiklos Vajna <vmiklos@collabora.com>2019-10-10 20:24:26 +0200
commit68549e00d5e23aa22bc974a8151d93cd948444b3 (patch)
tree62ea4e15d0f5da26d2d46c4603403fcbf74f0237
parent7d9932ade30464abf297f2e3c3690cca68d6bf71 (diff)
vcl, BitmapEx transformed draw: special-case simple rotations
In case OutputDevice::DrawTransformedBitmapEx() has to do both shearing and rotation, then recording to a metafile is unchanged. But if we need to do rotation, then it's not necessary to go via transformations. This has the additional benefit that 90/180/270 degree rotations don't introduce an off-by-one error, where the first row and col of the transformed bitmap is transparent. (At the moment it's not clear what introduces the unwanted translation, but at least the direct Rotate() way resolves the visible end-user problem, see the test.) Change-Id: Ie1adbdb2221b086c19cc66f69308b6b7256fe29a Reviewed-on: https://gerrit.libreoffice.org/80626 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--vcl/qa/cppunit/outdev.cxx37
-rw-r--r--vcl/source/outdev/bitmap.cxx22
2 files changed, 55 insertions, 4 deletions
diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx
index 53f2424f5dbe..e6a6b8f1c5f6 100644
--- a/vcl/qa/cppunit/outdev.cxx
+++ b/vcl/qa/cppunit/outdev.cxx
@@ -15,6 +15,7 @@
#include <vcl/bitmapaccess.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/metaact.hxx>
+#include <bitmapwriteaccess.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
@@ -142,9 +143,22 @@ void VclOutdevTest::testDrawTransformedBitmapEx()
// Also create a 16x16 bitmap.
ScopedVclPtrInstance<VirtualDevice> pVDev;
Bitmap aBitmap(Size(16, 16), 24);
+ {
+ // Fill the top left quarter with black.
+ BitmapScopedWriteAccess pWriteAccess(aBitmap);
+ pWriteAccess->Erase(COL_WHITE);
+ for (int i = 0; i < 8; ++i)
+ {
+ for (int j = 0; j < 8; ++j)
+ {
+ pWriteAccess->SetPixel(j, i, COL_BLACK);
+ }
+ }
+ }
BitmapEx aBitmapEx(aBitmap);
basegfx::B2DHomMatrix aMatrix;
aMatrix.scale(8, 8);
+ // Rotate 90 degrees clockwise, so the black part goes to the top right.
aMatrix.rotate(M_PI / 2);
GDIMetaFile aMtf;
aMtf.Record(pVDev.get());
@@ -162,6 +176,29 @@ void VclOutdevTest::testDrawTransformedBitmapEx()
// - Actual : 8x8
// I.e. the bitmap before scaling was already scaled down, just because it was rotated.
CPPUNIT_ASSERT_EQUAL(Size(16, 16), aTransformedSize);
+
+ aBitmap = rBitmapEx.GetBitmap();
+ Bitmap::ScopedReadAccess pAccess(aBitmap);
+ for (int i = 0; i < 16; ++i)
+ {
+ for (int j = 0; j < 16; ++j)
+ {
+ BitmapColor aColor = pAccess->GetPixel(j, i);
+ Color aExpected = i >= 8 && j < 8 ? COL_BLACK : COL_WHITE;
+ std::stringstream ss;
+ ss << "Color is expected to be ";
+ ss << ((aExpected == COL_WHITE) ? "white" : "black");
+ ss << ", is " << aColor.AsRGBHexString();
+ ss << " (row " << j << ", col " << i << ")";
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: c[00000000]
+ // - Actual : c[ffffff00]
+ // - Color is expected to be black, is ffffff (row 0, col 8)
+ // i.e. the top right quarter of the image was not fully black, there was a white first
+ // row.
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str(), aExpected, Color(aColor));
+ }
+ }
}
CPPUNIT_TEST_SUITE_REGISTRATION(VclOutdevTest);
diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index 2cbdb2fdb2b3..93c1f76aef1f 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -1285,10 +1285,24 @@ void OutputDevice::DrawTransformedBitmapEx(
aFullTransform *= aTransform;
}
- aTransformed = aTransformed.getTransformed(
- aFullTransform,
- aVisibleRange,
- fMaximumArea);
+ if (bSheared)
+ {
+ aTransformed = aTransformed.getTransformed(
+ aFullTransform,
+ aVisibleRange,
+ fMaximumArea);
+ }
+ else
+ {
+ // Just rotation, can do that directly.
+ fFullRotate = fmod(fFullRotate * -1, F_2PI);
+ if (fFullRotate < 0)
+ {
+ fFullRotate += F_2PI;
+ }
+ long nAngle10 = basegfx::fround(basegfx::rad2deg(fFullRotate) * 10);
+ aTransformed.Rotate(nAngle10, COL_TRANSPARENT);
+ }
basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
// get logic object target range