[Libreoffice-commits] core.git: Branch 'distro/vector/vector-5.4' - 3 commits - vcl/CppunitTest_vcl_outdev.mk vcl/qa vcl/source
Miklos Vajna (via logerrit)
logerrit at kemper.freedesktop.org
Fri Oct 11 10:34:10 UTC 2019
vcl/CppunitTest_vcl_outdev.mk | 1
vcl/qa/cppunit/outdev.cxx | 69 ++++++++++++++++++++++++++++++++++++++++++
vcl/source/gdi/bitmapex.cxx | 33 ++++++++++++++++++++
vcl/source/outdev/bitmap.cxx | 39 ++++++++++++++++++++---
4 files changed, 136 insertions(+), 6 deletions(-)
New commits:
commit 3a6a4ff5971d32ebd47e94368f398003ee31576f
Author: Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Thu Oct 10 19:03:53 2019 +0200
Commit: Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Oct 11 12:33:15 2019 +0200
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.)
(cherry picked from commit 68549e00d5e23aa22bc974a8151d93cd948444b3)
Conflicts:
vcl/source/outdev/bitmap.cxx
Change-Id: Ie1adbdb2221b086c19cc66f69308b6b7256fe29a
diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx
index b91eef31e4fa..244496857ce5 100644
--- a/vcl/qa/cppunit/outdev.cxx
+++ b/vcl/qa/cppunit/outdev.cxx
@@ -90,9 +90,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.
+ Bitmap::ScopedWriteAccess pWriteAccess(aBitmap);
+ pWriteAccess->Erase(COL_WHITE);
+ for (int i = 0; i < 8; ++i)
+ {
+ for (int j = 0; j < 8; ++j)
+ {
+ pWriteAccess->SetPixel(j, i, Color(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());
@@ -110,6 +123,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 " << Color(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 2b274b32f8dc..5257d20997f8 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -1296,11 +1296,25 @@ void OutputDevice::DrawTransformedBitmapEx(
aFullTransform *= aTransform;
}
- aTransformed = aTransformed.getTransformed(
- aFullTransform,
- aVisibleRange,
- fMaximumArea,
- bDoSmoothAtAll);
+ if (bSheared)
+ {
+ aTransformed = aTransformed.getTransformed(
+ aFullTransform,
+ aVisibleRange,
+ fMaximumArea,
+ bDoSmoothAtAll);
+ }
+ 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
commit eca544b84624b188c8fbaa5d6501f6b796da127d
Author: Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Thu Oct 10 09:49:29 2019 +0200
Commit: Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Oct 11 10:06:24 2019 +0200
vcl: only smooth bitmap transform when needed
If you have a very small bitmap and you rotate it by 90 degrees, then
smoothing is not needed, but the result will be blurry. So in case
scaling / shear doesn't need it and we do 90/180/270 rotation, avoid
smoothing.
(cherry picked from commit 55b4d5ea9e1a42edf71d2eef6028830983dbc11c)
Conflicts:
vcl/qa/cppunit/BitmapExTest.cxx
vcl/source/gdi/bitmapex.cxx
Change-Id: I4b8fad4b0b70516d35eaecfa70a707e6e8362d18
diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx
index fc75f9e5b120..5378b10dd322 100644
--- a/vcl/source/gdi/bitmapex.cxx
+++ b/vcl/source/gdi/bitmapex.cxx
@@ -872,6 +872,38 @@ namespace
return aDestination;
}
+
+ /// Decides if rTransformation needs smoothing or not (e.g. 180 deg rotation doesn't need it).
+ 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, F_2PI );
+ if (fRotate < 0)
+ {
+ fRotate += F_2PI;
+ }
+ if (!rtl::math::approxEqual(fRotate, 0)
+ && !rtl::math::approxEqual(fRotate, F_PI2)
+ && !rtl::math::approxEqual(fRotate, F_PI)
+ && !rtl::math::approxEqual(fRotate, 3 * F_PI2))
+ {
+ return true;
+ }
+
+ if (!rtl::math::approxEqual(fShearX, 0))
+ {
+ return true;
+ }
+
+ return false;
+ }
} // end of anonymous namespace
BitmapEx BitmapEx::TransformBitmapEx(
@@ -885,6 +917,7 @@ BitmapEx BitmapEx::TransformBitmapEx(
// force destination to 24 bit, we want to smooth output
const Size aDestinationSize(basegfx::fround(fWidth), basegfx::fround(fHeight));
+ bSmooth = implTransformNeedsSmooth(rTransformation);
const Bitmap aDestination(impTransformBitmap(GetBitmap(), aDestinationSize, rTransformation, bSmooth));
// create mask
commit 1109d0a36651b1523a1a310a8497ab115b857fb8
Author: Miklos Vajna <vmiklos at collabora.com>
AuthorDate: Tue Oct 8 09:16:27 2019 +0200
Commit: Miklos Vajna <vmiklos at collabora.com>
CommitDate: Fri Oct 11 09:55:25 2019 +0200
vcl: avoid downscale && upscale in DrawTransformedBitmapEx()
If we rotate a bitmap and put it to a metafile, we'll create a
MetaBmpExScaleAction. But just because we need to store a transformed
bitmap for rotation purposes, it doesn't mean we also need to scale it.
This helps in case later the metafile is upscaled and the downscaled
bitmap would look blurry.
(cherry picked from commit dd4a67084853a030bf4b9f1f85d728620e0604a5)
Conflicts:
vcl/qa/cppunit/outdev.cxx
Change-Id: I7d64a88af460e80dffde8052186888eddbb440fe
diff --git a/vcl/CppunitTest_vcl_outdev.mk b/vcl/CppunitTest_vcl_outdev.mk
index 183432fccfe6..f15d2e26d17d 100644
--- a/vcl/CppunitTest_vcl_outdev.mk
+++ b/vcl/CppunitTest_vcl_outdev.mk
@@ -21,6 +21,7 @@ $(eval $(call gb_CppunitTest_add_exception_objects,vcl_outdev, \
$(eval $(call gb_CppunitTest_use_externals,vcl_outdev,boost_headers))
$(eval $(call gb_CppunitTest_use_libraries,vcl_outdev, \
+ basegfx \
comphelper \
cppu \
cppuhelper \
diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx
index 1e6508789574..b91eef31e4fa 100644
--- a/vcl/qa/cppunit/outdev.cxx
+++ b/vcl/qa/cppunit/outdev.cxx
@@ -14,9 +14,12 @@
#include <vcl/salbtype.hxx>
#include <vcl/bitmapaccess.hxx>
#include <vcl/wrkwin.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
#include <tools/stream.hxx>
#include <vcl/pngwrite.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
class VclOutdevTest : public test::BootstrapFixture
{
@@ -24,9 +27,11 @@ public:
VclOutdevTest() : BootstrapFixture(true, false) {}
void testVirtualDevice();
+ void testDrawTransformedBitmapEx();
CPPUNIT_TEST_SUITE(VclOutdevTest);
CPPUNIT_TEST(testVirtualDevice);
+ CPPUNIT_TEST(testDrawTransformedBitmapEx);
CPPUNIT_TEST_SUITE_END();
};
@@ -79,6 +84,34 @@ void VclOutdevTest::testVirtualDevice()
#endif
}
+void VclOutdevTest::testDrawTransformedBitmapEx()
+{
+ // Create a virtual device, and connect a metafile to it.
+ // Also create a 16x16 bitmap.
+ ScopedVclPtrInstance<VirtualDevice> pVDev;
+ Bitmap aBitmap(Size(16, 16), 24);
+ BitmapEx aBitmapEx(aBitmap);
+ basegfx::B2DHomMatrix aMatrix;
+ aMatrix.scale(8, 8);
+ aMatrix.rotate(M_PI / 2);
+ GDIMetaFile aMtf;
+ aMtf.Record(pVDev.get());
+
+ // Draw the rotated bitmap on the vdev.
+ pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx);
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aMtf.GetActionSize());
+ MetaAction* pAction = aMtf.GetAction(0);
+ CPPUNIT_ASSERT_EQUAL(MetaActionType::BMPEXSCALE, pAction->GetType());
+ auto pBitmapAction = static_cast<MetaBmpExScaleAction*>(pAction);
+ const BitmapEx& rBitmapEx = pBitmapAction->GetBitmapEx();
+ Size aTransformedSize = rBitmapEx.GetSizePixel();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 16x16
+ // - Actual : 8x8
+ // I.e. the bitmap before scaling was already scaled down, just because it was rotated.
+ CPPUNIT_ASSERT_EQUAL(Size(16, 16), aTransformedSize);
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(VclOutdevTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx
index 4ae3c84d37ce..2b274b32f8dc 100644
--- a/vcl/source/outdev/bitmap.cxx
+++ b/vcl/source/outdev/bitmap.cxx
@@ -1220,7 +1220,7 @@ void OutputDevice::DrawTransformedBitmapEx(
const bool bInvert(RasterOp::Invert == meRasterOp);
const bool bBitmapChangedColor(mnDrawMode & (DrawModeFlags::BlackBitmap | DrawModeFlags::WhiteBitmap | DrawModeFlags::GrayBitmap | DrawModeFlags::GhostedBitmap));
bool bDone(false);
- const basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation);
+ basegfx::B2DHomMatrix aFullTransform(GetViewTransformation() * rTransformation);
const bool bTryDirectPaint(!bInvert && !bBitmapChangedColor && !bMetafile );
if(!bForceToOwnTransformer && bTryDirectPaint)
@@ -1283,6 +1283,19 @@ void OutputDevice::DrawTransformedBitmapEx(
aTransformed = BitmapEx(aContent, aMaskBmp);
}
+ // Remove scaling from aFulltransform: we transform due to shearing or rotation, scaling
+ // will happen according to aDestSize.
+ basegfx::B2DVector aFullScale, aFullTranslate;
+ double fFullRotate, fFullShearX;
+ aFullTransform.decompose(aFullScale, aFullTranslate, fFullRotate, fFullShearX);
+ if (aFullScale.getX() != 0 && aFullScale.getY() != 0)
+ {
+ basegfx::B2DHomMatrix aTransform = basegfx::tools::createScaleB2DHomMatrix(
+ rOriginalSizePixel.getWidth() / aFullScale.getX(),
+ rOriginalSizePixel.getHeight() / aFullScale.getY());
+ aFullTransform *= aTransform;
+ }
+
aTransformed = aTransformed.getTransformed(
aFullTransform,
aVisibleRange,
More information about the Libreoffice-commits
mailing list