1 /* 2 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * 4 * This is part of HarfBuzz, an OpenType Layout engine library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 */ 24 25 /* 26 !!!!!! Warning !!!!! 27 Please don't save this file in emacs. It contains utf8 text sequences emacs will 28 silently convert to a series of question marks. 29 */ 30 #include <QtTest/QtTest> 31 #include <QtCore/qdebug.h> 32 33 #include <harfbuzz-shaper.h> 34 35 static QVector<HB_CharAttributes> getCharAttributes(const QString &str, HB_Script script = HB_Script_Common) 36 { 37 QVector<HB_CharAttributes> attrs(str.length()); 38 HB_ScriptItem item; 39 item.pos = 0; 40 item.length = str.length(); 41 item.script = script; 42 HB_GetCharAttributes(str.utf16(), str.length(), 43 &item, 1, 44 attrs.data()); 45 return attrs; 46 } 47 48 class tst_CharAttributes : public QObject 49 { 50 Q_OBJECT 51 52 public: 53 tst_CharAttributes(); 54 virtual ~tst_CharAttributes(); 55 56 public slots: 57 void init(); 58 void cleanup(); 59 private slots: 60 void lineBreaking(); 61 void charWordStopOnLineSeparator(); 62 void charStopForSurrogatePairs(); 63 void thaiWordBreak(); 64 }; 65 66 67 tst_CharAttributes::tst_CharAttributes() 68 { 69 } 70 71 tst_CharAttributes::~tst_CharAttributes() 72 { 73 } 74 75 void tst_CharAttributes::init() 76 { 77 } 78 79 void tst_CharAttributes::cleanup() 80 { 81 } 82 83 84 void tst_CharAttributes::lineBreaking() 85 { 86 struct Breaks { 87 const char *utf8; 88 uchar breaks[32]; 89 }; 90 Breaks brks[] = { 91 { "11", { false, 0xff } }, 92 { "aa", { false, 0xff } }, 93 { "++", { false, 0xff } }, 94 { "--", { false, 0xff } }, 95 { "((", { false, 0xff } }, 96 { "))", { false, 0xff } }, 97 { "..", { false, 0xff } }, 98 { "\"\"", { false, 0xff } }, 99 { "$$", { false, 0xff } }, 100 { "!!", { false, 0xff } }, 101 { "??", { false, 0xff } }, 102 { ",,", { false, 0xff } }, 103 104 { ")()", { true, false, 0xff } }, 105 { "?!?", { false, false, 0xff } }, 106 { ".,.", { false, false, 0xff } }, 107 { "+-+", { false, false, 0xff } }, 108 { "+=+", { false, false, 0xff } }, 109 { "+(+", { false, false, 0xff } }, 110 { "+)+", { false, false, 0xff } }, 111 112 { "a b", { false, true, 0xff } }, 113 { "a(b", { false, false, 0xff } }, 114 { "a)b", { false, false, 0xff } }, 115 { "a-b", { false, true, 0xff } }, 116 { "a.b", { false, false, 0xff } }, 117 { "a+b", { false, false, 0xff } }, 118 { "a?b", { false, false, 0xff } }, 119 { "a!b", { false, false, 0xff } }, 120 { "a$b", { false, false, 0xff } }, 121 { "a,b", { false, false, 0xff } }, 122 { "a/b", { false, false, 0xff } }, 123 { "1/2", { false, false, 0xff } }, 124 { "./.", { false, false, 0xff } }, 125 { ",/,", { false, false, 0xff } }, 126 { "!/!", { false, false, 0xff } }, 127 { "\\/\\", { false, false, 0xff } }, 128 { "1 2", { false, true, 0xff } }, 129 { "1(2", { false, false, 0xff } }, 130 { "1)2", { false, false, 0xff } }, 131 { "1-2", { false, false, 0xff } }, 132 { "1.2", { false, false, 0xff } }, 133 { "1+2", { false, false, 0xff } }, 134 { "1?2", { false, true, 0xff } }, 135 { "1!2", { false, true, 0xff } }, 136 { "1$2", { false, false, 0xff } }, 137 { "1,2", { false, false, 0xff } }, 138 { "1/2", { false, false, 0xff } }, 139 { "\330\260\331\216\331\204\331\220\331\203\331\216", { false, false, false, false, false, 0xff } }, 140 { "\330\247\331\204\331\205 \330\247\331\204\331\205", { false, false, false, true, false, false, 0xff } }, 141 { "1#2", { false, false, 0xff } }, 142 { "!#!", { false, false, 0xff } }, 143 { 0, {} } 144 }; 145 Breaks *b = brks; 146 while (b->utf8) { 147 QString str = QString::fromUtf8(b->utf8); 148 149 QVector<HB_CharAttributes> attrs = getCharAttributes(str); 150 151 int i; 152 for (i = 0; i < (int)str.length() - 1; ++i) { 153 QVERIFY(b->breaks[i] != 0xff); 154 if ( (attrs[i].lineBreakType != HB_NoBreak) != (bool)b->breaks[i] ) { 155 qDebug("test case \"%s\" failed at char %d; break type: %d", b->utf8, i, attrs[i].lineBreakType); 156 QCOMPARE( (attrs[i].lineBreakType != HB_NoBreak), (bool)b->breaks[i] ); 157 } 158 } 159 QVERIFY(attrs[i].lineBreakType == HB_ForcedBreak); 160 QCOMPARE(b->breaks[i], (uchar)0xff); 161 ++b; 162 } 163 } 164 165 void tst_CharAttributes::charWordStopOnLineSeparator() 166 { 167 const QChar lineSeparator(QChar::LineSeparator); 168 QString txt; 169 txt.append(lineSeparator); 170 txt.append(lineSeparator); 171 QVector<HB_CharAttributes> attrs = getCharAttributes(txt); 172 QVERIFY(attrs[1].charStop); 173 } 174 175 void tst_CharAttributes::charStopForSurrogatePairs() 176 { 177 QString txt; 178 txt.append("a"); 179 txt.append(0xd87e); 180 txt.append(0xdc25); 181 txt.append("b"); 182 QVector<HB_CharAttributes> attrs = getCharAttributes(txt); 183 QVERIFY(attrs[0].charStop); 184 QVERIFY(attrs[1].charStop); 185 QVERIFY(!attrs[2].charStop); 186 QVERIFY(attrs[3].charStop); 187 } 188 189 void tst_CharAttributes::thaiWordBreak() 190 { 191 // 192 QTextCodec *codec = QTextCodec::codecForMib(2259); 193 QString txt = codec->toUnicode(QByteArray("\xca\xc7\xd1\xca\xb4\xd5\xa4\xc3\xd1\xba\x20\xb9\xd5\xe8\xe0\xbb\xe7\xb9\xa1\xd2\xc3\xb7\xb4\xca\xcd\xba\xb5\xd1\xc7\xe0\xcd\xa7")); 194 195 196 QCOMPARE(txt.length(), 32); 197 QVector<HB_CharAttributes> attrs = getCharAttributes(txt, HB_Script_Thai); 198 QVERIFY(attrs[0].lineBreakType == HB_NoBreak); 199 QVERIFY(attrs[1].lineBreakType == HB_NoBreak); 200 QVERIFY(attrs[2].lineBreakType == HB_NoBreak); 201 QVERIFY(attrs[3].lineBreakType == HB_NoBreak); 202 QVERIFY(attrs[4].lineBreakType == HB_NoBreak); 203 QVERIFY(attrs[5].lineBreakType == HB_Break); 204 QVERIFY(attrs[6].lineBreakType == HB_NoBreak); 205 QVERIFY(attrs[7].lineBreakType == HB_NoBreak); 206 QVERIFY(attrs[8].lineBreakType == HB_NoBreak); 207 QVERIFY(attrs[9].lineBreakType == HB_NoBreak); 208 QVERIFY(attrs[10].lineBreakType == HB_Break); 209 QVERIFY(attrs[11].lineBreakType == HB_NoBreak); 210 QVERIFY(attrs[12].lineBreakType == HB_NoBreak); 211 QVERIFY(attrs[13].lineBreakType == HB_Break); 212 QVERIFY(attrs[14].lineBreakType == HB_NoBreak); 213 QVERIFY(attrs[15].lineBreakType == HB_NoBreak); 214 QVERIFY(attrs[16].lineBreakType == HB_NoBreak); 215 QVERIFY(attrs[17].lineBreakType == HB_Break); 216 QVERIFY(attrs[18].lineBreakType == HB_NoBreak); 217 QVERIFY(attrs[19].lineBreakType == HB_NoBreak); 218 QVERIFY(attrs[20].lineBreakType == HB_Break); 219 QVERIFY(attrs[21].lineBreakType == HB_NoBreak); 220 QVERIFY(attrs[22].lineBreakType == HB_NoBreak); 221 QVERIFY(attrs[23].lineBreakType == HB_NoBreak); 222 QVERIFY(attrs[24].lineBreakType == HB_NoBreak); 223 QVERIFY(attrs[25].lineBreakType == HB_Break); 224 QVERIFY(attrs[26].lineBreakType == HB_NoBreak); 225 for (int i = 27; i < 32; ++i) 226 QVERIFY(attrs[i].lineBreakType == HB_NoBreak); 227 } 228 229 QTEST_MAIN(tst_CharAttributes) 230 #include "main.moc" 231