calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / vcl / qa / cppunit / text.cxx
blob833022ee22049a345b5505e8b818aefe10c1c1e1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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>
25 #include <salgdi.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)
35 if (mbExportBitmap)
37 BitmapEx aBitmapEx(device->GetBitmapEx(Point(0, 0), device->GetOutputSizePixel()));
38 OUString cwd;
39 CPPUNIT_ASSERT_EQUAL(osl_Process_E_None, osl_getProcessWorkingDir(&cwd.pData));
40 OUString url;
41 CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None,
42 osl::FileBase::getAbsoluteFileURL(cwd, filename, url));
43 SvFileStream aStream(url, StreamMode::WRITE | StreamMode::TRUNC);
44 CPPUNIT_ASSERT_EQUAL(
45 ERRCODE_NONE, GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx, aStream));
49 public:
50 VclTextTest()
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
103 // pixels:
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())))
120 --y;
121 if (y < 0)
122 return -1;
123 tools::Long xmin = start.X();
124 while (xmin >= 0 && access->GetColor(y, xmin) != COL_WHITE)
125 --xmin;
126 tools::Long xmax = start.X();
127 while (xmax < bitmap.GetSizePixel().Width() && access->GetColor(y, xmax) != COL_WHITE)
128 ++xmax;
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())))
139 ++y;
140 if (y >= bitmap.GetSizePixel().Height())
141 return -1;
142 tools::Long xmin = start.X();
143 while (xmin >= 0 && access->GetColor(y, xmin) != COL_WHITE)
144 --xmin;
145 tools::Long xmax = start.X();
146 while (xmax < bitmap.GetSizePixel().Width() && access->GetColor(y, xmax) != COL_WHITE)
147 ++xmax;
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)))
160 ++x;
161 if (x >= bitmap.GetSizePixel().Width())
162 return -1;
163 tools::Long ymin = start.Y();
164 while (ymin >= 0 && access->GetColor(ymin, x) != COL_WHITE)
165 --ymin;
166 tools::Long ymax = start.Y();
167 while (ymax < bitmap.GetSizePixel().Width() && access->GetColor(ymax, x) != COL_WHITE)
168 ++ymax;
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()
177 OUString text("L");
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")
192 return;
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));
197 device->Erase();
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);
211 device->Erase();
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));
222 device->Erase();
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);
233 device->Erase();
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));
244 #ifdef _WIN32
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());
248 #endif
249 device->Erase();
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));
260 #ifdef _WIN32
261 font.SetAverageFontWidth(0.5 * font.GetOrCalculateAverageFontWidth());
262 #endif
263 device->Erase();
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);
302 int nCharPos(0);
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));
336 aRuns.ResetPos();
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);
346 aRuns.NextRun();
347 CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
348 CPPUNIT_ASSERT_EQUAL(4, nMinRunPos);
349 CPPUNIT_ASSERT_EQUAL(5, nEndRunPos);
350 CPPUNIT_ASSERT(bRightToLeft);
352 aRuns.NextRun();
353 CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
354 CPPUNIT_ASSERT_EQUAL(5, nMinRunPos);
355 CPPUNIT_ASSERT_EQUAL(6, nEndRunPos);
356 CPPUNIT_ASSERT(!bRightToLeft);
358 aRuns.NextRun();
359 CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
360 CPPUNIT_ASSERT_EQUAL(6, nMinRunPos);
361 CPPUNIT_ASSERT_EQUAL(7, nEndRunPos);
362 CPPUNIT_ASSERT(bRightToLeft);
364 // test clear
365 aRuns.Clear();
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);
377 int nCharPos(0);
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));
407 aRuns.ResetPos();
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);
417 aRuns.NextRun();
418 CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
419 CPPUNIT_ASSERT_EQUAL(4, nMinRunPos);
420 CPPUNIT_ASSERT_EQUAL(5, nEndRunPos);
421 CPPUNIT_ASSERT(bRightToLeft);
423 aRuns.NextRun();
424 CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, &bRightToLeft));
425 CPPUNIT_ASSERT_EQUAL(5, nMinRunPos);
426 CPPUNIT_ASSERT_EQUAL(6, nEndRunPos);
427 CPPUNIT_ASSERT(!bRightToLeft);
429 aRuns.NextRun();
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));
448 aRuns.NextRun();
449 CPPUNIT_ASSERT(aRuns.PosIsInRun(4));
451 aRuns.NextRun();
452 CPPUNIT_ASSERT(aRuns.PosIsInRun(5));
454 aRuns.NextRun();
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"
475 "العاشر";
476 vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
477 SalLayoutFlags::BiDiStrong, LanguageTag(LANGUAGE_NONE),
478 nullptr);
480 int nMinRunPos(0);
481 int nEndRunPos(0);
482 bool bRTL(false);
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"
502 "العاشر";
503 vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
504 SalLayoutFlags::BiDiRtl, LanguageTag(LANGUAGE_NONE), nullptr);
506 int nMinRunPos(0);
507 int nEndRunPos(0);
508 bool bRTL(false);
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"
534 "العاشر";
535 vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
536 SalLayoutFlags::RightAlign, LanguageTag(LANGUAGE_NONE),
537 nullptr);
539 int nMinRunPos(0);
540 int nEndRunPos(0);
541 bool bRTL(false);
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),
577 nullptr);
579 aArgs.PrepareFallback(pGlyphsImpl);
581 int nMinRunPos(0);
582 int nEndRunPos(0);
583 bool bRTL(false);
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)),
726 "This is test text",
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)),
753 "This is test text",
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)),
778 "This is test text",
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: */