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;
34 void exportDevice(const OUString
& filename
, const VclPtr
<VirtualDevice
>& device
)
38 BitmapEx
aBitmapEx(device
->GetBitmapEx(Point(0, 0), device
->GetOutputSizePixel()));
40 CPPUNIT_ASSERT_EQUAL(osl_Process_E_None
, osl_getProcessWorkingDir(&cwd
.pData
));
42 CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None
,
43 osl::FileBase::getAbsoluteFileURL(cwd
, filename
, url
));
44 SvFileStream
aStream(url
, StreamMode::WRITE
| StreamMode::TRUNC
);
46 ERRCODE_NONE
, GraphicFilter::GetGraphicFilter().compressAsPNG(aBitmapEx
, aStream
));
51 : BootstrapFixture(true, false)
56 static std::ostream
& operator<<(std::ostream
& s
, const ImplLayoutRuns::Run
& rRun
)
58 return s
<< "{" << rRun
.m_nMinRunPos
<< ", " << rRun
.m_nEndRunPos
<< ", " << rRun
.m_bRTL
<< "}";
61 // Avoid issues when colorized antialiasing generates slightly tinted rather than truly black
63 static bool isBlack(Color col
)
65 return col
.GetRed() < 25 && col
.GetGreen() < 25 && col
.GetBlue() < 25;
68 // Return pixel width of the base of the given character located above
69 // the starting position.
70 // In other words, go up in y direction until a black pixel is found,
71 // then return the horizontal width of the area of those pixels.
72 // For 'L' this gives the width of the base of the character.
73 static tools::Long
getCharacterBaseWidth(VirtualDevice
* device
, const Point
& start
)
75 Bitmap bitmap
= device
->GetBitmap(Point(), device
->GetOutputSizePixel());
76 BitmapScopedReadAccess
access(bitmap
);
77 tools::Long y
= start
.Y();
78 while (y
>= 0 && !isBlack(access
->GetColor(y
, start
.X())))
82 tools::Long xmin
= start
.X();
83 while (xmin
>= 0 && access
->GetColor(y
, xmin
) != COL_WHITE
)
85 tools::Long xmax
= start
.X();
86 while (xmax
< bitmap
.GetSizePixel().Width() && access
->GetColor(y
, xmax
) != COL_WHITE
)
88 return xmax
- xmin
+ 1;
91 // Similar to above but this time from the top, for U+30E8 (it's straight at the top, not at the bottom).
92 static tools::Long
getCharacterTopWidth(VirtualDevice
* device
, const Point
& start
)
94 Bitmap bitmap
= device
->GetBitmap(Point(), device
->GetOutputSizePixel());
95 BitmapScopedReadAccess
access(bitmap
);
96 tools::Long y
= start
.Y();
97 while (y
< bitmap
.GetSizePixel().Height() && !isBlack(access
->GetColor(y
, start
.X())))
99 if (y
>= bitmap
.GetSizePixel().Height())
101 tools::Long xmin
= start
.X();
102 while (xmin
>= 0 && access
->GetColor(y
, xmin
) != COL_WHITE
)
104 tools::Long xmax
= start
.X();
105 while (xmax
< bitmap
.GetSizePixel().Width() && access
->GetColor(y
, xmax
) != COL_WHITE
)
107 return xmax
- xmin
+ 1;
110 // Similar to above, but this time return the pixel height of the left-most
111 // line of the character, going right from the starting point.
112 // For 'L' this gives the height of the left line.
113 static tools::Long
getCharacterLeftSideHeight(VirtualDevice
* device
, const Point
& start
)
115 Bitmap bitmap
= device
->GetBitmap(Point(), device
->GetOutputSizePixel());
116 BitmapScopedReadAccess
access(bitmap
);
117 tools::Long x
= start
.X();
118 while (x
< bitmap
.GetSizePixel().Width() && !isBlack(access
->GetColor(start
.Y(), x
)))
120 if (x
>= bitmap
.GetSizePixel().Width())
122 tools::Long ymin
= start
.Y();
123 while (ymin
>= 0 && access
->GetColor(ymin
, x
) != COL_WHITE
)
125 tools::Long ymax
= start
.Y();
126 while (ymax
< bitmap
.GetSizePixel().Width() && access
->GetColor(ymax
, x
) != COL_WHITE
)
128 return ymax
- ymin
+ 1;
131 // Test rendering of the 'L' character (chosen because L is a simple shape).
132 // Check things like using a double font size doubling the size of the character, correct rotation, etc.
133 // IMPORTANT: If you modify this, check also the VclCjkTextTest::testVerticalText().
134 CPPUNIT_TEST_FIXTURE(VclTextTest
, testSimpleText
)
136 OUString
text(u
"L"_ustr
);
137 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
138 device
->SetOutputSizePixel(Size(100, 100));
139 device
->SetBackground(Wallpaper(COL_WHITE
));
140 // Disable AA, to make all pixels be black or white.
141 device
->SetAntialiasing(AntialiasingFlags::DisableText
);
143 // Bail out on all backends that do not work (or I didn't test). Opt-out rather than opt-in
144 // to make sure new backends fail initially.
145 if (device
->GetGraphics()->getRenderBackendName() == "qt"
146 || device
->GetGraphics()->getRenderBackendName() == "qtsvp"
147 || device
->GetGraphics()->getRenderBackendName() == "gtk3svp"
148 || device
->GetGraphics()->getRenderBackendName() == "aqua"
149 || device
->GetGraphics()->getRenderBackendName() == "gen"
150 || device
->GetGraphics()->getRenderBackendName() == "genpsp")
153 // Use Dejavu fonts, they are shipped with LO, so they should be ~always available.
154 // Use Sans variant for simpler glyph shapes (no serifs).
155 vcl::Font
font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 36));
157 device
->SetFont(font
);
158 device
->DrawText(Point(10, 10), text
);
159 exportDevice(u
"simple-text-36.png"_ustr
, device
);
160 // Height of 'L' with font 36 size should be roughly 28 pixels.
161 // Use the 'doubles' variant of the test, since that one allows
162 // a delta, and allow several pixels of delta to account
163 // for different rendering methods and whatnot.
164 tools::Long height36
= getCharacterLeftSideHeight(device
, Point(0, 30));
165 CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(28), height36
, 4);
166 tools::Long width36
= getCharacterBaseWidth(device
, Point(20, 99));
167 CPPUNIT_ASSERT_DOUBLES_EQUAL(tools::Long(19), width36
, 4);
169 font
.SetOrientation(2700_deg10
);
171 device
->SetFont(font
);
172 device
->DrawText(Point(90, 10), text
);
173 exportDevice(u
"simple-text-36-270deg.png"_ustr
, device
);
174 // Width and height here should be swapped, again allowing for some imprecisions.
175 tools::Long height36Rotated
= getCharacterLeftSideHeight(device
, Point(0, 20));
176 CPPUNIT_ASSERT_DOUBLES_EQUAL(width36
, height36Rotated
, 2);
177 tools::Long width36Rotated
= getCharacterTopWidth(device
, Point(70, 0));
178 CPPUNIT_ASSERT_DOUBLES_EQUAL(height36
, width36Rotated
, 2);
180 font
= vcl::Font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 72));
182 device
->SetFont(font
);
183 device
->DrawText(Point(10, 10), text
);
184 exportDevice(u
"simple-text-72.png"_ustr
, device
);
185 // Font size is doubled, so pixel sizes should also roughly double.
186 tools::Long height72
= getCharacterLeftSideHeight(device
, Point(0, 30));
187 CPPUNIT_ASSERT_DOUBLES_EQUAL(height36
* 2, height72
, 4);
188 tools::Long width72
= getCharacterBaseWidth(device
, Point(20, 99));
189 CPPUNIT_ASSERT_DOUBLES_EQUAL(width36
* 2, width72
, 5);
191 font
.SetOrientation(2700_deg10
);
193 device
->SetFont(font
);
194 device
->DrawText(Point(90, 10), text
);
195 exportDevice(u
"simple-text-72-270deg.png"_ustr
, device
);
196 tools::Long height72Rotated
= getCharacterLeftSideHeight(device
, Point(0, 35));
197 CPPUNIT_ASSERT_DOUBLES_EQUAL(width72
, height72Rotated
, 2);
198 tools::Long width72Rotated
= getCharacterTopWidth(device
, Point(50, 0));
199 CPPUNIT_ASSERT_DOUBLES_EQUAL(height72
, width72Rotated
, 2);
201 // Test width scaled to 200%.
202 font
= vcl::Font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(72, 36));
204 // TODO: What is the proper way to draw 200%-wide text? This is needed on Windows
205 // but it breaks Linux.
206 font
.SetAverageFontWidth(2 * font
.GetOrCalculateAverageFontWidth());
209 device
->SetFont(font
);
210 device
->DrawText(Point(10, 10), text
);
211 exportDevice(u
"simple-text-36-200pct.png"_ustr
, device
);
212 tools::Long height36pct200
= getCharacterLeftSideHeight(device
, Point(0, 30));
213 CPPUNIT_ASSERT_DOUBLES_EQUAL(height36
, height36pct200
, 2);
214 tools::Long width36pct200
= getCharacterBaseWidth(device
, Point(20, 99));
215 CPPUNIT_ASSERT_DOUBLES_EQUAL(width36
* 2, width36pct200
, 5);
217 // Test width scaled to 50%.
218 font
= vcl::Font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(18, 36));
220 font
.SetAverageFontWidth(0.5 * font
.GetOrCalculateAverageFontWidth());
223 device
->SetFont(font
);
224 device
->DrawText(Point(10, 10), text
);
225 exportDevice(u
"simple-text-36-50pct.png"_ustr
, device
);
226 tools::Long height36pct50
= getCharacterLeftSideHeight(device
, Point(0, 40));
227 CPPUNIT_ASSERT_DOUBLES_EQUAL(height36
, height36pct50
, 2);
228 tools::Long width36pct50
= getCharacterBaseWidth(device
, Point(15, 99));
229 CPPUNIT_ASSERT_DOUBLES_EQUAL(width36
/ 2, width36pct50
, 2);
232 CPPUNIT_TEST_FIXTURE(VclTextTest
, testSimpleTextFontSpecificKerning
)
234 OUString
aAV(u
"AV"_ustr
);
236 vcl::Font
aFont(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 2048));
238 ScopedVclPtrInstance
<VirtualDevice
> pOutDev
;
239 pOutDev
->SetFont(aFont
);
241 // absolute character widths AKA text array.
242 tools::Long nRefTextWidth
= 2671;
243 KernArray aRefCharWidths
{ 1270, 2671 };
244 KernArray aCharWidths
;
245 tools::Long nTextWidth
246 = basegfx::fround
<tools::Long
>(pOutDev
->GetTextArray(aAV
, &aCharWidths
).nWidth
);
248 CPPUNIT_ASSERT_EQUAL(aRefCharWidths
[0], aCharWidths
[0]);
249 CPPUNIT_ASSERT_EQUAL(aRefCharWidths
[1], aCharWidths
[1]);
250 // this sporadically returns 75 or 74 on some of the windows tinderboxes eg. tb73
251 CPPUNIT_ASSERT_EQUAL(nRefTextWidth
, nTextWidth
);
252 CPPUNIT_ASSERT_EQUAL(nTextWidth
, tools::Long(aCharWidths
.back()));
254 // text advance width and line height
255 CPPUNIT_ASSERT_EQUAL(nRefTextWidth
, pOutDev
->GetTextWidth(aAV
));
256 CPPUNIT_ASSERT_EQUAL(tools::Long(2384), pOutDev
->GetTextHeight());
258 // exact bounding rectangle, not essentially the same as text width/height
259 tools::Rectangle aBoundRect
;
260 pOutDev
->GetTextBoundRect(aBoundRect
, aAV
);
261 CPPUNIT_ASSERT_EQUAL(tools::Long(16), aBoundRect
.Left());
262 CPPUNIT_ASSERT_EQUAL(tools::Long(408), aBoundRect
.Top());
263 CPPUNIT_ASSERT_EQUAL(tools::Long(2639), aBoundRect
.GetWidth());
264 CPPUNIT_ASSERT_EQUAL(tools::Long(1493), aBoundRect
.getOpenHeight());
266 // normal orientation
267 tools::Rectangle aInput
;
268 tools::Rectangle aRect
= pOutDev
->GetTextRect(aInput
, aAV
);
270 // now rotate 270 degrees
271 vcl::Font
aRotated(aFont
);
272 aRotated
.SetOrientation(2700_deg10
);
273 pOutDev
->SetFont(aRotated
);
274 tools::Rectangle aRectRot
= pOutDev
->GetTextRect(aInput
, aAV
);
276 // Check that we did do the rotation...
277 CPPUNIT_ASSERT_EQUAL(aRectRot
.GetWidth(), aRect
.GetHeight());
278 CPPUNIT_ASSERT_EQUAL(aRectRot
.GetHeight(), aRect
.GetWidth());
281 CPPUNIT_TEST_FIXTURE(VclTextTest
, testSimpleTextNoKerning
)
283 OUString
aAV(u
"AV"_ustr
);
285 vcl::Font
aFont(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 2048));
286 aFont
.SetKerning(FontKerning::NONE
);
288 ScopedVclPtrInstance
<VirtualDevice
> pOutDev
;
289 pOutDev
->SetFont(aFont
);
291 // absolute character widths AKA text array.
292 tools::Long nRefTextWidth
= 2802;
293 KernArray aRefCharWidths
{ 1401, 2802 };
294 KernArray aCharWidths
;
295 tools::Long nTextWidth
296 = basegfx::fround
<tools::Long
>(pOutDev
->GetTextArray(aAV
, &aCharWidths
).nWidth
);
298 CPPUNIT_ASSERT_EQUAL(aRefCharWidths
[0], aCharWidths
[0]);
299 CPPUNIT_ASSERT_EQUAL(aRefCharWidths
[1], aCharWidths
[1]);
300 // this sporadically returns 75 or 74 on some of the windows tinderboxes eg. tb73
301 CPPUNIT_ASSERT_EQUAL(nRefTextWidth
, nTextWidth
);
302 CPPUNIT_ASSERT_EQUAL(nTextWidth
, tools::Long(aCharWidths
.back()));
304 // text advance width and line height
305 CPPUNIT_ASSERT_EQUAL(nRefTextWidth
, pOutDev
->GetTextWidth(aAV
));
306 CPPUNIT_ASSERT_EQUAL(tools::Long(2384), pOutDev
->GetTextHeight());
308 // exact bounding rectangle, not essentially the same as text width/height
309 tools::Rectangle aBoundRect
;
310 pOutDev
->GetTextBoundRect(aBoundRect
, aAV
);
311 CPPUNIT_ASSERT_EQUAL(tools::Long(16), aBoundRect
.Left());
312 CPPUNIT_ASSERT_EQUAL(tools::Long(408), aBoundRect
.Top());
313 CPPUNIT_ASSERT_EQUAL(tools::Long(2770), aBoundRect
.GetWidth());
314 CPPUNIT_ASSERT_EQUAL(tools::Long(1493), aBoundRect
.getOpenHeight());
316 // normal orientation
317 tools::Rectangle aInput
;
318 tools::Rectangle aRect
= pOutDev
->GetTextRect(aInput
, aAV
);
320 // now rotate 270 degrees
321 vcl::Font
aRotated(aFont
);
322 aRotated
.SetOrientation(2700_deg10
);
323 pOutDev
->SetFont(aRotated
);
324 tools::Rectangle aRectRot
= pOutDev
->GetTextRect(aInput
, aAV
);
326 // Check that we did do the rotation...
327 CPPUNIT_ASSERT_EQUAL(aRectRot
.GetWidth(), aRect
.GetHeight());
328 CPPUNIT_ASSERT_EQUAL(aRectRot
.GetHeight(), aRect
.GetWidth());
331 CPPUNIT_TEST_FIXTURE(VclTextTest
, testTextLayoutCache
)
333 OUString sTestString
= u
"The quick brown fox\n jumped over the lazy dogالعاشر"_ustr
;
334 vcl::text::TextLayoutCache
cache(sTestString
.getStr(), sTestString
.getLength());
336 vcl::text::Run run1
= cache
.runs
[0];
337 vcl::text::Run run2
= cache
.runs
[1];
339 bool bCorrectRuns
= (cache
.runs
.size() == 2);
340 CPPUNIT_ASSERT_MESSAGE("Wrong number of runs", bCorrectRuns
);
341 CPPUNIT_ASSERT_EQUAL(USCRIPT_LATIN
, run1
.nCode
);
342 CPPUNIT_ASSERT_EQUAL(0, run1
.nStart
);
343 CPPUNIT_ASSERT_EQUAL(45, run1
.nEnd
);
344 CPPUNIT_ASSERT_EQUAL(USCRIPT_ARABIC
, run2
.nCode
);
345 CPPUNIT_ASSERT_EQUAL(45, run2
.nStart
);
346 CPPUNIT_ASSERT_EQUAL(51, run2
.nEnd
);
349 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_AddPos
)
351 ImplLayoutRuns aRuns
;
352 aRuns
.AddPos(1, false);
353 aRuns
.AddPos(2, false);
354 aRuns
.AddPos(3, false);
355 aRuns
.AddPos(4, true); // add RTL marker glyph
356 aRuns
.AddPos(5, false);
357 aRuns
.AddPos(6, true); // add RTL marker glyph
358 aRuns
.AddPos(7, false);
361 bool bRightToLeftMarker(false);
363 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
364 CPPUNIT_ASSERT_EQUAL(1, nCharPos
);
365 CPPUNIT_ASSERT(!bRightToLeftMarker
);
367 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
368 CPPUNIT_ASSERT_EQUAL(2, nCharPos
);
369 CPPUNIT_ASSERT(!bRightToLeftMarker
);
371 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
372 CPPUNIT_ASSERT_EQUAL(3, nCharPos
);
373 CPPUNIT_ASSERT(!bRightToLeftMarker
);
375 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
376 CPPUNIT_ASSERT_EQUAL(4, nCharPos
);
377 CPPUNIT_ASSERT(bRightToLeftMarker
);
379 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
380 CPPUNIT_ASSERT_EQUAL(5, nCharPos
);
381 CPPUNIT_ASSERT(!bRightToLeftMarker
);
383 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
384 CPPUNIT_ASSERT_EQUAL(6, nCharPos
);
385 CPPUNIT_ASSERT(bRightToLeftMarker
);
387 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
388 CPPUNIT_ASSERT_EQUAL(7, nCharPos
);
389 CPPUNIT_ASSERT(!bRightToLeftMarker
);
391 // no next position, we are running off the end
392 CPPUNIT_ASSERT(!aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
396 int nMinRunPos
, nEndRunPos
;
397 bool bRightToLeft(false);
399 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
400 CPPUNIT_ASSERT_EQUAL(1, nMinRunPos
);
401 CPPUNIT_ASSERT_EQUAL(4, nEndRunPos
);
402 CPPUNIT_ASSERT(!bRightToLeft
);
405 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
406 CPPUNIT_ASSERT_EQUAL(4, nMinRunPos
);
407 CPPUNIT_ASSERT_EQUAL(5, nEndRunPos
);
408 CPPUNIT_ASSERT(bRightToLeft
);
411 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
412 CPPUNIT_ASSERT_EQUAL(5, nMinRunPos
);
413 CPPUNIT_ASSERT_EQUAL(6, nEndRunPos
);
414 CPPUNIT_ASSERT(!bRightToLeft
);
417 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
418 CPPUNIT_ASSERT_EQUAL(6, nMinRunPos
);
419 CPPUNIT_ASSERT_EQUAL(7, nEndRunPos
);
420 CPPUNIT_ASSERT(bRightToLeft
);
424 CPPUNIT_ASSERT(aRuns
.IsEmpty());
427 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_AddRuns
)
429 ImplLayoutRuns aRuns
;
430 aRuns
.AddRun(1, 4, false);
431 aRuns
.AddRun(5, 4, true);
432 aRuns
.AddRun(5, 6, false);
433 aRuns
.AddRun(6, 7, true);
436 bool bRightToLeftMarker(false);
438 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
439 CPPUNIT_ASSERT_EQUAL(1, nCharPos
);
440 CPPUNIT_ASSERT(!bRightToLeftMarker
);
442 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
443 CPPUNIT_ASSERT_EQUAL(2, nCharPos
);
444 CPPUNIT_ASSERT(!bRightToLeftMarker
);
446 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
447 CPPUNIT_ASSERT_EQUAL(3, nCharPos
);
448 CPPUNIT_ASSERT(!bRightToLeftMarker
);
450 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
451 CPPUNIT_ASSERT_EQUAL(4, nCharPos
);
452 CPPUNIT_ASSERT(bRightToLeftMarker
);
454 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
455 CPPUNIT_ASSERT_EQUAL(5, nCharPos
);
456 CPPUNIT_ASSERT(!bRightToLeftMarker
);
458 CPPUNIT_ASSERT(aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
459 CPPUNIT_ASSERT_EQUAL(6, nCharPos
);
460 CPPUNIT_ASSERT(bRightToLeftMarker
);
462 // no next position, we are running off the end
463 CPPUNIT_ASSERT(!aRuns
.GetNextPos(&nCharPos
, &bRightToLeftMarker
));
467 int nMinRunPos
, nEndRunPos
;
468 bool bRightToLeft(false);
470 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
471 CPPUNIT_ASSERT_EQUAL(1, nMinRunPos
);
472 CPPUNIT_ASSERT_EQUAL(4, nEndRunPos
);
473 CPPUNIT_ASSERT(!bRightToLeft
);
476 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
477 CPPUNIT_ASSERT_EQUAL(4, nMinRunPos
);
478 CPPUNIT_ASSERT_EQUAL(5, nEndRunPos
);
479 CPPUNIT_ASSERT(bRightToLeft
);
482 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
483 CPPUNIT_ASSERT_EQUAL(5, nMinRunPos
);
484 CPPUNIT_ASSERT_EQUAL(6, nEndRunPos
);
485 CPPUNIT_ASSERT(!bRightToLeft
);
488 CPPUNIT_ASSERT(aRuns
.GetRun(&nMinRunPos
, &nEndRunPos
, &bRightToLeft
));
489 CPPUNIT_ASSERT_EQUAL(6, nMinRunPos
);
490 CPPUNIT_ASSERT_EQUAL(7, nEndRunPos
);
491 CPPUNIT_ASSERT(bRightToLeft
);
494 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_PosIsInRun
)
496 ImplLayoutRuns aRuns
;
497 aRuns
.AddRun(1, 4, false);
498 aRuns
.AddRun(4, 5, true);
499 aRuns
.AddRun(5, 6, false);
500 aRuns
.AddRun(6, 7, true);
502 CPPUNIT_ASSERT(aRuns
.PosIsInRun(1));
503 CPPUNIT_ASSERT(aRuns
.PosIsInRun(2));
504 CPPUNIT_ASSERT(aRuns
.PosIsInRun(3));
507 CPPUNIT_ASSERT(aRuns
.PosIsInRun(4));
510 CPPUNIT_ASSERT(aRuns
.PosIsInRun(5));
513 CPPUNIT_ASSERT(aRuns
.PosIsInRun(6));
515 CPPUNIT_ASSERT(!aRuns
.PosIsInRun(7));
518 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_PosIsInAnyRun
)
520 ImplLayoutRuns aRuns
;
521 aRuns
.AddRun(1, 4, false);
522 aRuns
.AddRun(4, 5, true);
523 aRuns
.AddRun(5, 6, false);
524 aRuns
.AddRun(6, 7, true);
526 CPPUNIT_ASSERT(aRuns
.PosIsInAnyRun(1));
527 CPPUNIT_ASSERT(!aRuns
.PosIsInAnyRun(7));
530 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_Normalize
)
532 ImplLayoutRuns aRuns
;
533 aRuns
.AddRun(8, 10, true);
534 aRuns
.AddRun(5, 8, false);
535 aRuns
.AddRun(2, 5, false);
536 aRuns
.AddRun(1, 3, false);
537 aRuns
.AddRun(14, 15, false);
539 CPPUNIT_ASSERT_EQUAL(size_t(5), aRuns
.size());
540 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(8, 10, true), aRuns
.at(0));
541 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(5, 8, false), aRuns
.at(1));
542 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(2, 5, false), aRuns
.at(2));
543 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(1, 3, false), aRuns
.at(3));
544 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(14, 15, false), aRuns
.at(4));
548 CPPUNIT_ASSERT_EQUAL(size_t(2), aRuns
.size());
549 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(1, 10, false), aRuns
.at(0));
550 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(14, 15, false), aRuns
.at(1));
553 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_PrepareFallbackRuns_LTR
)
555 ImplLayoutRuns aRuns
;
556 aRuns
.AddRun(0, 10, false); // First 5 characters excluded
557 aRuns
.AddRun(11, 15, false); // Entire run included
558 aRuns
.AddRun(16, 25, false); // First 4 characters included
559 aRuns
.AddRun(26, 30, false); // Entire run excluded
560 aRuns
.AddRun(31, 35, false); // Exact match
562 CPPUNIT_ASSERT_EQUAL(size_t(5), aRuns
.size());
564 ImplLayoutRuns aFallbackRuns
;
565 aFallbackRuns
.AddRun(5, 20, false);
566 aFallbackRuns
.AddRun(31, 35, false);
568 CPPUNIT_ASSERT_EQUAL(size_t(2), aFallbackRuns
.size());
570 ImplLayoutRuns::PrepareFallbackRuns(&aRuns
, &aFallbackRuns
);
572 CPPUNIT_ASSERT_EQUAL(size_t(0), aFallbackRuns
.size());
574 CPPUNIT_ASSERT_EQUAL(size_t(4), aRuns
.size());
575 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(5, 10, false), aRuns
.at(0));
576 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(11, 15, false), aRuns
.at(1));
577 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(16, 20, false), aRuns
.at(2));
578 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(31, 35, false), aRuns
.at(3));
581 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_PrepareFallbackRuns_LTR_PreservesOrder
)
583 ImplLayoutRuns aRuns
;
584 aRuns
.AddRun(16, 25, false); // First 4 characters included
585 aRuns
.AddRun(31, 35, false); // Exact match
586 aRuns
.AddRun(0, 10, false); // First 5 characters excluded
587 aRuns
.AddRun(26, 30, false); // Entire run excluded
588 aRuns
.AddRun(11, 15, false); // Entire run included
590 CPPUNIT_ASSERT_EQUAL(size_t(5), aRuns
.size());
592 ImplLayoutRuns aFallbackRuns
;
593 aFallbackRuns
.AddRun(5, 20, false);
594 aFallbackRuns
.AddRun(31, 35, false);
596 CPPUNIT_ASSERT_EQUAL(size_t(2), aFallbackRuns
.size());
598 ImplLayoutRuns::PrepareFallbackRuns(&aRuns
, &aFallbackRuns
);
600 CPPUNIT_ASSERT_EQUAL(size_t(0), aFallbackRuns
.size());
602 CPPUNIT_ASSERT_EQUAL(size_t(4), aRuns
.size());
603 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(16, 20, false), aRuns
.at(0));
604 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(31, 35, false), aRuns
.at(1));
605 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(5, 10, false), aRuns
.at(2));
606 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(11, 15, false), aRuns
.at(3));
609 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_PrepareFallbackRuns_RTL
)
611 ImplLayoutRuns aRuns
;
612 aRuns
.AddRun(0, 10, false);
613 aRuns
.AddRun(10, 90, true);
614 aRuns
.AddRun(90, 100, false);
616 CPPUNIT_ASSERT_EQUAL(size_t(3), aRuns
.size());
618 ImplLayoutRuns aFallbackRuns
;
619 aFallbackRuns
.AddRun(0, 5, false);
620 aFallbackRuns
.AddRun(6, 10, false);
621 aFallbackRuns
.AddRun(10, 20, true);
622 aFallbackRuns
.AddRun(21, 30, true);
623 aFallbackRuns
.AddRun(31, 40, true);
624 aFallbackRuns
.AddRun(41, 50, true);
625 aFallbackRuns
.AddRun(92, 95, false);
626 aFallbackRuns
.AddRun(96, 98, false);
628 CPPUNIT_ASSERT_EQUAL(size_t(8), aFallbackRuns
.size());
630 ImplLayoutRuns::PrepareFallbackRuns(&aRuns
, &aFallbackRuns
);
632 CPPUNIT_ASSERT_EQUAL(size_t(0), aFallbackRuns
.size());
634 CPPUNIT_ASSERT_EQUAL(size_t(8), aRuns
.size());
635 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(0, 5, false), aRuns
.at(0));
636 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(6, 10, false), aRuns
.at(1));
637 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(41, 50, true), aRuns
.at(2));
638 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(31, 40, true), aRuns
.at(3));
639 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(21, 30, true), aRuns
.at(4));
640 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(10, 20, true), aRuns
.at(5));
641 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(92, 95, false), aRuns
.at(6));
642 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(96, 98, false), aRuns
.at(7));
645 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_tdf161397
)
647 // Fallback run characteristic test from a particular case
649 ImplLayoutRuns aRuns
;
650 aRuns
.AddRun(0, 13, true);
652 ImplLayoutRuns aFallbackRuns
;
653 aFallbackRuns
.AddRun(12, 13, true);
654 aFallbackRuns
.AddRun(7, 12, true);
655 aFallbackRuns
.AddRun(5, 6, true);
656 aFallbackRuns
.AddRun(0, 5, true);
658 ImplLayoutRuns::PrepareFallbackRuns(&aRuns
, &aFallbackRuns
);
660 CPPUNIT_ASSERT_EQUAL(size_t(2), aRuns
.size());
661 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(7, 13, true), aRuns
.at(0));
662 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(0, 6, true), aRuns
.at(1));
665 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_GrowBidirectional
)
667 ImplLayoutRuns aRuns
;
668 aRuns
.AddPos(16, true);
669 aRuns
.AddPos(17, true);
670 aRuns
.AddPos(18, true);
671 aRuns
.AddPos(15, true);
672 aRuns
.AddPos(19, true);
673 aRuns
.AddPos(14, true);
675 CPPUNIT_ASSERT_EQUAL(size_t(1), aRuns
.size());
676 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(14, 20, true), aRuns
.at(0));
679 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutRuns_ReverseTail
)
681 ImplLayoutRuns aRuns
;
682 aRuns
.AddRun(10, 20, true);
683 aRuns
.AddRun(30, 40, false);
684 aRuns
.AddRun(50, 60, true);
685 aRuns
.AddRun(70, 80, true);
686 aRuns
.AddRun(90, 100, false);
688 aRuns
.ReverseTail(size_t(2));
690 CPPUNIT_ASSERT_EQUAL(size_t(5), aRuns
.size());
691 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(10, 20, true), aRuns
.at(0));
692 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(30, 40, false), aRuns
.at(1));
693 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(90, 100, false), aRuns
.at(2));
694 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(70, 80, true), aRuns
.at(3));
695 CPPUNIT_ASSERT_EQUAL(ImplLayoutRuns::Run(50, 60, true), aRuns
.at(4));
698 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutArgsBiDiStrong
)
700 OUString sTestString
= u
"The quick brown fox\n jumped over the lazy dog"
702 vcl::text::ImplLayoutArgs
aArgs(sTestString
, 0, sTestString
.getLength(),
703 SalLayoutFlags::BiDiStrong
, LanguageTag(LANGUAGE_NONE
),
710 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
711 CPPUNIT_ASSERT_EQUAL(0, nMinRunPos
);
712 CPPUNIT_ASSERT_EQUAL(19, nEndRunPos
);
713 CPPUNIT_ASSERT(!bRTL
);
715 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
716 CPPUNIT_ASSERT_EQUAL(20, nMinRunPos
);
717 CPPUNIT_ASSERT_EQUAL(51, nEndRunPos
);
718 CPPUNIT_ASSERT(!bRTL
);
720 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
721 CPPUNIT_ASSERT_EQUAL(20, nMinRunPos
);
722 CPPUNIT_ASSERT_EQUAL(51, nEndRunPos
);
725 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutArgsBiDiRtl
)
727 OUString sTestString
= u
"The quick brown fox\n jumped over the lazy dog"
729 vcl::text::ImplLayoutArgs
aArgs(sTestString
, 0, sTestString
.getLength(),
730 SalLayoutFlags::BiDiRtl
, LanguageTag(LANGUAGE_NONE
), nullptr);
736 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
737 CPPUNIT_ASSERT_EQUAL(45, nMinRunPos
);
738 CPPUNIT_ASSERT_EQUAL(51, nEndRunPos
);
739 CPPUNIT_ASSERT(&bRTL
);
741 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
742 CPPUNIT_ASSERT_EQUAL(21, nMinRunPos
);
743 CPPUNIT_ASSERT_EQUAL(45, nEndRunPos
);
744 CPPUNIT_ASSERT(!bRTL
);
746 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
747 CPPUNIT_ASSERT_EQUAL(20, nMinRunPos
);
748 CPPUNIT_ASSERT_EQUAL(21, nEndRunPos
);
749 CPPUNIT_ASSERT(bRTL
);
751 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
752 CPPUNIT_ASSERT_EQUAL(0, nMinRunPos
);
753 CPPUNIT_ASSERT_EQUAL(19, nEndRunPos
);
754 CPPUNIT_ASSERT(!bRTL
);
757 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutArgsRightAlign
)
759 OUString sTestString
= u
"The quick brown fox\n jumped over the lazy dog"
761 vcl::text::ImplLayoutArgs
aArgs(sTestString
, 0, sTestString
.getLength(),
762 SalLayoutFlags::RightAlign
, LanguageTag(LANGUAGE_NONE
),
769 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
770 CPPUNIT_ASSERT_EQUAL(0, nMinRunPos
);
771 CPPUNIT_ASSERT_EQUAL(19, nEndRunPos
);
772 CPPUNIT_ASSERT(!bRTL
);
774 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
775 CPPUNIT_ASSERT_EQUAL(20, nMinRunPos
);
776 CPPUNIT_ASSERT_EQUAL(45, nEndRunPos
);
777 CPPUNIT_ASSERT(!bRTL
);
779 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
780 CPPUNIT_ASSERT_EQUAL(45, nMinRunPos
);
781 CPPUNIT_ASSERT_EQUAL(51, nEndRunPos
);
782 CPPUNIT_ASSERT(bRTL
);
785 CPPUNIT_TEST_FIXTURE(VclTextTest
, testImplLayoutArgs_PrepareFallback_precalculatedglyphs
)
787 // this font has no Cyrillic characters and thus needs fallback
788 const vcl::Font
aFont(u
"Amiri"_ustr
, Size(0, 36));
790 ScopedVclPtrInstance
<VirtualDevice
> pVirDev
;
791 pVirDev
->SetFont(aFont
);
793 static constexpr OStringLiteral
sUTF8String(u8
"Тхе яуицк\n ыумпед овер");
794 const OUString
sTestString(OUString::fromUtf8(sUTF8String
));
795 std::unique_ptr
<SalLayout
> pLayout
796 = pVirDev
->ImplLayout(sTestString
, 0, sTestString
.getLength(), Point(0, 0), 0, {}, {},
797 SalLayoutFlags::GlyphItemsOnly
);
798 SalLayoutGlyphs aGlyphs
= pLayout
->GetGlyphs();
799 SalLayoutGlyphsImpl
* pGlyphsImpl
= aGlyphs
.Impl(1);
801 vcl::text::ImplLayoutArgs
aArgs(sTestString
, 0, sTestString
.getLength(),
802 SalLayoutFlags::BiDiRtl
, LanguageTag(LANGUAGE_RUSSIAN
),
805 aArgs
.PrepareFallback(pGlyphsImpl
);
811 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
812 CPPUNIT_ASSERT_EQUAL(0, nMinRunPos
);
813 CPPUNIT_ASSERT_EQUAL(3, nEndRunPos
);
814 CPPUNIT_ASSERT(!bRTL
);
816 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
817 CPPUNIT_ASSERT_EQUAL(4, nMinRunPos
);
818 CPPUNIT_ASSERT_EQUAL(9, nEndRunPos
);
819 CPPUNIT_ASSERT(!bRTL
);
821 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
822 CPPUNIT_ASSERT_EQUAL(11, nMinRunPos
);
823 CPPUNIT_ASSERT_EQUAL(17, nEndRunPos
);
824 CPPUNIT_ASSERT(!bRTL
);
826 aArgs
.GetNextRun(&nMinRunPos
, &nEndRunPos
, &bRTL
);
827 CPPUNIT_ASSERT_EQUAL(18, nMinRunPos
);
828 CPPUNIT_ASSERT_EQUAL(22, nEndRunPos
);
829 CPPUNIT_ASSERT(!bRTL
);
832 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetStringWithCenterEllpsis
)
834 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
835 device
->SetOutputSizePixel(Size(1000, 1000));
836 device
->SetFont(vcl::Font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 11)));
838 CPPUNIT_ASSERT_EQUAL(
839 u
"a b c d ...v w x y z"_ustr
,
840 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,
841 DrawTextFlags::CenterEllipsis
));
844 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetStringWithEndEllpsis
)
846 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
847 device
->SetOutputSizePixel(Size(1000, 1000));
848 device
->SetFont(vcl::Font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 11)));
850 CPPUNIT_ASSERT_EQUAL(u
"a"_ustr
, device
->GetEllipsisString(u
"abcde. f g h i j ..."_ustr
, 10,
851 DrawTextFlags::EndEllipsis
));
853 CPPUNIT_ASSERT_EQUAL(
854 u
"a b c d e f g h i j ..."_ustr
,
855 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,
856 DrawTextFlags::EndEllipsis
));
858 CPPUNIT_ASSERT_EQUAL(
859 u
"a"_ustr
, device
->GetEllipsisString(u
"abcde. f g h i j ..."_ustr
, 1,
860 DrawTextFlags::EndEllipsis
| DrawTextFlags::Clip
));
863 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetStringWithNewsEllpsis
)
865 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
866 device
->SetOutputSizePixel(Size(1000, 1000));
867 device
->SetFont(vcl::Font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 11)));
869 CPPUNIT_ASSERT_EQUAL(u
"a"_ustr
, device
->GetEllipsisString(u
"abcde. f g h i j ..."_ustr
, 10,
870 DrawTextFlags::NewsEllipsis
));
872 CPPUNIT_ASSERT_EQUAL(
873 u
"a b .... x y z"_ustr
,
874 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
,
875 100, DrawTextFlags::NewsEllipsis
));
877 CPPUNIT_ASSERT_EQUAL(
878 u
"a b .... x y z"_ustr
,
879 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
,
880 100, DrawTextFlags::NewsEllipsis
));
882 CPPUNIT_ASSERT_EQUAL(
883 u
"a b c d e f g h i j ..."_ustr
,
884 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,
885 DrawTextFlags::NewsEllipsis
));
887 CPPUNIT_ASSERT_EQUAL(
888 u
"a..... x y z"_ustr
,
889 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
,
890 100, DrawTextFlags::NewsEllipsis
));
892 CPPUNIT_ASSERT_EQUAL(
894 device
->GetEllipsisString(u
"ab. cde. x y z"_ustr
, 50, DrawTextFlags::NewsEllipsis
));
897 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetTextBreak_invalid_index
)
899 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
900 device
->SetOutputSizePixel(Size(1000, 1000));
901 device
->SetFont(vcl::Font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 11)));
903 const OUString
sTestStr(u
"textline_ text_"_ustr
);
904 const auto nLen
= sTestStr
.getLength();
905 const auto nTextWidth
= device
->GetTextWidth(u
"text"_ustr
);
906 const auto nInvalidIndex
= sTestStr
.getLength() + 2;
908 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(-1),
909 device
->GetTextBreak(sTestStr
, nTextWidth
, nInvalidIndex
, nLen
));
912 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetTextBreak
)
914 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
915 device
->SetOutputSizePixel(Size(1000, 1000));
916 device
->SetFont(vcl::Font(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 11)));
918 const OUString
sTestStr(u
"textline_ text_"_ustr
);
919 const auto nLen
= sTestStr
.getLength();
920 const auto nTextWidth
= device
->GetTextWidth(u
"text"_ustr
);
922 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(4),
923 device
->GetTextBreak(sTestStr
, nTextWidth
, 0, nLen
));
924 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(7),
925 device
->GetTextBreak(sTestStr
, nTextWidth
, 3, nLen
));
926 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(9),
927 device
->GetTextBreak(sTestStr
, nTextWidth
, 6, nLen
));
928 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(12),
929 device
->GetTextBreak(sTestStr
, nTextWidth
, 8, nLen
));
930 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(14),
931 device
->GetTextBreak(sTestStr
, nTextWidth
, 11, nLen
));
932 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(-1),
933 device
->GetTextBreak(sTestStr
, nTextWidth
, 13, nLen
));
936 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetSingleLineTextRect
)
938 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
939 device
->SetOutputSizePixel(Size(1000, 1000));
940 device
->SetFont(vcl::Font(u
"Liberation Sans"_ustr
, Size(0, 11)));
942 CPPUNIT_ASSERT_EQUAL(
943 tools::Rectangle(Point(), Size(75, 12)),
944 device
->GetTextRect(tools::Rectangle(Point(), Point(100, 100)), u
"This is test text"_ustr
));
947 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetSingleLineTextRectWithEndEllipsis
)
949 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
950 device
->SetOutputSizePixel(Size(1000, 1000));
951 device
->SetFont(vcl::Font(u
"Liberation Sans"_ustr
, Size(0, 11)));
953 CPPUNIT_ASSERT_EQUAL(
954 tools::Rectangle(Point(), Size(52, 12)),
955 device
->GetTextRect(tools::Rectangle(Point(), Point(50, 50)), u
"This is test text"_ustr
,
956 DrawTextFlags::WordBreak
| DrawTextFlags::EndEllipsis
));
959 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetRightBottomAlignedSingleLineTextRect
)
961 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
962 device
->SetOutputSizePixel(Size(1000, 1000));
963 device
->SetFont(vcl::Font(u
"Liberation Sans"_ustr
, Size(0, 11)));
965 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(926, 989), Size(75, 12)),
966 device
->GetTextRect(tools::Rectangle(Point(), Point(1000, 1000)),
967 u
"This is test text"_ustr
,
968 DrawTextFlags::Right
| DrawTextFlags::Bottom
));
971 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetRotatedSingleLineTextRect
)
973 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
974 device
->SetOutputSizePixel(Size(1000, 1000));
975 device
->SetFont(vcl::Font(u
"Liberation Sans"_ustr
, Size(0, 11)));
977 vcl::Font
aFont(device
->GetFont());
978 aFont
.SetOrientation(45_deg10
);
979 device
->SetFont(aFont
);
981 CPPUNIT_ASSERT_EQUAL(
982 tools::Rectangle(Point(0, -3), Size(75, 18)),
983 device
->GetTextRect(tools::Rectangle(Point(), Point(100, 100)), u
"This is test text"_ustr
));
986 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetMultiLineTextRect
)
988 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
989 device
->SetOutputSizePixel(Size(1000, 1000));
990 device
->SetFont(vcl::Font(u
"Liberation Sans"_ustr
, Size(0, 11)));
992 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(), Size(75, 12)),
993 device
->GetTextRect(tools::Rectangle(Point(), Point(100, 100)),
994 u
"This is test text"_ustr
,
995 DrawTextFlags::WordBreak
| DrawTextFlags::MultiLine
));
998 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetMultiLineTextRectWithEndEllipsis
)
1000 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
1001 device
->SetOutputSizePixel(Size(1000, 1000));
1002 device
->SetFont(vcl::Font(u
"Liberation Sans"_ustr
, Size(0, 11)));
1004 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(), Size(52, 48)),
1005 device
->GetTextRect(tools::Rectangle(Point(), Point(50, 50)),
1006 u
"This is test text xyzabc123abcdefghijk"_ustr
,
1007 DrawTextFlags::WordBreak
| DrawTextFlags::EndEllipsis
1008 | DrawTextFlags::MultiLine
));
1011 CPPUNIT_TEST_FIXTURE(VclTextTest
, testGetRightBottomAlignedMultiLineTextRect
)
1013 ScopedVclPtr
<VirtualDevice
> device
= VclPtr
<VirtualDevice
>::Create(DeviceFormat::WITHOUT_ALPHA
);
1014 device
->SetOutputSizePixel(Size(1000, 1000));
1015 device
->SetFont(vcl::Font(u
"Liberation Sans"_ustr
, Size(0, 11)));
1017 CPPUNIT_ASSERT_EQUAL(tools::Rectangle(Point(926, 989), Size(75, 12)),
1018 device
->GetTextRect(tools::Rectangle(Point(), Point(1000, 1000)),
1019 u
"This is test text"_ustr
,
1020 DrawTextFlags::Right
| DrawTextFlags::Bottom
1021 | DrawTextFlags::MultiLine
));
1024 CPPUNIT_TEST_FIXTURE(VclTextTest
, testPartialTextArraySizeMatch
)
1026 OUString aWater
= u
"Water"_ustr
;
1027 vcl::Font
aFont(u
"DejaVu Sans"_ustr
, u
"Book"_ustr
, Size(0, 2048));
1029 ScopedVclPtrInstance
<VirtualDevice
> pOutDev
;
1030 pOutDev
->SetFont(aFont
);
1032 // Absolute character widths for the complete array.
1033 KernArray aCompleteWidths
;
1034 auto nCompleteWidth
= pOutDev
->GetTextArray(aWater
, &aCompleteWidths
).nWidth
;
1036 CPPUNIT_ASSERT_EQUAL(size_t{ 5 }, aCompleteWidths
.size());
1038 // Accumulate partial widths
1039 double nPartialWidth
= 0.0;
1041 sal_Int32 nPrevWidth
= 0;
1042 for (sal_Int32 i
= 0; i
< 5; ++i
)
1044 KernArray aFragmentWidths
;
1047 ->GetPartialTextArray(aWater
, &aFragmentWidths
, /*nIndex*/ 0, /*nLen*/ 5,
1048 /*nPartIndex*/ i
, /*nPartLen*/ 1)
1050 nPartialWidth
+= nFragmentWidth
;
1052 CPPUNIT_ASSERT_EQUAL(size_t{ 1 }, aFragmentWidths
.size());
1053 CPPUNIT_ASSERT_EQUAL(aCompleteWidths
[i
] - nPrevWidth
, aFragmentWidths
[0]);
1054 nPrevWidth
= aCompleteWidths
[i
];
1057 CPPUNIT_ASSERT_DOUBLES_EQUAL(nCompleteWidth
, nPartialWidth
, /*delta*/ 0.01);
1060 CPPUNIT_PLUGIN_IMPLEMENT();
1062 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */