1
0
Fork 0
libreoffice/vcl/qa/cppunit/text.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

1062 lines
41 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- 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/.
*/
#include <osl/file.hxx>
#include <osl/process.h>
#include <test/bootstrapfixture.hxx>
#include <sal/log.hxx>
#include <tools/stream.hxx>
#include <vcl/BitmapReadAccess.hxx>
#include <comphelper/errcode.hxx>
#include <vcl/graphicfilter.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>
#include <ImplLayoutArgs.hxx>
#include <TextLayoutCache.hxx>
#include <salgdi.hxx>
class VclTextTest : public test::BootstrapFixture
{
// if enabled - check the result images with:
// "xdg-open ./workdir/CppunitTest/vcl_text_test.test.core/"
static constexpr const bool mbExportBitmap = false;
public:
void exportDevice(const OUString& filename, const VclPtr<VirtualDevice>& device)
{
if (mbExportBitmap)
{
BitmapEx aBitmapEx(device->GetBitmapEx(Point(0, 0), device->GetOutputSizePixel()));
OUString cwd;
CPPUNIT_ASSERT_EQUAL(osl_Process_E_None, osl_getProcessWorkingDir(&cwd.pData));
OUString url;
CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None,
osl::FileBase::getAbsoluteFileURL(cwd, filename, url));
SvFileStream aStream(url, StreamMode::WRITE | StreamMode::TRUNC);
CPPUNIT_ASSERT_EQUAL(
ERRCODE_NONE, GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream));
}
}
VclTextTest()
: BootstrapFixture(true, false)
{
}
};
static std::ostream& operator<<(std::ostream& s, const ImplLayoutRuns::Run& rRun)
{
return s << "{" << rRun.m_nMinRunPos << ", " << rRun.m_nEndRunPos << ", " << rRun.m_bRTL << "}";
}
// Avoid issues when colorized antialiasing generates slightly tinted rather than truly black
// pixels:
static bool isBlack(Color col)
{
return col.GetRed() < 25 && col.GetGreen() < 25 && col.GetBlue() < 25;
}
// Return pixel width of the base of the given character located above
// the starting position.
// In other words, go up in y direction until a black pixel is found,
// then return the horizontal width of the area of those pixels.
// For 'L' this gives the width of the base of the character.
static tools::Long getCharacterBaseWidth(VirtualDevice* device, const Point& start)
{
Bitmap bitmap = device->GetBitmap(Point(), device->GetOutputSizePixel());
BitmapScopedReadAccess access(bitmap);
tools::Long y = start.Y();
while (y >= 0 && !isBlack(access->GetColor(y, start.X())))
--y;
if (y < 0)
return -1;
tools::Long xmin = start.X();
while (xmin >= 0 && access->GetColor(y, xmin) != COL_WHITE)
--xmin;
tools::Long xmax = start.X();
while (xmax < bitmap.GetSizePixel().Width() && access->GetColor(y, xmax) != COL_WHITE)
++xmax;
return xmax - xmin + 1;
}
// Similar to above but this time from the top, for U+30E8 (it's straight at the top, not at the bottom).
static tools::Long getCharacterTopWidth(VirtualDevice* device, const Point& start)
{
Bitmap bitmap = device->GetBitmap(Point(), device->GetOutputSizePixel());
BitmapScopedReadAccess access(bitmap);
tools::Long y = start.Y();
while (y < bitmap.GetSizePixel().Height() && !isBlack(access->GetColor(y, start.X())))
++y;
if (y >= bitmap.GetSizePixel().Height())
return -1;
tools::Long xmin = start.X();
while (xmin >= 0 && access->GetColor(y, xmin) != COL_WHITE)
--xmin;
tools::Long xmax = start.X();
while (xmax < bitmap.GetSizePixel().Width() && access->GetColor(y, xmax) != COL_WHITE)
++xmax;
return xmax - xmin + 1;
}
// Similar to above, but this time return the pixel height of the left-most
// line of the character, going right from the starting point.
// For 'L' this gives the height of the left line.
static tools::Long getCharacterLeftSideHeight(VirtualDevice* device, const Point& start)
{
Bitmap bitmap = device->GetBitmap(Point(), device->GetOutputSizePixel());
BitmapScopedReadAccess access(bitmap);
tools::Long x = start.X();
while (x < bitmap.GetSizePixel().Width() && !isBlack(access->GetColor(start.Y(), x)))
++x;
if (x >= bitmap.GetSizePixel().Width())
return -1;
tools::Long ymin = start.Y();
while (ymin >= 0 && access->GetColor(ymin, x) != COL_WHITE)
--ymin;
tools::Long ymax = start.Y();
while (ymax < bitmap.GetSizePixel().Width() && access->GetColor(ymax, x) != COL_WHITE)
++ymax;
return ymax - ymin + 1;
}
// Test rendering of the 'L' character (chosen because L is a simple shape).
// Check things like using a double font size doubling the size of the character, correct rotation, etc.
// IMPORTANT: If you modify this, check also the VclCjkTextTest::testVerticalText().
CPPUNIT_TEST_FIXTURE(VclTextTest, testSimpleText)
{
OUString text(u"L"_ustr);
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(100, 100));
device->SetBackground(Wallpaper(COL_WHITE));
// Disable AA, to make all pixels be black or white.
device->SetAntialiasing(AntialiasingFlags::DisableText);
// Bail out on all backends that do not work (or I didn't test). Opt-out rather than opt-in
// to make sure new backends fail initially.
if (device->GetGraphics()->getRenderBackendName() == "qt"
|| device->GetGraphics()->getRenderBackendName() == "qtsvp"
|| device->GetGraphics()->getRenderBackendName() == "gtk3svp"
|| device->GetGraphics()->getRenderBackendName() == "aqua"
|| device->GetGraphics()->getRenderBackendName() == "gen"
|| device->GetGraphics()->getRenderBackendName() == "genpsp")
return;
// 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));
device->Erase();
device->SetFont(font);
device->DrawText(Point(10, 10), text);
exportDevice(u"simple-text-36.png"_ustr, device);
// Height of 'L' with font 36 size should be roughly 28 pixels.
// Use the 'doubles' variant of the test, since that one allows
// a delta, and allow several pixels of delta to account
// for different rendering methods and whatnot.
tools::Long height36 = getCharacterLeftSideHeight(device, Point(0, 30));
CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(28), height36, 4);
tools::Long width36 = getCharacterBaseWidth(device, Point(20, 99));
CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(19), width36, 4);
font.SetOrientation(2700_deg10);
device->Erase();
device->SetFont(font);
device->DrawText(Point(90, 10), text);
exportDevice(u"simple-text-36-270deg.png"_ustr, device);
// Width and height here should be swapped, again allowing for some imprecisions.
tools::Long height36Rotated = getCharacterLeftSideHeight(device, Point(0, 20));
CPPUNIT_ASSERT_DOUBLES_EQUAL(width36, height36Rotated, 2);
tools::Long width36Rotated = getCharacterTopWidth(device, Point(70, 0));
CPPUNIT_ASSERT_DOUBLES_EQUAL(height36, width36Rotated, 2);
font = vcl::Font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 72));
device->Erase();
device->SetFont(font);
device->DrawText(Point(10, 10), text);
exportDevice(u"simple-text-72.png"_ustr, device);
// Font size is doubled, so pixel sizes should also roughly double.
tools::Long height72 = getCharacterLeftSideHeight(device, Point(0, 30));
CPPUNIT_ASSERT_DOUBLES_EQUAL(height36 * 2, height72, 4);
tools::Long width72 = getCharacterBaseWidth(device, Point(20, 99));
CPPUNIT_ASSERT_DOUBLES_EQUAL(width36 * 2, width72, 5);
font.SetOrientation(2700_deg10);
device->Erase();
device->SetFont(font);
device->DrawText(Point(90, 10), text);
exportDevice(u"simple-text-72-270deg.png"_ustr, device);
tools::Long height72Rotated = getCharacterLeftSideHeight(device, Point(0, 35));
CPPUNIT_ASSERT_DOUBLES_EQUAL(width72, height72Rotated, 2);
tools::Long width72Rotated = getCharacterTopWidth(device, Point(50, 0));
CPPUNIT_ASSERT_DOUBLES_EQUAL(height72, width72Rotated, 2);
// Test width scaled to 200%.
font = vcl::Font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(72, 36));
#ifdef _WIN32
// TODO: What is the proper way to draw 200%-wide text? This is needed on Windows
// but it breaks Linux.
font.SetAverageFontWidth(2 * font.GetOrCalculateAverageFontWidth());
#endif
device->Erase();
device->SetFont(font);
device->DrawText(Point(10, 10), text);
exportDevice(u"simple-text-36-200pct.png"_ustr, device);
tools::Long height36pct200 = getCharacterLeftSideHeight(device, Point(0, 30));
CPPUNIT_ASSERT_DOUBLES_EQUAL(height36, height36pct200, 2);
tools::Long width36pct200 = getCharacterBaseWidth(device, Point(20, 99));
CPPUNIT_ASSERT_DOUBLES_EQUAL(width36 * 2, width36pct200, 5);
// Test width scaled to 50%.
font = vcl::Font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(18, 36));
#ifdef _WIN32
font.SetAverageFontWidth(0.5 * font.GetOrCalculateAverageFontWidth());
#endif
device->Erase();
device->SetFont(font);
device->DrawText(Point(10, 10), text);
exportDevice(u"simple-text-36-50pct.png"_ustr, device);
tools::Long height36pct50 = getCharacterLeftSideHeight(device, Point(0, 40));
CPPUNIT_ASSERT_DOUBLES_EQUAL(height36, height36pct50, 2);
tools::Long width36pct50 = getCharacterBaseWidth(device, Point(15, 99));
CPPUNIT_ASSERT_DOUBLES_EQUAL(width36 / 2, width36pct50, 2);
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testSimpleTextFontSpecificKerning)
{
OUString aAV(u"AV"_ustr);
vcl::Font aFont(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 2048));
ScopedVclPtrInstance<VirtualDevice> pOutDev;
pOutDev->SetFont(aFont);
// absolute character widths AKA text array.
tools::Long nRefTextWidth = 2671;
KernArray aRefCharWidths{ 1270, 2671 };
KernArray aCharWidths;
tools::Long nTextWidth
= basegfx::fround<tools::Long>(pOutDev->GetTextArray(aAV, &aCharWidths).nWidth);
CPPUNIT_ASSERT_EQUAL(aRefCharWidths[0], aCharWidths[0]);
CPPUNIT_ASSERT_EQUAL(aRefCharWidths[1], aCharWidths[1]);
// this sporadically returns 75 or 74 on some of the windows tinderboxes eg. tb73
CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth);
CPPUNIT_ASSERT_EQUAL(nTextWidth, tools::Long(aCharWidths.back()));
// text advance width and line height
CPPUNIT_ASSERT_EQUAL(nRefTextWidth, pOutDev->GetTextWidth(aAV));
CPPUNIT_ASSERT_EQUAL(tools::Long(2384), pOutDev->GetTextHeight());
// exact bounding rectangle, not essentially the same as text width/height
tools::Rectangle aBoundRect;
pOutDev->GetTextBoundRect(aBoundRect, aAV);
CPPUNIT_ASSERT_EQUAL(tools::Long(16), aBoundRect.Left());
CPPUNIT_ASSERT_EQUAL(tools::Long(408), aBoundRect.Top());
CPPUNIT_ASSERT_EQUAL(tools::Long(2639), aBoundRect.GetWidth());
CPPUNIT_ASSERT_EQUAL(tools::Long(1493), aBoundRect.getOpenHeight());
// normal orientation
tools::Rectangle aInput;
tools::Rectangle aRect = pOutDev->GetTextRect(aInput, aAV);
// now rotate 270 degrees
vcl::Font aRotated(aFont);
aRotated.SetOrientation(2700_deg10);
pOutDev->SetFont(aRotated);
tools::Rectangle aRectRot = pOutDev->GetTextRect(aInput, aAV);
// Check that we did do the rotation...
CPPUNIT_ASSERT_EQUAL(aRectRot.GetWidth(), aRect.GetHeight());
CPPUNIT_ASSERT_EQUAL(aRectRot.GetHeight(), aRect.GetWidth());
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testSimpleTextNoKerning)
{
OUString aAV(u"AV"_ustr);
vcl::Font aFont(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 2048));
aFont.SetKerning(FontKerning::NONE);
ScopedVclPtrInstance<VirtualDevice> pOutDev;
pOutDev->SetFont(aFont);
// absolute character widths AKA text array.
tools::Long nRefTextWidth = 2802;
KernArray aRefCharWidths{ 1401, 2802 };
KernArray aCharWidths;
tools::Long nTextWidth
= basegfx::fround<tools::Long>(pOutDev->GetTextArray(aAV, &aCharWidths).nWidth);
CPPUNIT_ASSERT_EQUAL(aRefCharWidths[0], aCharWidths[0]);
CPPUNIT_ASSERT_EQUAL(aRefCharWidths[1], aCharWidths[1]);
// this sporadically returns 75 or 74 on some of the windows tinderboxes eg. tb73
CPPUNIT_ASSERT_EQUAL(nRefTextWidth, nTextWidth);
CPPUNIT_ASSERT_EQUAL(nTextWidth, tools::Long(aCharWidths.back()));
// text advance width and line height
CPPUNIT_ASSERT_EQUAL(nRefTextWidth, pOutDev->GetTextWidth(aAV));
CPPUNIT_ASSERT_EQUAL(tools::Long(2384), pOutDev->GetTextHeight());
// exact bounding rectangle, not essentially the same as text width/height
tools::Rectangle aBoundRect;
pOutDev->GetTextBoundRect(aBoundRect, aAV);
CPPUNIT_ASSERT_EQUAL(tools::Long(16), aBoundRect.Left());
CPPUNIT_ASSERT_EQUAL(tools::Long(408), aBoundRect.Top());
CPPUNIT_ASSERT_EQUAL(tools::Long(2770), aBoundRect.GetWidth());
CPPUNIT_ASSERT_EQUAL(tools::Long(1493), aBoundRect.getOpenHeight());
// normal orientation
tools::Rectangle aInput;
tools::Rectangle aRect = pOutDev->GetTextRect(aInput, aAV);
// now rotate 270 degrees
vcl::Font aRotated(aFont);
aRotated.SetOrientation(2700_deg10);
pOutDev->SetFont(aRotated);
tools::Rectangle aRectRot = pOutDev->GetTextRect(aInput, aAV);
// Check that we did do the rotation...
CPPUNIT_ASSERT_EQUAL(aRectRot.GetWidth(), aRect.GetHeight());
CPPUNIT_ASSERT_EQUAL(aRectRot.GetHeight(), aRect.GetWidth());
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testTextLayoutCache)
{
OUString sTestString = u"The quick brown fox\n jumped over the lazy dogالعاشر"_ustr;
vcl::text::TextLayoutCache cache(sTestString.getStr(), sTestString.getLength());
vcl::text::Run run1 = cache.runs[0];
vcl::text::Run run2 = cache.runs[1];
bool bCorrectRuns = (cache.runs.size() == 2);
CPPUNIT_ASSERT_MESSAGE("Wrong number of runs", bCorrectRuns);
CPPUNIT_ASSERT_EQUAL(USCRIPT_LATIN, run1.nCode);
CPPUNIT_ASSERT_EQUAL(0, run1.nStart);
CPPUNIT_ASSERT_EQUAL(45, run1.nEnd);
CPPUNIT_ASSERT_EQUAL(USCRIPT_ARABIC, run2.nCode);
CPPUNIT_ASSERT_EQUAL(45, run2.nStart);
CPPUNIT_ASSERT_EQUAL(51, run2.nEnd);
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_AddPos)
{
ImplLayoutRuns aRuns;
aRuns.AddPos(1, false);
aRuns.AddPos(2, false);
aRuns.AddPos(3, false);
aRuns.AddPos(4, true); // add RTL marker glyph
aRuns.AddPos(5, false);
aRuns.AddPos(6, true); // add RTL marker glyph
aRuns.AddPos(7, false);
int nCharPos(0);
bool bRightToLeftMarker(false);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(1, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(2, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(3, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(4, nCharPos);
CPPUNIT_ASSERT(bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(5, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(6, nCharPos);
CPPUNIT_ASSERT(bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(7, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
// no next position, we are running off the end
CPPUNIT_ASSERT(!aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
aRuns.ResetPos();
int nMinRunPos, nEndRunPos;
bool bRightToLeft(false);
CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
CPPUNIT_ASSERT_EQUAL(1, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(4, nEndRunPos);
CPPUNIT_ASSERT(!bRightToLeft);
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
CPPUNIT_ASSERT_EQUAL(4, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(5, nEndRunPos);
CPPUNIT_ASSERT(bRightToLeft);
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
CPPUNIT_ASSERT_EQUAL(5, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(6, nEndRunPos);
CPPUNIT_ASSERT(!bRightToLeft);
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
CPPUNIT_ASSERT_EQUAL(6, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(7, nEndRunPos);
CPPUNIT_ASSERT(bRightToLeft);
// test clear
aRuns.Clear();
CPPUNIT_ASSERT(aRuns.IsEmpty());
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_AddRuns)
{
ImplLayoutRuns aRuns;
aRuns.AddRun(1, 4, false);
aRuns.AddRun(5, 4, true);
aRuns.AddRun(5, 6, false);
aRuns.AddRun(6, 7, true);
int nCharPos(0);
bool bRightToLeftMarker(false);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(1, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(2, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(3, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(4, nCharPos);
CPPUNIT_ASSERT(bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(5, nCharPos);
CPPUNIT_ASSERT(!bRightToLeftMarker);
CPPUNIT_ASSERT(aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
CPPUNIT_ASSERT_EQUAL(6, nCharPos);
CPPUNIT_ASSERT(bRightToLeftMarker);
// no next position, we are running off the end
CPPUNIT_ASSERT(!aRuns.GetNextPos(&nCharPos, &bRightToLeftMarker));
aRuns.ResetPos();
int nMinRunPos, nEndRunPos;
bool bRightToLeft(false);
CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
CPPUNIT_ASSERT_EQUAL(1, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(4, nEndRunPos);
CPPUNIT_ASSERT(!bRightToLeft);
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
CPPUNIT_ASSERT_EQUAL(4, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(5, nEndRunPos);
CPPUNIT_ASSERT(bRightToLeft);
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
CPPUNIT_ASSERT_EQUAL(5, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(6, nEndRunPos);
CPPUNIT_ASSERT(!bRightToLeft);
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
CPPUNIT_ASSERT_EQUAL(6, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(7, nEndRunPos);
CPPUNIT_ASSERT(bRightToLeft);
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_PosIsInRun)
{
ImplLayoutRuns aRuns;
aRuns.AddRun(1, 4, false);
aRuns.AddRun(4, 5, true);
aRuns.AddRun(5, 6, false);
aRuns.AddRun(6, 7, true);
CPPUNIT_ASSERT(aRuns.PosIsInRun(1));
CPPUNIT_ASSERT(aRuns.PosIsInRun(2));
CPPUNIT_ASSERT(aRuns.PosIsInRun(3));
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.PosIsInRun(4));
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.PosIsInRun(5));
aRuns.NextRun();
CPPUNIT_ASSERT(aRuns.PosIsInRun(6));
CPPUNIT_ASSERT(!aRuns.PosIsInRun(7));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_PosIsInAnyRun)
{
ImplLayoutRuns aRuns;
aRuns.AddRun(1, 4, false);
aRuns.AddRun(4, 5, true);
aRuns.AddRun(5, 6, false);
aRuns.AddRun(6, 7, true);
CPPUNIT_ASSERT(aRuns.PosIsInAnyRun(1));
CPPUNIT_ASSERT(!aRuns.PosIsInAnyRun(7));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_Normalize)
{
ImplLayoutRuns aRuns;
aRuns.AddRun(8, 10, true);
aRuns.AddRun(5, 8, false);
aRuns.AddRun(2, 5, false);
aRuns.AddRun(1, 3, false);
aRuns.AddRun(14, 15, false);
CPPUNIT_ASSERT_EQUAL(size_t(5), aRuns.size());
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(8, 10, true), aRuns.at(0));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(5, 8, false), aRuns.at(1));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(2, 5, false), aRuns.at(2));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(1, 3, false), aRuns.at(3));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(14, 15, false), aRuns.at(4));
aRuns.Normalize();
CPPUNIT_ASSERT_EQUAL(size_t(2), aRuns.size());
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(1, 10, false), aRuns.at(0));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(14, 15, false), aRuns.at(1));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_PrepareFallbackRuns_LTR)
{
ImplLayoutRuns aRuns;
aRuns.AddRun(0, 10, false); // First 5 characters excluded
aRuns.AddRun(11, 15, false); // Entire run included
aRuns.AddRun(16, 25, false); // First 4 characters included
aRuns.AddRun(26, 30, false); // Entire run excluded
aRuns.AddRun(31, 35, false); // Exact match
CPPUNIT_ASSERT_EQUAL(size_t(5), aRuns.size());
ImplLayoutRuns aFallbackRuns;
aFallbackRuns.AddRun(5, 20, false);
aFallbackRuns.AddRun(31, 35, false);
CPPUNIT_ASSERT_EQUAL(size_t(2), aFallbackRuns.size());
ImplLayoutRuns::PrepareFallbackRuns(&aRuns, &aFallbackRuns);
CPPUNIT_ASSERT_EQUAL(size_t(0), aFallbackRuns.size());
CPPUNIT_ASSERT_EQUAL(size_t(4), aRuns.size());
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(5, 10, false), aRuns.at(0));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(11, 15, false), aRuns.at(1));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(16, 20, false), aRuns.at(2));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(31, 35, false), aRuns.at(3));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_PrepareFallbackRuns_LTR_PreservesOrder)
{
ImplLayoutRuns aRuns;
aRuns.AddRun(16, 25, false); // First 4 characters included
aRuns.AddRun(31, 35, false); // Exact match
aRuns.AddRun(0, 10, false); // First 5 characters excluded
aRuns.AddRun(26, 30, false); // Entire run excluded
aRuns.AddRun(11, 15, false); // Entire run included
CPPUNIT_ASSERT_EQUAL(size_t(5), aRuns.size());
ImplLayoutRuns aFallbackRuns;
aFallbackRuns.AddRun(5, 20, false);
aFallbackRuns.AddRun(31, 35, false);
CPPUNIT_ASSERT_EQUAL(size_t(2), aFallbackRuns.size());
ImplLayoutRuns::PrepareFallbackRuns(&aRuns, &aFallbackRuns);
CPPUNIT_ASSERT_EQUAL(size_t(0), aFallbackRuns.size());
CPPUNIT_ASSERT_EQUAL(size_t(4), aRuns.size());
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(16, 20, false), aRuns.at(0));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(31, 35, false), aRuns.at(1));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(5, 10, false), aRuns.at(2));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(11, 15, false), aRuns.at(3));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_PrepareFallbackRuns_RTL)
{
ImplLayoutRuns aRuns;
aRuns.AddRun(0, 10, false);
aRuns.AddRun(10, 90, true);
aRuns.AddRun(90, 100, false);
CPPUNIT_ASSERT_EQUAL(size_t(3), aRuns.size());
ImplLayoutRuns aFallbackRuns;
aFallbackRuns.AddRun(0, 5, false);
aFallbackRuns.AddRun(6, 10, false);
aFallbackRuns.AddRun(10, 20, true);
aFallbackRuns.AddRun(21, 30, true);
aFallbackRuns.AddRun(31, 40, true);
aFallbackRuns.AddRun(41, 50, true);
aFallbackRuns.AddRun(92, 95, false);
aFallbackRuns.AddRun(96, 98, false);
CPPUNIT_ASSERT_EQUAL(size_t(8), aFallbackRuns.size());
ImplLayoutRuns::PrepareFallbackRuns(&aRuns, &aFallbackRuns);
CPPUNIT_ASSERT_EQUAL(size_t(0), aFallbackRuns.size());
CPPUNIT_ASSERT_EQUAL(size_t(8), aRuns.size());
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(0, 5, false), aRuns.at(0));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(6, 10, false), aRuns.at(1));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(41, 50, true), aRuns.at(2));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(31, 40, true), aRuns.at(3));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(21, 30, true), aRuns.at(4));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(10, 20, true), aRuns.at(5));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(92, 95, false), aRuns.at(6));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(96, 98, false), aRuns.at(7));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_tdf161397)
{
// Fallback run characteristic test from a particular case
ImplLayoutRuns aRuns;
aRuns.AddRun(0, 13, true);
ImplLayoutRuns aFallbackRuns;
aFallbackRuns.AddRun(12, 13, true);
aFallbackRuns.AddRun(7, 12, true);
aFallbackRuns.AddRun(5, 6, true);
aFallbackRuns.AddRun(0, 5, true);
ImplLayoutRuns::PrepareFallbackRuns(&aRuns, &aFallbackRuns);
CPPUNIT_ASSERT_EQUAL(size_t(2), aRuns.size());
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(7, 13, true), aRuns.at(0));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(0, 6, true), aRuns.at(1));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_GrowBidirectional)
{
ImplLayoutRuns aRuns;
aRuns.AddPos(16, true);
aRuns.AddPos(17, true);
aRuns.AddPos(18, true);
aRuns.AddPos(15, true);
aRuns.AddPos(19, true);
aRuns.AddPos(14, true);
CPPUNIT_ASSERT_EQUAL(size_t(1), aRuns.size());
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(14, 20, true), aRuns.at(0));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutRuns_ReverseTail)
{
ImplLayoutRuns aRuns;
aRuns.AddRun(10, 20, true);
aRuns.AddRun(30, 40, false);
aRuns.AddRun(50, 60, true);
aRuns.AddRun(70, 80, true);
aRuns.AddRun(90, 100, false);
aRuns.ReverseTail(size_t(2));
CPPUNIT_ASSERT_EQUAL(size_t(5), aRuns.size());
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(10, 20, true), aRuns.at(0));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(30, 40, false), aRuns.at(1));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(90, 100, false), aRuns.at(2));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(70, 80, true), aRuns.at(3));
CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(50, 60, true), aRuns.at(4));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutArgsBiDiStrong)
{
OUString sTestString = u"The quick brown fox\n jumped over the lazy dog"
"العاشر"_ustr;
vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
SalLayoutFlags::BiDiStrong, LanguageTag(LANGUAGE_NONE),
nullptr);
int nMinRunPos(0);
int nEndRunPos(0);
bool bRTL(false);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(0, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(19, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(20, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(51, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(20, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(51, nEndRunPos);
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutArgsBiDiRtl)
{
OUString sTestString = u"The quick brown fox\n jumped over the lazy dog"
"العاشر"_ustr;
vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
SalLayoutFlags::BiDiRtl, LanguageTag(LANGUAGE_NONE), nullptr);
int nMinRunPos(0);
int nEndRunPos(0);
bool bRTL(false);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(45, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(51, nEndRunPos);
CPPUNIT_ASSERT(&bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(21, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(45, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(20, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(21, nEndRunPos);
CPPUNIT_ASSERT(bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(0, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(19, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutArgsRightAlign)
{
OUString sTestString = u"The quick brown fox\n jumped over the lazy dog"
"العاشر"_ustr;
vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
SalLayoutFlags::RightAlign, LanguageTag(LANGUAGE_NONE),
nullptr);
int nMinRunPos(0);
int nEndRunPos(0);
bool bRTL(false);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(0, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(19, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(20, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(45, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(45, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(51, nEndRunPos);
CPPUNIT_ASSERT(bRTL);
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testImplLayoutArgs_PrepareFallback_precalculatedglyphs)
{
// this font has no Cyrillic characters and thus needs fallback
const vcl::Font aFont(u"Amiri"_ustr, Size(0, 36));
ScopedVclPtrInstance<VirtualDevice> pVirDev;
pVirDev->SetFont(aFont);
static constexpr OStringLiteral sUTF8String(u8"Тхе яуицк\n ыумпед овер");
const OUString sTestString(OUString::fromUtf8(sUTF8String));
std::unique_ptr<SalLayout> pLayout
= pVirDev->ImplLayout(sTestString, 0, sTestString.getLength(), Point(0, 0), 0, {}, {},
SalLayoutFlags::GlyphItemsOnly);
SalLayoutGlyphs aGlyphs = pLayout->GetGlyphs();
SalLayoutGlyphsImpl* pGlyphsImpl = aGlyphs.Impl(1);
vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
SalLayoutFlags::BiDiRtl, LanguageTag(LANGUAGE_RUSSIAN),
nullptr);
aArgs.PrepareFallback(pGlyphsImpl);
int nMinRunPos(0);
int nEndRunPos(0);
bool bRTL(false);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(0, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(3, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(4, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(9, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(11, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(17, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
aArgs.GetNextRun(&nMinRunPos, &nEndRunPos, &bRTL);
CPPUNIT_ASSERT_EQUAL(18, nMinRunPos);
CPPUNIT_ASSERT_EQUAL(22, nEndRunPos);
CPPUNIT_ASSERT(!bRTL);
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetStringWithCenterEllpsis)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(
u"a b c d ...v w x y z"_ustr,
device->GetEllipsisString(u"a b c d e f g h i j k l m n o p q r s t u v w x y z"_ustr, 100,
DrawTextFlags::CenterEllipsis));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetStringWithEndEllpsis)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(u"a"_ustr, device->GetEllipsisString(u"abcde. f g h i j ..."_ustr, 10,
DrawTextFlags::EndEllipsis));
CPPUNIT_ASSERT_EQUAL(
u"a b c d e f g h i j ..."_ustr,
device->GetEllipsisString(u"a b c d e f g h i j k l m n o p q r s t u v w x y z"_ustr, 100,
DrawTextFlags::EndEllipsis));
CPPUNIT_ASSERT_EQUAL(
u"a"_ustr, device->GetEllipsisString(u"abcde. f g h i j ..."_ustr, 1,
DrawTextFlags::EndEllipsis | DrawTextFlags::Clip));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetStringWithNewsEllpsis)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(u"a"_ustr, device->GetEllipsisString(u"abcde. f g h i j ..."_ustr, 10,
DrawTextFlags::NewsEllipsis));
CPPUNIT_ASSERT_EQUAL(
u"a b .... x y z"_ustr,
device->GetEllipsisString(u"a b c d. e f g. h i j k l m n o p q r s t u v w. x y z"_ustr,
100, DrawTextFlags::NewsEllipsis));
CPPUNIT_ASSERT_EQUAL(
u"a b .... x y z"_ustr,
device->GetEllipsisString(u"a b c d. e f g h i j k l m n o p q r s t u v w. x y z"_ustr,
100, DrawTextFlags::NewsEllipsis));
CPPUNIT_ASSERT_EQUAL(
u"a b c d e f g h i j ..."_ustr,
device->GetEllipsisString(u"a b c d e f g h i j k l m n o p q r s t u v w. x y z"_ustr, 100,
DrawTextFlags::NewsEllipsis));
CPPUNIT_ASSERT_EQUAL(
u"a..... x y z"_ustr,
device->GetEllipsisString(u"a. b c d e f g h i j k l m n o p q r s t u v w. x y z"_ustr,
100, DrawTextFlags::NewsEllipsis));
CPPUNIT_ASSERT_EQUAL(
u"ab. cde..."_ustr,
device->GetEllipsisString(u"ab. cde. x y z"_ustr, 50, DrawTextFlags::NewsEllipsis));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetTextBreak_invalid_index)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 11)));
const OUString sTestStr(u"textline_ text_"_ustr);
const auto nLen = sTestStr.getLength();
const auto nTextWidth = device->GetTextWidth(u"text"_ustr);
const auto nInvalidIndex = sTestStr.getLength() + 2;
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-1),
device->GetTextBreak(sTestStr, nTextWidth, nInvalidIndex, nLen));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetTextBreak)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 11)));
const OUString sTestStr(u"textline_ text_"_ustr);
const auto nLen = sTestStr.getLength();
const auto nTextWidth = device->GetTextWidth(u"text"_ustr);
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(4),
device->GetTextBreak(sTestStr, nTextWidth, 0, nLen));
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(7),
device->GetTextBreak(sTestStr, nTextWidth, 3, nLen));
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(9),
device->GetTextBreak(sTestStr, nTextWidth, 6, nLen));
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(12),
device->GetTextBreak(sTestStr, nTextWidth, 8, nLen));
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(14),
device->GetTextBreak(sTestStr, nTextWidth, 11, nLen));
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-1),
device->GetTextBreak(sTestStr, nTextWidth, 13, nLen));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetSingleLineTextRect)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"Liberation Sans"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(
tools::Rectangle(Point(), Size(75, 12)),
device->GetTextRect(tools::Rectangle(Point(), Point(100, 100)), u"This is test text"_ustr));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetSingleLineTextRectWithEndEllipsis)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"Liberation Sans"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(
tools::Rectangle(Point(), Size(52, 12)),
device->GetTextRect(tools::Rectangle(Point(), Point(50, 50)), u"This is test text"_ustr,
DrawTextFlags::WordBreak | DrawTextFlags::EndEllipsis));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetRightBottomAlignedSingleLineTextRect)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"Liberation Sans"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(926, 989), Size(75, 12)),
device->GetTextRect(tools::Rectangle(Point(), Point(1000, 1000)),
u"This is test text"_ustr,
DrawTextFlags::Right | DrawTextFlags::Bottom));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetRotatedSingleLineTextRect)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"Liberation Sans"_ustr, Size(0, 11)));
vcl::Font aFont(device->GetFont());
aFont.SetOrientation(45_deg10);
device->SetFont(aFont);
CPPUNIT_ASSERT_EQUAL(
tools::Rectangle(Point(0, -3), Size(75, 18)),
device->GetTextRect(tools::Rectangle(Point(), Point(100, 100)), u"This is test text"_ustr));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetMultiLineTextRect)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"Liberation Sans"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(), Size(75, 12)),
device->GetTextRect(tools::Rectangle(Point(), Point(100, 100)),
u"This is test text"_ustr,
DrawTextFlags::WordBreak | DrawTextFlags::MultiLine));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetMultiLineTextRectWithEndEllipsis)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"Liberation Sans"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(), Size(52, 48)),
device->GetTextRect(tools::Rectangle(Point(), Point(50, 50)),
u"This is test text xyzabc123abcdefghijk"_ustr,
DrawTextFlags::WordBreak | DrawTextFlags::EndEllipsis
| DrawTextFlags::MultiLine));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testGetRightBottomAlignedMultiLineTextRect)
{
ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::WITHOUT_ALPHA);
device->SetOutputSizePixel(Size(1000, 1000));
device->SetFont(vcl::Font(u"Liberation Sans"_ustr, Size(0, 11)));
CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(926, 989), Size(75, 12)),
device->GetTextRect(tools::Rectangle(Point(), Point(1000, 1000)),
u"This is test text"_ustr,
DrawTextFlags::Right | DrawTextFlags::Bottom
| DrawTextFlags::MultiLine));
}
CPPUNIT_TEST_FIXTURE(VclTextTest, testPartialTextArraySizeMatch)
{
OUString aWater = u"Water"_ustr;
vcl::Font aFont(u"DejaVu Sans"_ustr, u"Book"_ustr, Size(0, 2048));
ScopedVclPtrInstance<VirtualDevice> pOutDev;
pOutDev->SetFont(aFont);
// Absolute character widths for the complete array.
KernArray aCompleteWidths;
auto nCompleteWidth = pOutDev->GetTextArray(aWater, &aCompleteWidths).nWidth;
CPPUNIT_ASSERT_EQUAL(size_t{ 5 }, aCompleteWidths.size());
// Accumulate partial widths
double nPartialWidth = 0.0;
sal_Int32 nPrevWidth = 0;
for (sal_Int32 i = 0; i < 5; ++i)
{
KernArray aFragmentWidths;
auto nFragmentWidth
= pOutDev
->GetPartialTextArray(aWater, &aFragmentWidths, /*nIndex*/ 0, /*nLen*/ 5,
/*nPartIndex*/ i, /*nPartLen*/ 1)
.nWidth;
nPartialWidth += nFragmentWidth;
CPPUNIT_ASSERT_EQUAL(size_t{ 1 }, aFragmentWidths.size());
CPPUNIT_ASSERT_EQUAL(aCompleteWidths[i] - nPrevWidth, aFragmentWidths[0]);
nPrevWidth = aCompleteWidths[i];
}
CPPUNIT_ASSERT_DOUBLES_EQUAL(nCompleteWidth, nPartialWidth, /*delta*/ 0.01);
}
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */