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