/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testVirtualDevice)
{ // TODO: This unit test is not executed for macOS unless bitmap scaling is implemented #ifndef MACOSX
ScopedVclPtrInstance<VirtualDevice> pVDev;
pVDev->SetOutputSizePixel(Size(32, 32));
pVDev->SetBackground(Wallpaper(COL_WHITE));
CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(0, 0))); #if !defined _WIN32 //TODO: various failures on Windows tinderboxes
CPPUNIT_ASSERT_EQUAL(COL_BLUE, pVDev->GetPixel(Point(1, 2)));
CPPUNIT_ASSERT_EQUAL(COL_RED, pVDev->GetPixel(Point(31, 30))); #endif
CPPUNIT_ASSERT_EQUAL(COL_WHITE, pVDev->GetPixel(Point(30, 31)));
// Gotcha: y and x swap for BitmapReadAccess: deep joy.
BitmapScopedReadAccess pAcc(aBmp);
CPPUNIT_ASSERT_EQUAL(COL_WHITE, static_cast<Color>(pAcc->GetPixel(0, 0))); #if !defined _WIN32 //TODO: various failures on Windows tinderboxes
CPPUNIT_ASSERT_EQUAL(COL_BLUE, static_cast<Color>(pAcc->GetPixel(2, 1)));
CPPUNIT_ASSERT_EQUAL(COL_RED, static_cast<Color>(pAcc->GetPixel(30, 31))); #endif
CPPUNIT_ASSERT_EQUAL(COL_WHITE, static_cast<Color>(pAcc->GetPixel(31, 30)));
// test to see if the color is black
Bitmap aBlackBmp(pVDev->GetBitmap(Point(0, 0), Size(10, 10)));
BitmapScopedReadAccess pReadAccess(aBlackBmp); const BitmapColor aColor = pReadAccess->GetColor(0, 0);
CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_BLACK), aColor);
}
// test to see if the color is white
Bitmap aWhiteBmp(pVDev->GetBitmap(Point(0, 0), Size(10, 10)));
BitmapScopedReadAccess pReadAccess(aWhiteBmp); const BitmapColor aColor = pReadAccess->GetColor(0, 0);
CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_WHITE), aColor);
}
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDrawGrayBitmap)
{ // draw a red 1x1 bitmap
Bitmap aBmp(Size(1, 1), vcl::PixelFormat::N24_BPP);
aBmp.Erase(COL_RED);
// check to ensure that the bitmap is red
{
BitmapScopedReadAccess pReadAccess(aBmp); const BitmapColor aColor = pReadAccess->GetColor(0, 0);
CPPUNIT_ASSERT_EQUAL(BitmapColor(COL_RED), aColor);
}
// When drawing that with a transform:
BitmapEx aBitmapEx(aBitmap);
pVDev->DrawTransformedBitmapEx(aMatrix, aBitmapEx);
// Then make sure the bitmap recorded in the metafile doesn't get a scaled down width:
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 greater or equal than: 100 // - Actual : 80 // i.e. an unwanted scaling down lead to blurry presentation output.
CPPUNIT_ASSERT_GREATEREQUAL(static_cast<tools::Long>(100), aTransformedSize.getWidth());
}
CPPUNIT_TEST_FIXTURE(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), vcl::PixelFormat::N24_BPP);
{ // 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());
// 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);
aBitmap = rBitmapEx.GetBitmap();
BitmapScopedReadAccess 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_FIXTURE(VclOutdevTest, testDrawTransformedBitmapExFlip)
{ // Create a virtual device, and connect a metafile to it. // Also create a 16x16 bitmap.
ScopedVclPtrInstance<VirtualDevice> pVDev;
Bitmap aBitmap(Size(16, 16), vcl::PixelFormat::N24_BPP);
{ // 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; // Negative y scale: bitmap should be upside down, so the black part goes to the bottom left.
aMatrix.scale(8, -8); // Rotate 90 degrees clockwise, so the black part goes back to the top left.
aMatrix.rotate(M_PI / 2);
GDIMetaFile aMtf;
aMtf.Record(pVDev.get());
// Draw the scaled and 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();
aBitmap = rBitmapEx.GetBitmap();
BitmapScopedReadAccess pAccess(aBitmap); int nX = 8 * 0.25; int nY = 8 * 0.25;
BitmapColor aColor = pAccess->GetPixel(nY, nX);
std::stringstream ss;
ss << "Color is expected to be black, is " << aColor.AsRGBHexString();
ss << " (row " << nY << ", col " << nX << ")"; // 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 2, col 2) // i.e. the top left quarter of the image was not black, due to a missing flip.
CPPUNIT_ASSERT_EQUAL_MESSAGE(ss.str(), COL_BLACK, Color(aColor));
}
// Without the accompanying fix in place, this test would have failed, because the RTL status // from pWindow was not propagated to pBuffer.
CPPUNIT_ASSERT(pBuffer->IsRTLEnabled());
}
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testRTLGuard)
{
ScopedVclPtrInstance<vcl::Window> pWindow(nullptr, WB_APP | WB_STDWORK);
pWindow->EnableRTL();
pWindow->RequestDoubleBuffering(true);
ImplFrameData* pFrameData = pWindow->ImplGetWindowImpl()->mpFrameData;
vcl::PaintBufferGuard aGuard(pFrameData, pWindow); // Without the accompanying fix in place, this test would have failed, because the RTL status // from pWindow was not propagated to aGuard.
CPPUNIT_ASSERT(aGuard.GetRenderContext()->IsRTLEnabled());
}
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDefaultFillColor)
{ // Create a virtual device, and connect a metafile to it.
ScopedVclPtrInstance<VirtualDevice> pVDev;
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testTransparentFillColor)
{ // Create a virtual device, and connect a metafile to it.
ScopedVclPtrInstance<VirtualDevice> pVDev;
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testFillColor)
{ // Create a virtual device, and connect a metafile to it.
ScopedVclPtrInstance<VirtualDevice> pVDev;
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testDefaultLineColor)
{ // Create a virtual device, and connect a metafile to it.
ScopedVclPtrInstance<VirtualDevice> pVDev;
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testTransparentLineColor)
{ // Create a virtual device, and connect a metafile to it.
ScopedVclPtrInstance<VirtualDevice> pVDev;
CPPUNIT_TEST_FIXTURE(VclOutdevTest, testLineColor)
{ // Create a virtual device, and connect a metafile to it.
ScopedVclPtrInstance<VirtualDevice> pVDev;
// Use Dejavu fonts, they are shipped with LO, so they should be ~always available. // Use Sans variant for simpler glyph shapes (no serifs).
vcl::Font font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 36));
font.SetColor(COL_BLACK);
font.SetFillColor(COL_RED);
GDIMetaFile aMtf;
aMtf.Record(pVDev.get());
pVDev->SetFont(font); bool bSameFont(font == pVDev->GetFont());
CPPUNIT_ASSERT_MESSAGE("Font is not the same", bSameFont);
// four actions: // 1. Font action // 2. Text alignment action // 3. Text fill color action // 4. As not COL_TRANSPARENT (means use system font color), font color action
size_t nActionsExpected = 4;
CPPUNIT_ASSERT_EQUAL(nActionsExpected, aMtf.GetActionSize());
MetaAction* pAction = aMtf.GetAction(0);
CPPUNIT_ASSERT_EQUAL(MetaActionType::FONT, pAction->GetType()); auto pFontAction = static_cast<MetaFontAction*>(pAction); bool bSameMetaFont = (font == pFontAction->GetFont());
CPPUNIT_ASSERT_MESSAGE("Metafile font is not the same", bSameMetaFont);
// Use Dejavu fonts, they are shipped with LO, so they should be ~always available. // Use Sans variant for simpler glyph shapes (no serifs).
vcl::Font font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 36));
font.SetColor(COL_TRANSPARENT);
GDIMetaFile aMtf;
aMtf.Record(pVDev.get());
pVDev->SetFont(font);
// three actions as it sets the colour to the default system color (and doesn't add a text color action): // 1. Font action // 2. Text alignment action // 3. Text fill color action
size_t nActionsExpected = 3;
CPPUNIT_ASSERT_EQUAL(nActionsExpected, aMtf.GetActionSize());
}
// this actually triggers Erase()
pVDev->SetOutputSizePixel(Size(10, 10));
pVDev->Erase();
MetaAction* pAction = aMtf.GetAction(INITIAL_SETUP_ACTION_COUNT);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color action (start)", MetaActionType::LINECOLOR,
pAction->GetType());
pAction = aMtf.GetAction(INITIAL_SETUP_ACTION_COUNT + 1);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action (start)", MetaActionType::FILLCOLOR,
pAction->GetType());
pAction = aMtf.GetAction(INITIAL_SETUP_ACTION_COUNT + 2);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a rect action", MetaActionType::RECT, pAction->GetType());
pAction = aMtf.GetAction(INITIAL_SETUP_ACTION_COUNT + 3);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action (end)", MetaActionType::FILLCOLOR,
pAction->GetType());
pAction = aMtf.GetAction(INITIAL_SETUP_ACTION_COUNT + 4);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color action (end)", MetaActionType::LINECOLOR,
pAction->GetType());
}
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color", MetaActionType::LINECOLOR, pAction->GetType());
// Row 1
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 1, rect 1",
MetaActionType::FILLCOLOR, pAction->GetType());
MetaFillColorAction* pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 1, rect 1", COL_WHITE,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 1, rect 2",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 1, rect 1", COL_BLACK,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 1, rect 3",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 1, rect 1", COL_WHITE,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 1, rect 4",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 1, rect 4", COL_BLACK,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 1, rect 5",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 1, rect 5", COL_WHITE,
pFillColorAction->GetColor());
// Row 2
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 2, rect 1",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 2, rect 1", COL_BLACK,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 2, rect 2",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 2, rect 1", COL_WHITE,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 2, rect 3",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 2, rect 1", COL_BLACK,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 2, rect 4",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 2, rect 4", COL_WHITE,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 2, rect 5",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 2, rect 5", COL_BLACK,
pFillColorAction->GetColor());
// Row 3
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 3, rect 1",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 3, rect 1", COL_WHITE,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 3, rect 2",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 3, rect 1", COL_BLACK,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 3, rect 3",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 3, rect 1", COL_WHITE,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 3, rect 4",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 3, rect 4", COL_BLACK,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 3, rect 5",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 3, rect 5", COL_WHITE,
pFillColorAction->GetColor());
// Row 4
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 4, rect 1",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 4, rect 1", COL_BLACK,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 4, rect 2",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 4, rect 1", COL_WHITE,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 4, rect 3",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 4, rect 1", COL_BLACK,
pFillColorAction->GetColor());
nIndex++;
pAction = aMtf.GetAction(nIndex);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action for row 4, rect 4",
MetaActionType::FILLCOLOR, pAction->GetType());
pFillColorAction = dynamic_cast<MetaFillColorAction*>(pAction);
CPPUNIT_ASSERT_EQUAL_MESSAGE("Fill color wrong for row 4, rect 4", COL_WHITE,
pFillColorAction->GetColor());
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.