1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <osl/file.hxx>
11 #include <osl/process.h>
12 #include <test/bootstrapfixture.hxx>
13 #include <sal/log.hxx>
14 #include <tools/stream.hxx>
16 #include <vcl/BitmapReadAccess.hxx>
17 #include <comphelper/errcode.hxx>
18 #include <vcl/graphicfilter.hxx>
19 #include <vcl/settings.hxx>
20 #include <vcl/svapp.hxx>
21 #include <vcl/virdev.hxx>
23 #include <ImplLayoutArgs.hxx>
24 #include <TextLayoutCache.hxx>
27 class VclTextTest
: public test::BootstrapFixture
29 // if enabled - check the result images with:
30 // "xdg-open ./workdir/CppunitTest/vcl_text_test.test.core/"
31 static constexpr const bool mbExportBitmap
= false;
33 void exportDevice(const OUString
& filename
, const VclPtr
<VirtualDevice
>& device
)
37 BitmapEx
aBitmapEx(device
->GetBitmapEx(Point(0, 0), device
->GetOutputSizePixel()));
39 CPPUNIT_ASSERT_EQUAL(osl_Process_E_None
, osl_getProcessWorkingDir(&cwd
.pData
));
41 CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None
,
42 osl::FileBase::getAbsoluteFileURL(cwd
, filename
, url
));
43 SvFileStream
aStream(url
, StreamMode::WRITE
| StreamMode::TRUNC
);
45 ERRCODE_NONE
, GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx
, aStream
));
51 : BootstrapFixture(true, false)
55 void testSimpleText();
56 void testTextLayoutCache();
57 void testImplLayoutRuns_AddPos();
58 void testImplLayoutRuns_AddRuns();
59 void testImplLayoutRuns_PosIsInRun();
60 void testImplLayoutRuns_PosIsInAnyRun();
61 void testImplLayoutArgsBiDiStrong();
62 void testImplLayoutArgsBiDiRtl();
63 void testImplLayoutArgsRightAlign();
64 void testImplLayoutArgs_PrepareFallback_precalculatedglyphs();
65 void testGetStringWithCenterEllpsis();
66 void testGetStringWithEndEllpsis();
67 void testGetStringWithNewsEllpsis();
68 void testGetTextBreak();
69 void testGetSingleLineTextRect();
70 void testGetSingleLineTextRectWithEndEllipsis();
71 void testGetRightBottomAlignedSingleLineTextRect();
72 void testGetMultiLineTextRect();
73 void testGetMultiLineTextRectWithEndEllipsis();
74 void testGetRightBottomAlignedMultiLineTextRect();
75 void testGetRotatedSingleLineTextRect();
77 CPPUNIT_TEST_SUITE(VclTextTest
);
78 CPPUNIT_TEST(testSimpleText
);
79 CPPUNIT_TEST(testTextLayoutCache
);
80 CPPUNIT_TEST(testImplLayoutRuns_AddPos
);
81 CPPUNIT_TEST(testImplLayoutRuns_AddRuns
);
82 CPPUNIT_TEST(testImplLayoutRuns_PosIsInRun
);
83 CPPUNIT_TEST(testImplLayoutRuns_PosIsInAnyRun
);
84 CPPUNIT_TEST(testImplLayoutArgsBiDiStrong
);
85 CPPUNIT_TEST(testImplLayoutArgsBiDiRtl
);
86 CPPUNIT_TEST(testImplLayoutArgsRightAlign
);
87 CPPUNIT_TEST(testImplLayoutArgs_PrepareFallback_precalculatedglyphs
);
88 CPPUNIT_TEST(testGetStringWithCenterEllpsis
);
89 CPPUNIT_TEST(testGetStringWithEndEllpsis
);
90 CPPUNIT_TEST(testGetStringWithNewsEllpsis
);
91 CPPUNIT_TEST(testGetTextBreak
);
92 CPPUNIT_TEST(testGetSingleLineTextRect
);
93 CPPUNIT_TEST(testGetSingleLineTextRectWithEndEllipsis
);
94 CPPUNIT_TEST(testGetRightBottomAlignedSingleLineTextRect
);
95 CPPUNIT_TEST(testGetMultiLineTextRect
);
96 CPPUNIT_TEST(testGetMultiLineTextRectWithEndEllipsis
);
97 CPPUNIT_TEST(testGetRightBottomAlignedMultiLineTextRect
);
98 CPPUNIT_TEST(testGetRotatedSingleLineTextRect
);
99 CPPUNIT_TEST_SUITE_END();
102 // Avoid issues when colorized antialiasing generates slightly tinted rather than truly black
104 static bool isBlack(Color col
)
106 return col
.GetRed() < 25 && col
.GetGreen() < 25 && col
.GetBlue() < 25;
109 // Return pixel width of the base of the given character located above
110 // the starting position.
111 // In other words, go up in y direction until a black pixel is found,
112 // then return the horizontal width of the area of those pixels.
113 // For 'L' this gives the width of the base of the character.
114 static tools::Long
getCharacterBaseWidth(VirtualDevice
* device
, const Point
& start
)
116 Bitmap bitmap
= device
->GetBitmap(Point(), device
->GetOutputSizePixel());
117 Bitmap::ScopedReadAccess
access(bitmap
);
118 tools::Long y
= start
.Y();
119 while (y
>= 0 && !isBlack(access
->GetColor(y
, start
.X())))
123 tools::Long xmin
= start
.X();
124 while (xmin
>= 0 && access
->GetColor(y
, xmin
) != COL_WHITE
)
126 tools::Long xmax
= start
.X();
127 while (xmax
< bitmap
.GetSizePixel().Width() && access
->GetColor(y
, xmax
) != COL_WHITE
)
129 return xmax
- xmin
+ 1;
132 // Similar to above but this time from the top, for U+30E8 (it's straight at the top, not at the bottom).
133 static tools::Long
getCharacterTopWidth(VirtualDevice
* device
, const Point
& start
)
135 Bitmap bitmap
= device
->GetBitmap(Point(), device
->GetOutputSizePixel());
136 Bitmap::ScopedReadAccess
access(bitmap
);
137 tools::Long y
= start
.Y();
138 while (y
< bitmap
.GetSizePixel().Height() && !isBlack(access
->GetColor(y
, start
.X())))
140 if (y
>= bitmap
.GetSizePixel().Height())
142 tools::Long xmin
= start
.X();
143 while (xmin
>= 0 && access
->GetColor(y
, xmin
) != COL_WHITE
)
145 tools::Long xmax
= start
.X();
146 while (xmax
< bitmap
.GetSizePixel().Width() && access
->GetColor(y
, xmax
) != COL_WHITE
)
148 return xmax
- xmin
+ 1;
151 // Similar to above, but this time return the pixel height of the left-most
152 // line of the character, going right from the starting point.
153 // For 'L' this gives the height of the left line.
154 static tools::Long
getCharacterLeftSideHeight(VirtualDevice
* device
, const Point
& start
)
156 Bitmap bitmap
= device
->GetBitmap(Point(), device
->GetOutputSizePixel());
157 Bitmap::ScopedReadAccess
access(bitmap
);
158 tools::Long x
= start
.X();
159 while (x
< bitmap
.GetSizePixel().Width() && !isBlack(access
->GetColor(start
.Y(), x
)))
161 if (x
>= bitmap
.GetSizePixel().Width())
163 tools::Long ymin
= start
.Y();
164 while (ymin
>= 0 && access
->GetColor(ymin
, x
) != COL_WHITE
)
166 tools::Long ymax
= start
.Y();
167 while (ymax
< bitmap
.GetSizePixel().Width() && access
->GetColor(ymax
, x
) != COL_WHITE
)
169 return ymax
- ymin
+ 1;
172 // Test rendering of the 'L' character (chosen because L is a simple shape).
173 // Check things like using a double font size doubling the size of the character, correct rotation, etc.
174 // IMPORTANT: If you modify this, check also the VclCjkTextTest::testVerticalText().
175 void VclTextTest::testSimpleText()
178 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
179 device
->SetOutputSizePixel(Size(100, 100));
180 device
->SetBackground(Wallpaper(COL_WHITE
));
181 // Disable AA, to make all pixels be black or white.
182 device
->SetAntialiasing(AntialiasingFlags::DisableText
);
184 // Bail out on all backends that do not work (or I didn't test). Opt-out rather than opt-in
185 // to make sure new backends fail initially.
186 if (device
->GetGraphics()->getRenderBackendName() == "qt5"
187 || device
->GetGraphics()->getRenderBackendName() == "qt5svp"
188 || device
->GetGraphics()->getRenderBackendName() == "gtk3svp"
189 || device
->GetGraphics()->getRenderBackendName() == "aqua"
190 || device
->GetGraphics()->getRenderBackendName() == "gen"
191 || device
->GetGraphics()->getRenderBackendName() == "genpsp")
194 // Use Dejavu fonts, they are shipped with LO, so they should be ~always available.
195 // Use Sans variant for simpler glyph shapes (no serifs).
196 vcl::Font
font("DejaVu Sans", "Book", Size(0, 36));
198 device
->SetFont(font
);
199 device
->DrawText(Point(10, 10), text
);
200 exportDevice("simple-text-36.png", device
);
201 // Height of 'L' with font 36 size should be roughly 28 pixels.
202 // Use the 'doubles' variant of the test, since that one allows
203 // a delta, and allow several pixels of delta to account
204 // for different rendering methods and whatnot.
205 tools::Long height36
= getCharacterLeftSideHeight(device
, Point(0, 30));
206 CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(28), height36
, 4);
207 tools::Long width36
= getCharacterBaseWidth(device
, Point(20, 99));
208 CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(19), width36
, 4);
210 font
.SetOrientation(2700_deg10
);
212 device
->SetFont(font
);
213 device
->DrawText(Point(90, 10), text
);
214 exportDevice("simple-text-36-270deg.png", device
);
215 // Width and height here should be swapped, again allowing for some imprecisions.
216 tools::Long height36Rotated
= getCharacterLeftSideHeight(device
, Point(0, 20));
217 CPPUNIT_ASSERT_DOUBLES_EQUAL(width36
, height36Rotated
, 2);
218 tools::Long width36Rotated
= getCharacterTopWidth(device
, Point(70, 0));
219 CPPUNIT_ASSERT_DOUBLES_EQUAL(height36
, width36Rotated
, 2);
221 font
= vcl::Font("DejaVu Sans", "Book", Size(0, 72));
223 device
->SetFont(font
);
224 device
->DrawText(Point(10, 10), text
);
225 exportDevice("simple-text-72.png", device
);
226 // Font size is doubled, so pixel sizes should also roughly double.
227 tools::Long height72
= getCharacterLeftSideHeight(device
, Point(0, 30));
228 CPPUNIT_ASSERT_DOUBLES_EQUAL(height36
* 2, height72
, 4);
229 tools::Long width72
= getCharacterBaseWidth(device
, Point(20, 99));
230 CPPUNIT_ASSERT_DOUBLES_EQUAL(width36
* 2, width72
, 4);
232 font
.SetOrientation(2700_deg10
);
234 device
->SetFont(font
);
235 device
->DrawText(Point(90, 10), text
);
236 exportDevice("simple-text-72-270deg.png", device
);
237 tools::Long height72Rotated
= getCharacterLeftSideHeight(device
, Point(0, 35));
238 CPPUNIT_ASSERT_DOUBLES_EQUAL(width72
, height72Rotated
, 2);
239 tools::Long width72Rotated
= getCharacterTopWidth(device
, Point(50, 0));
240 CPPUNIT_ASSERT_DOUBLES_EQUAL(height72
, width72Rotated
, 2);
242 // Test width scaled to 200%.
243 font
= vcl::Font("DejaVu Sans", "Book", Size(72, 36));
245 // TODO: What is the proper way to draw 200%-wide text? This is needed on Windows
246 // but it breaks Linux.
247 font
.SetAverageFontWidth(2 * font
.GetOrCalculateAverageFontWidth());
250 device
->SetFont(font
);
251 device
->DrawText(Point(10, 10), text
);
252 exportDevice("simple-text-36-200pct.png", device
);
253 tools::Long height36pct200
= getCharacterLeftSideHeight(device
, Point(0, 30));
254 CPPUNIT_ASSERT_DOUBLES_EQUAL(height36
, height36pct200
, 2);
255 tools::Long width36pct200
= getCharacterBaseWidth(device
, Point(20, 99));
256 CPPUNIT_ASSERT_DOUBLES_EQUAL(width36
* 2, width36pct200
, 4);
258 // Test width scaled to 50%.
259 font
= vcl::Font("DejaVu Sans", "Book", Size(18, 36));
261 font
.SetAverageFontWidth(0.5 * font
.GetOrCalculateAverageFontWidth());
264 device
->SetFont(font
);
265 device
->DrawText(Point(10, 10), text
);
266 exportDevice("simple-text-36-50pct.png", device
);
267 tools::Long height36pct50
= getCharacterLeftSideHeight(device
, Point(0, 30));
268 CPPUNIT_ASSERT_DOUBLES_EQUAL(height36
, height36pct50
, 2);
269 tools::Long width36pct50
= getCharacterBaseWidth(device
, Point(15, 99));
270 CPPUNIT_ASSERT_DOUBLES_EQUAL(width36
/ 2, width36pct50
, 2);
273 void VclTextTest::testTextLayoutCache()
275 OUString sTestString
= u
"The quick brown fox\n jumped over the lazy dogالعاشر";
276 vcl::text::TextLayoutCache
cache(sTestString
.getStr(), sTestString
.getLength());
278 vcl::text::Run run1
= cache
.runs
[0];
279 vcl::text::Run run2
= cache
.runs
[1];
281 bool bCorrectRuns
= (cache
.runs
.size() == 2);
282 CPPUNIT_ASSERT_MESSAGE("Wrong number of runs", bCorrectRuns
);
283 CPPUNIT_ASSERT_EQUAL(USCRIPT_LATIN
, run1
.nCode
);
284 CPPUNIT_ASSERT_EQUAL(0, run1
.nStart
);
285 CPPUNIT_ASSERT_EQUAL(45, run1
.nEnd
);
286 CPPUNIT_ASSERT_EQUAL(USCRIPT_ARABIC
, run2
.nCode
);
287 CPPUNIT_ASSERT_EQUAL(45, run2
.nStart
);
288 CPPUNIT_ASSERT_EQUAL(51, run2
.nEnd
);
291 void VclTextTest::testImplLayoutRuns_AddPos()
293 ImplLayoutRuns aRuns
;
294 aRuns
.AddPos(1, false);
295 aRuns
.AddPos(2, false);
296 aRuns
.AddPos(3, false);
297 aRuns
.AddPos(4, true); // add RTL marker glyph
298 aRuns
.AddPos(5, false);
299 aRuns
.AddPos(6, true); // add RTL marker glyph
300 aRuns
.AddPos(7, false);
303 bool bRightToLeftMarker(false);
305 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
306 CPPUNIT_ASSERT_EQUAL(1, nCharPos
);
307 CPPUNIT_ASSERT(!bRightToLeftMarker
);
309 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
310 CPPUNIT_ASSERT_EQUAL(2, nCharPos
);
311 CPPUNIT_ASSERT(!bRightToLeftMarker
);
313 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
314 CPPUNIT_ASSERT_EQUAL(3, nCharPos
);
315 CPPUNIT_ASSERT(!bRightToLeftMarker
);
317 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
318 CPPUNIT_ASSERT_EQUAL(4, nCharPos
);
319 CPPUNIT_ASSERT(bRightToLeftMarker
);
321 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
322 CPPUNIT_ASSERT_EQUAL(5, nCharPos
);
323 CPPUNIT_ASSERT(!bRightToLeftMarker
);
325 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
326 CPPUNIT_ASSERT_EQUAL(6, nCharPos
);
327 CPPUNIT_ASSERT(bRightToLeftMarker
);
329 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
330 CPPUNIT_ASSERT_EQUAL(7, nCharPos
);
331 CPPUNIT_ASSERT(!bRightToLeftMarker
);
333 // no next position, we are running off the end
334 CPPUNIT_ASSERT(!aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
338 int nMinRunPos
, nEndRunPos
;
339 bool bRightToLeft(false);
341 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
342 CPPUNIT_ASSERT_EQUAL(1, nMinRunPos
);
343 CPPUNIT_ASSERT_EQUAL(4, nEndRunPos
);
344 CPPUNIT_ASSERT(!bRightToLeft
);
347 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
348 CPPUNIT_ASSERT_EQUAL(4, nMinRunPos
);
349 CPPUNIT_ASSERT_EQUAL(5, nEndRunPos
);
350 CPPUNIT_ASSERT(bRightToLeft
);
353 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
354 CPPUNIT_ASSERT_EQUAL(5, nMinRunPos
);
355 CPPUNIT_ASSERT_EQUAL(6, nEndRunPos
);
356 CPPUNIT_ASSERT(!bRightToLeft
);
359 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
360 CPPUNIT_ASSERT_EQUAL(6, nMinRunPos
);
361 CPPUNIT_ASSERT_EQUAL(7, nEndRunPos
);
362 CPPUNIT_ASSERT(bRightToLeft
);
366 CPPUNIT_ASSERT(aRuns
.IsEmpty());
369 void VclTextTest::testImplLayoutRuns_AddRuns()
371 ImplLayoutRuns aRuns
;
372 aRuns
.AddRun(1, 4, false);
373 aRuns
.AddRun(5, 4, true);
374 aRuns
.AddRun(5, 6, false);
375 aRuns
.AddRun(6, 7, true);
378 bool bRightToLeftMarker(false);
380 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
381 CPPUNIT_ASSERT_EQUAL(1, nCharPos
);
382 CPPUNIT_ASSERT(!bRightToLeftMarker
);
384 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
385 CPPUNIT_ASSERT_EQUAL(2, nCharPos
);
386 CPPUNIT_ASSERT(!bRightToLeftMarker
);
388 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
389 CPPUNIT_ASSERT_EQUAL(3, nCharPos
);
390 CPPUNIT_ASSERT(!bRightToLeftMarker
);
392 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
393 CPPUNIT_ASSERT_EQUAL(4, nCharPos
);
394 CPPUNIT_ASSERT(bRightToLeftMarker
);
396 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
397 CPPUNIT_ASSERT_EQUAL(5, nCharPos
);
398 CPPUNIT_ASSERT(!bRightToLeftMarker
);
400 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
401 CPPUNIT_ASSERT_EQUAL(6, nCharPos
);
402 CPPUNIT_ASSERT(bRightToLeftMarker
);
404 // no next position, we are running off the end
405 CPPUNIT_ASSERT(!aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
409 int nMinRunPos
, nEndRunPos
;
410 bool bRightToLeft(false);
412 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
413 CPPUNIT_ASSERT_EQUAL(1, nMinRunPos
);
414 CPPUNIT_ASSERT_EQUAL(4, nEndRunPos
);
415 CPPUNIT_ASSERT(!bRightToLeft
);
418 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
419 CPPUNIT_ASSERT_EQUAL(4, nMinRunPos
);
420 CPPUNIT_ASSERT_EQUAL(5, nEndRunPos
);
421 CPPUNIT_ASSERT(bRightToLeft
);
424 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
425 CPPUNIT_ASSERT_EQUAL(5, nMinRunPos
);
426 CPPUNIT_ASSERT_EQUAL(6, nEndRunPos
);
427 CPPUNIT_ASSERT(!bRightToLeft
);
430 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
431 CPPUNIT_ASSERT_EQUAL(6, nMinRunPos
);
432 CPPUNIT_ASSERT_EQUAL(7, nEndRunPos
);
433 CPPUNIT_ASSERT(bRightToLeft
);
436 void VclTextTest::testImplLayoutRuns_PosIsInRun()
438 ImplLayoutRuns aRuns
;
439 aRuns
.AddRun(1, 4, false);
440 aRuns
.AddRun(4, 5, true);
441 aRuns
.AddRun(5, 6, false);
442 aRuns
.AddRun(6, 7, true);
444 CPPUNIT_ASSERT(aRuns
.PosIsInRun(1));
445 CPPUNIT_ASSERT(aRuns
.PosIsInRun(2));
446 CPPUNIT_ASSERT(aRuns
.PosIsInRun(3));
449 CPPUNIT_ASSERT(aRuns
.PosIsInRun(4));
452 CPPUNIT_ASSERT(aRuns
.PosIsInRun(5));
455 CPPUNIT_ASSERT(aRuns
.PosIsInRun(6));
457 CPPUNIT_ASSERT(!aRuns
.PosIsInRun(7));
460 void VclTextTest::testImplLayoutRuns_PosIsInAnyRun()
462 ImplLayoutRuns aRuns
;
463 aRuns
.AddRun(1, 4, false);
464 aRuns
.AddRun(4, 5, true);
465 aRuns
.AddRun(5, 6, false);
466 aRuns
.AddRun(6, 7, true);
468 CPPUNIT_ASSERT(aRuns
.PosIsInAnyRun(1));
469 CPPUNIT_ASSERT(!aRuns
.PosIsInAnyRun(7));
472 void VclTextTest::testImplLayoutArgsBiDiStrong()
474 OUString sTestString
= u
"The quick brown fox\n jumped over the lazy dog"
476 vcl::text::ImplLayoutArgs
aArgs(sTestString
, 0, sTestString
.getLength(),
477 SalLayoutFlags::BiDiStrong
, LanguageTag(LANGUAGE_NONE
),
484 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
485 CPPUNIT_ASSERT_EQUAL(0, nMinRunPos
);
486 CPPUNIT_ASSERT_EQUAL(19, nEndRunPos
);
487 CPPUNIT_ASSERT(!bRTL
);
489 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
490 CPPUNIT_ASSERT_EQUAL(20, nMinRunPos
);
491 CPPUNIT_ASSERT_EQUAL(51, nEndRunPos
);
492 CPPUNIT_ASSERT(!bRTL
);
494 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
495 CPPUNIT_ASSERT_EQUAL(20, nMinRunPos
);
496 CPPUNIT_ASSERT_EQUAL(51, nEndRunPos
);
499 void VclTextTest::testImplLayoutArgsBiDiRtl()
501 OUString sTestString
= u
"The quick brown fox\n jumped over the lazy dog"
503 vcl::text::ImplLayoutArgs
aArgs(sTestString
, 0, sTestString
.getLength(),
504 SalLayoutFlags::BiDiRtl
, LanguageTag(LANGUAGE_NONE
), nullptr);
510 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
511 CPPUNIT_ASSERT_EQUAL(45, nMinRunPos
);
512 CPPUNIT_ASSERT_EQUAL(51, nEndRunPos
);
513 CPPUNIT_ASSERT(&bRTL
);
515 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
516 CPPUNIT_ASSERT_EQUAL(21, nMinRunPos
);
517 CPPUNIT_ASSERT_EQUAL(45, nEndRunPos
);
518 CPPUNIT_ASSERT(!bRTL
);
520 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
521 CPPUNIT_ASSERT_EQUAL(20, nMinRunPos
);
522 CPPUNIT_ASSERT_EQUAL(21, nEndRunPos
);
523 CPPUNIT_ASSERT(bRTL
);
525 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
526 CPPUNIT_ASSERT_EQUAL(0, nMinRunPos
);
527 CPPUNIT_ASSERT_EQUAL(19, nEndRunPos
);
528 CPPUNIT_ASSERT(!bRTL
);
531 void VclTextTest::testImplLayoutArgsRightAlign()
533 OUString sTestString
= u
"The quick brown fox\n jumped over the lazy dog"
535 vcl::text::ImplLayoutArgs
aArgs(sTestString
, 0, sTestString
.getLength(),
536 SalLayoutFlags::RightAlign
, LanguageTag(LANGUAGE_NONE
),
543 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
544 CPPUNIT_ASSERT_EQUAL(0, nMinRunPos
);
545 CPPUNIT_ASSERT_EQUAL(19, nEndRunPos
);
546 CPPUNIT_ASSERT(!bRTL
);
548 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
549 CPPUNIT_ASSERT_EQUAL(20, nMinRunPos
);
550 CPPUNIT_ASSERT_EQUAL(45, nEndRunPos
);
551 CPPUNIT_ASSERT(!bRTL
);
553 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
554 CPPUNIT_ASSERT_EQUAL(45, nMinRunPos
);
555 CPPUNIT_ASSERT_EQUAL(51, nEndRunPos
);
556 CPPUNIT_ASSERT(bRTL
);
559 void VclTextTest::testImplLayoutArgs_PrepareFallback_precalculatedglyphs()
561 // this font has no Cyrillic characters and thus needs fallback
562 const vcl::Font
aFont("Amiri", Size(0, 36));
564 ScopedVclPtrInstance
<VirtualDevice
> pVirDev
;
565 pVirDev
->SetFont(aFont
);
567 const OString
sUTF8String(u8
"Тхе яуицк\n ыумпед овер");
568 const OUString
sTestString(OUString::fromUtf8(sUTF8String
));
569 std::unique_ptr
<SalLayout
> pLayout
570 = pVirDev
->ImplLayout(sTestString
, 0, sTestString
.getLength(), Point(0, 0), 0, {}, {},
571 SalLayoutFlags::GlyphItemsOnly
);
572 SalLayoutGlyphs aGlyphs
= pLayout
->GetGlyphs();
573 SalLayoutGlyphsImpl
* pGlyphsImpl
= aGlyphs
.Impl(1);
575 vcl::text::ImplLayoutArgs
aArgs(sTestString
, 0, sTestString
.getLength(),
576 SalLayoutFlags::BiDiRtl
, LanguageTag(LANGUAGE_RUSSIAN
),
579 aArgs
.PrepareFallback(pGlyphsImpl
);
585 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
586 CPPUNIT_ASSERT_EQUAL(0, nMinRunPos
);
587 CPPUNIT_ASSERT_EQUAL(3, nEndRunPos
);
588 CPPUNIT_ASSERT(!bRTL
);
590 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
591 CPPUNIT_ASSERT_EQUAL(4, nMinRunPos
);
592 CPPUNIT_ASSERT_EQUAL(9, nEndRunPos
);
593 CPPUNIT_ASSERT(!bRTL
);
595 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
596 CPPUNIT_ASSERT_EQUAL(11, nMinRunPos
);
597 CPPUNIT_ASSERT_EQUAL(17, nEndRunPos
);
598 CPPUNIT_ASSERT(!bRTL
);
600 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
601 CPPUNIT_ASSERT_EQUAL(18, nMinRunPos
);
602 CPPUNIT_ASSERT_EQUAL(22, nEndRunPos
);
603 CPPUNIT_ASSERT(!bRTL
);
606 void VclTextTest::testGetStringWithCenterEllpsis()
608 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
609 device
->SetOutputSizePixel(Size(1000, 1000));
610 device
->SetFont(vcl::Font("DejaVu Sans", "Book", Size(0, 11)));
612 CPPUNIT_ASSERT_EQUAL(
613 OUString(u
"a b c d ...v w x y z"),
614 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", 100,
615 DrawTextFlags::CenterEllipsis
));
618 void VclTextTest::testGetStringWithEndEllpsis()
620 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
621 device
->SetOutputSizePixel(Size(1000, 1000));
622 device
->SetFont(vcl::Font("DejaVu Sans", "Book", Size(0, 11)));
624 CPPUNIT_ASSERT_EQUAL(OUString(u
"a"), device
->GetEllipsisString(u
"abcde. f g h i j ...", 10,
625 DrawTextFlags::EndEllipsis
));
627 CPPUNIT_ASSERT_EQUAL(
628 OUString(u
"a b c d e f g h i j ..."),
629 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", 100,
630 DrawTextFlags::EndEllipsis
));
632 CPPUNIT_ASSERT_EQUAL(OUString(u
"a"), device
->GetEllipsisString(u
"abcde. f g h i j ...", 1,
633 DrawTextFlags::EndEllipsis
634 | DrawTextFlags::Clip
));
637 void VclTextTest::testGetStringWithNewsEllpsis()
639 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
640 device
->SetOutputSizePixel(Size(1000, 1000));
641 device
->SetFont(vcl::Font("DejaVu Sans", "Book", Size(0, 11)));
643 CPPUNIT_ASSERT_EQUAL(OUString(u
"a"), device
->GetEllipsisString(u
"abcde. f g h i j ...", 10,
644 DrawTextFlags::NewsEllipsis
));
646 CPPUNIT_ASSERT_EQUAL(
647 OUString(u
"a b .... x y z"),
648 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", 100,
649 DrawTextFlags::NewsEllipsis
));
651 CPPUNIT_ASSERT_EQUAL(
652 OUString(u
"a b .... x y z"),
653 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", 100,
654 DrawTextFlags::NewsEllipsis
));
656 CPPUNIT_ASSERT_EQUAL(
657 OUString(u
"a b c d e f g h i j ..."),
658 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", 100,
659 DrawTextFlags::NewsEllipsis
));
661 CPPUNIT_ASSERT_EQUAL(
662 OUString(u
"a..... x y z"),
663 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", 100,
664 DrawTextFlags::NewsEllipsis
));
666 CPPUNIT_ASSERT_EQUAL(
667 OUString(u
"ab. cde..."),
668 device
->GetEllipsisString(u
"ab. cde. x y z", 50, DrawTextFlags::NewsEllipsis
));
671 void VclTextTest::testGetTextBreak()
673 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
674 device
->SetOutputSizePixel(Size(1000, 1000));
675 device
->SetFont(vcl::Font("DejaVu Sans", "Book", Size(0, 11)));
677 const OUString
sTestStr(u
"textline_ text_");
678 const auto nLen
= sTestStr
.getLength();
679 const auto nTextWidth
= device
->GetTextWidth("text");
681 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(4),
682 device
->GetTextBreak(sTestStr
, nTextWidth
, 0, nLen
));
683 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(7),
684 device
->GetTextBreak(sTestStr
, nTextWidth
, 3, nLen
));
685 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(9),
686 device
->GetTextBreak(sTestStr
, nTextWidth
, 6, nLen
));
687 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(12),
688 device
->GetTextBreak(sTestStr
, nTextWidth
, 8, nLen
));
689 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(14),
690 device
->GetTextBreak(sTestStr
, nTextWidth
, 11, nLen
));
691 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(-1),
692 device
->GetTextBreak(sTestStr
, nTextWidth
, 13, nLen
));
695 void VclTextTest::testGetSingleLineTextRect()
697 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
698 device
->SetOutputSizePixel(Size(1000, 1000));
699 device
->SetFont(vcl::Font("Liberation Sans", Size(0, 11)));
701 CPPUNIT_ASSERT_EQUAL(
702 tools::Rectangle(Point(), Size(75, 12)),
703 device
->GetTextRect(tools::Rectangle(Point(), Point(100, 100)), "This is test text"));
706 void VclTextTest::testGetSingleLineTextRectWithEndEllipsis()
708 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
709 device
->SetOutputSizePixel(Size(1000, 1000));
710 device
->SetFont(vcl::Font("Liberation Sans", Size(0, 11)));
712 CPPUNIT_ASSERT_EQUAL(
713 tools::Rectangle(Point(), Size(52, 12)),
714 device
->GetTextRect(tools::Rectangle(Point(), Point(50, 50)), "This is test text",
715 DrawTextFlags::WordBreak
| DrawTextFlags::EndEllipsis
));
718 void VclTextTest::testGetRightBottomAlignedSingleLineTextRect()
720 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
721 device
->SetOutputSizePixel(Size(1000, 1000));
722 device
->SetFont(vcl::Font("Liberation Sans", Size(0, 11)));
724 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(926, 989), Size(75, 12)),
725 device
->GetTextRect(tools::Rectangle(Point(), Point(1000, 1000)),
727 DrawTextFlags::Right
| DrawTextFlags::Bottom
));
730 void VclTextTest::testGetRotatedSingleLineTextRect()
732 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
733 device
->SetOutputSizePixel(Size(1000, 1000));
734 device
->SetFont(vcl::Font("Liberation Sans", Size(0, 11)));
736 vcl::Font
aFont(device
->GetFont());
737 aFont
.SetOrientation(45_deg10
);
738 device
->SetFont(aFont
);
740 CPPUNIT_ASSERT_EQUAL(
741 tools::Rectangle(Point(0, -3), Size(75, 18)),
742 device
->GetTextRect(tools::Rectangle(Point(), Point(100, 100)), "This is test text"));
745 void VclTextTest::testGetMultiLineTextRect()
747 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
748 device
->SetOutputSizePixel(Size(1000, 1000));
749 device
->SetFont(vcl::Font("Liberation Sans", Size(0, 11)));
751 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(), Size(75, 12)),
752 device
->GetTextRect(tools::Rectangle(Point(), Point(100, 100)),
754 DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
));
757 void VclTextTest::testGetMultiLineTextRectWithEndEllipsis()
759 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
760 device
->SetOutputSizePixel(Size(1000, 1000));
761 device
->SetFont(vcl::Font("Liberation Sans", Size(0, 11)));
763 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(), Size(52, 48)),
764 device
->GetTextRect(tools::Rectangle(Point(), Point(50, 50)),
765 "This is test text xyzabc123abcdefghijk",
766 DrawTextFlags::WordBreak
| DrawTextFlags::EndEllipsis
767 | DrawTextFlags::MultiLine
));
770 void VclTextTest::testGetRightBottomAlignedMultiLineTextRect()
772 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::DEFAULT
);
773 device
->SetOutputSizePixel(Size(1000, 1000));
774 device
->SetFont(vcl::Font("Liberation Sans", Size(0, 11)));
776 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(926, 989), Size(75, 12)),
777 device
->GetTextRect(tools::Rectangle(Point(), Point(1000, 1000)),
779 DrawTextFlags::Right
| DrawTextFlags::Bottom
780 | DrawTextFlags::MultiLine
));
783 CPPUNIT_TEST_SUITE_REGISTRATION(VclTextTest
);
785 CPPUNIT_PLUGIN_IMPLEMENT();
787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */