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 <config_features.h>
14 #include <tools/long.hxx>
17 // must be declared before inclusion of test/bootstrapfixture.hxx
18 static std::ostream
& operator<<(std::ostream
& rStream
, const std::vector
<tools::Long
>& rVec
);
20 #include <test/bootstrapfixture.hxx>
22 #include <vcl/wrkwin.hxx>
23 #include <vcl/virdev.hxx>
24 // workaround MSVC2015 issue with std::unique_ptr
25 #include <sallayout.hxx>
29 static std::ostream
& operator<<(std::ostream
& rStream
, const std::vector
<tools::Long
>& rVec
)
32 for (size_t i
= 0; i
< rVec
.size() - 1; i
++)
33 rStream
<< rVec
[i
] << ", ";
34 rStream
<< rVec
.back();
40 class VclComplexTextTest
: public test::BootstrapFixture
43 VclComplexTextTest() : BootstrapFixture(true, false) {}
45 /// Play with font measuring etc.
48 void testTdf95650(); // Windows-only issue
50 CPPUNIT_TEST_SUITE(VclComplexTextTest
);
51 CPPUNIT_TEST(testArabic
);
52 CPPUNIT_TEST(testKashida
);
53 CPPUNIT_TEST(testTdf95650
);
54 CPPUNIT_TEST_SUITE_END();
57 void VclComplexTextTest::testArabic()
60 const unsigned char pOneTwoThreeUTF8
[] = {
61 0xd9, 0x88, 0xd8, 0xa7, 0xd8, 0xad, 0xd9, 0x90,
62 0xd8, 0xaf, 0xd9, 0x92, 0x20, 0xd8, 0xa5, 0xd8,
63 0xab, 0xd9, 0x8d, 0xd9, 0x86, 0xd9, 0x8a, 0xd9,
64 0x86, 0x20, 0xd8, 0xab, 0xd9, 0x84, 0xd8, 0xa7,
65 0xd8, 0xab, 0xd8, 0xa9, 0xd9, 0x8c, 0x00
67 OUString
aOneTwoThree( reinterpret_cast<char const *>(pOneTwoThreeUTF8
),
68 SAL_N_ELEMENTS( pOneTwoThreeUTF8
) - 1,
69 RTL_TEXTENCODING_UTF8
);
70 ScopedVclPtrInstance
<WorkWindow
> pWin(static_cast<vcl::Window
*>(nullptr));
71 CPPUNIT_ASSERT( pWin
);
73 vcl::Font
aFont("DejaVu Sans", "Book", Size(0, 12));
75 OutputDevice
*pOutDev
= pWin
.get();
76 pOutDev
->SetFont( aFont
);
78 // absolute character widths AKA text array.
79 std::vector
<tools::Long
> aRefCharWidths
{6, 9, 16, 16, 22, 22, 26, 29, 32, 32,
80 36, 40, 49, 53, 56, 63, 63, 66, 72, 72};
81 std::vector
<tools::Long
> aCharWidths(aOneTwoThree
.getLength(), 0);
82 tools::Long nTextWidth
= pOutDev
->GetTextArray(aOneTwoThree
, aCharWidths
.data());
84 CPPUNIT_ASSERT_EQUAL(aRefCharWidths
, aCharWidths
);
85 // this sporadically returns 75 or 74 on some of the windows tinderboxes eg. tb73
86 CPPUNIT_ASSERT_EQUAL(tools::Long(72), nTextWidth
);
87 CPPUNIT_ASSERT_EQUAL(nTextWidth
, aCharWidths
.back());
89 // text advance width and line height
90 CPPUNIT_ASSERT_EQUAL(tools::Long(72), pOutDev
->GetTextWidth(aOneTwoThree
));
91 CPPUNIT_ASSERT_EQUAL(tools::Long(14), pOutDev
->GetTextHeight());
93 // exact bounding rectangle, not essentially the same as text width/height
94 tools::Rectangle aBoundRect
;
95 pOutDev
->GetTextBoundRect(aBoundRect
, aOneTwoThree
);
96 CPPUNIT_ASSERT_DOUBLES_EQUAL(0, aBoundRect
.getX(), 1); // This sometimes equals to 1
97 CPPUNIT_ASSERT_DOUBLES_EQUAL(1, aBoundRect
.getY(), 1);
98 CPPUNIT_ASSERT_DOUBLES_EQUAL(71, aBoundRect
.getWidth(), 1); // This sometimes equals to 70
99 CPPUNIT_ASSERT_DOUBLES_EQUAL(15, aBoundRect
.getHeight(), 1);
102 // FIXME: This seems to be wishful thinking, GetTextRect() does not take
103 // rotation into account.
105 // normal orientation
106 tools::Rectangle aInput
;
107 tools::Rectangle aRect
= pOutDev
->GetTextRect( aInput
, aOneTwoThree
);
109 // now rotate 270 degrees
110 vcl::Font
aRotated( aFont
);
111 aRotated
.SetOrientation( 2700 );
112 pOutDev
->SetFont( aRotated
);
113 tools::Rectangle aRectRot
= pOutDev
->GetTextRect( aInput
, aOneTwoThree
);
115 // Check that we did do the rotation...
116 fprintf( stderr
, "%" SAL_PRIdINT64
" %" SAL_PRIdINT64
" %" SAL_PRIdINT64
" %" SAL_PRIdINT64
"\n",
117 sal_Int64(aRect
.GetWidth()), sal_Int64(aRect
.GetHeight()),
118 sal
-Int64(aRectRot
.GetWidth()), sal_Int64(aRectRot
.GetHeight()) );
119 CPPUNIT_ASSERT( aRectRot
.GetWidth() == aRect
.GetHeight() );
120 CPPUNIT_ASSERT( aRectRot
.GetHeight() == aRect
.GetWidth() );
125 void VclComplexTextTest::testKashida()
128 // Cache the glyph list of some Arabic text.
129 ScopedVclPtrInstance
<VirtualDevice
> pOutputDevice
;
131 = OUString::fromUtf8(u8
"ﻊﻨﺻﺭ ﺎﻠﻓﻮﺴﻓﻭﺭ ﻊﻨﺻﺭ ﻒﻟﺰﻳ ﺺﻠﺑ. ﺖﺘﻛﻮﻧ ﺎﻟﺩﻭﺭﺓ ﺎﻟﺭﺎﺒﻋﺓ ﻢﻧ ١٥ ﻊﻨﺻﺭﺍ.");
132 std::unique_ptr
<SalLayout
> pLayout
= pOutputDevice
->ImplLayout(
133 aText
, 0, aText
.getLength(), Point(0, 0), 0, nullptr, SalLayoutFlags::GlyphItemsOnly
);
134 const SalLayoutGlyphs
* pGlyphs
= pLayout
->GetGlyphs();
136 // Failed in some non-interesting ways.
138 SalLayoutGlyphs aGlyphs
= *pGlyphs
;
140 // Now lay it out using the cached glyph list.
141 ImplLayoutArgs
aLayoutArgs(aText
, 0, aText
.getLength(), SalLayoutFlags::NONE
,
142 pOutputDevice
->GetFont().GetLanguageTag(), nullptr);
143 pLayout
= pOutputDevice
->GetGraphics()->GetTextLayout(0);
144 CPPUNIT_ASSERT(pLayout
->LayoutText(aLayoutArgs
, &aGlyphs
));
146 // Without the accompanying fix in place, this test would have failed with 'assertion failed'.
147 // The kashida justification flag was lost when going via the glyph cache.
148 CPPUNIT_ASSERT(aLayoutArgs
.mnFlags
& SalLayoutFlags::KashidaJustification
);
152 void VclComplexTextTest::testTdf95650()
154 const sal_Unicode pTxt
[] = {
155 0x0131, 0x0302, 0x0504, 0x4E44, 0x3031, 0x3030, 0x3531, 0x2D30,
156 0x3037, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E, 0x072E, 0x100A,
157 0x0D11, 0x1312, 0x0105, 0x020A, 0x0512, 0x1403, 0x030C, 0x1528,
158 0x2931, 0x632E, 0x7074, 0x0D20, 0x0E0A, 0x100A, 0xF00D, 0x0D20,
159 0x030A, 0x0C0B, 0x20E0, 0x0A0D
161 OUString
aTxt(pTxt
, SAL_N_ELEMENTS(pTxt
) - 1);
162 ScopedVclPtrInstance
<WorkWindow
> pWin(static_cast<vcl::Window
*>(nullptr));
163 CPPUNIT_ASSERT(pWin
);
165 OutputDevice
*pOutDev
= pWin
.get();
166 // Check that the following executes without failing assertion
167 pOutDev
->ImplLayout(aTxt
, 9, 1, Point(), 0, nullptr, SalLayoutFlags::BiDiRtl
);
170 CPPUNIT_TEST_SUITE_REGISTRATION(VclComplexTextTest
);
172 CPPUNIT_PLUGIN_IMPLEMENT();
174 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */