This set of changes is to enable the capability of setting a fragment's visibility...
[qt:ganesh-qt.git] / tests / auto / qtextlayout / tst_qtextlayout.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 /*
44     !!!!!! Warning !!!!!
45     Please don't save this file in emacs. It contains utf8 text sequences emacs will
46     silently convert to a series of question marks.
47  */
48 #include <QtTest/QtTest>
49
50
51
52 #include <private/qtextengine_p.h>
53 #include <qtextlayout.h>
54 #include <QTextCursor>
55 #include <qdebug.h>
56
57
58 #define TESTFONT_SIZE 12
59
60 //TESTED_CLASS=
61 //TESTED_FILES=
62
63 class tst_QTextLayout : public QObject
64 {
65     Q_OBJECT
66
67 public:
68     tst_QTextLayout();
69     virtual ~tst_QTextLayout();
70
71
72 public slots:
73     void init();
74     void cleanup();
75 private slots:
76     void getSetCheck();
77     void lineBreaking();
78     void simpleBoundingRect();
79     void threeLineBoundingRect();
80     void boundingRectWithLongLineAndNoWrap();
81     void forcedBreaks();
82     void breakAny();
83     void noWrap();
84     void cursorToXForInlineObjects();
85     void cursorToXForSetColumns();
86     void defaultWordSeparators_data();
87     void defaultWordSeparators();
88     void cursorMovementInsideSpaces();
89     void charWordStopOnLineSeparator();
90     void xToCursorAtEndOfLine();
91     void boundingRectTopLeft();
92     void charStopForSurrogatePairs();
93     void tabStops();
94     void integerOverflow();
95     void testDefaultTabs();
96     void testTabs();
97     void testMultilineTab();
98     void testRightTab();
99     void testTabsInAlignedParag();
100     void testCenteredTab();
101     void testDelimiterTab();
102     void testMultiTab();
103     void testTabDPIScale();
104     void tabsForRtl();
105     void tabHeight();
106     void capitalization_allUpperCase();
107     void capitalization_allLowerCase();
108     void capitalization_smallCaps();
109     void capitalization_capitalize();
110     void longText();
111     void widthOfTabs();
112     void columnWrapWithTabs();
113
114     // QTextLine stuff
115     void setNumColumnsWrapAtWordBoundaryOrAnywhere();
116     void setNumColumnsWordWrap();
117     void smallTextLengthNoWrap();
118     void smallTextLengthWordWrap();
119     void smallTextLengthWrapAtWordBoundaryOrAnywhere();
120     void testLineBreakingAllSpaces();
121     void lineWidthFromBOM();
122     void testFragmentVisibility();
123
124 private:
125     QFont testFont;
126 };
127
128 // Testing get/set functions
129 void tst_QTextLayout::getSetCheck()
130 {
131     QString str("Bogus text");
132     QTextLayout layout(str, testFont);
133     layout.beginLayout();
134     QTextEngine *engine = layout.engine();
135     QTextInlineObject obj1(0, engine);
136     // qreal QTextInlineObject::width()
137     // void QTextInlineObject::setWidth(qreal)
138     obj1.setWidth(0.0);
139     QCOMPARE(0.0, obj1.width());
140     obj1.setWidth(1.2);
141     QVERIFY(1.0 < obj1.width());
142
143     // qreal QTextInlineObject::ascent()
144     // void QTextInlineObject::setAscent(qreal)
145     obj1.setAscent(0.0);
146     QCOMPARE(0.0, obj1.ascent());
147     obj1.setAscent(1.2);
148     QVERIFY(1.0 < obj1.ascent());
149
150     // qreal QTextInlineObject::descent()
151     // void QTextInlineObject::setDescent(qreal)
152     obj1.setDescent(0.0);
153     QCOMPARE(0.0, obj1.descent());
154     obj1.setDescent(1.2);
155     QVERIFY(1.0 < obj1.descent());
156
157     QTextLayout obj2;
158     // bool QTextLayout::cacheEnabled()
159     // void QTextLayout::setCacheEnabled(bool)
160     obj2.setCacheEnabled(false);
161     QCOMPARE(false, obj2.cacheEnabled());
162     obj2.setCacheEnabled(true);
163     QCOMPARE(true, obj2.cacheEnabled());
164 }
165
166 QT_BEGIN_NAMESPACE
167 extern void qt_setQtEnableTestFont(bool value);
168 QT_END_NAMESPACE
169
170 tst_QTextLayout::tst_QTextLayout()
171 {
172     qt_setQtEnableTestFont(true);
173 }
174
175 tst_QTextLayout::~tst_QTextLayout()
176 {
177 }
178
179 void tst_QTextLayout::init()
180 {
181     testFont = QFont();
182     testFont.setFamily("__Qt__Box__Engine__");
183     testFont.setPixelSize(TESTFONT_SIZE);
184     testFont.setWeight(QFont::Normal);
185     QCOMPARE(QFontMetrics(testFont).width('a'), testFont.pixelSize());
186 }
187
188 void tst_QTextLayout::cleanup()
189 {
190     testFont = QFont();
191 }
192
193
194 void tst_QTextLayout::lineBreaking()
195 {
196 #if defined(Q_WS_X11)
197     struct Breaks {
198         const char *utf8;
199         uchar breaks[32];
200     };
201     Breaks brks[] = {
202         { "11", { false, 0xff } },
203         { "aa", { false, 0xff } },
204         { "++", { false, 0xff } },
205         { "--", { false, 0xff } },
206         { "((", { false, 0xff } },
207         { "))", { false, 0xff } },
208         { "..", { false, 0xff } },
209         { "\"\"", { false, 0xff } },
210         { "$$", { false, 0xff } },
211         { "!!", { false, 0xff } },
212         { "??", { false, 0xff } },
213         { ",,", { false, 0xff } },
214
215         { ")()", { true, false, 0xff } },
216         { "?!?", { false, false, 0xff } },
217         { ".,.", { false, false, 0xff } },
218         { "+-+", { false, false, 0xff } },
219         { "+=+", { false, false, 0xff } },
220         { "+(+", { false, false, 0xff } },
221         { "+)+", { false, false, 0xff } },
222
223         { "a b", { false, true, 0xff } },
224         { "a(b", { false, false, 0xff } },
225         { "a)b", { false, false, 0xff } },
226         { "a-b", { false, true, 0xff } },
227         { "a.b", { false, false, 0xff } },
228         { "a+b", { false, false, 0xff } },
229         { "a?b", { false, false, 0xff } },
230         { "a!b", { false, false, 0xff } },
231         { "a$b", { false, false, 0xff } },
232         { "a,b", { false, false, 0xff } },
233         { "a/b", { false, false, 0xff } },
234         { "1/2", { false, false, 0xff } },
235         { "./.", { false, false, 0xff } },
236         { ",/,", { false, false, 0xff } },
237         { "!/!", { false, false, 0xff } },
238         { "\\/\\", { false, false, 0xff } },
239         { "1 2", { false, true, 0xff } },
240         { "1(2", { false, false, 0xff } },
241         { "1)2", { false, false, 0xff } },
242         { "1-2", { false, false, 0xff } },
243         { "1.2", { false, false, 0xff } },
244         { "1+2", { false, false, 0xff } },
245         { "1?2", { false, true, 0xff } },
246         { "1!2", { false, true, 0xff } },
247         { "1$2", { false, false, 0xff } },
248         { "1,2", { false, false, 0xff } },
249         { "1/2", { false, false, 0xff } },
250         { "\330\260\331\216\331\204\331\220\331\203\331\216", { false, false, false, false, false, 0xff } },
251         { "\330\247\331\204\331\205 \330\247\331\204\331\205", { false, false, false, true, false, false, 0xff } },
252         { "1#2", { false, false, 0xff } },
253         { "!#!", { false, false, 0xff } },
254         { 0, {} }
255     };
256     Breaks *b = brks;
257     while (b->utf8) {
258         QString str = QString::fromUtf8(b->utf8);
259         QTextEngine engine(str, QFont());
260         const HB_CharAttributes *attrs = engine.attributes();
261         int i;
262         for (i = 0; i < (int)str.length() - 1; ++i) {
263             QVERIFY(b->breaks[i] != 0xff);
264             if ( (attrs[i].lineBreakType != HB_NoBreak) != (bool)b->breaks[i] ) {
265                 qDebug("test case \"%s\" failed at char %d; break type: %d", b->utf8, i, attrs[i].lineBreakType);
266                 QCOMPARE( (attrs[i].lineBreakType != HB_NoBreak), (bool)b->breaks[i] );
267             }
268         }
269         QVERIFY(attrs[i].lineBreakType == HB_ForcedBreak);
270         QCOMPARE(b->breaks[i], (uchar)0xff);
271         ++b;
272     }
273 #else
274     QSKIP("This test can not be run on non-X11 platforms", SkipAll);
275 #endif
276 }
277
278 void tst_QTextLayout::simpleBoundingRect()
279 {
280     /* just check if boundingRect() gives sane values. The text is not broken. */
281
282     QString hello("hello world");
283
284     const int width = hello.length() * testFont.pixelSize();
285
286     QTextLayout layout(hello, testFont);
287     layout.beginLayout();
288
289     QTextLine line = layout.createLine();
290     line.setLineWidth(width);
291     QCOMPARE(line.textLength(), hello.length());
292     QCOMPARE(layout.boundingRect(), QRectF(0, 0, width, QFontMetrics(testFont).height()));
293 }
294
295 void tst_QTextLayout::threeLineBoundingRect()
296 {
297 #if defined(Q_WS_MAC)
298     QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll);
299 #endif
300     /* stricter check. break text into three lines */
301
302     QString firstWord("hello");
303     QString secondWord("world");
304     QString thirdWord("test");
305     QString text(firstWord + ' ' + secondWord + ' ' + thirdWord);
306
307     const int firstLineWidth = firstWord.length() * testFont.pixelSize();
308     const int secondLineWidth = secondWord.length() * testFont.pixelSize();
309     const int thirdLineWidth = thirdWord.length() * testFont.pixelSize();
310
311     const int longestLine = qMax(firstLineWidth, qMax(secondLineWidth, thirdLineWidth));
312
313     QTextLayout layout(text, testFont);
314     layout.beginLayout();
315
316     int pos = 0;
317     int y = 0;
318     QTextLine line = layout.createLine();
319     line.setLineWidth(firstLineWidth);
320     line.setPosition(QPoint(0, y));
321     QCOMPARE(line.textStart(), pos);
322     // + 1 for trailing space
323     QCOMPARE(line.textLength(), firstWord.length() + 1);
324     QCOMPARE(qRound(line.naturalTextWidth()), firstLineWidth);
325
326     pos += line.textLength();
327     y += qRound(line.ascent() + line.descent());
328
329     line = layout.createLine();
330     line.setLineWidth(secondLineWidth);
331     line.setPosition(QPoint(0, y));
332     // + 1 for trailing space
333     QCOMPARE(line.textStart(), pos);
334     QCOMPARE(line.textLength(), secondWord.length() + 1);
335     QCOMPARE(qRound(line.naturalTextWidth()), secondLineWidth);
336
337     pos += line.textLength();
338     y += qRound(line.ascent() + line.descent());
339
340     line = layout.createLine();
341     line.setLineWidth(secondLineWidth);
342     line.setPosition(QPoint(0, y));
343     // no trailing space here!
344     QCOMPARE(line.textStart(), pos);
345     QCOMPARE(line.textLength(), thirdWord.length());
346     QCOMPARE(qRound(line.naturalTextWidth()), thirdLineWidth);
347     y += qRound(line.ascent() + line.descent());
348
349     QCOMPARE(layout.boundingRect(), QRectF(0, 0, longestLine, y + 1));
350 }
351
352 void tst_QTextLayout::boundingRectWithLongLineAndNoWrap()
353 {
354     QString longString("thisisaverylongstringthatcannotbewrappedatallitjustgoesonandonlikeonebigword");
355
356     const int width = longString.length() * testFont.pixelSize() / 20; // very small widthx
357
358     QTextLayout layout(longString, testFont);
359     layout.beginLayout();
360     QTextLine line = layout.createLine();
361     line.setLineWidth(width);
362
363     QVERIFY(layout.boundingRect().width() >= line.width());
364     QCOMPARE(layout.boundingRect().width(), line.naturalTextWidth());
365 }
366
367 void tst_QTextLayout::forcedBreaks()
368 {
369     QString text = "A\n\nB\nC";
370     text.replace('\n', QChar::LineSeparator);
371
372     QTextLayout layout(text, testFont);
373
374     layout.beginLayout();
375
376     int pos = 0;
377
378     QTextLine line = layout.createLine();
379     line.setLineWidth(0x10000);
380     QCOMPARE(line.textStart(), pos);
381     QCOMPARE(line.textLength(),2);
382     QCOMPARE(qRound(line.naturalTextWidth()),testFont.pixelSize());
383     QCOMPARE((int) line.height(), testFont.pixelSize() + 1); // + 1 baseline
384     QCOMPARE(line.xToCursor(0), line.textStart());
385     pos += line.textLength();
386
387     line = layout.createLine();
388     line.setLineWidth(0x10000);
389     QCOMPARE(line.textStart(),pos);
390     QCOMPARE(line.textLength(),1);
391     QCOMPARE(qRound(line.naturalTextWidth()), 0);
392     QCOMPARE((int) line.height(), testFont.pixelSize() + 1); // + 1 baseline
393     QCOMPARE(line.xToCursor(0), line.textStart());
394     pos += line.textLength();
395
396     line = layout.createLine();
397     line.setLineWidth(0x10000);
398     QCOMPARE(line.textStart(),pos);
399     QCOMPARE(line.textLength(),2);
400     QCOMPARE(qRound(line.naturalTextWidth()),testFont.pixelSize());
401     QCOMPARE(qRound(line.height()), testFont.pixelSize() + 1); // + 1 baseline
402     QCOMPARE(line.xToCursor(0), line.textStart());
403     pos += line.textLength();
404
405     line = layout.createLine();
406     line.setLineWidth(0x10000);
407     QCOMPARE(line.textStart(),pos);
408     QCOMPARE(line.textLength(),1);
409     QCOMPARE(qRound(line.naturalTextWidth()), testFont.pixelSize());
410     QCOMPARE((int) line.height(), testFont.pixelSize() + 1); // + 1 baseline
411     QCOMPARE(line.xToCursor(0), line.textStart());
412 }
413
414 void tst_QTextLayout::breakAny()
415 {
416 #if defined(Q_WS_MAC)
417     QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll);
418 #endif
419     QString text = "ABCD";
420
421     QTextLayout layout(text, testFont);
422     QTextLine line;
423
424     QTextOption opt;
425     opt.setWrapMode(QTextOption::WrapAnywhere);
426     layout.setTextOption(opt);
427     layout.beginLayout();
428
429     line = layout.createLine();
430     line.setLineWidth(testFont.pixelSize() * 2);
431     QCOMPARE(line.textStart(), 0);
432     QCOMPARE(line.textLength(), 2);
433
434     line = layout.createLine();
435     line.setLineWidth(testFont.pixelSize() * 2);
436     QCOMPARE(line.textStart(), 2);
437     QCOMPARE(line.textLength(), 2);
438
439     line = layout.createLine();
440     QVERIFY(!line.isValid());
441
442     layout.endLayout();
443
444     text = "ABCD EFGH";
445     layout.setText(text);
446     layout.beginLayout();
447
448     line = layout.createLine();
449     line.setLineWidth(testFont.pixelSize() * 7);
450     QCOMPARE(line.textStart(), 0);
451     QCOMPARE(line.textLength(), 7);
452
453     layout.endLayout();
454 }
455
456 void tst_QTextLayout::noWrap()
457 {
458 #if defined(Q_WS_MAC)
459     QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll);
460 #endif
461     QString text = "AB CD";
462
463     QTextLayout layout(text, testFont);
464     QTextLine line;
465
466     QTextOption opt;
467     opt.setWrapMode(QTextOption::NoWrap);
468     layout.setTextOption(opt);
469     layout.beginLayout();
470
471     line = layout.createLine();
472     line.setLineWidth(testFont.pixelSize() * 2);
473     QCOMPARE(line.textStart(), 0);
474     QCOMPARE(line.textLength(), 5);
475
476     line = layout.createLine();
477     QVERIFY(!line.isValid());
478
479     layout.endLayout();
480 }
481
482 void tst_QTextLayout::cursorToXForInlineObjects()
483 {
484     QChar ch(QChar::ObjectReplacementCharacter);
485     QString text(ch);
486     QTextLayout layout(text, testFont);
487     layout.beginLayout();
488
489     QTextEngine *engine = layout.engine();
490     const int item = engine->findItem(0);
491     engine->layoutData->items[item].width = 32;
492
493     QTextLine line = layout.createLine();
494     line.setLineWidth(0x10000);
495
496     QCOMPARE(line.cursorToX(0), qreal(0));
497     QCOMPARE(line.cursorToX(1), qreal(32));
498 }
499
500 void tst_QTextLayout::cursorToXForSetColumns()
501 {
502     QTextLayout lay("abc", testFont);
503     QTextOption o = lay.textOption();
504     o.setWrapMode(QTextOption::WrapAnywhere);
505
506     // enable/disable this line for full effect ;)
507     o.setAlignment(Qt::AlignHCenter);
508
509     lay.setTextOption(o);
510     lay.beginLayout();
511     QTextLine line = lay.createLine();
512     line.setNumColumns(1);
513     lay.endLayout();
514     QCOMPARE(line.cursorToX(0), 0.);
515     QCOMPARE(line.cursorToX(1), (qreal) TESTFONT_SIZE);
516 }
517
518 void tst_QTextLayout::defaultWordSeparators_data()
519 {
520     QTest::addColumn<QString>("text");
521     QTest::addColumn<int>("startPos");
522     QTest::addColumn<int>("endPos");
523
524     QString separators(".,:;-<>[](){}=/+%&^*");
525     separators += QLatin1String("!?");
526     for (int i = 0; i < separators.count(); ++i) {
527         QTest::newRow(QString::number(i).toAscii().data())
528             << QString::fromLatin1("abcd") + separators.at(i) + QString::fromLatin1("efgh")
529             <<  0 << 4;
530     }
531
532     QTest::newRow("nbsp")
533             << QString::fromLatin1("abcd") + QString(QChar::Nbsp) + QString::fromLatin1("efgh")
534             << 0 << 5;
535
536     QTest::newRow("tab")
537         << QString::fromLatin1("abcd") + QString::fromLatin1("\t") + QString::fromLatin1("efgh")
538             << 0 << 5;
539
540     QTest::newRow("lineseparator")
541             << QString::fromLatin1("abcd") + QString(QChar::LineSeparator) + QString::fromLatin1("efgh")
542             << 0 << 5;
543 }
544
545 void tst_QTextLayout::defaultWordSeparators()
546 {
547     QFETCH(QString, text);
548     QFETCH(int, startPos);
549     QFETCH(int, endPos);
550     QTextLayout layout(text, testFont);
551
552     QCOMPARE(layout.nextCursorPosition(startPos, QTextLayout::SkipWords), endPos);
553     QCOMPARE(layout.previousCursorPosition(endPos, QTextLayout::SkipWords), startPos);
554 }
555
556 void tst_QTextLayout::cursorMovementInsideSpaces()
557 {
558     QTextLayout layout("ABC            DEF", testFont);
559
560     QCOMPARE(layout.previousCursorPosition(6, QTextLayout::SkipWords), 0);
561     QCOMPARE(layout.nextCursorPosition(6, QTextLayout::SkipWords), 15);
562 }
563
564 void tst_QTextLayout::charWordStopOnLineSeparator()
565 {
566     const QChar lineSeparator(QChar::LineSeparator);
567     QString txt;
568     txt.append(lineSeparator);
569     txt.append(lineSeparator);
570     QTextLayout layout(txt, testFont);
571     QTextEngine *engine = layout.engine();
572     const HB_CharAttributes *attrs = engine->attributes();
573     QVERIFY(attrs);
574     QVERIFY(attrs[1].charStop);
575 }
576
577 void tst_QTextLayout::xToCursorAtEndOfLine()
578 {
579 #if defined(Q_WS_MAC)
580     QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll);
581 #endif
582     QString text = "FirstLine SecondLine";
583     text.replace('\n', QChar::LineSeparator);
584
585     const qreal firstLineWidth = QString("FirstLine").length() * testFont.pixelSize();
586
587     QTextLayout layout(text, testFont);
588
589     layout.beginLayout();
590     QTextLine line = layout.createLine();
591     QVERIFY(line.isValid());
592     line.setLineWidth(firstLineWidth);
593     QVERIFY(layout.createLine().isValid());
594     QVERIFY(!layout.createLine().isValid());
595     layout.endLayout();
596
597     line = layout.lineAt(0);
598     QCOMPARE(line.xToCursor(100000), 9);
599     line = layout.lineAt(1);
600     QCOMPARE(line.xToCursor(100000), 20);
601 }
602
603 void tst_QTextLayout::boundingRectTopLeft()
604 {
605     QString text = "FirstLine\nSecondLine";
606     text.replace('\n', QChar::LineSeparator);
607
608     QTextLayout layout(text, testFont);
609
610     layout.beginLayout();
611     QTextLine firstLine = layout.createLine();
612     QVERIFY(firstLine.isValid());
613     firstLine.setPosition(QPointF(10, 10));
614     QTextLine secondLine = layout.createLine();
615     QVERIFY(secondLine.isValid());
616     secondLine.setPosition(QPointF(20, 20));
617     layout.endLayout();
618
619     QCOMPARE(layout.boundingRect().topLeft(), firstLine.position());
620 }
621
622 void tst_QTextLayout::charStopForSurrogatePairs()
623 {
624     QString txt;
625     txt.append("a");
626     txt.append(0xd87e);
627     txt.append(0xdc25);
628     txt.append("b");
629     QTextLayout layout(txt, testFont);
630     QTextEngine *engine = layout.engine();
631     const HB_CharAttributes *attrs = engine->attributes();
632     QVERIFY(attrs);
633     QVERIFY(attrs[0].charStop);
634     QVERIFY(attrs[1].charStop);
635     QVERIFY(!attrs[2].charStop);
636     QVERIFY(attrs[3].charStop);
637 }
638
639 void tst_QTextLayout::tabStops()
640 {
641 #if defined(Q_WS_MAC)
642     QSKIP("QTestFontEngine on the mac does not support logclusters at the moment", SkipAll);
643 #endif
644     QString txt("Hello there\tworld");
645     QTextLayout layout(txt, testFont);
646     layout.beginLayout();
647     QTextLine line = layout.createLine();
648
649     QVERIFY(line.isValid());
650     line.setNumColumns(11);
651     QCOMPARE(line.textLength(), TESTFONT_SIZE);
652
653     line = layout.createLine();
654     QVERIFY(line.isValid());
655     line.setNumColumns(5);
656     QCOMPARE(line.textLength(), 5);
657
658     layout.endLayout();
659 }
660
661 void tst_QTextLayout::integerOverflow()
662 {
663     QString txt("Hello world... ");
664
665     for (int i = 0; i < 8; ++i)
666         txt += txt;
667
668     QTextLayout layout(txt, testFont);
669     layout.beginLayout();
670     QTextLine line = layout.createLine();
671
672     QVERIFY(line.isValid());
673     line.setLineWidth(INT_MAX);
674     QCOMPARE(line.textLength(), txt.length());
675
676     QVERIFY(!layout.createLine().isValid());
677
678     layout.endLayout();
679 }
680
681 void tst_QTextLayout::setNumColumnsWrapAtWordBoundaryOrAnywhere()
682 {
683     QString txt("This is a small test text");
684     QTextLayout layout(txt, testFont);
685     QTextOption option = layout.textOption();
686     option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
687     layout.setTextOption(option);
688
689     layout.beginLayout();
690     QTextLine line1 = layout.createLine();
691     QVERIFY(line1.isValid());
692     line1.setNumColumns(1);
693
694     // qDebug() << line1.naturalTextWidth();
695     QCOMPARE(line1.textLength(), 1);
696     QVERIFY(line1.naturalTextWidth() == testFont.pixelSize()); // contains only one character
697
698     QTextLine line2 = layout.createLine();
699     QVERIFY(line2.isValid());
700
701     layout.endLayout();
702 }
703
704 void tst_QTextLayout::setNumColumnsWordWrap()
705 {
706     QString txt("This is a small test text");
707     QTextLayout layout(txt, testFont);
708     QTextOption option = layout.textOption();
709     option.setWrapMode(QTextOption::WordWrap);
710     layout.setTextOption(option);
711
712     layout.beginLayout();
713     QTextLine line1 = layout.createLine();
714     QVERIFY(line1.isValid());
715     line1.setNumColumns(1);
716
717     // qDebug() << line1.naturalTextWidth();
718     QCOMPARE(line1.textLength(), 5);
719     QVERIFY(line1.naturalTextWidth() > 20.0); // contains the whole first word.
720
721     QTextLine line2 = layout.createLine();
722     QVERIFY(line2.isValid());
723
724     layout.endLayout();
725 }
726
727 void tst_QTextLayout::smallTextLengthNoWrap()
728 {
729     QString txt("This is a small test text");
730     QTextLayout layout(txt, testFont);
731     QTextOption option = layout.textOption();
732     option.setWrapMode(QTextOption::NoWrap);
733     layout.setTextOption(option);
734
735     /// NoWrap
736     layout.beginLayout();
737     QTextLine line1 = layout.createLine();
738     QVERIFY(line1.isValid());
739     line1.setLineWidth(5); // most certainly too short for the word 'This' to fit.
740
741     QCOMPARE(line1.width(), 5.0);
742     QVERIFY(line1.naturalTextWidth() > 70); // contains all the text.
743
744     QTextLine line2 = layout.createLine();
745     QVERIFY(! line2.isValid());
746
747     layout.endLayout();
748 }
749
750 void tst_QTextLayout::smallTextLengthWordWrap()
751 {
752     QString txt("This is a small test text");
753     QTextLayout layout(txt, testFont);
754     QTextOption option = layout.textOption();
755     option.setWrapMode(QTextOption::WordWrap);
756     layout.setTextOption(option);
757
758     /// WordWrap
759     layout.beginLayout();
760     QTextLine line1 = layout.createLine();
761     QVERIFY(line1.isValid());
762     line1.setLineWidth(5); // most certainly too short for the word 'This' to fit.
763
764     QCOMPARE(line1.width(), 5.0);
765     QVERIFY(line1.naturalTextWidth() > 20.0); // contains the whole first word.
766     QCOMPARE(line1.textLength(), 5);
767
768     QTextLine line2 = layout.createLine();
769     QVERIFY(line2.isValid());
770
771     layout.endLayout();
772 }
773
774 void tst_QTextLayout::smallTextLengthWrapAtWordBoundaryOrAnywhere()
775 {
776     QString txt("This is a small test text");
777     QTextLayout layout(txt, testFont);
778     QTextOption option = layout.textOption();
779     option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
780     layout.setTextOption(option);
781
782     layout.beginLayout();
783     QTextLine line1 = layout.createLine();
784     QVERIFY(line1.isValid());
785     line1.setLineWidth(5); // most certainly too short for the word 'This' to fit.
786
787     QCOMPARE(line1.width(), 5.0);
788     // qDebug() << line1.naturalTextWidth();
789     QCOMPARE(line1.textLength(), 1);
790     QVERIFY(line1.naturalTextWidth() == testFont.pixelSize()); // contains just the characters that fit.
791
792     QTextLine line2 = layout.createLine();
793     QVERIFY(line2.isValid());
794
795     layout.endLayout();
796 }
797
798 void tst_QTextLayout::testDefaultTabs()
799 {
800     QTextLayout layout("Foo\tBar\ta slightly longer text\tend.", testFont);
801     layout.beginLayout();
802     QTextLine line = layout.createLine();
803     line.setLineWidth(1000);
804     layout.endLayout();
805
806     //qDebug() << "After the tab: " << line.cursorToX(4);
807     QCOMPARE(line.cursorToX(4), 80.); // default tab is 80
808     QCOMPARE(line.cursorToX(8), 160.);
809     QCOMPARE(line.cursorToX(31), 480.);
810
811     QTextOption option = layout.textOption();
812     option.setTabStop(90);
813     layout.setTextOption(option);
814     layout.beginLayout();
815     line = layout.createLine();
816     line.setLineWidth(1000);
817     layout.endLayout();
818
819     QCOMPARE(line.cursorToX(4), 90.);
820     QCOMPARE(line.cursorToX(8), 180.);
821     QCOMPARE(line.cursorToX(31), 450.);
822
823     QList<QTextOption::Tab> tabs;
824     QTextOption::Tab tab;
825     tab.position = 110; // set one tab to 110, but since the rest is unset they will be at the normal interval again.
826     tabs.append(tab);
827     option.setTabs(tabs);
828     layout.setTextOption(option);
829     layout.beginLayout();
830     line = layout.createLine();
831     line.setLineWidth(1000);
832     layout.endLayout();
833
834     QCOMPARE(line.cursorToX(4), 110.);
835     QCOMPARE(line.cursorToX(8), 180.);
836     QCOMPARE(line.cursorToX(31), 450.);
837 }
838
839 void tst_QTextLayout::testTabs()
840 {
841     QTextLayout layout("Foo\tBar.", testFont);
842     QTextOption option = layout.textOption();
843     option.setTabStop(150);
844     layout.setTextOption(option);
845
846     layout.beginLayout();
847     QTextLine line = layout.createLine();
848     line.setLineWidth(200.);
849     layout.endLayout();
850
851     QVERIFY(line.naturalTextWidth() > 150);
852     QCOMPARE(line.cursorToX(4), 150.);
853 }
854
855 void tst_QTextLayout::testMultilineTab()
856 {
857     QTextLayout layout("Lorem ipsum dolor sit\tBar.", testFont);
858     // test if this works on the second line.
859     layout.beginLayout();
860     QTextLine line = layout.createLine();
861     line.setLineWidth(220.); // moves 'sit' to next line.
862     line = layout.createLine();
863     line.setLineWidth(220.);
864     layout.endLayout();
865
866     QCOMPARE(line.cursorToX(22), 80.);
867 }
868
869 void tst_QTextLayout::testMultiTab()
870 {
871     QTextLayout layout("Foo\t\t\tBar.", testFont);
872     layout.beginLayout();
873     QTextLine line = layout.createLine();
874     line.setLineWidth(1000.);
875     layout.endLayout();
876
877     QCOMPARE(line.cursorToX(6), 80. * 3);
878 }
879
880 void tst_QTextLayout::testTabsInAlignedParag()
881 {
882     QTextLayout layout("Foo\tsome more words", testFont);
883     QTextOption option = layout.textOption();
884     // right
885     option.setAlignment(Qt::AlignRight);
886     layout.setTextOption(option);
887
888     layout.beginLayout();
889     QTextLine line = layout.createLine();
890     line.setLineWidth(300.);
891     layout.endLayout();
892
893     const qreal textWidth = 80 + 15 * TESTFONT_SIZE; // 15 chars right of the tab
894     QCOMPARE(line.naturalTextWidth(), textWidth);
895     QCOMPARE(line.cursorToX(0), 300. - textWidth);
896
897     // centered
898     option.setAlignment(Qt::AlignCenter);
899     layout.setTextOption(option);
900
901     layout.beginLayout();
902     line = layout.createLine();
903     line.setLineWidth(300.);
904     layout.endLayout();
905
906     QCOMPARE(line.naturalTextWidth(), textWidth);
907     QCOMPARE(line.cursorToX(0), (300. - textWidth) / 2.);
908
909     // justified
910     option.setAlignment(Qt::AlignJustify);
911     layout.setTextOption(option);
912
913     layout.beginLayout();
914     line = layout.createLine();
915     line.setLineWidth(textWidth - 10); // make the last word slip to the next line so justification actually happens.
916     layout.endLayout();
917
918     QCOMPARE(line.cursorToX(0), 0.);
919     QCOMPARE(line.cursorToX(4), 80.);
920
921     //QTextLayout layout2("Foo\tUt wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis", testFont); // means it will be more then one line long.
922 }
923
924 void tst_QTextLayout::testRightTab()
925 {
926     QTextLayout layout("Foo\tLorem ipsum te sit\tBar baz\tText\tEnd", testFont);
927     /*                     ^ a                 ^ b      ^ c   ^ d
928      a = 4, b = 22, c = 30, d = 35 (position)
929
930      I expect the output to be:
931         Foo Lorem ipsum te
932         sit      Bar Baz
933         Text         End
934
935      a) tab replaced with a single space due to the text not fitting before the tab.
936      b) tab takes space so the text until the 3th tab fits to the tab pos.
937      c) tab is after last tab (both auto and defined) and thus moves text to start of next line.
938      d) tab takes space so text until enter fits to tab pos.
939     */
940
941     QTextOption option = layout.textOption();
942     QList<QTextOption::Tab> tabs;
943     QTextOption::Tab tab;
944     tab.type = QTextOption::RightTab;
945     tab.position = 190; // which means only 15(.8) chars of our test font fit left of it.
946     tabs.append(tab);
947     option.setTabs(tabs);
948     layout.setTextOption(option);
949
950     layout.beginLayout();
951     QTextLine line1 = layout.createLine();
952     line1.setLineWidth(220.);
953     // qDebug() << "=====line 2";
954     QTextLine line2 = layout.createLine();
955     QVERIFY(line2.isValid());
956     line2.setLineWidth(220.);
957     // qDebug() << "=====line 3";
958     QTextLine line3 = layout.createLine();
959     QVERIFY(line3.isValid());
960     line3.setLineWidth(220.);
961     // qDebug() << "=====line 4";
962     QTextLine line4 = layout.createLine();
963     QVERIFY(! line4.isValid());
964     layout.endLayout();
965     // qDebug() << "--------";
966
967     QCOMPARE(line1.cursorToX(4), 3. * TESTFONT_SIZE ); // a
968     QCOMPARE(line1.textLength(), 19);
969     QCOMPARE(line2.cursorToX(23), 190. - 7. * TESTFONT_SIZE); // b
970     QCOMPARE(line2.textLength(), 12);
971     QCOMPARE(line3.cursorToX(31), 0.); // c
972     QCOMPARE(line3.cursorToX(36), 190 - 3. * TESTFONT_SIZE); // d
973 }
974
975 void tst_QTextLayout::testCenteredTab()
976 {
977     QTextLayout layout("Foo\tBar", testFont);
978     // test if centering the tab works.  We expect the center of 'Bar.' to be at the tab point.
979     QTextOption option = layout.textOption();
980     QList<QTextOption::Tab> tabs;
981     QTextOption::Tab tab;
982     tab.type = QTextOption::CenterTab;
983     tab.position = 150;
984     tabs.append(tab);
985     option.setTabs(tabs);
986     layout.setTextOption(option);
987
988     layout.beginLayout();
989     QTextLine line = layout.createLine();
990     line.setLineWidth(200.);
991     layout.endLayout();
992
993     const qreal wordLength = 3 * TESTFONT_SIZE; // the length of 'Bar'
994     QCOMPARE(line.cursorToX(4), 150 - wordLength / 2.);
995 }
996
997 void tst_QTextLayout::testDelimiterTab()
998 {
999     QTextLayout layout("Foo\tBar. Barrabas", testFont);
1000     // try the different delimiter characters to see if the alignment works there.
1001     QTextOption option = layout.textOption();
1002     QList<QTextOption::Tab> tabs;
1003     QTextOption::Tab tab;
1004     tab.type = QTextOption::DelimiterTab;
1005     tab.delimiter = QChar('.');
1006     tab.position = 100;
1007     tabs.append(tab);
1008     option.setTabs(tabs);
1009     layout.setTextOption(option);
1010
1011     layout.beginLayout();
1012     QTextLine line = layout.createLine();
1013     line.setLineWidth(200.);
1014     layout.endLayout();
1015
1016     const qreal distanceBeforeTab = 3.5 * TESTFONT_SIZE; // the length of 'bar' and half the width of the dot.
1017     QCOMPARE(line.cursorToX(4), 100 - distanceBeforeTab);
1018 }
1019
1020 void tst_QTextLayout::testLineBreakingAllSpaces()
1021 {
1022     QTextLayout layout("                    123", testFont); // thats 20 spaces
1023     const qreal firstLineWidth = 17 * TESTFONT_SIZE;
1024     layout.beginLayout();
1025     QTextLine line1 = layout.createLine();
1026     line1.setLineWidth(firstLineWidth);
1027     QTextLine line2 = layout.createLine();
1028     line2.setLineWidth(1000); // the rest
1029     layout.endLayout();
1030     QCOMPARE(line1.width(), firstLineWidth);
1031     QCOMPARE(line1.naturalTextWidth(), 0.); // spaces don't take space
1032     QCOMPARE(line1.textLength(), 20);
1033     QCOMPARE(line2.textLength(), 3);
1034     QCOMPARE(line2.naturalTextWidth(), 3. * TESTFONT_SIZE);
1035 }
1036
1037 void tst_QTextLayout::tabsForRtl()
1038 {
1039     QString word(QChar(0x5e9)); // a hebrew character
1040     word = word + word + word;  // 3 hebrew characters ;)
1041
1042     QTextLayout layout(word +'\t'+ word +'\t'+ word +'\t'+ word, testFont);
1043 //QTextLayout layout(word +' '+ word +' '+ word +' '+ word, testFont);// tester ;)
1044     /*                             ^ a         ^ b         ^ c
1045      a = 4, b = 8, c = 12, d = 16 (position)
1046
1047      a) Left tab in RTL is a righ tab; so a is at width - 80
1048      b) Like a
1049      c) right tab on RTL is a left tab; so its at width - 240
1050      d) center tab is still a centered tab.
1051     */
1052
1053     QTextOption option = layout.textOption();
1054     QList<QTextOption::Tab> tabs;
1055     QTextOption::Tab tab;
1056     tab.position = 80;
1057     tabs.append(tab);
1058     tab.position = 160;
1059     tabs.append(tab);
1060     tab.position = 240;
1061     tab.type = QTextOption::RightTab;
1062     tabs.append(tab);
1063     option.setTabs(tabs);
1064     option.setTextDirection(Qt::RightToLeft);
1065     option.setAlignment(Qt::AlignRight);
1066     layout.setTextOption(option);
1067
1068     layout.beginLayout();
1069     QTextLine line = layout.createLine();
1070     const qreal WIDTH = 400.;
1071     line.setLineWidth(WIDTH);
1072     layout.endLayout();
1073
1074 //qDebug() << "layout ended --------------";
1075
1076     QCOMPARE(line.cursorToX(0), WIDTH);
1077     QCOMPARE(line.cursorToX(1), WIDTH - TESTFONT_SIZE); // check its right-aligned
1078     QCOMPARE(line.cursorToX(4), WIDTH - 80 + 3 * TESTFONT_SIZE);
1079     QCOMPARE(line.cursorToX(8), WIDTH - 160 + 3 * TESTFONT_SIZE);
1080     QCOMPARE(line.cursorToX(12), WIDTH - 240);
1081 }
1082
1083 QT_BEGIN_NAMESPACE
1084 extern int qt_defaultDpiY();
1085 QT_END_NAMESPACE
1086
1087 void tst_QTextLayout::testTabDPIScale()
1088 {
1089     class MyPaintDevice : public QPaintDevice {
1090         QPaintEngine *paintEngine () const { return 0; }
1091         int metric (QPaintDevice::PaintDeviceMetric metric) const {
1092             switch(metric) {
1093             case QPaintDevice::PdmWidth:
1094             case QPaintDevice::PdmHeight:
1095             case QPaintDevice::PdmWidthMM:
1096             case QPaintDevice::PdmHeightMM:
1097             case QPaintDevice::PdmNumColors:
1098                 return INT_MAX;
1099             case QPaintDevice::PdmDepth:
1100                 return 32;
1101             case QPaintDevice::PdmDpiX:
1102             case QPaintDevice::PdmDpiY:
1103             case QPaintDevice::PdmPhysicalDpiX:
1104             case QPaintDevice::PdmPhysicalDpiY:
1105                 return 72;
1106             }
1107             return 0;
1108         }
1109     };
1110
1111     MyPaintDevice pd;
1112
1113     QTextLayout layout("text1\ttext2\ttext3\tend", testFont, &pd);
1114
1115     QTextOption option = layout.textOption();
1116     QList<QTextOption::Tab> tabs;
1117     QTextOption::Tab tab;
1118     tab.position = 300;
1119     tabs.append(tab);
1120
1121     tab.position = 600;
1122     tab.type = QTextOption::RightTab;
1123     tabs.append(tab);
1124
1125     tab.position = 800;
1126     tab.type = QTextOption::CenterTab;
1127     tabs.append(tab);
1128     option.setTabs(tabs);
1129     layout.setTextOption(option);
1130
1131     layout.beginLayout();
1132     QTextLine line = layout.createLine();
1133     line.setLineWidth(1500.);
1134     layout.endLayout();
1135     QCOMPARE(line.cursorToX(0), 0.);
1136     QCOMPARE(line.cursorToX(1), (double) TESTFONT_SIZE); // check that the font does not resize
1137     qreal scale = 72 / (qreal) qt_defaultDpiY();
1138     // lets do the transformation of deminishing resolution that QFixed has as effect.
1139     int fixedScale = (int)( scale * qreal(64)); // into a QFixed
1140     scale = ((qreal)fixedScale)/(qreal)64;      // and out of a QFixed
1141
1142     QCOMPARE(line.cursorToX(6),  tabs.at(0).position * scale);
1143     QCOMPARE(line.cursorToX(12), tabs.at(1).position * scale - TESTFONT_SIZE * 5);
1144     QCOMPARE(line.cursorToX(18), tabs.at(2).position * scale - TESTFONT_SIZE * 3 / 2.0);
1145 }
1146
1147 void tst_QTextLayout::tabHeight()
1148 {
1149     QTextLayout layout("\t", testFont);
1150     layout.beginLayout();
1151     QTextLine line = layout.createLine();
1152     layout.endLayout();
1153
1154     QCOMPARE(qRound(line.ascent()), QFontMetrics(testFont).ascent());
1155     QCOMPARE(qRound(line.descent()), QFontMetrics(testFont).descent());
1156 }
1157
1158 void tst_QTextLayout::capitalization_allUpperCase()
1159 {
1160     QFont font(testFont);
1161     font.setCapitalization(QFont::AllUppercase);
1162     QTextLayout layout("Test", font);
1163     layout.beginLayout();
1164     QTextLine line = layout.createLine();
1165     layout.endLayout();
1166
1167     QTextEngine *engine = layout.engine();
1168     engine->itemize();
1169     QCOMPARE(engine->layoutData->items.count(), 1);
1170     QVERIFY(engine->layoutData->items.at(0).analysis.flags == QScriptAnalysis::Uppercase);
1171 }
1172
1173 void tst_QTextLayout::capitalization_allLowerCase()
1174 {
1175     QFont font(testFont);
1176     font.setCapitalization(QFont::AllLowercase);
1177     QTextLayout layout("Test", font);
1178     layout.beginLayout();
1179     QTextLine line = layout.createLine();
1180     layout.endLayout();
1181
1182     QTextEngine *engine = layout.engine();
1183     engine->itemize();
1184     QCOMPARE(engine->layoutData->items.count(), 1);
1185     QVERIFY(engine->layoutData->items.at(0).analysis.flags == QScriptAnalysis::Lowercase);
1186 }
1187
1188 void tst_QTextLayout::capitalization_smallCaps()
1189 {
1190     QFont font(testFont);
1191     font.setCapitalization(QFont::SmallCaps);
1192     QTextLayout layout("Test", font);
1193     layout.beginLayout();
1194     QTextLine line = layout.createLine();
1195     layout.endLayout();
1196
1197     QTextEngine *engine = layout.engine();
1198     engine->itemize();
1199     QCOMPARE(engine->layoutData->items.count(), 2);
1200     QVERIFY(engine->layoutData->items.at(0).analysis.flags == QScriptAnalysis::None);
1201     QVERIFY(engine->layoutData->items.at(1).analysis.flags == QScriptAnalysis::SmallCaps);
1202 }
1203
1204 void tst_QTextLayout::capitalization_capitalize()
1205 {
1206     QFont font(testFont);
1207     font.setCapitalization(QFont::Capitalize);
1208     QTextLayout layout("hello\tworld", font);
1209     layout.beginLayout();
1210     QTextLine line = layout.createLine();
1211     layout.endLayout();
1212
1213     QTextEngine *engine = layout.engine();
1214     engine->itemize();
1215     QCOMPARE(engine->layoutData->items.count(), 5);
1216     QVERIFY(engine->layoutData->items.at(0).analysis.flags == QScriptAnalysis::Uppercase);
1217     QVERIFY(engine->layoutData->items.at(1).analysis.flags == QScriptAnalysis::None);
1218     QVERIFY(engine->layoutData->items.at(2).analysis.flags == QScriptAnalysis::Tab);
1219     QVERIFY(engine->layoutData->items.at(3).analysis.flags == QScriptAnalysis::Uppercase);
1220     QVERIFY(engine->layoutData->items.at(4).analysis.flags == QScriptAnalysis::None);
1221 }
1222
1223 void tst_QTextLayout::longText()
1224 {
1225     QString longText(128000, 'a');
1226
1227     {
1228         QTextLayout layout(longText, testFont);
1229         layout.beginLayout();
1230         QTextLine line = layout.createLine();
1231         layout.endLayout();
1232         QVERIFY(line.isValid());
1233         QVERIFY(line.cursorToX(line.textLength() - 1) > 0);
1234     }
1235
1236     for (int cap = QFont::MixedCase; cap < QFont::Capitalize + 1; ++cap) {
1237         QFont f(testFont);
1238         f.setCapitalization(QFont::Capitalization(cap));
1239         QTextLayout layout(longText, f);
1240         layout.beginLayout();
1241         QTextLine line = layout.createLine();
1242         layout.endLayout();
1243         QVERIFY(line.isValid());
1244         QVERIFY(line.cursorToX(line.textLength() - 1) > 0);
1245     }
1246
1247     {
1248         QTextLayout layout(longText, testFont);
1249         layout.setFlags(Qt::TextForceLeftToRight);
1250         layout.beginLayout();
1251         QTextLine line = layout.createLine();
1252         layout.endLayout();
1253         QVERIFY(line.isValid());
1254         QVERIFY(line.cursorToX(line.textLength() - 1) > 0);
1255     }
1256
1257     {
1258         QTextLayout layout(longText, testFont);
1259         layout.setFlags(Qt::TextForceRightToLeft);
1260         layout.beginLayout();
1261         QTextLine line = layout.createLine();
1262         layout.endLayout();
1263         QVERIFY(line.isValid());
1264         QVERIFY(line.cursorToX(line.textLength() - 1) > 0);
1265     }
1266 }
1267
1268 void tst_QTextLayout::widthOfTabs()
1269 {
1270     QTextEngine engine("ddd\t\t", testFont);
1271     engine.ignoreBidi = true;
1272     engine.itemize();
1273     QCOMPARE(qRound(engine.width(0, 5)), qRound(engine.boundingBox(0, 5).width));
1274 }
1275
1276 void tst_QTextLayout::columnWrapWithTabs()
1277 {
1278     QTextLayout textLayout;
1279     {
1280         QTextOption textOption;
1281         textOption.setWrapMode(QTextOption::WordWrap);
1282         textLayout.setTextOption(textOption);
1283     }
1284
1285     // Make sure string with spaces does not break
1286     {
1287         QString text = "Foo bar foo bar foo bar";
1288         textLayout.setText(text);
1289
1290         textLayout.beginLayout();
1291         QTextLine line = textLayout.createLine();
1292         line.setNumColumns(30);
1293         QCOMPARE(line.textLength(), text.length());
1294         textLayout.endLayout();
1295     }
1296
1297     // Make sure string with tabs breaks
1298     {
1299         QString text = "Foo\tbar\tfoo\tbar\tfoo\tbar";
1300         textLayout.setText(text);
1301         textLayout.beginLayout();
1302         QTextLine line = textLayout.createLine();
1303         line.setNumColumns(30);
1304         QVERIFY(line.textLength() < text.length());
1305         textLayout.endLayout();
1306     }
1307
1308 }
1309
1310 void tst_QTextLayout::lineWidthFromBOM()
1311 {
1312     const QString string(QChar(0xfeff)); // BYTE ORDER MARK
1313     QTextLayout layout(string);
1314     layout.beginLayout();
1315     QTextLine line = layout.createLine();
1316     line.setLineWidth(INT_MAX / 256);
1317     layout.endLayout();
1318
1319     // Don't spin into an infinite loop
1320  }
1321
1322 void tst_QTextLayout::testFragmentVisibility()
1323 {
1324     QTextDocument *doc1 = new QTextDocument();
1325     QTextDocument *doc2 = new QTextDocument();
1326
1327     QTextCursor cursor1(doc1);
1328     QTextCursor cursor2(doc2);
1329     QTextCharFormat format;
1330
1331     cursor1.insertText("First");
1332     cursor2.insertText("First");
1333
1334     format.setFontWeight(QFont::Bold);
1335     cursor1.insertText("Second",format);
1336
1337     format.setFontItalic(true);
1338     cursor1.insertText("Third", format);
1339     cursor2.insertText("Third", format);
1340
1341     QTextBlock block1 = doc1->firstBlock();
1342     QTextBlock block2 = doc2->firstBlock();
1343
1344     QTextBlock::iterator it = block1.begin();
1345     it++;
1346     it.fragment().setVisible(false);
1347
1348     QTextLayout *layout1 = block1.layout();
1349     QTextLayout *layout2 = block2.layout();
1350     layout1->beginLayout();
1351     layout2->beginLayout();
1352
1353     QTextLine line1 = layout1->createLine();
1354     QTextLine line2 = layout2->createLine();
1355     line1.setLineWidth(70000);
1356     line2.setLineWidth(70000);
1357     QCOMPARE(line1.naturalTextWidth(), line2.naturalTextWidth()) ;
1358     layout1->endLayout();
1359     layout2->endLayout();
1360
1361     it.fragment().setVisible(true);
1362     layout1->beginLayout();
1363     line1 = layout1->createLine();
1364     line1.setLineWidth(70000);
1365     QCOMPARE(line1.textLength(), QString("First").length() + QString("Second").length() + QString("Third").length()) ;
1366
1367     delete doc1;
1368     delete doc2;
1369 }
1370
1371 QTEST_MAIN(tst_QTextLayout)
1372 #include "tst_qtextlayout.moc"