1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QDebug>
43 #include <QTextDocument>
44 #include <QTextDocumentWriter>
45 #include <QTextLayout>
46 #include <QTextCursor>
47 #include <private/qtextcontrol_p.h>
48 #include <qmath.h>
49 #include <QFile>
50 #include <QPainter>
51 #include <QBuffer>
52 #include <qtest.h>
53
54 #ifdef Q_OS_SYMBIAN
55 // In Symbian OS test data is located in applications private dir
56 // Application private dir is default serach path for files, so SRCDIR can be set to empty
57 #define SRCDIR ""
58 #endif
59
60 Q_DECLARE_METATYPE(QTextDocument*)
61
62 class tst_QText: public QObject
63 {
64 Q_OBJECT
65 public:
tst_QText()66 tst_QText() {
67 m_lorem = QString::fromLatin1("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.");
68 m_shortLorem = QString::fromLatin1("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
69 }
70
71 private slots:
72 void loadHtml_data();
73 void loadHtml();
74
75 void shaping_data();
76 void shaping();
77
78 void odfWriting_empty();
79 void odfWriting_text();
80 void odfWriting_images();
81
82 void constructControl();
83 void constructDocument();
84
85 void newLineReplacement();
86 void formatManipulation();
87 void fontResolution();
88
89 void layout_data();
90 void layout();
91 void formattedLayout();
92 void paintLayoutToPixmap();
93 void paintLayoutToPixmap_painterFill();
94
95 void document();
96 void paintDocToPixmap();
97 void paintDocToPixmap_painterFill();
98
99 void control();
100 void paintControlToPixmap();
101 void paintControlToPixmap_painterFill();
102
103 private:
104 QSize setupTextLayout(QTextLayout *layout, bool wrap = true, int wrapWidth = 100);
105
106 QString m_lorem;
107 QString m_shortLorem;
108 };
109
loadHtml_data()110 void tst_QText::loadHtml_data()
111 {
112 QTest::addColumn<QString>("source");
113 QTest::newRow("empty") << QString();
114 QTest::newRow("simple") << QString::fromLatin1("<html><b>Foo</b></html>");
115 QTest::newRow("simple2") << QString::fromLatin1("<b>Foo</b>");
116
117 QString parag = QString::fromLatin1("<p>%1</p>").arg(m_lorem);
118 QString header = QString::fromLatin1("<html><head><title>test</title></head><body>");
119 QTest::newRow("long") << QString::fromLatin1("<html><head><title>test</title></head><body>") + parag + parag + parag
120 + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag + parag
121 + QString::fromLatin1("</html>");
122 QTest::newRow("table") << header + QLatin1String("<table border=\"1\"1><tr><td>xx</td></tr><tr><td colspan=\"2\">")
123 + parag + QLatin1String("</td></tr></table></html");
124 QTest::newRow("crappy") << header + QLatin1String("<table border=\"1\"1><tr><td>xx</td></tr><tr><td colspan=\"2\">")
125 + parag;
126 }
127
loadHtml()128 void tst_QText::loadHtml()
129 {
130 QFETCH(QString, source);
131 QTextDocument doc;
132 QBENCHMARK {
133 doc.setHtml(source);
134 }
135 }
136
shaping_data()137 void tst_QText::shaping_data()
138 {
139 QTest::addColumn<QString>("parag");
140 QTest::newRow("empty") << QString();
141 QTest::newRow("lorem") << m_lorem;
142 QTest::newRow("short") << QString::fromLatin1("Lorem ipsum dolor sit amet");
143
144 #if !defined(Q_OS_SYMBIAN)
145 QFile file(QString::fromLatin1(SRCDIR) + QLatin1String("/bidi.txt"));
146 #else
147 QFile file( SRCDIR "bidi.txt" );
148 #endif
149 QVERIFY(file.open(QFile::ReadOnly));
150 QByteArray data = file.readAll();
151 QVERIFY(data.count() > 1000);
152 QStringList list = QString::fromUtf8(data.data()).split(QLatin1Char('\n'), QString::SkipEmptyParts);
153 QVERIFY(list.count() %2 == 0); // even amount as we have title and then content.
154 for (int i=0; i < list.count(); i+=2) {
155 QTest::newRow(list.at(i).toLatin1()) << list.at(i+1);
156 }
157 }
158
shaping()159 void tst_QText::shaping()
160 {
161 QFETCH(QString, parag);
162
163 QTextLayout lay(parag);
164 lay.setCacheEnabled(false);
165
166 // do one run to make sure any fonts are loaded.
167 lay.beginLayout();
168 lay.createLine();
169 lay.endLayout();
170
171 QBENCHMARK {
172 lay.beginLayout();
173 lay.createLine();
174 lay.endLayout();
175 }
176 }
177
odfWriting_empty()178 void tst_QText::odfWriting_empty()
179 {
180 QVERIFY(QTextDocumentWriter::supportedDocumentFormats().contains("ODF")); // odf compiled in
181 QTextDocument *doc = new QTextDocument();
182 // write it
183 QBENCHMARK {
184 QBuffer buffer;
185 buffer.open(QIODevice::WriteOnly);
186 QTextDocumentWriter writer(&buffer, "ODF");
187 writer.write(doc);
188 }
189 delete doc;
190 }
191
odfWriting_text()192 void tst_QText::odfWriting_text()
193 {
194 QTextDocument *doc = new QTextDocument();
195 QTextCursor cursor(doc);
196 QTextBlockFormat bf;
197 bf.setIndent(2);
198 cursor.insertBlock(bf);
199 cursor.insertText(m_lorem);
200 bf.setTopMargin(10);
201 cursor.insertBlock(bf);
202 cursor.insertText(m_lorem);
203 bf.setRightMargin(30);
204 cursor.insertBlock(bf);
205 cursor.insertText(m_lorem);
206
207 // write it
208 QBENCHMARK {
209 QBuffer buffer;
210 buffer.open(QIODevice::WriteOnly);
211 QTextDocumentWriter writer(&buffer, "ODF");
212 writer.write(doc);
213 }
214 delete doc;
215 }
216
odfWriting_images()217 void tst_QText::odfWriting_images()
218 {
219 QTextDocument *doc = new QTextDocument();
220 QTextCursor cursor(doc);
221 cursor.insertText(m_lorem);
222 QImage image(400, 200, QImage::Format_ARGB32_Premultiplied);
223 cursor.insertImage(image);
224 cursor.insertText(m_lorem);
225
226 // write it
227 QBENCHMARK {
228 QBuffer buffer;
229 buffer.open(QIODevice::WriteOnly);
230 QTextDocumentWriter writer(&buffer, "ODF");
231 writer.write(doc);
232 }
233 delete doc;
234 }
235
setupTextLayout(QTextLayout * layout,bool wrap,int wrapWidth)236 QSize tst_QText::setupTextLayout(QTextLayout *layout, bool wrap, int wrapWidth)
237 {
238 layout->setCacheEnabled(true);
239
240 int height = 0;
241 qreal widthUsed = 0;
242 qreal lineWidth = 0;
243
244 //set manual width
245 if (wrap)
246 lineWidth = wrapWidth;
247
248 layout->beginLayout();
249 while (1) {
250 QTextLine line = layout->createLine();
251 if (!line.isValid())
252 break;
253
254 if (wrap)
255 line.setLineWidth(lineWidth);
256 }
257 layout->endLayout();
258
259 for (int i = 0; i < layout->lineCount(); ++i) {
260 QTextLine line = layout->lineAt(i);
261 widthUsed = qMax(widthUsed, line.naturalTextWidth());
262 line.setPosition(QPointF(0, height));
263 height += int(line.height());
264 }
265 return QSize(qCeil(widthUsed), height);
266 }
267
constructControl()268 void tst_QText::constructControl()
269 {
270 QTextControl *control = new QTextControl;
271 delete control;
272
273 QBENCHMARK {
274 QTextControl *control = new QTextControl;
275 delete control;
276 }
277 }
278
constructDocument()279 void tst_QText::constructDocument()
280 {
281 QTextDocument *doc = new QTextDocument;
282 delete doc;
283
284 QBENCHMARK {
285 QTextDocument *doc = new QTextDocument;
286 delete doc;
287 }
288 }
289
290 //this step is needed before giving the string to a QTextLayout
newLineReplacement()291 void tst_QText::newLineReplacement()
292 {
293 QString text = QString::fromLatin1("H\ne\nl\nl\no\n\nW\no\nr\nl\nd");
294
295 QBENCHMARK {
296 QString tmp = text;
297 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
298 }
299 }
300
formatManipulation()301 void tst_QText::formatManipulation()
302 {
303 QFont font;
304
305 QBENCHMARK {
306 QTextCharFormat format;
307 format.setFont(font);
308 }
309 }
310
fontResolution()311 void tst_QText::fontResolution()
312 {
313 QFont font;
314 QFont font2;
315 font.setFamily("DejaVu");
316 font2.setBold(true);
317
318 QBENCHMARK {
319 QFont res = font.resolve(font2);
320 }
321 }
322
layout_data()323 void tst_QText::layout_data()
324 {
325 QTest::addColumn<bool>("wrap");
326 QTest::newRow("wrap") << true;
327 QTest::newRow("nowrap") << false;
328 }
329
layout()330 void tst_QText::layout()
331 {
332 QFETCH(bool,wrap);
333 QTextLayout layout(m_shortLorem);
334 setupTextLayout(&layout, wrap);
335
336 QBENCHMARK {
337 QTextLayout layout(m_shortLorem);
338 setupTextLayout(&layout, wrap);
339 }
340 }
341
342 //### requires tst_QText to be a friend of QTextLayout
343 /*void tst_QText::stackTextLayout()
344 {
345 QStackTextEngine engine(m_shortLorem, qApp->font());
346 QTextLayout layout(&engine);
347 setupTextLayout(&layout);
348
349 QBENCHMARK {
350 QStackTextEngine engine(m_shortLorem, qApp->font());
351 QTextLayout layout(&engine);
352 setupTextLayout(&layout);
353 }
354 }*/
355
formattedLayout()356 void tst_QText::formattedLayout()
357 {
358 //set up formatting
359 QList<QTextLayout::FormatRange> ranges;
360 {
361 QTextCharFormat format;
362 format.setForeground(QColor("steelblue"));
363
364 QTextLayout::FormatRange formatRange;
365 formatRange.format = format;
366 formatRange.start = 0;
367 formatRange.length = 50;
368
369 ranges.append(formatRange);
370 }
371
372 QTextLayout layout(m_shortLorem);
373 layout.setAdditionalFormats(ranges);
374 setupTextLayout(&layout);
375
376 QBENCHMARK {
377 QTextLayout layout(m_shortLorem);
378 layout.setAdditionalFormats(ranges);
379 setupTextLayout(&layout);
380 }
381 }
382
paintLayoutToPixmap()383 void tst_QText::paintLayoutToPixmap()
384 {
385 QTextLayout layout(m_shortLorem);
386 QSize size = setupTextLayout(&layout);
387
388 QBENCHMARK {
389 QPixmap img(size);
390 img.fill(Qt::transparent);
391 QPainter p(&img);
392 layout.draw(&p, QPointF(0, 0));
393 }
394 }
395
paintLayoutToPixmap_painterFill()396 void tst_QText::paintLayoutToPixmap_painterFill()
397 {
398 QTextLayout layout(m_shortLorem);
399 QSize size = setupTextLayout(&layout);
400
401 QBENCHMARK {
402 QPixmap img(size);
403 QPainter p(&img);
404 p.setCompositionMode(QPainter::CompositionMode_Source);
405 p.fillRect(0, 0, img.width(), img.height(), Qt::transparent);
406 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
407 layout.draw(&p, QPointF(0, 0));
408 }
409 }
410
document()411 void tst_QText::document()
412 {
413 QTextDocument *doc = new QTextDocument;
414
415 QBENCHMARK {
416 QTextDocument *doc = new QTextDocument;
417 doc->setHtml(m_shortLorem);
418 }
419 }
420
paintDocToPixmap()421 void tst_QText::paintDocToPixmap()
422 {
423 QTextDocument *doc = new QTextDocument;
424 doc->setHtml(m_shortLorem);
425 doc->setTextWidth(300);
426 QSize size = doc->size().toSize();
427
428 QBENCHMARK {
429 QPixmap img(size);
430 img.fill(Qt::transparent);
431 QPainter p(&img);
432 doc->drawContents(&p);
433 }
434 }
435
paintDocToPixmap_painterFill()436 void tst_QText::paintDocToPixmap_painterFill()
437 {
438 QTextDocument *doc = new QTextDocument;
439 doc->setHtml(m_shortLorem);
440 doc->setTextWidth(300);
441 QSize size = doc->size().toSize();
442
443 QBENCHMARK {
444 QPixmap img(size);
445 QPainter p(&img);
446 p.setCompositionMode(QPainter::CompositionMode_Source);
447 p.fillRect(0, 0, img.width(), img.height(), Qt::transparent);
448 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
449 doc->drawContents(&p);
450 }
451 }
452
control()453 void tst_QText::control()
454 {
455 QTextControl *control = new QTextControl(m_shortLorem);
456
457 QBENCHMARK {
458 QTextControl *control = new QTextControl;
459 QTextDocument *doc = control->document();
460 doc->setHtml(m_shortLorem);
461 }
462 }
463
paintControlToPixmap()464 void tst_QText::paintControlToPixmap()
465 {
466 QTextControl *control = new QTextControl;
467 QTextDocument *doc = control->document();
468 doc->setHtml(m_shortLorem);
469 doc->setTextWidth(300);
470 QSize size = doc->size().toSize();
471
472 QBENCHMARK {
473 QPixmap img(size);
474 img.fill(Qt::transparent);
475 QPainter p(&img);
476 control->drawContents(&p, QRectF(QPointF(0, 0), QSizeF(size)));
477 }
478 }
479
paintControlToPixmap_painterFill()480 void tst_QText::paintControlToPixmap_painterFill()
481 {
482 QTextControl *control = new QTextControl;
483 QTextDocument *doc = control->document();
484 doc->setHtml(m_shortLorem);
485 doc->setTextWidth(300);
486 QSize size = doc->size().toSize();
487
488 QBENCHMARK {
489 QPixmap img(size);
490 QPainter p(&img);
491 p.setCompositionMode(QPainter::CompositionMode_Source);
492 p.fillRect(0, 0, img.width(), img.height(), Qt::transparent);
493 p.setCompositionMode(QPainter::CompositionMode_SourceOver);
494 control->drawContents(&p, QRectF(QPointF(0, 0), QSizeF(size)));
495 }
496 }
497
498 QTEST_MAIN(tst_QText)
499
500 #include "main.moc"
501