Make QSGTextNode back-end for QML's TextInput and TextEdit
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qsgtext / tst_qsgtext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QTextDocument>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativecomponent.h>
45 #include <private/qsgtext_p.h>
46 #include <private/qsgtext_p_p.h>
47 #include <private/qdeclarativevaluetype_p.h>
48 #include <private/qsgdistancefieldglyphcache_p.h>
49 #include <QFontMetrics>
50 #include <QGraphicsSceneMouseEvent>
51 #include <qmath.h>
52 #include <QSGView>
53 #include <private/qapplication_p.h>
54 #include <limits.h>
55
56 #include "../../../shared/util.h"
57 #include "testhttpserver.h"
58 #include <QtOpenGL/QGLShaderProgram>
59
60 #ifdef Q_OS_SYMBIAN
61 // In Symbian OS test data is located in applications private dir
62 #define SRCDIR "."
63 #endif
64
65 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
66
67 class tst_qsgtext : public QObject
68
69 {
70     Q_OBJECT
71 public:
72     tst_qsgtext();
73
74 private slots:
75     void initTestCase();
76     void cleanupTestCase();
77     void text();
78     void width();
79     void wrap();
80     void elide();
81     void textFormat();
82
83     void alignments_data();
84     void alignments();
85
86     void embeddedImages_data();
87     void embeddedImages();
88
89     void lineCount();
90     void lineHeight();
91
92     // ### these tests may be trivial    
93     void horizontalAlignment();
94     void horizontalAlignment_RightToLeft();
95     void verticalAlignment();
96     void font();
97     void style();
98     void color();
99     void smooth();
100
101     // QDeclarativeFontValueType
102     void weight();
103     void underline();
104     void overline();
105     void strikeout();
106     void capitalization();
107     void letterSpacing();
108     void wordSpacing();
109
110     void clickLink();
111
112     void QTBUG_12291();
113     void implicitSize_data();
114     void implicitSize();
115
116     void qtbug_14734();
117 private:
118     QStringList standard;
119     QStringList richText;
120
121     QStringList horizontalAlignmentmentStrings;
122     QStringList verticalAlignmentmentStrings;
123
124     QList<Qt::Alignment> verticalAlignmentments;
125     QList<Qt::Alignment> horizontalAlignmentments;
126
127     QStringList styleStrings;
128     QList<QSGText::TextStyle> styles;
129
130     QStringList colorStrings;
131
132     QDeclarativeEngine engine;
133
134     QSGView *createView(const QString &filename);
135 };
136 void tst_qsgtext::initTestCase()
137 {
138     QSGView canvas;
139     if (!QGLShaderProgram::hasOpenGLShaderPrograms(canvas.context()))
140         QSKIP("Text item needs OpenGL 2.0", SkipAll);
141 }
142
143 void tst_qsgtext::cleanupTestCase()
144 {
145
146 }
147 tst_qsgtext::tst_qsgtext()
148 {
149     standard << "the quick brown fox jumped over the lazy dog"
150             << "the quick brown fox\n jumped over the lazy dog";
151
152     richText << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a> jumped over the <b>lazy</b> dog</i>"
153             << "<i>the <b>quick</b> brown <a href=\\\"http://www.google.com\\\">fox</a><br>jumped over the <b>lazy</b> dog</i>";
154
155     horizontalAlignmentmentStrings << "AlignLeft"
156             << "AlignRight"
157             << "AlignHCenter";
158
159     verticalAlignmentmentStrings << "AlignTop"
160             << "AlignBottom"
161             << "AlignVCenter";
162
163     horizontalAlignmentments << Qt::AlignLeft
164             << Qt::AlignRight
165             << Qt::AlignHCenter;
166
167     verticalAlignmentments << Qt::AlignTop
168             << Qt::AlignBottom
169             << Qt::AlignVCenter;
170
171     styleStrings << "Normal"
172             << "Outline"
173             << "Raised"
174             << "Sunken";
175
176     styles << QSGText::Normal
177             << QSGText::Outline
178             << QSGText::Raised
179             << QSGText::Sunken;
180
181     colorStrings << "aliceblue"
182             << "antiquewhite"
183             << "aqua"
184             << "darkkhaki"
185             << "darkolivegreen"
186             << "dimgray"
187             << "palevioletred"
188             << "lightsteelblue"
189             << "#000000"
190             << "#AAAAAA"
191             << "#FFFFFF"
192             << "#2AC05F";
193     //
194     // need a different test to do alpha channel test
195     // << "#AA0011DD"
196     // << "#00F16B11";
197     //
198 }
199
200 QSGView *tst_qsgtext::createView(const QString &filename)
201 {
202     QSGView *canvas = new QSGView(0);
203
204     canvas->setSource(QUrl::fromLocalFile(filename));
205     return canvas;
206 }
207
208 void tst_qsgtext::text()
209 {
210     {
211         QDeclarativeComponent textComponent(&engine);
212         textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
213         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
214
215         QVERIFY(textObject != 0);
216         QCOMPARE(textObject->text(), QString(""));
217         QVERIFY(textObject->width() == 0);
218
219         delete textObject;
220     }
221
222     for (int i = 0; i < standard.size(); i++)
223     {
224         QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
225         QDeclarativeComponent textComponent(&engine);
226         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
227
228         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
229
230         QVERIFY(textObject != 0);
231         QCOMPARE(textObject->text(), standard.at(i));
232         QVERIFY(textObject->width() > 0);
233
234         delete textObject;
235     }
236
237     for (int i = 0; i < richText.size(); i++)
238     {
239         QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
240         QDeclarativeComponent textComponent(&engine);
241         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
242         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
243
244         QVERIFY(textObject != 0);
245         QString expected = richText.at(i);
246         QCOMPARE(textObject->text(), expected.replace("\\\"", "\""));
247         QVERIFY(textObject->width() > 0);
248
249         delete textObject;
250     }
251 }
252
253 void tst_qsgtext::width()
254 {
255     // uses Font metrics to find the width for standard and document to find the width for rich
256     {
257         QDeclarativeComponent textComponent(&engine);
258         textComponent.setData("import QtQuick 2.0\nText { text: \"\" }", QUrl::fromLocalFile(""));
259         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
260
261         QVERIFY(textObject != 0);
262         QCOMPARE(textObject->width(), 0.);
263
264         delete textObject;
265     }
266
267     bool requiresUnhintedMetrics = !qmlDisableDistanceField();
268
269     for (int i = 0; i < standard.size(); i++)
270     {
271         QVERIFY(!Qt::mightBeRichText(standard.at(i))); // self-test
272
273         QFont f;
274         qreal metricWidth = 0.0;
275
276         if (requiresUnhintedMetrics) {
277             QString s = standard.at(i);
278             s.replace(QLatin1Char('\n'), QChar::LineSeparator);
279
280             QTextLayout layout(s);
281             layout.setFlags(Qt::TextExpandTabs | Qt::TextShowMnemonic);
282             {
283                 QTextOption option;
284                 option.setUseDesignMetrics(true);
285                 layout.setTextOption(option);
286             }
287
288             layout.beginLayout();
289             forever {
290                 QTextLine line = layout.createLine();
291                 if (!line.isValid())
292                     break;
293             }
294
295             layout.endLayout();
296
297             metricWidth = qCeil(layout.boundingRect().width());
298         } else {
299             QFontMetricsF fm(f);
300             qreal metricWidth = fm.size(Qt::TextExpandTabs && Qt::TextShowMnemonic, standard.at(i)).width();
301             metricWidth = qCeil(metricWidth);
302         }
303
304         QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
305         QDeclarativeComponent textComponent(&engine);
306         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
307         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
308
309         QVERIFY(textObject != 0);
310         QVERIFY(textObject->boundingRect().width() > 0);
311         QCOMPARE(textObject->width(), qreal(metricWidth));
312         QVERIFY(textObject->textFormat() == QSGText::AutoText); // setting text doesn't change format
313
314         delete textObject;
315     }
316
317     for (int i = 0; i < richText.size(); i++)
318     {
319         QVERIFY(Qt::mightBeRichText(richText.at(i))); // self-test
320
321         QTextDocument document;
322         document.setHtml(richText.at(i));
323         document.setDocumentMargin(0);
324
325         int documentWidth = document.idealWidth();
326
327         QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
328         QDeclarativeComponent textComponent(&engine);
329         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
330         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
331
332         QVERIFY(textObject != 0);
333         QCOMPARE(textObject->width(), qreal(documentWidth));
334         QVERIFY(textObject->textFormat() == QSGText::AutoText); // setting text doesn't change format
335
336         delete textObject;
337     }
338 }
339
340 void tst_qsgtext::wrap()
341 {
342     int textHeight = 0;
343     // for specified width and wrap set true
344     {
345         QDeclarativeComponent textComponent(&engine);
346         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; wrapMode: Text.WordWrap; width: 300 }", QUrl::fromLocalFile(""));
347         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
348         textHeight = textObject->height();
349
350         QVERIFY(textObject != 0);
351         QVERIFY(textObject->wrapMode() == QSGText::WordWrap);
352         QCOMPARE(textObject->width(), 300.);
353
354         delete textObject;
355     }
356
357     for (int i = 0; i < standard.size(); i++)
358     {
359         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + standard.at(i) + "\" }";
360         QDeclarativeComponent textComponent(&engine);
361         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
362         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
363
364         QVERIFY(textObject != 0);
365         QCOMPARE(textObject->width(), 30.);
366         QVERIFY(textObject->height() > textHeight);
367
368         int oldHeight = textObject->height();
369         textObject->setWidth(100);
370         QVERIFY(textObject->height() < oldHeight);
371
372         delete textObject;
373     }
374
375     for (int i = 0; i < richText.size(); i++)
376     {
377         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; text: \"" + richText.at(i) + "\" }";
378         QDeclarativeComponent textComponent(&engine);
379         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
380         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
381
382         QVERIFY(textObject != 0);
383         QCOMPARE(textObject->width(), 30.);
384         QVERIFY(textObject->height() > textHeight);
385
386         qreal oldHeight = textObject->height();
387         textObject->setWidth(100);
388         QVERIFY(textObject->height() < oldHeight);
389
390         delete textObject;
391     }
392
393     // richtext again with a fixed height
394     for (int i = 0; i < richText.size(); i++)
395     {
396         QString componentStr = "import QtQuick 2.0\nText { wrapMode: Text.WordWrap; width: 30; height: 50; text: \"" + richText.at(i) + "\" }";
397         QDeclarativeComponent textComponent(&engine);
398         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
399         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
400
401         QVERIFY(textObject != 0);
402         QCOMPARE(textObject->width(), 30.);
403         QVERIFY(textObject->implicitHeight() > textHeight);
404
405         qreal oldHeight = textObject->implicitHeight();
406         textObject->setWidth(100);
407         QVERIFY(textObject->implicitHeight() < oldHeight);
408
409         delete textObject;
410     }
411 }
412
413 void tst_qsgtext::elide()
414 {
415     for (QSGText::TextElideMode m = QSGText::ElideLeft; m<=QSGText::ElideNone; m=QSGText::TextElideMode(int(m)+1)) {
416         const char* elidename[]={"ElideLeft", "ElideRight", "ElideMiddle", "ElideNone"};
417         QString elide = "elide: Text." + QString(elidename[int(m)]) + ";";
418
419         // XXX Poor coverage.
420
421         {
422             QDeclarativeComponent textComponent(&engine);
423             textComponent.setData(("import QtQuick 2.0\nText { text: \"\"; "+elide+" width: 100 }").toLatin1(), QUrl::fromLocalFile(""));
424             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
425
426             QCOMPARE(textObject->elideMode(), m);
427             QCOMPARE(textObject->width(), 100.);
428
429             delete textObject;
430         }
431
432         for (int i = 0; i < standard.size(); i++)
433         {
434             QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + standard.at(i) + "\" }";
435             QDeclarativeComponent textComponent(&engine);
436             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
437             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
438
439             QCOMPARE(textObject->elideMode(), m);
440             QCOMPARE(textObject->width(), 100.);
441
442             delete textObject;
443         }
444
445         // richtext - does nothing
446         for (int i = 0; i < richText.size(); i++)
447         {
448             QString componentStr = "import QtQuick 2.0\nText { "+elide+" width: 100; text: \"" + richText.at(i) + "\" }";
449             QDeclarativeComponent textComponent(&engine);
450             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
451             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
452
453             QCOMPARE(textObject->elideMode(), m);
454             QCOMPARE(textObject->width(), 100.);
455
456             delete textObject;
457         }
458     }
459 }
460
461 void tst_qsgtext::textFormat()
462 {
463     {
464         QDeclarativeComponent textComponent(&engine);
465         textComponent.setData("import QtQuick 2.0\nText { text: \"Hello\"; textFormat: Text.RichText }", QUrl::fromLocalFile(""));
466         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
467
468         QVERIFY(textObject != 0);
469         QVERIFY(textObject->textFormat() == QSGText::RichText);
470
471         delete textObject;
472     }
473     {
474         QDeclarativeComponent textComponent(&engine);
475         textComponent.setData("import QtQuick 2.0\nText { text: \"<b>Hello</b>\"; textFormat: Text.PlainText }", QUrl::fromLocalFile(""));
476         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
477
478         QVERIFY(textObject != 0);
479         QVERIFY(textObject->textFormat() == QSGText::PlainText);
480
481         delete textObject;
482     }
483 }
484
485
486 void tst_qsgtext::alignments_data()
487 {
488     QTest::addColumn<int>("hAlign");
489     QTest::addColumn<int>("vAlign");
490     QTest::addColumn<QString>("expectfile");
491
492     QTest::newRow("LT") << int(Qt::AlignLeft) << int(Qt::AlignTop) << SRCDIR "/data/alignments_lt.png";
493     QTest::newRow("RT") << int(Qt::AlignRight) << int(Qt::AlignTop) << SRCDIR "/data/alignments_rt.png";
494     QTest::newRow("CT") << int(Qt::AlignHCenter) << int(Qt::AlignTop) << SRCDIR "/data/alignments_ct.png";
495
496     QTest::newRow("LB") << int(Qt::AlignLeft) << int(Qt::AlignBottom) << SRCDIR "/data/alignments_lb.png";
497     QTest::newRow("RB") << int(Qt::AlignRight) << int(Qt::AlignBottom) << SRCDIR "/data/alignments_rb.png";
498     QTest::newRow("CB") << int(Qt::AlignHCenter) << int(Qt::AlignBottom) << SRCDIR "/data/alignments_cb.png";
499
500     QTest::newRow("LC") << int(Qt::AlignLeft) << int(Qt::AlignVCenter) << SRCDIR "/data/alignments_lc.png";
501     QTest::newRow("RC") << int(Qt::AlignRight) << int(Qt::AlignVCenter) << SRCDIR "/data/alignments_rc.png";
502     QTest::newRow("CC") << int(Qt::AlignHCenter) << int(Qt::AlignVCenter) << SRCDIR "/data/alignments_cc.png";
503 }
504
505
506 void tst_qsgtext::alignments()
507 {
508     QSKIP("Text alignment pixmap comparison tests will not work with scenegraph", SkipAll);
509
510     QFETCH(int, hAlign);
511     QFETCH(int, vAlign);
512     QFETCH(QString, expectfile);
513
514 #ifdef Q_WS_X11
515     // Font-specific, but not likely platform-specific, so only test on one platform
516     QFont fn;
517     fn.setRawName("-misc-fixed-medium-r-*-*-8-*-*-*-*-*-*-*");
518     QApplication::setFont(fn);
519 #endif
520
521     QSGView *canvas = createView(SRCDIR "/data/alignments.qml");
522
523     canvas->show();
524     QApplication::setActiveWindow(canvas);
525     QTest::qWaitForWindowShown(canvas);
526     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
527
528     QObject *ob = canvas->rootObject();
529     QVERIFY(ob != 0);
530     ob->setProperty("horizontalAlignment",hAlign);
531     ob->setProperty("verticalAlignment",vAlign);
532     QTRY_COMPARE(ob->property("running").toBool(),false);
533     QImage actual(canvas->width(), canvas->height(), QImage::Format_RGB32);
534     actual.fill(qRgb(255,255,255));
535     QPainter p(&actual);
536     canvas->render(&p);
537
538     QImage expect(expectfile);
539
540 #ifdef Q_WS_X11
541     // Font-specific, but not likely platform-specific, so only test on one platform
542     if (QApplicationPrivate::graphics_system_name == "raster" || QApplicationPrivate::graphics_system_name == "") {
543         QCOMPARE(actual,expect);
544     }
545 #endif
546
547     delete canvas;
548 }
549
550 //the alignment tests may be trivial o.oa
551 void tst_qsgtext::horizontalAlignment()
552 {
553     //test one align each, and then test if two align fails.
554
555     for (int i = 0; i < standard.size(); i++)
556     {
557         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
558         {
559             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
560             QDeclarativeComponent textComponent(&engine);
561             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
562             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
563
564             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
565
566             delete textObject;
567         }
568     }
569
570     for (int i = 0; i < richText.size(); i++)
571     {
572         for (int j=0; j < horizontalAlignmentmentStrings.size(); j++)
573         {
574             QString componentStr = "import QtQuick 2.0\nText { horizontalAlignment: \"" + horizontalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
575             QDeclarativeComponent textComponent(&engine);
576             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
577             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
578
579             QCOMPARE((int)textObject->hAlign(), (int)horizontalAlignmentments.at(j));
580
581             delete textObject;
582         }
583     }
584
585 }
586
587 void tst_qsgtext::horizontalAlignment_RightToLeft()
588 {
589     QSGView *canvas = createView(SRCDIR "/data/horizontalAlignment_RightToLeft.qml");
590     QSGText *text = canvas->rootObject()->findChild<QSGText*>("text");
591     QVERIFY(text != 0);
592     canvas->show();
593
594     QSGTextPrivate *textPrivate = QSGTextPrivate::get(text);
595     QVERIFY(textPrivate != 0);
596
597     // implicit alignment should follow the reading direction of RTL text
598     QCOMPARE(text->hAlign(), QSGText::AlignRight);
599     QCOMPARE(text->effectiveHAlign(), text->hAlign());
600     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
601
602     // explicitly left aligned text
603     text->setHAlign(QSGText::AlignLeft);
604     QCOMPARE(text->hAlign(), QSGText::AlignLeft);
605     QCOMPARE(text->effectiveHAlign(), text->hAlign());
606     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
607
608     // explicitly right aligned text
609     text->setHAlign(QSGText::AlignRight);
610     QCOMPARE(text->hAlign(), QSGText::AlignRight);
611     QCOMPARE(text->effectiveHAlign(), text->hAlign());
612     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
613
614     // change to rich text
615     QString textString = text->text();
616     text->setText(QString("<i>") + textString + QString("</i>"));
617     text->setTextFormat(QSGText::RichText);
618     text->resetHAlign();
619
620     // implicitly aligned rich text should follow the reading direction of text
621     QCOMPARE(text->hAlign(), QSGText::AlignRight);
622     QCOMPARE(text->effectiveHAlign(), text->hAlign());
623     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
624
625     // explicitly left aligned rich text
626     text->setHAlign(QSGText::AlignLeft);
627     QCOMPARE(text->hAlign(), QSGText::AlignLeft);
628     QCOMPARE(text->effectiveHAlign(), text->hAlign());
629     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignRight);
630
631     // explicitly right aligned rich text
632     text->setHAlign(QSGText::AlignRight);
633     QCOMPARE(text->hAlign(), QSGText::AlignRight);
634     QCOMPARE(text->effectiveHAlign(), text->hAlign());
635     QVERIFY(textPrivate->textDocument()->defaultTextOption().alignment() & Qt::AlignLeft);
636
637     text->setText(textString);
638     text->setTextFormat(QSGText::PlainText);
639
640     // explicitly center aligned
641     text->setHAlign(QSGText::AlignHCenter);
642     QCOMPARE(text->hAlign(), QSGText::AlignHCenter);
643     QCOMPARE(text->effectiveHAlign(), text->hAlign());
644     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
645     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().right() > canvas->width()/2);
646
647     // reseted alignment should go back to following the text reading direction
648     text->resetHAlign();
649     QCOMPARE(text->hAlign(), QSGText::AlignRight);
650     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
651
652     // mirror the text item
653     QSGItemPrivate::get(text)->setLayoutMirror(true);
654
655     // mirrored implicit alignment should continue to follow the reading direction of the text
656     QCOMPARE(text->hAlign(), QSGText::AlignRight);
657     QCOMPARE(text->effectiveHAlign(), QSGText::AlignRight);
658     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
659
660     // mirrored explicitly right aligned behaves as left aligned
661     text->setHAlign(QSGText::AlignRight);
662     QCOMPARE(text->hAlign(), QSGText::AlignRight);
663     QCOMPARE(text->effectiveHAlign(), QSGText::AlignLeft);
664     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
665
666     // mirrored explicitly left aligned behaves as right aligned
667     text->setHAlign(QSGText::AlignLeft);
668     QCOMPARE(text->hAlign(), QSGText::AlignLeft);
669     QCOMPARE(text->effectiveHAlign(), QSGText::AlignRight);
670     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() > canvas->width()/2);
671
672     // disable mirroring
673     QSGItemPrivate::get(text)->setLayoutMirror(false);
674     text->resetHAlign();
675
676     // English text should be implicitly left aligned
677     text->setText("Hello world!");
678     QCOMPARE(text->hAlign(), QSGText::AlignLeft);
679     QVERIFY(textPrivate->layout.lineAt(0).naturalTextRect().left() < canvas->width()/2);
680
681 #ifndef Q_OS_MAC    // QTBUG-18040
682     // empty text with implicit alignment follows the system locale-based
683     // keyboard input direction from QApplication::keyboardInputDirection
684     text->setText("");
685     QCOMPARE(text->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
686                                   QSGText::AlignLeft : QSGText::AlignRight);
687     text->setHAlign(QSGText::AlignRight);
688     QCOMPARE(text->hAlign(), QSGText::AlignRight);
689 #endif
690
691     delete canvas;
692
693 #ifndef Q_OS_MAC    // QTBUG-18040
694     // alignment of Text with no text set to it
695     QString componentStr = "import QtQuick 2.0\nText {}";
696     QDeclarativeComponent textComponent(&engine);
697     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
698     QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
699     QCOMPARE(textObject->hAlign(), QApplication::keyboardInputDirection() == Qt::LeftToRight ?
700                                   QSGText::AlignLeft : QSGText::AlignRight);
701     delete textObject;
702 #endif
703 }
704
705 void tst_qsgtext::verticalAlignment()
706 {
707     //test one align each, and then test if two align fails.
708
709     for (int i = 0; i < standard.size(); i++)
710     {
711         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
712         {
713             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + standard.at(i) + "\" }";
714             QDeclarativeComponent textComponent(&engine);
715             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
716             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
717
718             QVERIFY(textObject != 0);
719             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
720
721             delete textObject;
722         }
723     }
724
725     for (int i = 0; i < richText.size(); i++)
726     {
727         for (int j=0; j < verticalAlignmentmentStrings.size(); j++)
728         {
729             QString componentStr = "import QtQuick 2.0\nText { verticalAlignment: \"" + verticalAlignmentmentStrings.at(j) + "\"; text: \"" + richText.at(i) + "\" }";
730             QDeclarativeComponent textComponent(&engine);
731             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
732             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
733
734             QVERIFY(textObject != 0);
735             QCOMPARE((int)textObject->vAlign(), (int)verticalAlignmentments.at(j));
736
737             delete textObject;
738         }
739     }
740
741 }
742
743 void tst_qsgtext::font()
744 {
745     //test size, then bold, then italic, then family
746     {
747         QString componentStr = "import QtQuick 2.0\nText { font.pointSize: 40; text: \"Hello World\" }";
748         QDeclarativeComponent textComponent(&engine);
749         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
750         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
751
752         QCOMPARE(textObject->font().pointSize(), 40);
753         QCOMPARE(textObject->font().bold(), false);
754         QCOMPARE(textObject->font().italic(), false);
755
756         delete textObject;
757     }
758
759     {
760         QString componentStr = "import QtQuick 2.0\nText { font.pixelSize: 40; text: \"Hello World\" }";
761         QDeclarativeComponent textComponent(&engine);
762         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
763         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
764
765         QCOMPARE(textObject->font().pixelSize(), 40);
766         QCOMPARE(textObject->font().bold(), false);
767         QCOMPARE(textObject->font().italic(), false);
768
769         delete textObject;
770     }
771
772     { 
773         QString componentStr = "import QtQuick 2.0\nText { font.bold: true; text: \"Hello World\" }";
774         QDeclarativeComponent textComponent(&engine);
775         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
776         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
777
778         QCOMPARE(textObject->font().bold(), true);
779         QCOMPARE(textObject->font().italic(), false);
780
781         delete textObject;
782     }
783
784     { 
785         QString componentStr = "import QtQuick 2.0\nText { font.italic: true; text: \"Hello World\" }";
786         QDeclarativeComponent textComponent(&engine);
787         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
788         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
789
790         QCOMPARE(textObject->font().italic(), true);
791         QCOMPARE(textObject->font().bold(), false);
792
793         delete textObject;
794     }
795
796     { 
797         QString componentStr = "import QtQuick 2.0\nText { font.family: \"Helvetica\"; text: \"Hello World\" }";
798         QDeclarativeComponent textComponent(&engine);
799         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
800         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
801
802         QCOMPARE(textObject->font().family(), QString("Helvetica"));
803         QCOMPARE(textObject->font().bold(), false);
804         QCOMPARE(textObject->font().italic(), false);
805
806         delete textObject;
807     }
808
809     { 
810         QString componentStr = "import QtQuick 2.0\nText { font.family: \"\"; text: \"Hello World\" }";
811         QDeclarativeComponent textComponent(&engine);
812         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
813         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
814
815         QCOMPARE(textObject->font().family(), QString(""));
816
817         delete textObject;
818     }
819 }
820
821 void tst_qsgtext::style()
822 {
823     //test style
824     for (int i = 0; i < styles.size(); i++)
825     { 
826         QString componentStr = "import QtQuick 2.0\nText { style: \"" + styleStrings.at(i) + "\"; styleColor: \"white\"; text: \"Hello World\" }";
827         QDeclarativeComponent textComponent(&engine);
828         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
829         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
830
831         QCOMPARE((int)textObject->style(), (int)styles.at(i));
832         QCOMPARE(textObject->styleColor(), QColor("white"));
833
834         delete textObject;
835     }
836     QString componentStr = "import QtQuick 2.0\nText { text: \"Hello World\" }";
837     QDeclarativeComponent textComponent(&engine);
838     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
839     QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
840
841     QRectF brPre = textObject->boundingRect();
842     textObject->setStyle(QSGText::Outline);
843     QRectF brPost = textObject->boundingRect();
844
845     QVERIFY(brPre.width() < brPost.width());
846     QVERIFY(brPre.height() < brPost.height());
847
848     delete textObject;
849 }
850
851 void tst_qsgtext::color()
852 {
853     //test style
854     for (int i = 0; i < colorStrings.size(); i++)
855     { 
856         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
857         QDeclarativeComponent textComponent(&engine);
858         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
859         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
860
861         QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
862         QCOMPARE(textObject->styleColor(), QColor());
863
864         delete textObject;
865     }
866
867     for (int i = 0; i < colorStrings.size(); i++)
868     { 
869         QString componentStr = "import QtQuick 2.0\nText { styleColor: \"" + colorStrings.at(i) + "\"; text: \"Hello World\" }";
870         QDeclarativeComponent textComponent(&engine);
871         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
872         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
873
874         QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(i)));
875         // default color to black?
876         QCOMPARE(textObject->color(), QColor("black"));
877
878         delete textObject;
879     }
880     
881     for (int i = 0; i < colorStrings.size(); i++)
882     { 
883         for (int j = 0; j < colorStrings.size(); j++)
884         {
885             QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStrings.at(i) + "\"; styleColor: \"" + colorStrings.at(j) + "\"; text: \"Hello World\" }";
886             QDeclarativeComponent textComponent(&engine);
887             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
888             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
889
890             QCOMPARE(textObject->color(), QColor(colorStrings.at(i)));
891             QCOMPARE(textObject->styleColor(), QColor(colorStrings.at(j)));
892
893             delete textObject;
894         }
895     }
896     {
897         QString colorStr = "#AA001234";
898         QColor testColor("#001234");
899         testColor.setAlpha(170);
900
901         QString componentStr = "import QtQuick 2.0\nText { color: \"" + colorStr + "\"; text: \"Hello World\" }";
902         QDeclarativeComponent textComponent(&engine);
903         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
904         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
905
906         QCOMPARE(textObject->color(), testColor);
907
908         delete textObject;
909     }
910 }
911
912 void tst_qsgtext::smooth()
913 {
914     for (int i = 0; i < standard.size(); i++)
915     {
916         {
917             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + standard.at(i) + "\" }";
918             QDeclarativeComponent textComponent(&engine);
919             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
920             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
921             QCOMPARE(textObject->smooth(), true);
922
923             delete textObject;
924         }
925         {
926             QString componentStr = "import QtQuick 2.0\nText { text: \"" + standard.at(i) + "\" }";
927             QDeclarativeComponent textComponent(&engine);
928             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
929             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
930             QCOMPARE(textObject->smooth(), false);
931
932             delete textObject;
933         }
934     }
935     for (int i = 0; i < richText.size(); i++)
936     {
937         {
938             QString componentStr = "import QtQuick 2.0\nText { smooth: true; text: \"" + richText.at(i) + "\" }";
939             QDeclarativeComponent textComponent(&engine);
940             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
941             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
942             QCOMPARE(textObject->smooth(), true);
943
944             delete textObject;
945         }
946         {
947             QString componentStr = "import QtQuick 2.0\nText { text: \"" + richText.at(i) + "\" }";
948             QDeclarativeComponent textComponent(&engine);
949             textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
950             QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
951             QCOMPARE(textObject->smooth(), false);
952
953             delete textObject;
954         }
955     }
956 }
957
958 void tst_qsgtext::weight()
959 {
960     {
961         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
962         QDeclarativeComponent textComponent(&engine);
963         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
964         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
965
966         QVERIFY(textObject != 0);
967         QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Normal);
968
969         delete textObject;
970     }
971     {
972         QString componentStr = "import QtQuick 2.0\nText { font.weight: \"Bold\"; text: \"Hello world!\" }";
973         QDeclarativeComponent textComponent(&engine);
974         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
975         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
976
977         QVERIFY(textObject != 0);
978         QCOMPARE((int)textObject->font().weight(), (int)QDeclarativeFontValueType::Bold);
979
980         delete textObject;
981     }
982 }
983
984 void tst_qsgtext::underline()
985 {
986     {
987         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
988         QDeclarativeComponent textComponent(&engine);
989         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
990         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
991
992         QVERIFY(textObject != 0);
993         QCOMPARE(textObject->font().underline(), false);
994
995         delete textObject;
996     }
997     {
998         QString componentStr = "import QtQuick 2.0\nText { font.underline: true; text: \"Hello world!\" }";
999         QDeclarativeComponent textComponent(&engine);
1000         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1001         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1002
1003         QVERIFY(textObject != 0);
1004         QCOMPARE(textObject->font().underline(), true);
1005
1006         delete textObject;
1007     }
1008 }
1009
1010 void tst_qsgtext::overline()
1011 {
1012     {
1013         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1014         QDeclarativeComponent textComponent(&engine);
1015         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1016         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1017
1018         QVERIFY(textObject != 0);
1019         QCOMPARE(textObject->font().overline(), false);
1020
1021         delete textObject;
1022     }
1023     {
1024         QString componentStr = "import QtQuick 2.0\nText { font.overline: true; text: \"Hello world!\" }";
1025         QDeclarativeComponent textComponent(&engine);
1026         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1027         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1028
1029         QVERIFY(textObject != 0);
1030         QCOMPARE(textObject->font().overline(), true);
1031
1032         delete textObject;
1033     }
1034 }
1035
1036 void tst_qsgtext::strikeout()
1037 {
1038     {
1039         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1040         QDeclarativeComponent textComponent(&engine);
1041         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1042         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1043
1044         QVERIFY(textObject != 0);
1045         QCOMPARE(textObject->font().strikeOut(), false);
1046
1047         delete textObject;
1048     }
1049     {
1050         QString componentStr = "import QtQuick 2.0\nText { font.strikeout: true; text: \"Hello world!\" }";
1051         QDeclarativeComponent textComponent(&engine);
1052         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1053         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1054
1055         QVERIFY(textObject != 0);
1056         QCOMPARE(textObject->font().strikeOut(), true);
1057
1058         delete textObject;
1059     }
1060 }
1061
1062 void tst_qsgtext::capitalization()
1063 {
1064     {
1065         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1066         QDeclarativeComponent textComponent(&engine);
1067         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1068         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1069
1070         QVERIFY(textObject != 0);
1071         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::MixedCase);
1072
1073         delete textObject;
1074     }
1075     {
1076         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllUppercase\" }";
1077         QDeclarativeComponent textComponent(&engine);
1078         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1079         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1080
1081         QVERIFY(textObject != 0);
1082         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllUppercase);
1083
1084         delete textObject;
1085     }
1086     {
1087         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"AllLowercase\" }";
1088         QDeclarativeComponent textComponent(&engine);
1089         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1090         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1091
1092         QVERIFY(textObject != 0);
1093         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::AllLowercase);
1094
1095         delete textObject;
1096     }
1097     {
1098         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"SmallCaps\" }";
1099         QDeclarativeComponent textComponent(&engine);
1100         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1101         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1102
1103         QVERIFY(textObject != 0);
1104         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::SmallCaps);
1105
1106         delete textObject;
1107     }
1108     {
1109         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.capitalization: \"Capitalize\" }";
1110         QDeclarativeComponent textComponent(&engine);
1111         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1112         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1113
1114         QVERIFY(textObject != 0);
1115         QCOMPARE((int)textObject->font().capitalization(), (int)QDeclarativeFontValueType::Capitalize);
1116
1117         delete textObject;
1118     }
1119 }
1120
1121 void tst_qsgtext::letterSpacing()
1122 {
1123     {
1124         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1125         QDeclarativeComponent textComponent(&engine);
1126         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1127         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1128
1129         QVERIFY(textObject != 0);
1130         QCOMPARE(textObject->font().letterSpacing(), 0.0);
1131
1132         delete textObject;
1133     }
1134     {
1135         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: -2 }";
1136         QDeclarativeComponent textComponent(&engine);
1137         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1138         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1139
1140         QVERIFY(textObject != 0);
1141         QCOMPARE(textObject->font().letterSpacing(), -2.);
1142
1143         delete textObject;
1144     }
1145     {
1146         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.letterSpacing: 3 }";
1147         QDeclarativeComponent textComponent(&engine);
1148         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1149         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1150
1151         QVERIFY(textObject != 0);
1152         QCOMPARE(textObject->font().letterSpacing(), 3.);
1153
1154         delete textObject;
1155     }
1156 }
1157
1158 void tst_qsgtext::wordSpacing()
1159 {
1160     {
1161         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\" }";
1162         QDeclarativeComponent textComponent(&engine);
1163         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1164         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1165
1166         QVERIFY(textObject != 0);
1167         QCOMPARE(textObject->font().wordSpacing(), 0.0);
1168
1169         delete textObject;
1170     }
1171     {
1172         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: -50 }";
1173         QDeclarativeComponent textComponent(&engine);
1174         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1175         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1176
1177         QVERIFY(textObject != 0);
1178         QCOMPARE(textObject->font().wordSpacing(), -50.);
1179
1180         delete textObject;
1181     }
1182     {
1183         QString componentStr = "import QtQuick 2.0\nText { text: \"Hello world!\"; font.wordSpacing: 200 }";
1184         QDeclarativeComponent textComponent(&engine);
1185         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1186         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1187
1188         QVERIFY(textObject != 0);
1189         QCOMPARE(textObject->font().wordSpacing(), 200.);
1190
1191         delete textObject;
1192     }
1193 }
1194
1195 void tst_qsgtext::QTBUG_12291()
1196 {
1197     QSGView *canvas = createView(SRCDIR "/data/rotated.qml");
1198
1199     canvas->show();
1200     QApplication::setActiveWindow(canvas);
1201     QTest::qWaitForWindowShown(canvas);
1202     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1203
1204     QObject *ob = canvas->rootObject();
1205     QVERIFY(ob != 0);
1206
1207     QSGText *text = ob->findChild<QSGText*>("text");
1208     QVERIFY(text);
1209     QVERIFY(text->boundingRect().isValid());
1210
1211     delete canvas;
1212 }
1213
1214 class EventSender : public QSGItem
1215 {
1216 public:
1217     void sendEvent(QEvent *event) {
1218         if (event->type() == QEvent::GraphicsSceneMousePress)
1219             mousePressEvent(static_cast<QGraphicsSceneMouseEvent*>(event));
1220         else if (event->type() == QEvent::GraphicsSceneMouseRelease)
1221             mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent*>(event));
1222         else
1223             qWarning() << "Trying to send unsupported event type";
1224     }
1225 };
1226
1227 class LinkTest : public QObject
1228 {
1229     Q_OBJECT
1230 public:
1231     LinkTest() {}
1232
1233     QString link;
1234
1235 public slots:
1236     void linkClicked(QString l) { link = l; }
1237 };
1238
1239 void tst_qsgtext::clickLink()
1240 {
1241     {
1242         QString componentStr = "import QtQuick 2.0\nText { text: \"<a href=\\\"http://qt.nokia.com\\\">Hello world!</a>\" }";
1243         QDeclarativeComponent textComponent(&engine);
1244         textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1245         QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1246
1247         QVERIFY(textObject != 0);
1248
1249         LinkTest test;
1250         QObject::connect(textObject, SIGNAL(linkActivated(QString)), &test, SLOT(linkClicked(QString)));
1251
1252         {
1253             QGraphicsSceneMouseEvent me(QEvent::GraphicsSceneMousePress);
1254             me.setPos(QPointF(textObject->x()/2, textObject->y()/2));
1255             me.setButton(Qt::LeftButton);
1256             static_cast<EventSender*>(static_cast<QSGItem*>(textObject))->sendEvent(&me);
1257         }
1258
1259         {
1260             QGraphicsSceneMouseEvent me(QEvent::GraphicsSceneMouseRelease);
1261             me.setPos(QPointF(textObject->x()/2, textObject->y()/2));
1262             me.setButton(Qt::LeftButton);
1263             static_cast<EventSender*>(static_cast<QSGItem*>(textObject))->sendEvent(&me);
1264         }
1265
1266         QCOMPARE(test.link, QLatin1String("http://qt.nokia.com"));
1267
1268         delete textObject;
1269     }
1270 }
1271
1272 void tst_qsgtext::embeddedImages_data()
1273 {
1274     QTest::addColumn<QUrl>("qmlfile");
1275     QTest::addColumn<QString>("error");
1276     QTest::newRow("local") << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesLocal.qml") << "";
1277     QTest::newRow("local-error") << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesLocalError.qml")
1278         << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesLocalError.qml").toString()+":3:1: QML Text: Cannot open: " + QUrl::fromLocalFile(SRCDIR "/data/http/notexists.png").toString();
1279     QTest::newRow("remote") << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesRemote.qml") << "";
1280     QTest::newRow("remote-error") << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesRemoteError.qml")
1281         << QUrl::fromLocalFile(SRCDIR "/data/embeddedImagesRemoteError.qml").toString()+":3:1: QML Text: Error downloading http://127.0.0.1:14453/notexists.png - server replied: Not found";
1282 }
1283
1284 void tst_qsgtext::embeddedImages()
1285 {
1286     // Tests QTBUG-9900
1287
1288     QFETCH(QUrl, qmlfile);
1289     QFETCH(QString, error);
1290
1291     TestHTTPServer server(14453);
1292     server.serveDirectory(SRCDIR "/data/http");
1293
1294     if (!error.isEmpty())
1295         QTest::ignoreMessage(QtWarningMsg, error.toLatin1());
1296     
1297     QDeclarativeComponent textComponent(&engine, qmlfile);
1298     QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1299
1300     QVERIFY(textObject != 0);
1301
1302     QTRY_COMPARE(textObject->resourcesLoading(), 0);
1303
1304     QPixmap pm(SRCDIR "/data/http/exists.png");
1305     if (error.isEmpty()) {
1306         QCOMPARE(textObject->width(), double(pm.width()));
1307         QCOMPARE(textObject->height(), double(pm.height()));
1308     } else {
1309         QVERIFY(16 != pm.width()); // check test is effective
1310         QCOMPARE(textObject->width(), 16.0); // default size of QTextDocument broken image icon
1311         QCOMPARE(textObject->height(), 16.0);
1312     }
1313
1314     delete textObject;
1315 }
1316
1317 void tst_qsgtext::lineCount()
1318 {
1319     QSGView *canvas = createView(SRCDIR "/data/lineCount.qml");
1320
1321     QSGText *myText = canvas->rootObject()->findChild<QSGText*>("myText");
1322     QVERIFY(myText != 0);
1323
1324     QVERIFY(myText->lineCount() > 1);
1325     QVERIFY(!myText->truncated());
1326     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1327
1328     myText->setMaximumLineCount(2);
1329     QCOMPARE(myText->lineCount(), 2);
1330     QCOMPARE(myText->truncated(), true);
1331     QCOMPARE(myText->maximumLineCount(), 2);
1332
1333     myText->resetMaximumLineCount();
1334     QCOMPARE(myText->maximumLineCount(), INT_MAX);
1335     QCOMPARE(myText->truncated(), false);
1336
1337     myText->setElideMode(QSGText::ElideRight);
1338     myText->setMaximumLineCount(2);
1339     QCOMPARE(myText->lineCount(), 2);
1340     QCOMPARE(myText->truncated(), true);
1341     QCOMPARE(myText->maximumLineCount(), 2);
1342
1343     delete canvas;
1344 }
1345
1346 void tst_qsgtext::lineHeight()
1347 {
1348     QSGView *canvas = createView(SRCDIR "/data/lineHeight.qml");
1349
1350     QSGText *myText = canvas->rootObject()->findChild<QSGText*>("myText");
1351     QVERIFY(myText != 0);
1352
1353     QVERIFY(myText->lineHeight() == 1);
1354     QVERIFY(myText->lineHeightMode() == QSGText::ProportionalHeight);
1355
1356     qreal h = myText->height();
1357     myText->setLineHeight(1.5);
1358     QVERIFY(myText->height() == h * 1.5);
1359
1360     myText->setLineHeightMode(QSGText::FixedHeight);
1361     myText->setLineHeight(20);
1362     QCOMPARE(myText->height(), myText->lineCount() * 20.0);
1363
1364     myText->setText("Lorem ipsum sit <b>amet</b>, consectetur adipiscing elit. Integer felis nisl, varius in pretium nec, venenatis non erat. Proin lobortis interdum dictum.");
1365     myText->setLineHeightMode(QSGText::ProportionalHeight);
1366     myText->setLineHeight(1.0);
1367
1368     qreal h2 = myText->height();
1369     myText->setLineHeight(2.0);
1370     QVERIFY(myText->height() == h2 * 2.0);
1371
1372     myText->setLineHeightMode(QSGText::FixedHeight);
1373     myText->setLineHeight(10);
1374     QCOMPARE(myText->height(), myText->lineCount() * 10.0);
1375
1376     delete canvas;
1377 }
1378
1379 void tst_qsgtext::implicitSize_data()
1380 {
1381     QTest::addColumn<QString>("text");
1382     QTest::addColumn<QString>("wrap");
1383     QTest::newRow("plain") << "The quick red fox jumped over the lazy brown dog" << "Text.NoWrap";
1384     QTest::newRow("richtext") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.NoWrap";
1385     QTest::newRow("plain_wrap") << "The quick red fox jumped over the lazy brown dog" << "Text.Wrap";
1386     QTest::newRow("richtext_wrap") << "<b>The quick red fox jumped over the lazy brown dog</b>" << "Text.Wrap";
1387 }
1388
1389 void tst_qsgtext::implicitSize()
1390 {
1391     QFETCH(QString, text);
1392     QFETCH(QString, wrap);
1393     QString componentStr = "import QtQuick 2.0\nText { text: \"" + text + "\"; width: 50; wrapMode: " + wrap + " }";
1394     QDeclarativeComponent textComponent(&engine);
1395     textComponent.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
1396     QSGText *textObject = qobject_cast<QSGText*>(textComponent.create());
1397
1398     QVERIFY(textObject->width() < textObject->implicitWidth());
1399     QVERIFY(textObject->height() == textObject->implicitHeight());
1400
1401     textObject->resetWidth();
1402     QVERIFY(textObject->width() == textObject->implicitWidth());
1403     QVERIFY(textObject->height() == textObject->implicitHeight());
1404
1405     delete textObject;
1406 }
1407
1408 void tst_qsgtext::qtbug_14734()
1409 {
1410     QSGView *canvas = createView(SRCDIR "/data/qtbug_14734.qml");
1411     QVERIFY(canvas);
1412
1413     canvas->show();
1414     QApplication::setActiveWindow(canvas);
1415     QTest::qWaitForWindowShown(canvas);
1416     QTRY_COMPARE(QApplication::activeWindow(), static_cast<QWidget *>(canvas));
1417
1418     delete canvas;
1419 }
1420
1421 QTEST_MAIN(tst_qsgtext)
1422
1423 #include "tst_qsgtext.moc"