1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QtTest> |
31 | |
32 | |
33 | #include <qtextdocument.h> |
34 | #include <qtextdocumentfragment.h> |
35 | #include <qtexttable.h> |
36 | #include <qtextlist.h> |
37 | #include <qregularexpression.h> |
38 | #include <qdebug.h> |
39 | #include <private/qtextdocument_p.h> |
40 | |
41 | |
42 | #include <qtextcursor.h> |
43 | |
44 | QT_FORWARD_DECLARE_CLASS(QTextDocument) |
45 | |
46 | class tst_QTextDocumentFragment : public QObject |
47 | { |
48 | Q_OBJECT |
49 | |
50 | public: |
51 | tst_QTextDocumentFragment(); |
52 | ~tst_QTextDocumentFragment(); |
53 | |
54 | public slots: |
55 | void init(); |
56 | void cleanup(); |
57 | private slots: |
58 | void listCopying(); |
59 | void listZeroCopying(); |
60 | void listCopying2(); |
61 | void tableCopying(); |
62 | void tableCopyingWithColSpans(); |
63 | void tableColSpanAndWidth(); |
64 | void tableImport(); |
65 | void tableImport2(); |
66 | void tableImport3(); |
67 | void tableImport4(); |
68 | void tableImport5(); |
69 | void textCopy(); |
70 | void copyWholeDocument(); |
71 | void title(); |
72 | void html_listIndents1(); |
73 | void html_listIndents2(); |
74 | void html_listIndents3(); |
75 | void html_listIndents4(); |
76 | void html_listIndents5(); |
77 | void html_listIndents6(); |
78 | void html_listIndents7(); |
79 | void blockCharFormat(); |
80 | void blockCharFormatCopied(); |
81 | void initialBlock(); |
82 | void clone(); |
83 | void dontRemoveInitialBlockIfItHoldsObjectIndexedCharFormat(); |
84 | void dosLineFeed(); |
85 | void unorderedListEnumeration(); |
86 | void resetHasBlockAfterClosedBlockTags(); |
87 | void ignoreStyleTags(); |
88 | void hrefAnchor(); |
89 | void namedAnchorFragments(); |
90 | void namedAnchorFragments2(); |
91 | void namedAnchorFragments3(); |
92 | void dontInheritAlignmentInTables(); |
93 | void cellBlockCount(); |
94 | void cellBlockCount2(); |
95 | void emptyTable(); |
96 | void emptyTable2(); |
97 | void emptyTable3(); |
98 | void doubleRowClose(); |
99 | void mayNotHaveChildren(); |
100 | void inheritAlignment(); |
101 | void dontEmitEmptyNodeWhenEmptyTagIsFollowedByCloseTag(); |
102 | void toPlainText(); |
103 | void copyTableRow(); |
104 | void copyTableColumn(); |
105 | void copySubTable(); |
106 | void html_textDecoration(); |
107 | void html_infiniteLoop(); |
108 | void html_blockIndent(); |
109 | void html_listIndent(); |
110 | void html_whitespace(); |
111 | void html_whitespace_data(); |
112 | void html_qt3Whitespace(); |
113 | void html_qt3WhitespaceWithFragments(); |
114 | void html_qt3WhitespaceAfterTags(); |
115 | void html_listStart1(); |
116 | void html_listStart2(); |
117 | void html_cssMargin(); |
118 | void html_hexEntities(); |
119 | void html_decEntities(); |
120 | void html_thCentered(); |
121 | void orderedListNumbering(); |
122 | void html_blockAfterList(); |
123 | void html_subAndSuperScript(); |
124 | void html_cssColors(); |
125 | void obeyFragmentMarkersInImport(); |
126 | void whitespaceWithFragmentMarkers(); |
127 | void html_emptyParapgraphs1(); |
128 | void html_emptyParapgraphs2(); |
129 | void html_emptyParagraphs3(); |
130 | void html_emptyParagraphs4(); |
131 | void html_font(); |
132 | void html_fontSize(); |
133 | void html_fontSizeAdjustment(); |
134 | void html_cssFontSize(); |
135 | void html_cssShorthandFont(); |
136 | void html_bodyBgColor(); |
137 | void html_qtBgColor(); |
138 | void html_blockLevelDiv(); |
139 | void html_spanNesting(); |
140 | void html_nestedLists(); |
141 | void noSpecialCharactersInPlainText(); |
142 | void html_doNotInheritBackground(); |
143 | void html_inheritBackgroundToInlineElements(); |
144 | void html_doNotInheritBackgroundFromBlockElements(); |
145 | void html_nobr(); |
146 | void fromPlainText(); |
147 | void fromPlainText2(); |
148 | void html_closingImageTag(); |
149 | void html_emptyDocument(); |
150 | void html_closingTag(); |
151 | void html_anchorAroundImage(); |
152 | void html_floatBorder(); |
153 | void html_frameImport(); |
154 | void html_frameImport2(); |
155 | void html_dontAddMarginsAcrossTableCells(); |
156 | void html_dontMergeCenterBlocks(); |
157 | void html_tableCellBgColor(); |
158 | void html_tableCellBgColor2(); |
159 | void html_cellSkip(); |
160 | void nonZeroMarginOnImport(); |
161 | void html_charFormatPropertiesUnset(); |
162 | void html_headings(); |
163 | void html_quotedFontFamily_data(); |
164 | void html_quotedFontFamily(); |
165 | void html_spanBackgroundColor(); |
166 | void defaultFont(); |
167 | void html_brokenTitle_data(); |
168 | void html_brokenTitle(); |
169 | void html_blockVsInline(); |
170 | void html_tbody(); |
171 | void html_nestedTables(); |
172 | void html_rowSpans(); |
173 | void html_rowSpans2(); |
174 | void html_implicitParagraphs(); |
175 | void html_missingCloseTag(); |
176 | void html_anchorColor(); |
177 | void html_lastParagraphClosing(); |
178 | void html_tableHeaderBodyFootParent(); |
179 | void html_columnWidths(); |
180 | void html_bodyBackground(); |
181 | void html_tableCellBackground(); |
182 | void css_bodyBackground(); |
183 | void css_tableCellBackground(); |
184 | void css_tableCellBorder(); |
185 | void css_tableCellBorderWidthOneValue(); |
186 | void css_tableCellBorderWidthTwoValues(); |
187 | void css_tableCellBorderShorthand(); |
188 | void css_tableCellAllBordersShorthand(); |
189 | void css_tableCellOverrideOneBorder(); |
190 | void css_tableBorderCollapse(); |
191 | void css_fontWeight(); |
192 | void css_float(); |
193 | void css_textIndent(); |
194 | void css_inline(); |
195 | void css_external(); |
196 | void css_import(); |
197 | void css_selectors_data(); |
198 | void css_selectors(); |
199 | void css_nodeNameCaseInsensitivity(); |
200 | void css_textUnderlineStyle_data(); |
201 | void css_textUnderlineStyle(); |
202 | void css_textUnderlineStyleAndDecoration(); |
203 | void css_listStyleType(); |
204 | void css_linkPseudo(); |
205 | void css_pageBreaks(); |
206 | void css_cellPaddings(); |
207 | void css_whiteSpace_data(); |
208 | void css_whiteSpace(); |
209 | void universalSelectors_data(); |
210 | void universalSelectors(); |
211 | void screenMedia(); |
212 | void htmlResourceLoading(); |
213 | void someCaseInsensitiveAttributeValues(); |
214 | void backgroundImage(); |
215 | void dontMergePreAndNonPre(); |
216 | void leftMarginInsideHtml(); |
217 | void html_margins(); |
218 | void newlineInsidePreShouldBecomeNewParagraph(); |
219 | void invalidColspan(); |
220 | void html_brokenTableWithJustTr(); |
221 | void html_brokenTableWithJustTd(); |
222 | void html_preNewlineHandling_data(); |
223 | void html_preNewlineHandling(); |
224 | void html_br(); |
225 | void html_dl(); |
226 | void html_tableStrangeNewline(); |
227 | void html_tableStrangeNewline2(); |
228 | void html_tableStrangeNewline3(); |
229 | void html_caption(); |
230 | void html_windowsEntities(); |
231 | void html_eatenText(); |
232 | void html_hr(); |
233 | void html_hrMargins(); |
234 | void html_blockQuoteMargins(); |
235 | void html_definitionListMargins(); |
236 | void html_listMargins(); |
237 | void html_titleAttribute(); |
238 | void html_compressDivs(); |
239 | void completeToPlainText(); |
240 | void copyContents(); |
241 | void html_textAfterHr(); |
242 | void blockTagClosing(); |
243 | void isEmpty(); |
244 | void html_alignmentInheritance(); |
245 | void html_ignoreEmptyDivs(); |
246 | void html_dontInheritAlignmentForFloatingImages(); |
247 | void html_verticalImageAlignment(); |
248 | void html_verticalCellAlignment(); |
249 | void html_borderColor(); |
250 | void html_borderStyle(); |
251 | void html_borderWidth(); |
252 | void html_userState(); |
253 | void html_rootFrameProperties(); |
254 | void html_alignmentPropertySet(); |
255 | void html_appendList(); |
256 | void html_appendList2(); |
257 | void html_qt3RichtextWhitespaceMode(); |
258 | void html_brAfterHr(); |
259 | void html_unclosedHead(); |
260 | void html_entities(); |
261 | void html_entities_data(); |
262 | void html_ignore_script(); |
263 | void html_directionWithHtml(); |
264 | void html_directionWithRichText(); |
265 | void html_metaInBody(); |
266 | void html_importImageWithoutAspectRatio(); |
267 | void html_fromFirefox(); |
268 | void html_emptyInlineInsideBlock(); |
269 | void css_fontAndWordSpacing(); |
270 | |
271 | private: |
272 | inline void setHtml(const QString &html) |
273 | // don't take the shortcut in QTextDocument::setHtml |
274 | { doc->clear(); QTextCursor(doc).insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); } |
275 | |
276 | inline void appendHtml(const QString &html) |
277 | { |
278 | QTextCursor cursor(doc); |
279 | cursor.movePosition(op: QTextCursor::End); |
280 | cursor.insertHtml(html); |
281 | } |
282 | |
283 | QTextDocument *doc; |
284 | QTextCursor cursor; |
285 | }; |
286 | |
287 | tst_QTextDocumentFragment::tst_QTextDocumentFragment() |
288 | { |
289 | QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); |
290 | img.save(fileName: "foo.png" ); |
291 | } |
292 | |
293 | tst_QTextDocumentFragment::~tst_QTextDocumentFragment() |
294 | { |
295 | QFile::remove(fileName: QLatin1String("foo.png" )); |
296 | } |
297 | |
298 | void tst_QTextDocumentFragment::init() |
299 | { |
300 | doc = new QTextDocument; |
301 | cursor = QTextCursor(doc); |
302 | } |
303 | |
304 | void tst_QTextDocumentFragment::cleanup() |
305 | { |
306 | cursor = QTextCursor(); |
307 | delete doc; |
308 | doc = 0; |
309 | } |
310 | |
311 | void tst_QTextDocumentFragment::listCopying() |
312 | { |
313 | cursor.insertList(style: QTextListFormat::ListDecimal); |
314 | |
315 | QTextFormat originalBlockFormat = cursor.blockFormat(); |
316 | QVERIFY(originalBlockFormat.objectIndex() != -1); |
317 | int originalListItemIdx = cursor.blockFormat().objectIndex(); |
318 | |
319 | cursor.insertText(text: "Hello World" ); |
320 | |
321 | QTextDocumentFragment fragment(doc); |
322 | |
323 | cursor.insertFragment(fragment); |
324 | |
325 | QVERIFY(cursor.currentList()); |
326 | QVERIFY(cursor.blockFormat() != originalBlockFormat); |
327 | QVERIFY(cursor.blockFormat().objectIndex() != originalListItemIdx); |
328 | } |
329 | |
330 | void tst_QTextDocumentFragment::listZeroCopying() |
331 | { |
332 | // same testcase as above but using the zero-copying |
333 | |
334 | cursor.insertList(style: QTextListFormat::ListDecimal); |
335 | |
336 | QTextFormat originalBlockFormat = cursor.blockFormat(); |
337 | int originalListItemIdx = cursor.blockFormat().objectIndex(); |
338 | |
339 | cursor.insertText(text: "Hello World" ); |
340 | |
341 | QTextDocumentFragment fragment(doc); |
342 | cursor.insertFragment(fragment); |
343 | |
344 | QVERIFY(cursor.currentList()); |
345 | QVERIFY(cursor.blockFormat() != originalBlockFormat); |
346 | QVERIFY(cursor.blockFormat().objectIndex() != originalListItemIdx); |
347 | } |
348 | |
349 | void tst_QTextDocumentFragment::listCopying2() |
350 | { |
351 | cursor.insertList(style: QTextListFormat::ListDecimal); |
352 | cursor.insertText(text: "Hello World" ); |
353 | |
354 | cursor.insertList(style: QTextListFormat::ListDisc); |
355 | cursor.insertText(text: "Hello World" ); |
356 | |
357 | QTextDocumentFragment fragment(doc); |
358 | |
359 | cursor.insertFragment(fragment); |
360 | |
361 | cursor.movePosition(op: QTextCursor::Start); |
362 | int listItemCount = 0; |
363 | do { |
364 | if (cursor.currentList()) |
365 | listItemCount++; |
366 | } while (cursor.movePosition(op: QTextCursor::NextBlock)); |
367 | |
368 | QCOMPARE(listItemCount, 4); |
369 | |
370 | // we call this here because it used to cause a failing assertion in the |
371 | // list manager. |
372 | doc->undo(); |
373 | } |
374 | |
375 | void tst_QTextDocumentFragment::tableCopying() |
376 | { |
377 | // this tests both, the fragment to use the direction insertion instead of using the |
378 | // cursor, which might adjuts its position when inserting a table step by step, as well |
379 | // as the pasiveness of the tablemanager. |
380 | QTextDocumentFragment fragment; |
381 | { |
382 | QTextDocument doc; |
383 | QTextCursor cursor(&doc); |
384 | |
385 | QTextTableFormat fmt; |
386 | QTextTable *table = cursor.insertTable(rows: 2, cols: 2, format: fmt); |
387 | |
388 | table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "First Cell" ); |
389 | table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Second Cell" ); |
390 | table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Third Cell" ); |
391 | table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Fourth Cell" ); |
392 | |
393 | fragment = QTextDocumentFragment(&doc); |
394 | } |
395 | { |
396 | QTextDocument doc; |
397 | QTextCursor cursor(&doc); |
398 | |
399 | cursor.insertText(text: "FooBar" ); |
400 | cursor.insertBlock(); |
401 | cursor.movePosition(op: QTextCursor::Left); |
402 | |
403 | cursor.insertFragment(fragment); |
404 | cursor.movePosition(op: QTextCursor::Start); |
405 | cursor.movePosition(op: QTextCursor::NextBlock); |
406 | |
407 | QTextTable *table = cursor.currentTable(); |
408 | QVERIFY(table); |
409 | QCOMPARE(table->rows(), 2); |
410 | QCOMPARE(table->columns(), 2); |
411 | } |
412 | } |
413 | |
414 | void tst_QTextDocumentFragment::tableCopyingWithColSpans() |
415 | { |
416 | const char html[] = "" |
417 | "<table border>" |
418 | " <tr>" |
419 | " <td>First Cell" |
420 | " <td>Second Cell" |
421 | " </tr>" |
422 | " <tr>" |
423 | " <td colspan=\"2\">Third Cell" |
424 | " </tr>" |
425 | " <tr>" |
426 | " <td>Fourth Cell" |
427 | " <td>Fifth Cell" |
428 | " </tr>" |
429 | "</table>" ; |
430 | setHtml(html); |
431 | |
432 | cursor.movePosition(op: QTextCursor::Start); |
433 | cursor.movePosition(op: QTextCursor::NextBlock); |
434 | QTextTable *table = cursor.currentTable(); |
435 | QVERIFY(table); |
436 | QVERIFY(table->columns() == 2 && table->rows() == 3); |
437 | |
438 | cursor = table->cellAt(row: 2, col: 0).lastCursorPosition(); |
439 | cursor.setPosition(pos: table->cellAt(row: 0, col: 0).firstPosition(), mode: QTextCursor::KeepAnchor); |
440 | QVERIFY(cursor.hasComplexSelection()); |
441 | |
442 | int firstRow = 0, numRows = 0, firstCol = 0, numCols = 0; |
443 | cursor.selectedTableCells(firstRow: &firstRow, numRows: &numRows, firstColumn: &firstCol, numColumns: &numCols); |
444 | QCOMPARE(firstRow, 0); |
445 | QCOMPARE(numRows, 3); |
446 | QCOMPARE(firstCol, 0); |
447 | QCOMPARE(numCols, 1); |
448 | |
449 | QTextDocumentFragment frag = cursor.selection(); |
450 | cleanup(); |
451 | init(); |
452 | cursor.insertFragment(fragment: frag); |
453 | |
454 | cursor.movePosition(op: QTextCursor::Start); |
455 | cursor.movePosition(op: QTextCursor::NextBlock); |
456 | table = cursor.currentTable(); |
457 | QVERIFY(table); |
458 | QVERIFY(table->columns() == 1 && table->rows() == 3); |
459 | } |
460 | |
461 | void tst_QTextDocumentFragment::tableColSpanAndWidth() |
462 | { |
463 | const char html[] = "" |
464 | "<table border=\"0\">" |
465 | " <tr>" |
466 | " <td colspan=\"4\" width=\"400\">First Cell</td>" |
467 | " </tr>" |
468 | "</table>" ; |
469 | setHtml(html); |
470 | |
471 | cursor.movePosition(op: QTextCursor::Start); |
472 | cursor.movePosition(op: QTextCursor::NextBlock); |
473 | QTextTable *table = cursor.currentTable(); |
474 | QVERIFY(table); |
475 | QVERIFY(table->columns() == 4 && table->rows() == 1); |
476 | // make sure its approx 400 and not a multiple due to the colspan |
477 | QVERIFY(doc->size().width()> 398.); |
478 | QVERIFY(doc->size().width() < 420.); |
479 | } |
480 | |
481 | void tst_QTextDocumentFragment::tableImport() |
482 | { |
483 | // used to cause a failing assertion, as HTMLImporter::closeTag was |
484 | // called twice with the last node. |
485 | QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: "<table><tr><td>Hey</td><td>Blah" )); |
486 | QVERIFY(!fragment.isEmpty()); |
487 | } |
488 | |
489 | void tst_QTextDocumentFragment::tableImport2() |
490 | { |
491 | { |
492 | const char html[] = "" |
493 | "<table>" |
494 | "<tr><td>First Cell</td><td>Second Cell</td></tr>" |
495 | "<tr><td>Third Cell</td><td>Fourth Cell</td></tr>" |
496 | "</table>" ; |
497 | |
498 | QTextDocument doc; |
499 | QTextCursor cursor(&doc); |
500 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QByteArray::fromRawData(html, size: sizeof(html) / sizeof(html[0])))); |
501 | |
502 | cursor.movePosition(op: QTextCursor::Start); |
503 | cursor.movePosition(op: QTextCursor::NextBlock); |
504 | QTextTable *table = cursor.currentTable(); |
505 | QVERIFY(table); |
506 | QCOMPARE(table->columns(), 2); |
507 | QCOMPARE(table->rows(), 2); |
508 | } |
509 | { |
510 | const char html[] = "" |
511 | "<table>" |
512 | "<tr><td>First Cell</td><td>Second Cell</td></tr>" |
513 | "<tr><td>Third Cell</td><td>" |
514 | " <table>" |
515 | " <tr><td>First Nested Cell</td><td>Second Nested Cell</td></tr>" |
516 | " <tr><td>Third Nested Cell</td><td>Fourth Nested Cell</td></tr>" |
517 | " <tr><td>Fifth Nested Cell</td><td>Sixth Nested Cell</td></tr>" |
518 | " </table></td></tr>" |
519 | "</table>" ; |
520 | |
521 | QTextDocument doc; |
522 | QTextCursor cursor(&doc); |
523 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QByteArray::fromRawData(html, size: sizeof(html) / sizeof(html[0])))); |
524 | |
525 | cursor.movePosition(op: QTextCursor::Start); |
526 | cursor.movePosition(op: QTextCursor::NextBlock); |
527 | QTextTable *table = cursor.currentTable(); |
528 | QVERIFY(table); |
529 | QCOMPARE(table->columns(), 2); |
530 | QCOMPARE(table->rows(), 2); |
531 | |
532 | /* |
533 | QTextCursor fourthCell = table->cellAt(1, 1).firstCursorPosition(); |
534 | fourthCell.movePosition(QTextCursor::NextBlock); |
535 | table = fourthCell.currentTable(); |
536 | QVERIFY(table); |
537 | QVERIFY(table != cursor.currentTable()); |
538 | QCOMPARE(table->columns(), 2); |
539 | QCOMPARE(table->rows(), 3); |
540 | */ |
541 | } |
542 | { |
543 | const char buggyHtml[] = "" |
544 | "<table>" |
545 | "<tr><td>First Cell<td>Second Cell" |
546 | "<tr><td>Third Cell<td>Fourth Cell" |
547 | "</table>" ; |
548 | |
549 | QTextDocument doc; |
550 | QTextCursor cursor(&doc); |
551 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QByteArray::fromRawData(buggyHtml, size: sizeof(buggyHtml) / sizeof(buggyHtml[0])))); |
552 | |
553 | cursor.movePosition(op: QTextCursor::Start); |
554 | cursor.movePosition(op: QTextCursor::NextBlock); |
555 | QTextTable *table = cursor.currentTable(); |
556 | QVERIFY(table); |
557 | QCOMPARE(table->columns(), 2); |
558 | QCOMPARE(table->rows(), 2); |
559 | } |
560 | { |
561 | const char buggyHtml[] = "" |
562 | "<table>" |
563 | "<tr><th>First Cell<th>Second Cell" |
564 | "<tr><td>Third Cell<td>Fourth Cell" |
565 | "</table>" ; |
566 | |
567 | QTextDocument doc; |
568 | QTextCursor cursor(&doc); |
569 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QByteArray::fromRawData(buggyHtml, size: sizeof(buggyHtml) / sizeof(buggyHtml[0])))); |
570 | |
571 | cursor.movePosition(op: QTextCursor::Start); |
572 | cursor.movePosition(op: QTextCursor::NextBlock); |
573 | QTextTable *table = cursor.currentTable(); |
574 | QVERIFY(table); |
575 | QCOMPARE(table->columns(), 2); |
576 | QCOMPARE(table->rows(), 2); |
577 | } |
578 | |
579 | } |
580 | |
581 | void tst_QTextDocumentFragment::tableImport3() |
582 | { |
583 | // ### would be better to have tree tests for QTextHtmlParser |
584 | // make sure the p is a child of the td. If not the following td |
585 | // ends up outside the table, causing an assertion |
586 | const char html[] = "<table><tr><td><p></p></td><td></td></tr></table>" ; |
587 | QTextDocumentFragment fragment = QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html)); |
588 | QVERIFY(!fragment.isEmpty()); |
589 | } |
590 | |
591 | void tst_QTextDocumentFragment::tableImport4() |
592 | { |
593 | const char html[] = "<table>" |
594 | "<tr><td>blah</td></tr>" |
595 | "<tr><td>blah</td><td>blah</td></tr>" |
596 | "</table>" ; |
597 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
598 | cursor.movePosition(op: QTextCursor::Start); |
599 | cursor.movePosition(op: QTextCursor::NextBlock); |
600 | QVERIFY(cursor.currentTable()); |
601 | QCOMPARE(cursor.currentTable()->columns(), 2); |
602 | } |
603 | |
604 | void tst_QTextDocumentFragment::tableImport5() |
605 | { |
606 | const char html[] = "<table>" |
607 | "<tr>" |
608 | " <td>Foo</td>" |
609 | " <td>Bar</td>" |
610 | " <td>Bleh</td>" |
611 | " <td>Blub</td>" |
612 | "</tr>" |
613 | "<tr>" |
614 | " <td>Ahh</td>" |
615 | " <td colspan=5>Gah</td>" |
616 | "</tr>" |
617 | "</table>" ; |
618 | |
619 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
620 | cursor.movePosition(op: QTextCursor::Start); |
621 | cursor.movePosition(op: QTextCursor::NextBlock); |
622 | QVERIFY(cursor.currentTable()); |
623 | QCOMPARE(cursor.currentTable()->rows(), 2); |
624 | QCOMPARE(cursor.currentTable()->columns(), 6); |
625 | } |
626 | |
627 | void tst_QTextDocumentFragment::textCopy() |
628 | { |
629 | /* this test used to cause failing assertions in QTextDocumentFragment */ |
630 | /* copy&paste 'lo\bwor' */ |
631 | cursor.insertText(text: "Hello" ); |
632 | cursor.insertBlock(); |
633 | cursor.insertText(text: "World" ); |
634 | |
635 | cursor.movePosition(op: QTextCursor::Start); |
636 | cursor.movePosition(op: QTextCursor::NextCharacter, QTextCursor::MoveAnchor, n: 3); |
637 | cursor.movePosition(op: QTextCursor::NextBlock, QTextCursor::KeepAnchor); |
638 | cursor.movePosition(op: QTextCursor::NextCharacter, QTextCursor::KeepAnchor, n: 3); |
639 | |
640 | QTextDocumentFragment fragment(cursor); |
641 | QVERIFY(!fragment.isEmpty()); |
642 | cursor.insertFragment(fragment); |
643 | } |
644 | |
645 | void tst_QTextDocumentFragment::copyWholeDocument() |
646 | { |
647 | // used to cause the famous currentBlock.position() == pos + 1 failing assertion |
648 | cursor.insertText(text: "\nHey\nBlah\n" ); |
649 | cursor.movePosition(op: QTextCursor::Start); |
650 | cursor.movePosition(op: QTextCursor::End, QTextCursor::KeepAnchor); |
651 | |
652 | QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); |
653 | fmt.setBackground(Qt::blue); |
654 | doc->rootFrame()->setFrameFormat(fmt); |
655 | |
656 | QTextDocumentFragment fragment(cursor); |
657 | QVERIFY(true); // good if we reach this point :) |
658 | |
659 | cleanup(); |
660 | init(); |
661 | |
662 | fmt.setBackground(Qt::red); |
663 | doc->rootFrame()->setFrameFormat(fmt); |
664 | |
665 | cursor.insertFragment(fragment); |
666 | |
667 | QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::red); |
668 | } |
669 | |
670 | void tst_QTextDocumentFragment::title() |
671 | { |
672 | doc->setHtml(QString::fromLatin1(str: "<html><head><title>Test</title></head><body>Blah</body></html>" )); |
673 | QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), QString::fromLatin1("Test" )); |
674 | } |
675 | |
676 | void tst_QTextDocumentFragment::html_listIndents1() |
677 | { |
678 | const char html[] = "<ul><li>Hey</li><li>Hah</li></ul>" ; |
679 | setHtml(QString::fromLatin1(str: html)); |
680 | cursor.movePosition(op: QTextCursor::Start); |
681 | cursor.movePosition(op: QTextCursor::NextBlock); |
682 | QTextList *list = cursor.currentList(); |
683 | QVERIFY(list); |
684 | QCOMPARE(list->format().indent(), 1); |
685 | QCOMPARE(cursor.block().blockFormat().indent(), 0); |
686 | } |
687 | |
688 | void tst_QTextDocumentFragment::html_listIndents2() |
689 | { |
690 | const char html[] = "<ul><li>Hey<p>Hah</ul>" ; |
691 | setHtml(QString::fromLatin1(str: html)); |
692 | cursor.movePosition(op: QTextCursor::Start); |
693 | QTextList *list = cursor.currentList(); |
694 | QVERIFY(list); |
695 | QCOMPARE(list->format().indent(), 1); |
696 | QCOMPARE(cursor.block().blockFormat().indent(), 0); |
697 | |
698 | cursor.movePosition(op: QTextCursor::NextBlock); |
699 | QCOMPARE(cursor.block().blockFormat().indent(), 1); |
700 | } |
701 | |
702 | void tst_QTextDocumentFragment::html_listIndents3() |
703 | { |
704 | const char html[] = "<ul><li><p>Hah</ul>" ; |
705 | setHtml(QString::fromLatin1(str: html)); |
706 | cursor.movePosition(op: QTextCursor::Start); |
707 | QTextList *list = cursor.currentList(); |
708 | QVERIFY(list); |
709 | QCOMPARE(list->format().indent(), 1); |
710 | QCOMPARE(cursor.block().blockFormat().indent(), 0); |
711 | } |
712 | |
713 | void tst_QTextDocumentFragment::html_listIndents4() |
714 | { |
715 | const char html[] = "<ul><li>Foo</ul><p>This should not have the same indent as Foo" ; |
716 | setHtml(QString::fromLatin1(str: html)); |
717 | cursor.movePosition(op: QTextCursor::Start); |
718 | QTextList *list = cursor.currentList(); |
719 | QVERIFY(list); |
720 | QCOMPARE(list->format().indent(), 1); |
721 | |
722 | cursor.movePosition(op: QTextCursor::NextBlock); |
723 | QVERIFY(!cursor.currentList()); |
724 | QCOMPARE(cursor.blockFormat().indent(), 0); |
725 | } |
726 | |
727 | void tst_QTextDocumentFragment::html_listIndents5() |
728 | { |
729 | const char html[] = "<ul><li>Foo<p><li>Bar</li></ul>" ; |
730 | setHtml(QString::fromLatin1(str: html)); |
731 | cursor.movePosition(op: QTextCursor::Start); |
732 | QTextList *list = cursor.currentList(); |
733 | QVERIFY(list); |
734 | QCOMPARE(list->format().indent(), 1); |
735 | |
736 | cursor.movePosition(op: QTextCursor::NextBlock); |
737 | QCOMPARE(cursor.currentList(), list); |
738 | QCOMPARE(cursor.blockFormat().indent(), 0); |
739 | } |
740 | |
741 | void tst_QTextDocumentFragment::html_listIndents6() |
742 | { |
743 | const char html[] = "<ul><li>Outer List<div class=\"testclass\"><ul><li>Nested Item 1</li></ul></div></li></ul>" ; |
744 | setHtml(QString::fromLatin1(str: html)); |
745 | cursor.movePosition(op: QTextCursor::Start); |
746 | QTextList *list = cursor.currentList(); |
747 | QVERIFY(list); |
748 | QCOMPARE(list->format().indent(), 1); |
749 | |
750 | cursor.movePosition(op: QTextCursor::NextBlock); |
751 | QVERIFY(cursor.currentList() != list); |
752 | list = cursor.currentList(); |
753 | QVERIFY(list); |
754 | QCOMPARE(list->format().indent(), 2); |
755 | |
756 | QCOMPARE(cursor.blockFormat().indent(), 0); |
757 | } |
758 | |
759 | void tst_QTextDocumentFragment::html_listIndents7() |
760 | { |
761 | const char html[] = "<ul><li style=\"-qt-block-indent:1;\">Hey</ul>" ; |
762 | setHtml(QString::fromLatin1(str: html)); |
763 | cursor.movePosition(op: QTextCursor::Start); |
764 | cursor.movePosition(op: QTextCursor::NextBlock); |
765 | QTextList *list = cursor.currentList(); |
766 | QVERIFY(list); |
767 | QCOMPARE(list->format().indent(), 1); |
768 | QCOMPARE(cursor.block().blockFormat().indent(), 1); |
769 | } |
770 | |
771 | void tst_QTextDocumentFragment::blockCharFormat() |
772 | { |
773 | const char html[] = "<p style=\"font-style:italic\"><span style=\"font-style:normal\">Test</span></p>" ; |
774 | setHtml(QString::fromLatin1(str: html)); |
775 | QVERIFY(doc->begin().charFormat().fontItalic()); |
776 | } |
777 | |
778 | void tst_QTextDocumentFragment::blockCharFormatCopied() |
779 | { |
780 | QTextCharFormat fmt; |
781 | fmt.setForeground(Qt::green); |
782 | cursor.setBlockCharFormat(fmt); |
783 | cursor.insertText(text: "Test" , format: QTextCharFormat()); |
784 | QTextDocumentFragment frag(doc); |
785 | cleanup(); |
786 | init(); |
787 | cursor.insertFragment(fragment: frag); |
788 | QCOMPARE(cursor.blockCharFormat(), fmt); |
789 | } |
790 | |
791 | void tst_QTextDocumentFragment::initialBlock() |
792 | { |
793 | const char html[] = "<p>Test</p>" ; |
794 | setHtml(QString::fromLatin1(str: html)); |
795 | QCOMPARE(doc->blockCount(), 1); |
796 | } |
797 | |
798 | void tst_QTextDocumentFragment::clone() |
799 | { |
800 | QTextBlockFormat mod; |
801 | mod.setAlignment(Qt::AlignCenter); |
802 | cursor.mergeBlockFormat(modifier: mod); |
803 | cursor.insertText(text: "Blah" ); |
804 | QCOMPARE(cursor.blockFormat().alignment(), Qt::AlignCenter); |
805 | QTextDocumentFragment frag(doc); |
806 | cleanup(); |
807 | init(); |
808 | cursor.insertFragment(fragment: frag); |
809 | cursor.movePosition(op: QTextCursor::Start); |
810 | QCOMPARE(cursor.blockFormat().alignment(), Qt::AlignCenter); |
811 | } |
812 | |
813 | void tst_QTextDocumentFragment::dontRemoveInitialBlockIfItHoldsObjectIndexedCharFormat() |
814 | { |
815 | const char html[] = "<table><tr><td>cell one<td>cell two</tr><tr><td>cell three<td>cell four</tr></table>" ; |
816 | QCOMPARE(doc->begin().charFormat().objectIndex(), -1); |
817 | setHtml(QString::fromLatin1(str: html)); |
818 | int cnt = 0; |
819 | |
820 | int objectIndexOfLast = -1; |
821 | for (QTextBlock blk = doc->begin(); blk.isValid(); blk = blk.next()) { |
822 | ++cnt; |
823 | objectIndexOfLast = blk.charFormat().objectIndex(); |
824 | } |
825 | // beginning of frame for first cell |
826 | // + beginning of frame for second cell |
827 | // + beginning of frame for third cell |
828 | // + beginning of frame for fourth cell |
829 | // + end of frame |
830 | // + initial block |
831 | // ==> 6 |
832 | QCOMPARE(cnt, 6); |
833 | QVERIFY(objectIndexOfLast != -1); |
834 | QVERIFY(doc->begin().next().charFormat().objectIndex() != -1); |
835 | } |
836 | |
837 | void tst_QTextDocumentFragment::dosLineFeed() |
838 | { |
839 | const char html[] = "<pre>Test\r\n</pre>Bar" ; |
840 | setHtml(QString::fromLatin1(str: html)); |
841 | QVERIFY(!doc->toPlainText().contains('\r')); |
842 | QCOMPARE(doc->toPlainText(), QString("Test\nBar" )); |
843 | } |
844 | |
845 | void tst_QTextDocumentFragment::unorderedListEnumeration() |
846 | { |
847 | const char html[] = "<ul><ul><ul><li>Blah</li></ul></ul>" ; |
848 | setHtml(QString::fromLatin1(str: html)); |
849 | cursor.movePosition(op: QTextCursor::End); |
850 | QVERIFY(cursor.currentList()); |
851 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListDisc); |
852 | |
853 | const char html2[] = "<ul><ul><ul type=circle><li>Blah</li></ul></ul>" ; |
854 | setHtml(QString::fromLatin1(str: html2)); |
855 | cursor.movePosition(op: QTextCursor::End); |
856 | QVERIFY(cursor.currentList()); |
857 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListCircle); |
858 | |
859 | } |
860 | |
861 | void tst_QTextDocumentFragment::resetHasBlockAfterClosedBlockTags() |
862 | { |
863 | // when closing tags we have to make sure hasBlock in import() gets reset |
864 | const char html[] = "<body><table><tr><td><td><p></table><p></body>" ; |
865 | setHtml(QString::fromLatin1(str: html)); |
866 | QVERIFY(!doc->isEmpty()); |
867 | } |
868 | |
869 | void tst_QTextDocumentFragment::ignoreStyleTags() |
870 | { |
871 | const char html[] = "<body><style>Blah</style>Hello</body>" ; |
872 | setHtml(QString::fromLatin1(str: html)); |
873 | QCOMPARE(doc->toPlainText(), QString("Hello" )); |
874 | } |
875 | |
876 | void tst_QTextDocumentFragment::hrefAnchor() |
877 | { |
878 | { |
879 | const char html[] = "<a href=\"test\">blah</a>" ; |
880 | setHtml(QString::fromLatin1(str: html)); |
881 | QVERIFY(doc->begin().begin().fragment().charFormat().isAnchor()); |
882 | QCOMPARE(doc->begin().begin().fragment().charFormat().anchorHref(), QString::fromLatin1("test" )); |
883 | QVERIFY(doc->begin().begin().fragment().charFormat().fontUnderline()); |
884 | } |
885 | |
886 | { |
887 | // only hyperlinks should have special formatting |
888 | const char html[] = "<a>blah</a>" ; |
889 | setHtml(QString::fromLatin1(str: html)); |
890 | QVERIFY(doc->begin().begin().fragment().charFormat().isAnchor()); |
891 | QVERIFY(!doc->begin().begin().fragment().charFormat().fontUnderline()); |
892 | } |
893 | } |
894 | |
895 | void tst_QTextDocumentFragment::namedAnchorFragments() |
896 | { |
897 | // named anchors should be 'invisible', but the fragment right after it should |
898 | // hold the attribute |
899 | const char html[] = "a<a name=\"test\" />blah" ; |
900 | setHtml(QString::fromLatin1(str: html)); |
901 | |
902 | QTextBlock firstBlock = doc->begin(); |
903 | QVERIFY(firstBlock.isValid()); |
904 | |
905 | QTextBlock::Iterator it = firstBlock.begin(); |
906 | QVERIFY(!it.atEnd()); |
907 | |
908 | // the 'a' |
909 | QVERIFY(it.fragment().isValid()); |
910 | QCOMPARE(it.fragment().text(), QString::fromLatin1("a" )); |
911 | QVERIFY(!it.fragment().charFormat().isAnchor()); |
912 | |
913 | // the 'b' of 'blah' as separate fragment with the anchor attribute |
914 | ++it; |
915 | QVERIFY(it.fragment().isValid()); |
916 | QCOMPARE(it.fragment().text(), QString::fromLatin1("b" )); |
917 | QVERIFY(it.fragment().charFormat().isAnchor()); |
918 | |
919 | // the 'lah' of 'blah' as remainder |
920 | ++it; |
921 | QVERIFY(it.fragment().isValid()); |
922 | QVERIFY(it.fragment().text().startsWith("lah" )); |
923 | QVERIFY(!it.fragment().charFormat().isAnchor()); |
924 | } |
925 | |
926 | void tst_QTextDocumentFragment::namedAnchorFragments2() |
927 | { |
928 | const char html[] = "<p> <a name=\"foo\"> Hello" ; |
929 | setHtml(QString::fromLatin1(str: html)); |
930 | |
931 | QCOMPARE(doc->toPlainText(), QString("Hello" )); |
932 | |
933 | QTextBlock::Iterator it = doc->begin().begin(); |
934 | QVERIFY(!it.atEnd()); |
935 | |
936 | QCOMPARE(it.fragment().text(), QString::fromLatin1("H" )); |
937 | QVERIFY(it.fragment().charFormat().isAnchor()); |
938 | |
939 | ++it; |
940 | |
941 | QCOMPARE(it.fragment().text(), QString::fromLatin1("ello" )); |
942 | QVERIFY(!it.fragment().charFormat().isAnchor()); |
943 | } |
944 | |
945 | void tst_QTextDocumentFragment::namedAnchorFragments3() |
946 | { |
947 | setHtml("<a name=\"target\" /><a name=\"target2\"/><span>Text</span>" ); |
948 | |
949 | QCOMPARE(doc->toPlainText(), QString("Text" )); |
950 | |
951 | QTextBlock::Iterator it = doc->begin().begin(); |
952 | QVERIFY(!it.atEnd()); |
953 | |
954 | QCOMPARE(it.fragment().text(), QString::fromLatin1("T" )); |
955 | QVERIFY(it.fragment().charFormat().isAnchor()); |
956 | QCOMPARE(it.fragment().charFormat().anchorNames().constFirst(), QLatin1String("target" )); |
957 | QStringList targets; targets << "target" << "target2" ; |
958 | QCOMPARE(it.fragment().charFormat().anchorNames(), targets); |
959 | |
960 | ++it; |
961 | |
962 | QCOMPARE(it.fragment().text(), QString::fromLatin1("ext" )); |
963 | QVERIFY(!it.fragment().charFormat().isAnchor()); |
964 | } |
965 | |
966 | void tst_QTextDocumentFragment::dontInheritAlignmentInTables() |
967 | { |
968 | const char html[] = "<table align=center><tr><td>Hey</td></tr></table>" ; |
969 | setHtml(QString::fromLatin1(str: html)); |
970 | |
971 | cursor.movePosition(op: QTextCursor::Start); |
972 | cursor.movePosition(op: QTextCursor::NextBlock); |
973 | QVERIFY(cursor.currentTable()); |
974 | QVERIFY(cursor.currentTable()->cellAt(0, 0).isValid()); |
975 | QVERIFY(cursor.currentTable()->cellAt(0, 0).firstCursorPosition().block().next().blockFormat().alignment() != Qt::AlignHCenter); |
976 | } |
977 | |
978 | void tst_QTextDocumentFragment::cellBlockCount() |
979 | { |
980 | const char html[] = "<table><tr><td>Hey</td></tr></table>" ; |
981 | setHtml(QString::fromLatin1(str: html)); |
982 | |
983 | cursor.movePosition(op: QTextCursor::Start); |
984 | cursor.movePosition(op: QTextCursor::NextBlock); |
985 | QVERIFY(cursor.currentTable()); |
986 | |
987 | QTextTableCell cell = cursor.currentTable()->cellAt(row: 0, col: 0); |
988 | QVERIFY(cell.isValid()); |
989 | |
990 | int blockCount = 0; |
991 | for (QTextFrame::iterator it = cell.begin(); !it.atEnd(); ++it) { |
992 | QVERIFY(!it.currentFrame()); |
993 | QVERIFY(it.currentBlock().isValid()); |
994 | ++blockCount; |
995 | } |
996 | QCOMPARE(blockCount, 1); |
997 | } |
998 | |
999 | void tst_QTextDocumentFragment::cellBlockCount2() |
1000 | { |
1001 | const char html[] = "<table><tr><td><p>Hey</p></td></tr></table>" ; |
1002 | setHtml(QString::fromLatin1(str: html)); |
1003 | |
1004 | cursor.movePosition(op: QTextCursor::Start); |
1005 | cursor.movePosition(op: QTextCursor::NextBlock); |
1006 | QVERIFY(cursor.currentTable()); |
1007 | |
1008 | QTextTableCell cell = cursor.currentTable()->cellAt(row: 0, col: 0); |
1009 | QVERIFY(cell.isValid()); |
1010 | |
1011 | int blockCount = 0; |
1012 | for (QTextFrame::iterator it = cell.begin(); !it.atEnd(); ++it) { |
1013 | QVERIFY(!it.currentFrame()); |
1014 | QVERIFY(it.currentBlock().isValid()); |
1015 | ++blockCount; |
1016 | } |
1017 | QCOMPARE(blockCount, 1); |
1018 | } |
1019 | |
1020 | void tst_QTextDocumentFragment::emptyTable() |
1021 | { |
1022 | const char html[] = "<table></table>" ; |
1023 | setHtml(QString::fromLatin1(str: html)); |
1024 | QVERIFY(true); // don't crash with a failing assertion |
1025 | } |
1026 | |
1027 | void tst_QTextDocumentFragment::emptyTable2() |
1028 | { |
1029 | const char html[] = "<table></td></tr></table><p>blah</p>" ; |
1030 | setHtml(QString::fromLatin1(str: html)); |
1031 | QVERIFY(true); // don't crash with a failing assertion |
1032 | } |
1033 | |
1034 | void tst_QTextDocumentFragment::emptyTable3() |
1035 | { |
1036 | const char html[] = "<table><tr><td><table></table></td><td>Foobar</td></tr></table>" ; |
1037 | setHtml(QString::fromLatin1(str: html)); |
1038 | |
1039 | cursor.movePosition(op: QTextCursor::Start); |
1040 | cursor.movePosition(op: QTextCursor::NextBlock); |
1041 | QTextTable *table = cursor.currentTable(); |
1042 | QVERIFY(table); |
1043 | QCOMPARE(table->rows(), 1); |
1044 | QCOMPARE(table->columns(), 2); |
1045 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1046 | QVERIFY(cell.isValid()); |
1047 | QCOMPARE(cell.firstPosition(), cell.lastPosition()); |
1048 | cell = table->cellAt(row: 0, col: 1); |
1049 | QTextCursor cursor = cell.firstCursorPosition(); |
1050 | cursor.setPosition(pos: cell.lastPosition(), mode: QTextCursor::KeepAnchor); |
1051 | QCOMPARE(cursor.selectedText(), QString("Foobar" )); |
1052 | } |
1053 | |
1054 | void tst_QTextDocumentFragment::doubleRowClose() |
1055 | { |
1056 | const char html[] = "<table><tr><td>Blah</td></tr></tr><tr><td>Hm</td></tr></table>" ; |
1057 | setHtml(QString::fromLatin1(str: html)); |
1058 | QVERIFY(true); // don't crash with a failing assertion |
1059 | } |
1060 | |
1061 | void tst_QTextDocumentFragment::mayNotHaveChildren() |
1062 | { |
1063 | // make sure the Hey does not end up as tag text for the img tag |
1064 | const char html[] = "<img />Hey" ; |
1065 | setHtml(QString::fromLatin1(str: html)); |
1066 | QCOMPARE(doc->toPlainText().mid(1), QString::fromLatin1("Hey" )); |
1067 | } |
1068 | |
1069 | void tst_QTextDocumentFragment::inheritAlignment() |
1070 | { |
1071 | // make sure attributes from the body tag get inherited |
1072 | const char html[] = "<body align=right><p>Hey" ; |
1073 | setHtml(QString::fromLatin1(str: html)); |
1074 | // html alignment is absolute |
1075 | QCOMPARE(doc->begin().blockFormat().alignment(), Qt::Alignment(Qt::AlignRight|Qt::AlignAbsolute)); |
1076 | } |
1077 | |
1078 | void tst_QTextDocumentFragment::dontEmitEmptyNodeWhenEmptyTagIsFollowedByCloseTag() |
1079 | { |
1080 | // make sure the Hey does not end up as tag text for the img tag |
1081 | const char html[] = "<body align=right><p align=left>Blah<img></img><p>Hey" ; |
1082 | setHtml(QString::fromLatin1(str: html)); |
1083 | QCOMPARE(doc->begin().blockFormat().alignment(), Qt::Alignment(Qt::AlignLeft|Qt::AlignAbsolute)); |
1084 | QCOMPARE(doc->begin().next().blockFormat().alignment(), Qt::Alignment(Qt::AlignRight|Qt::AlignAbsolute)); |
1085 | } |
1086 | |
1087 | void tst_QTextDocumentFragment::toPlainText() |
1088 | { |
1089 | QString input = "Hello\nWorld" ; |
1090 | input += QChar::ParagraphSeparator; |
1091 | input += "Blah" ; |
1092 | doc->setPlainText(input); |
1093 | QCOMPARE(doc->blockCount(), 3); |
1094 | } |
1095 | |
1096 | void tst_QTextDocumentFragment::copyTableRow() |
1097 | { |
1098 | QTextDocumentFragment frag; |
1099 | { |
1100 | QTextTable *table = cursor.insertTable(rows: 2, cols: 2); |
1101 | table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "Blah" ); |
1102 | table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Foo" ); |
1103 | table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Bar" ); |
1104 | table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Hah" ); |
1105 | |
1106 | // select second row |
1107 | cursor = table->cellAt(row: 1, col: 1).firstCursorPosition(); |
1108 | cursor.movePosition(op: QTextCursor::PreviousBlock, QTextCursor::KeepAnchor); |
1109 | |
1110 | QCOMPARE(table->cellAt(cursor.position()).row(), 1); |
1111 | QCOMPARE(table->cellAt(cursor.position()).column(), 0); |
1112 | QCOMPARE(table->cellAt(cursor.anchor()).row(), 1); |
1113 | QCOMPARE(table->cellAt(cursor.anchor()).column(), 1); |
1114 | |
1115 | frag = QTextDocumentFragment(cursor); |
1116 | } |
1117 | { |
1118 | QTextDocument doc2; |
1119 | cursor = QTextCursor(&doc2); |
1120 | cursor.insertFragment(fragment: frag); |
1121 | |
1122 | cursor.movePosition(op: QTextCursor::Start); |
1123 | cursor.movePosition(op: QTextCursor::NextBlock); |
1124 | QTextTable *table = cursor.currentTable(); |
1125 | |
1126 | QVERIFY(table); |
1127 | QCOMPARE(table->columns(), 2); |
1128 | QCOMPARE(table->rows(), 1); |
1129 | |
1130 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Bar" )); |
1131 | QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Hah" )); |
1132 | } |
1133 | } |
1134 | |
1135 | void tst_QTextDocumentFragment::copyTableColumn() |
1136 | { |
1137 | QTextDocumentFragment frag; |
1138 | { |
1139 | QTextTable *table = cursor.insertTable(rows: 2, cols: 2); |
1140 | table->cellAt(row: 0, col: 0).firstCursorPosition().insertText(text: "Blah" ); |
1141 | table->cellAt(row: 0, col: 1).firstCursorPosition().insertText(text: "Foo" ); |
1142 | table->cellAt(row: 1, col: 0).firstCursorPosition().insertText(text: "Bar" ); |
1143 | table->cellAt(row: 1, col: 1).firstCursorPosition().insertText(text: "Hah" ); |
1144 | |
1145 | // select second column |
1146 | cursor = table->cellAt(row: 0, col: 1).firstCursorPosition(); |
1147 | cursor.movePosition(op: QTextCursor::Down, QTextCursor::KeepAnchor); |
1148 | |
1149 | QCOMPARE(table->cellAt(cursor.anchor()).row(), 0); |
1150 | QCOMPARE(table->cellAt(cursor.anchor()).column(), 1); |
1151 | QCOMPARE(table->cellAt(cursor.position()).row(), 1); |
1152 | QCOMPARE(table->cellAt(cursor.position()).column(), 1); |
1153 | |
1154 | frag = QTextDocumentFragment(cursor); |
1155 | } |
1156 | { |
1157 | QTextDocument doc2; |
1158 | cursor = QTextCursor(&doc2); |
1159 | cursor.insertFragment(fragment: frag); |
1160 | |
1161 | cursor.movePosition(op: QTextCursor::Start); |
1162 | cursor.movePosition(op: QTextCursor::NextBlock); |
1163 | QTextTable *table = cursor.currentTable(); |
1164 | |
1165 | QVERIFY(table); |
1166 | QCOMPARE(table->columns(), 1); |
1167 | QCOMPARE(table->rows(), 2); |
1168 | |
1169 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Foo" )); |
1170 | QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Hah" )); |
1171 | } |
1172 | } |
1173 | |
1174 | void tst_QTextDocumentFragment::copySubTable() |
1175 | { |
1176 | QTextDocumentFragment frag; |
1177 | { |
1178 | QTextTableFormat fmt; |
1179 | QVector<QTextLength> constraints; |
1180 | constraints << QTextLength(QTextLength::PercentageLength, 16); |
1181 | constraints << QTextLength(QTextLength::PercentageLength, 28); |
1182 | constraints << QTextLength(QTextLength::PercentageLength, 28); |
1183 | constraints << QTextLength(QTextLength::PercentageLength, 28); |
1184 | fmt.setColumnWidthConstraints(constraints); |
1185 | |
1186 | QTextTable *table = cursor.insertTable(rows: 4, cols: 4, format: fmt); |
1187 | for (int row = 0; row < 4; ++row) { |
1188 | const QString rowS = QString::number(row) + QLatin1Char('/'); |
1189 | for (int col = 0; col < 4; ++col) |
1190 | table->cellAt(row, col).firstCursorPosition().insertText(text: rowS + QString::number(col)); |
1191 | } |
1192 | |
1193 | QCOMPARE(table->format().columnWidthConstraints().count(), table->columns()); |
1194 | |
1195 | // select 2x2 subtable |
1196 | cursor = table->cellAt(row: 1, col: 1).firstCursorPosition(); |
1197 | cursor.movePosition(op: QTextCursor::Down, QTextCursor::KeepAnchor); |
1198 | cursor.movePosition(op: QTextCursor::Right, QTextCursor::KeepAnchor); |
1199 | |
1200 | QCOMPARE(table->cellAt(cursor.anchor()).row(), 1); |
1201 | QCOMPARE(table->cellAt(cursor.anchor()).column(), 1); |
1202 | QCOMPARE(table->cellAt(cursor.position()).row(), 2); |
1203 | QCOMPARE(table->cellAt(cursor.position()).column(), 2); |
1204 | |
1205 | frag = QTextDocumentFragment(cursor); |
1206 | } |
1207 | { |
1208 | QTextDocument doc2; |
1209 | cursor = QTextCursor(&doc2); |
1210 | cursor.insertFragment(fragment: frag); |
1211 | |
1212 | cursor.movePosition(op: QTextCursor::Start); |
1213 | cursor.movePosition(op: QTextCursor::NextBlock); |
1214 | QTextTable *table = cursor.currentTable(); |
1215 | |
1216 | QVERIFY(table); |
1217 | QVERIFY(table->format().columnWidthConstraints().isEmpty()); |
1218 | QCOMPARE(table->columns(), 2); |
1219 | QCOMPARE(table->rows(), 2); |
1220 | |
1221 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("1/1" )); |
1222 | QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("1/2" )); |
1223 | QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("2/1" )); |
1224 | QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("2/2" )); |
1225 | } |
1226 | } |
1227 | |
1228 | void tst_QTextDocumentFragment::html_textDecoration() |
1229 | { |
1230 | const char html[] = "<span style='text-decoration: overline line-through underline'>Blah</span>" ; |
1231 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QByteArray::fromRawData(html, size: sizeof(html) / sizeof(html[0])))); |
1232 | |
1233 | cursor.movePosition(op: QTextCursor::Start); |
1234 | cursor.movePosition(op: QTextCursor::NextCharacter); |
1235 | QVERIFY(cursor.charFormat().fontUnderline()); |
1236 | QVERIFY(cursor.charFormat().fontOverline()); |
1237 | QVERIFY(cursor.charFormat().fontStrikeOut()); |
1238 | } |
1239 | |
1240 | void tst_QTextDocumentFragment::html_infiniteLoop() |
1241 | { |
1242 | { |
1243 | // used to cause an infinite loop due to the lack of a space after the |
1244 | // tag name |
1245 | const char html[] = "<ahref=\"argl\">Link</a>" ; |
1246 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1247 | QVERIFY(true); |
1248 | } |
1249 | |
1250 | { |
1251 | const char html[] = "<a href=\"\"a<" ; |
1252 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1253 | QVERIFY(true); |
1254 | } |
1255 | } |
1256 | |
1257 | void tst_QTextDocumentFragment::html_blockIndent() |
1258 | { |
1259 | const char html[] = "<p style=\"-qt-block-indent:3;\">Test</p>" ; |
1260 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1261 | QCOMPARE(cursor.blockFormat().indent(), 3); |
1262 | } |
1263 | |
1264 | void tst_QTextDocumentFragment::html_listIndent() |
1265 | { |
1266 | const char html[] = "<ul style=\"-qt-list-indent:4;\"><li>Blah</ul>" ; |
1267 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1268 | QVERIFY(cursor.currentList()); |
1269 | QCOMPARE(cursor.currentList()->format().indent(), 4); |
1270 | } |
1271 | |
1272 | void tst_QTextDocumentFragment::html_whitespace_data() |
1273 | { |
1274 | QTest::addColumn<QString>(name: "html" ); |
1275 | QTest::addColumn<QString>(name: "expectedPlainText" ); |
1276 | |
1277 | QTest::newRow(dataTag: "1" ) << QString("<span>This is some test</span><span> with spaces between words</span>" ) |
1278 | << QString("This is some test with spaces between words" ); |
1279 | |
1280 | QTest::newRow(dataTag: "2" ) << QString("<span> </span><span>nowhitespacehereplease</span>" ) |
1281 | << QString::fromLatin1(str: "nowhitespacehereplease" ); |
1282 | |
1283 | QTest::newRow(dataTag: "3" ) << QString("<span style=\"white-space: pre;\"> white space \n\n here </span>" ) |
1284 | << QString::fromLatin1(str: " white space \n\n here " ); |
1285 | |
1286 | QTest::newRow(dataTag: "4" ) << QString("<span style=\"white-space: pre-wrap;\"> white space \n\n here </span>" ) |
1287 | << QString::fromLatin1(str: " white space \n\n here " ); |
1288 | |
1289 | QTest::newRow(dataTag: "5" ) << QString("<a href=\"One.html\">One</a> <a href=\"Two.html\">Two</a> <b>Three</b>\n" |
1290 | "<b>Four</b>" ) |
1291 | << QString::fromLatin1(str: "One Two Three Four" ); |
1292 | |
1293 | QTest::newRow(dataTag: "6" ) << QString("<p>Testing: <b><i><u>BoldItalic</u></i></b> <i>Italic</i></p>" ) |
1294 | << QString("Testing: BoldItalic Italic" ); |
1295 | |
1296 | QTest::newRow(dataTag: "7" ) << QString("<table><tr><td>Blah</td></tr></table> <table border><tr><td>Foo</td></tr></table>" ) |
1297 | << QString("\nBlah\n\nFoo\n" ); |
1298 | |
1299 | QTest::newRow(dataTag: "8" ) << QString("<table><tr><td><i>Blah</i></td></tr></table> <i>Blub</i>" ) |
1300 | << QString("\nBlah\nBlub" ); |
1301 | |
1302 | QTest::newRow(dataTag: "9" ) << QString("<span style=\"white-space: nowrap;\"> white space \n\n here </span>" ) |
1303 | << QString::fromLatin1(str: "white space here " ); |
1304 | |
1305 | QTest::newRow(dataTag: "10" ) << QString("<span style=\"white-space: pre-line;\"> white space \n\n here </span>" ) |
1306 | << QString::fromLatin1(str: "white space\n\nhere " ); |
1307 | |
1308 | QTest::newRow(dataTag: "task116492" ) << QString("<p>a<font=\"Times\"> b </font>c</p>" ) |
1309 | << QString("a b c" ); |
1310 | |
1311 | QTest::newRow(dataTag: "task121653" ) << QString("abc<b> def</b>" ) |
1312 | << QString("abc def" ); |
1313 | |
1314 | QTest::newRow(dataTag: "task122650" ) << QString("<p>Foo</p> Bar" ) |
1315 | << QString("Foo\nBar" ); |
1316 | |
1317 | QTest::newRow(dataTag: "task122650-2" ) << QString("<p>Foo</p> <p> Bar" ) |
1318 | << QString("Foo \nBar" ); |
1319 | |
1320 | QTest::newRow(dataTag: "task122650-3" ) << QString("<html>Before<pre>\nTest</pre>" ) |
1321 | << QString("Before\nTest" ); |
1322 | |
1323 | QTest::newRow(dataTag: "br-with-whitespace" ) << QString("Foo<br>\nBlah" ) |
1324 | << QString("Foo\nBlah" ); |
1325 | |
1326 | QTest::newRow(dataTag: "collapse-p-with-newline" ) << QString("Foo<p>\n<p>\n<p>\n<p>\n<p>\n<p>\nBar" ) |
1327 | << QString("Foo\nBar" ); |
1328 | |
1329 | QTest::newRow(dataTag: "table" ) << QString("<table><tr><td>Blah</td></tr></table>\nTest" ) |
1330 | << QString("\nBlah\nTest" ); |
1331 | |
1332 | QTest::newRow(dataTag: "table2" ) << QString("<table><tr><td><pre>\nTest\n</pre></td>\n </tr></table>" ) |
1333 | << QString("\nTest\n" ); |
1334 | |
1335 | QTest::newRow(dataTag: "table3" ) << QString("<table><tr><td><pre>\nTest\n</pre> \n \n </td></tr></table>" ) |
1336 | << QString("\nTest \n" ); |
1337 | } |
1338 | |
1339 | void tst_QTextDocumentFragment::html_whitespace() |
1340 | { |
1341 | QFETCH(QString, html); |
1342 | QFETCH(QString, expectedPlainText); |
1343 | |
1344 | setHtml(html); |
1345 | |
1346 | QCOMPARE(doc->toPlainText(), expectedPlainText); |
1347 | } |
1348 | |
1349 | void tst_QTextDocumentFragment::html_qt3Whitespace() |
1350 | { |
1351 | QString text = "This text has some whitespace" |
1352 | "\n and \nnewlines that \n should be ignored\n\n" ; |
1353 | const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body>" ) |
1354 | + text |
1355 | + QString("</body></html>" ); |
1356 | |
1357 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1358 | |
1359 | text.remove(c: QChar::fromLatin1(c: '\n')); |
1360 | |
1361 | QCOMPARE(doc->toPlainText(), text); |
1362 | } |
1363 | |
1364 | void tst_QTextDocumentFragment::html_qt3WhitespaceWithFragments() |
1365 | { |
1366 | QString text = "This text has some whitespace" |
1367 | "\n and \nnewlines that \n should be ignored\n\n" ; |
1368 | const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body>" |
1369 | "blah blah<!--StartFragment--><span>" ) |
1370 | + text |
1371 | + QString("</span><!--EndFragment--></body></html>" ); |
1372 | |
1373 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1374 | |
1375 | text.remove(c: QChar::fromLatin1(c: '\n')); |
1376 | |
1377 | QCOMPARE(doc->toPlainText(), text); |
1378 | } |
1379 | |
1380 | void tst_QTextDocumentFragment::html_qt3WhitespaceAfterTags() |
1381 | { |
1382 | QString text = " This text has some whitespace " ; |
1383 | const QString html = QString("<html><head><meta name=\"qrichtext\" content=\"1\" /></head><body><span>" ) |
1384 | + text |
1385 | + QString("</span></body></html>" ); |
1386 | |
1387 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1388 | |
1389 | QCOMPARE(doc->toPlainText(), text); |
1390 | } |
1391 | |
1392 | void tst_QTextDocumentFragment::html_listStart1() |
1393 | { |
1394 | // don't create a block for the <ul> element, even if there's some whitespace between |
1395 | // it and the <li> |
1396 | const QString html = QStringLiteral("<ul> <li>list item</li><ul>" ); |
1397 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1398 | |
1399 | QCOMPARE(doc->blockCount(), 1); |
1400 | } |
1401 | |
1402 | void tst_QTextDocumentFragment::html_listStart2() |
1403 | { |
1404 | // unlike with html_listStart1 we want a block showing the 'buggy' text here |
1405 | const QString html = QStringLiteral("<ul>buggy, but text should appear<li>list item</li><ul>" ); |
1406 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1407 | |
1408 | QCOMPARE(doc->blockCount(), 2); |
1409 | } |
1410 | |
1411 | void tst_QTextDocumentFragment::html_cssMargin() |
1412 | { |
1413 | const char html[] = "<p style=\"margin-top: 1px; margin-bottom: 2px; margin-left: 3px; margin-right: 4px\">Test</p>" ; |
1414 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1415 | const QTextBlockFormat fmt = cursor.blockFormat(); |
1416 | QCOMPARE(fmt.topMargin(), qreal(1)); |
1417 | QCOMPARE(fmt.bottomMargin(), qreal(2)); |
1418 | QCOMPARE(fmt.leftMargin(), qreal(3)); |
1419 | QCOMPARE(fmt.rightMargin(), qreal(4)); |
1420 | } |
1421 | |
1422 | void tst_QTextDocumentFragment::html_hexEntities() |
1423 | { |
1424 | const char html[] = "@" ; |
1425 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1426 | QCOMPARE(doc->begin().begin().fragment().text(), QString("@" )); |
1427 | } |
1428 | |
1429 | void tst_QTextDocumentFragment::html_decEntities() |
1430 | { |
1431 | const char html[] = "@" ; |
1432 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1433 | QCOMPARE(doc->begin().begin().fragment().text(), QString("@" )); |
1434 | } |
1435 | |
1436 | void tst_QTextDocumentFragment::html_thCentered() |
1437 | { |
1438 | const char html[] = "<table><tr><th>This should be centered</th></tr></table>" ; |
1439 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1440 | |
1441 | cursor.movePosition(op: QTextCursor::PreviousBlock); |
1442 | QTextTable *table = cursor.currentTable(); |
1443 | QVERIFY(table); |
1444 | |
1445 | QVERIFY(table->cellAt(0, 0).begin().currentBlock().blockFormat().alignment() == Qt::AlignCenter); |
1446 | } |
1447 | |
1448 | void tst_QTextDocumentFragment::orderedListNumbering() |
1449 | { |
1450 | // Supporter issue 45941 - make sure _two_ separate lists |
1451 | // are imported, which have their own numbering |
1452 | const char html[] = "<html><body>" |
1453 | "<ol><li>elem 1</li></ol>" |
1454 | "<ol><li>elem 1</li></ol>" |
1455 | "</body></html>" ; |
1456 | |
1457 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1458 | |
1459 | int numberOfLists = 0; |
1460 | |
1461 | cursor.movePosition(op: QTextCursor::Start); |
1462 | QTextList *lastList = 0; |
1463 | do { |
1464 | QTextList *list = cursor.currentList(); |
1465 | if (list && list != lastList) { |
1466 | lastList = list; |
1467 | ++numberOfLists; |
1468 | } |
1469 | } while (cursor.movePosition(op: QTextCursor::NextBlock)); |
1470 | |
1471 | QCOMPARE(numberOfLists, 2); |
1472 | } |
1473 | |
1474 | void tst_QTextDocumentFragment::html_blockAfterList() |
1475 | { |
1476 | const char html[] = "<ul><li>Foo</ul>This should be a separate paragraph and not be indented at the same level as Foo" ; |
1477 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html)); |
1478 | |
1479 | cursor.movePosition(op: QTextCursor::Start); |
1480 | |
1481 | QVERIFY(cursor.currentList()); |
1482 | QCOMPARE(cursor.currentList()->format().indent(), 1); |
1483 | |
1484 | QVERIFY(cursor.movePosition(QTextCursor::NextBlock)); |
1485 | QVERIFY(!cursor.currentList()); |
1486 | QCOMPARE(cursor.blockFormat().indent(), 0); |
1487 | } |
1488 | |
1489 | void tst_QTextDocumentFragment::html_subAndSuperScript() |
1490 | { |
1491 | const char subHtml[] = "<sub>Subby</sub>" ; |
1492 | const char superHtml[] = "<sup>Super</sup>" ; |
1493 | const char subHtmlCss[] = "<span style=\"vertical-align: sub\">Subby</span>" ; |
1494 | const char superHtmlCss[] = "<span style=\"vertical-align: super\">Super</span>" ; |
1495 | const char alignmentInherited[] = "<sub><font face=\"Verdana\">Subby</font></sub>" ; |
1496 | |
1497 | setHtml(subHtml); |
1498 | QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSubScript); |
1499 | |
1500 | setHtml(subHtmlCss); |
1501 | QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSubScript); |
1502 | |
1503 | setHtml(superHtml); |
1504 | QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSuperScript); |
1505 | |
1506 | setHtml(superHtmlCss); |
1507 | QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSuperScript); |
1508 | |
1509 | setHtml(alignmentInherited); |
1510 | QCOMPARE(cursor.charFormat().verticalAlignment(), QTextCharFormat::AlignSubScript); |
1511 | } |
1512 | |
1513 | void tst_QTextDocumentFragment::html_cssColors() |
1514 | { |
1515 | const char color[] = "<span style=\"color:red\"><span style=\"color:blue\">Blue</span></span>" ; |
1516 | setHtml(color); |
1517 | QVERIFY(cursor.charFormat().foreground().color() == Qt::blue); |
1518 | |
1519 | const char rgbColor[] = "<span style=\"color:red\"><span style=\"color:rgb(0, 0, 255)\">Blue</span></span>" ; |
1520 | setHtml(rgbColor); |
1521 | QVERIFY(cursor.charFormat().foreground().color() == Qt::blue); |
1522 | } |
1523 | |
1524 | void tst_QTextDocumentFragment::obeyFragmentMarkersInImport() |
1525 | { |
1526 | const char html[] = "This leading text should not appear<!--StartFragment--><span>Text</span><!--EndFragment-->This text at the end should not appear" ; |
1527 | setHtml(html); |
1528 | |
1529 | QCOMPARE(doc->toPlainText(), QString("Text" )); |
1530 | } |
1531 | |
1532 | void tst_QTextDocumentFragment::whitespaceWithFragmentMarkers() |
1533 | { |
1534 | QString text(" text with leading and trailing whitespace " ); |
1535 | const char html[] = "This leading text should not appear<!--StartFragment-->%1<!--EndFragment-->This text at the end should not appear" ; |
1536 | setHtml(QString::fromLatin1(str: html).arg(a: text)); |
1537 | |
1538 | QString expected("text with leading and trailing whitespace " ); |
1539 | QCOMPARE(doc->toPlainText(), expected); |
1540 | } |
1541 | |
1542 | void tst_QTextDocumentFragment::html_emptyParapgraphs1() |
1543 | { |
1544 | const char html[] = "<p style=\"-qt-paragraph-type:empty;\"> </p><p>Two paragraphs</p>" ; |
1545 | setHtml(html); |
1546 | |
1547 | QCOMPARE(doc->blockCount(), 2); |
1548 | QVERIFY(doc->begin().text().isEmpty()); |
1549 | QCOMPARE(doc->begin().next().text(), QString("Two paragraphs" )); |
1550 | } |
1551 | |
1552 | void tst_QTextDocumentFragment::html_emptyParapgraphs2() |
1553 | { |
1554 | const char html[] = "<p style=\"margin-left:80px\"></p><p>One paragraph</p>" ; |
1555 | setHtml(html); |
1556 | |
1557 | QCOMPARE(doc->blockCount(), 1); |
1558 | QCOMPARE(cursor.blockFormat().leftMargin(), qreal(0)); |
1559 | |
1560 | const char html2[] = "<p style=\"margin-left:80px\"></p>One paragraph" ; |
1561 | setHtml(html2); |
1562 | QCOMPARE(doc->blockCount(), 1); |
1563 | QCOMPARE(cursor.blockFormat().leftMargin(), qreal(0)); |
1564 | |
1565 | const char html3[] = "<p style=\"margin-left:80px\">Foo</p><p></p>Two paragraphs" ; |
1566 | setHtml(html3); |
1567 | QCOMPARE(doc->blockCount(), 2); |
1568 | cursor = QTextCursor(doc); |
1569 | QCOMPARE(cursor.blockFormat().leftMargin(), qreal(80)); |
1570 | QCOMPARE(cursor.block().next().blockFormat().leftMargin(), qreal(0)); |
1571 | } |
1572 | |
1573 | void tst_QTextDocumentFragment::html_emptyParagraphs3() |
1574 | { |
1575 | const char html[] = "<ul><p>Foo</p><p></p></ul><h4>Bar</h4>" ; |
1576 | |
1577 | setHtml(html); |
1578 | |
1579 | QCOMPARE(doc->blockCount(), 2); |
1580 | |
1581 | cursor = QTextCursor(doc); |
1582 | QCOMPARE(cursor.block().next().blockFormat().indent(), 0); |
1583 | } |
1584 | |
1585 | void tst_QTextDocumentFragment::html_emptyParagraphs4() |
1586 | { |
1587 | const char html[] = "<p>foo</p><p style=\"page-break-before: always\"></p><p>bar</p>" ; |
1588 | setHtml(html); |
1589 | |
1590 | QTextBlock block = doc->begin(); |
1591 | QVERIFY(block.isValid()); |
1592 | QCOMPARE(block.text(), QString("foo" )); |
1593 | block = block.next(); |
1594 | QVERIFY(block.isValid()); |
1595 | QTextBlockFormat bf = block.blockFormat(); |
1596 | QVERIFY(bf.hasProperty(QTextFormat::PageBreakPolicy)); |
1597 | QCOMPARE(bf.pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore); |
1598 | QCOMPARE(block.text(), QString("bar" )); |
1599 | |
1600 | const char html2[] = "<p>foo</p><p style=\"page-break-after: always\"></p><p>bar</p>" ; |
1601 | setHtml(html2); |
1602 | |
1603 | block = doc->begin(); |
1604 | QVERIFY(block.isValid()); |
1605 | QCOMPARE(block.text(), QString("foo" )); |
1606 | block = block.next(); |
1607 | QVERIFY(block.isValid()); |
1608 | bf = block.blockFormat(); |
1609 | QVERIFY(bf.hasProperty(QTextFormat::PageBreakPolicy)); |
1610 | QCOMPARE(bf.pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore); // after the empty line means it should appear for 'bar' |
1611 | QCOMPARE(block.text(), QString("bar" )); |
1612 | } |
1613 | |
1614 | void tst_QTextDocumentFragment::html_font() |
1615 | { |
1616 | const char html[] = "<font color=\"blue\"><p>Hah</p></font>" ; |
1617 | setHtml(html); |
1618 | |
1619 | QVERIFY(cursor.charFormat().foreground().color() == Qt::blue); |
1620 | QVERIFY(cursor.blockCharFormat().foreground().color() == Qt::blue); |
1621 | } |
1622 | |
1623 | void tst_QTextDocumentFragment::html_fontSize() |
1624 | { |
1625 | const char html[] = "<font size=\"2\">Hah</font>" ; |
1626 | setHtml(html); |
1627 | |
1628 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), -1); |
1629 | } |
1630 | |
1631 | void tst_QTextDocumentFragment::html_fontSizeAdjustment() |
1632 | { |
1633 | const char html[] = "<font size=\"7\"><b>Hah</b></font>" ; |
1634 | setHtml(html); |
1635 | |
1636 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), 4); |
1637 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
1638 | } |
1639 | |
1640 | void tst_QTextDocumentFragment::html_cssFontSize() |
1641 | { |
1642 | const char html[] = "<span style=\"font-size: 50pt\">Foo</span>" ; |
1643 | setHtml(html); |
1644 | |
1645 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 50); |
1646 | |
1647 | const char html2[] = "<span style=\"font-size: 50px\">Foo</span>" ; |
1648 | setHtml(html2); |
1649 | |
1650 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontPixelSize).toInt(), 50); |
1651 | |
1652 | const char html3[] = "<span style=\"font-size: large\">Foo</span>" ; |
1653 | setHtml(html3); |
1654 | |
1655 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontSizeAdjustment).toInt(), 1); |
1656 | } |
1657 | |
1658 | void tst_QTextDocumentFragment::html_cssShorthandFont() |
1659 | { |
1660 | { |
1661 | const char html[] = "<span style=\"font: 50px sans-serif\">Foo</span>" ; |
1662 | setHtml(html); |
1663 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontPixelSize).toInt(), 50); |
1664 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("sans-serif" )); |
1665 | } |
1666 | { |
1667 | const char html[] = "<span style=\"font: 50pt sans-serif\">Foo</span>" ; |
1668 | setHtml(html); |
1669 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 50); |
1670 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("sans-serif" )); |
1671 | } |
1672 | { |
1673 | const char html[] = "<span style='font:7.0pt \"Times New Roman\"'>Foo</span>" ; |
1674 | setHtml(html); |
1675 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 7); |
1676 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontFamily).toString(), QString("Times New Roman" )); |
1677 | } |
1678 | { |
1679 | const char html[] = "<span style='font:bold 7.0pt'>Foo</span>" ; |
1680 | setHtml(html); |
1681 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontWeight).toInt(), int(QFont::Bold)); |
1682 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontPointSize).toInt(), 7); |
1683 | } |
1684 | { |
1685 | const char html[] = "<span style='font:bold italic 7.0pt'>Foo</span>" ; |
1686 | setHtml(html); |
1687 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontWeight).toInt(), int(QFont::Bold)); |
1688 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontItalic).toBool(), true); |
1689 | } |
1690 | } |
1691 | |
1692 | void tst_QTextDocumentFragment::html_bodyBgColor() |
1693 | { |
1694 | const char html[] = "<body bgcolor=\"blue\">Foo</body>" ; |
1695 | doc->setHtml(html); |
1696 | |
1697 | QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue); |
1698 | } |
1699 | |
1700 | void tst_QTextDocumentFragment::html_qtBgColor() |
1701 | { |
1702 | const char html[] = "<qt bgcolor=\"blue\">Foo</qt>" ; |
1703 | doc->setHtml(html); |
1704 | |
1705 | QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue); |
1706 | } |
1707 | |
1708 | void tst_QTextDocumentFragment::html_bodyBackground() |
1709 | { |
1710 | const char html[] = "<body background=\"foo.png\">Foo</body>" ; |
1711 | doc->setHtml(html); |
1712 | |
1713 | #ifdef Q_OS_WINRT |
1714 | QEXPECT_FAIL("" , "Fails on winrt. Investigate - QTBUG-68297" , Continue); |
1715 | #endif |
1716 | QCOMPARE(doc->rootFrame()->frameFormat().background().style(), Qt::TexturePattern); |
1717 | } |
1718 | |
1719 | void tst_QTextDocumentFragment::html_tableCellBackground() |
1720 | { |
1721 | const char html[] = "<body><table><tr><td background=\"foo.png\">Foo</td></tr></table></body>" ; |
1722 | doc->setHtml(html); |
1723 | |
1724 | cursor.movePosition(op: QTextCursor::Start); |
1725 | cursor.movePosition(op: QTextCursor::NextBlock); |
1726 | QTextTable *table = cursor.currentTable(); |
1727 | QVERIFY(table); |
1728 | |
1729 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1730 | #ifdef Q_OS_WINRT |
1731 | QEXPECT_FAIL("" , "Fails on winrt. Investigate - QTBUG-68297" , Continue); |
1732 | #endif |
1733 | QCOMPARE(cell.format().background().style(), Qt::TexturePattern); |
1734 | } |
1735 | |
1736 | void tst_QTextDocumentFragment::css_bodyBackground() |
1737 | { |
1738 | const char html[] = "<body style=\"background-image:url('foo.png')\">Foo</body>" ; |
1739 | doc->setHtml(html); |
1740 | |
1741 | #ifdef Q_OS_WINRT |
1742 | QEXPECT_FAIL("" , "Fails on winrt. Investigate - QTBUG-68297" , Continue); |
1743 | #endif |
1744 | QCOMPARE(doc->rootFrame()->frameFormat().background().style(), Qt::TexturePattern); |
1745 | } |
1746 | |
1747 | void tst_QTextDocumentFragment::css_tableCellBackground() |
1748 | { |
1749 | const char html[] = "<body><table><tr><td style=\"background-image:url('foo.png')\">Foo</td></tr></table></body>" ; |
1750 | doc->setHtml(html); |
1751 | |
1752 | cursor.movePosition(op: QTextCursor::Start); |
1753 | cursor.movePosition(op: QTextCursor::NextBlock); |
1754 | QTextTable *table = cursor.currentTable(); |
1755 | QVERIFY(table); |
1756 | |
1757 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1758 | #ifdef Q_OS_WINRT |
1759 | QEXPECT_FAIL("" , "Fails on winrt. Investigate - QTBUG-68297" , Continue); |
1760 | #endif |
1761 | QCOMPARE(cell.format().background().style(), Qt::TexturePattern); |
1762 | } |
1763 | |
1764 | void tst_QTextDocumentFragment::css_tableCellBorder() |
1765 | { |
1766 | const char html[] = "<body><table><tr><td style=\"border-width:8px;border-color:green;border-style:groove;border-left-style:dashed;border-left-color:red;border-left-width:4px\">Foo</td></tr></table></body>" ; |
1767 | doc->setHtml(html); |
1768 | |
1769 | cursor.movePosition(op: QTextCursor::Start); |
1770 | cursor.movePosition(op: QTextCursor::NextBlock); |
1771 | QTextTable *table = cursor.currentTable(); |
1772 | QVERIFY(table); |
1773 | |
1774 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1775 | QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); |
1776 | QCOMPARE(cellFormat.leftBorder(), qreal(4)); |
1777 | QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red" ))); |
1778 | QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1779 | |
1780 | QCOMPARE(cellFormat.rightBorder(), qreal(8)); |
1781 | QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green" ))); |
1782 | QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Groove); |
1783 | |
1784 | QCOMPARE(cellFormat.bottomBorder(), qreal(8)); |
1785 | QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green" ))); |
1786 | QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Groove); |
1787 | |
1788 | QCOMPARE(cellFormat.topBorder(), qreal(8)); |
1789 | QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green" ))); |
1790 | QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Groove); |
1791 | } |
1792 | |
1793 | void tst_QTextDocumentFragment::css_tableCellBorderWidthOneValue() // QTBUG-80496 |
1794 | { |
1795 | const char html[] = "<head><style type=\"text/css\"> body, td { border-width: 2px; }</style></head> <body> <table> <tr> <td></td> </tr> </table> </body> </html>" ; |
1796 | doc->setHtml(html); |
1797 | |
1798 | cursor.movePosition(op: QTextCursor::Start); |
1799 | cursor.movePosition(op: QTextCursor::NextBlock); |
1800 | QTextTable *table = cursor.currentTable(); |
1801 | QVERIFY(table); |
1802 | |
1803 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1804 | QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); |
1805 | QCOMPARE(cellFormat.leftBorder(), qreal(2)); |
1806 | QCOMPARE(cellFormat.rightBorder(), qreal(2)); |
1807 | QCOMPARE(cellFormat.bottomBorder(), qreal(2)); |
1808 | QCOMPARE(cellFormat.topBorder(), qreal(2)); |
1809 | } |
1810 | |
1811 | void tst_QTextDocumentFragment::css_tableCellBorderWidthTwoValues() // QTBUG-80496 |
1812 | { |
1813 | const char html[] = "<head><style type=\"text/css\"> body, td { border-width: 2px 3px; }</style></head> <body> <table> <tr> <td></td> </tr> </table> </body> </html>" ; |
1814 | doc->setHtml(html); |
1815 | |
1816 | cursor.movePosition(op: QTextCursor::Start); |
1817 | cursor.movePosition(op: QTextCursor::NextBlock); |
1818 | QTextTable *table = cursor.currentTable(); |
1819 | QVERIFY(table); |
1820 | |
1821 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1822 | QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); |
1823 | QCOMPARE(cellFormat.leftBorder(), qreal(3)); |
1824 | QCOMPARE(cellFormat.rightBorder(), qreal(3)); |
1825 | QCOMPARE(cellFormat.bottomBorder(), qreal(2)); |
1826 | QCOMPARE(cellFormat.topBorder(), qreal(2)); |
1827 | } |
1828 | |
1829 | void tst_QTextDocumentFragment::css_tableCellBorderShorthand() |
1830 | { |
1831 | const char html[] = "<body><table><tr><td style=\"border-left:1px solid green;border-right:2px dashed red;border-bottom:3px dotted yellow;border-top:4px dot-dash blue\">Foo</td></tr></table></body>" ; |
1832 | doc->setHtml(html); |
1833 | |
1834 | cursor.movePosition(op: QTextCursor::Start); |
1835 | cursor.movePosition(op: QTextCursor::NextBlock); |
1836 | QTextTable *table = cursor.currentTable(); |
1837 | QVERIFY(table); |
1838 | |
1839 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1840 | QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); |
1841 | QCOMPARE(cellFormat.leftBorder(), qreal(1)); |
1842 | QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green" ))); |
1843 | QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid); |
1844 | |
1845 | QCOMPARE(cellFormat.rightBorder(), qreal(2)); |
1846 | QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("red" ))); |
1847 | QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1848 | |
1849 | QCOMPARE(cellFormat.bottomBorder(), qreal(3)); |
1850 | QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("yellow" ))); |
1851 | QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dotted); |
1852 | |
1853 | QCOMPARE(cellFormat.topBorder(), qreal(4)); |
1854 | QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("blue" ))); |
1855 | QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_DotDash); |
1856 | } |
1857 | |
1858 | void tst_QTextDocumentFragment::css_tableCellAllBordersShorthand() |
1859 | { |
1860 | const char html[] = "<body><table><tr><td style=\"border:2px dashed green\">Foo</td></tr></table></body>" ; |
1861 | doc->setHtml(html); |
1862 | |
1863 | cursor.movePosition(op: QTextCursor::Start); |
1864 | cursor.movePosition(op: QTextCursor::NextBlock); |
1865 | QTextTable *table = cursor.currentTable(); |
1866 | QVERIFY(table); |
1867 | |
1868 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1869 | QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); |
1870 | QCOMPARE(cellFormat.leftBorder(), qreal(2)); |
1871 | QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("green" ))); |
1872 | QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1873 | |
1874 | QCOMPARE(cellFormat.rightBorder(), qreal(2)); |
1875 | QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green" ))); |
1876 | QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1877 | |
1878 | QCOMPARE(cellFormat.bottomBorder(), qreal(2)); |
1879 | QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green" ))); |
1880 | QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1881 | |
1882 | QCOMPARE(cellFormat.topBorder(), qreal(2)); |
1883 | QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green" ))); |
1884 | QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1885 | } |
1886 | |
1887 | void tst_QTextDocumentFragment::css_tableCellOverrideOneBorder() |
1888 | { |
1889 | const char html[] = "<body><table><tr><td style=\"border:2px dashed green;border-left:4px solid red\">Foo</td></tr></table></body>" ; |
1890 | doc->setHtml(html); |
1891 | |
1892 | cursor.movePosition(op: QTextCursor::Start); |
1893 | cursor.movePosition(op: QTextCursor::NextBlock); |
1894 | QTextTable *table = cursor.currentTable(); |
1895 | QVERIFY(table); |
1896 | |
1897 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1898 | QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); |
1899 | QCOMPARE(cellFormat.leftBorder(), qreal(4)); |
1900 | QCOMPARE(cellFormat.leftBorderBrush(), QBrush(QColor("red" ))); |
1901 | QCOMPARE(cellFormat.leftBorderStyle(), QTextFrameFormat::BorderStyle_Solid); |
1902 | |
1903 | QCOMPARE(cellFormat.rightBorder(), qreal(2)); |
1904 | QCOMPARE(cellFormat.rightBorderBrush(), QBrush(QColor("green" ))); |
1905 | QCOMPARE(cellFormat.rightBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1906 | |
1907 | QCOMPARE(cellFormat.bottomBorder(), qreal(2)); |
1908 | QCOMPARE(cellFormat.bottomBorderBrush(), QBrush(QColor("green" ))); |
1909 | QCOMPARE(cellFormat.bottomBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1910 | |
1911 | QCOMPARE(cellFormat.topBorder(), qreal(2)); |
1912 | QCOMPARE(cellFormat.topBorderBrush(), QBrush(QColor("green" ))); |
1913 | QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Dashed); |
1914 | } |
1915 | |
1916 | void tst_QTextDocumentFragment::css_tableBorderCollapse() |
1917 | { |
1918 | const char html[] = "<body><table style=\"border-collapse:collapse\"><tr><td>Foo</td></tr></table></body>" ; |
1919 | doc->setHtml(html); |
1920 | |
1921 | cursor.movePosition(op: QTextCursor::Start); |
1922 | cursor.movePosition(op: QTextCursor::NextBlock); |
1923 | QTextTable *table = cursor.currentTable(); |
1924 | QVERIFY(table); |
1925 | |
1926 | QCOMPARE(table->format().borderCollapse(), true); |
1927 | } |
1928 | |
1929 | void tst_QTextDocumentFragment::css_cellPaddings() |
1930 | { |
1931 | const char html[] = "<body><table><tr><td style=\"padding-left:1\">Foo</td>" |
1932 | "<td style=\"padding-right:1\"></td><td style=\"padding-top:10\"></td>" |
1933 | "<td style=\"padding-bottom:5\"></td><td style=\"padding:15\"></td></tr></table></body>" ; |
1934 | doc->setHtml(html); |
1935 | |
1936 | cursor.movePosition(op: QTextCursor::Start); |
1937 | cursor.movePosition(op: QTextCursor::NextBlock); |
1938 | QTextTable *table = cursor.currentTable(); |
1939 | QVERIFY(table); |
1940 | |
1941 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
1942 | QCOMPARE(cell.format().toTableCellFormat().leftPadding(), qreal(1)); |
1943 | cell = table->cellAt(row: 0, col: 1); |
1944 | QCOMPARE(cell.format().toTableCellFormat().rightPadding(), qreal(1)); |
1945 | cell = table->cellAt(row: 0, col: 2); |
1946 | QCOMPARE(cell.format().toTableCellFormat().topPadding(), qreal(10)); |
1947 | cell = table->cellAt(row: 0, col: 3); |
1948 | QCOMPARE(cell.format().toTableCellFormat().bottomPadding(), qreal(5)); |
1949 | cell = table->cellAt(row: 0, col: 4); |
1950 | QCOMPARE(cell.format().toTableCellFormat().leftPadding(), qreal(15)); |
1951 | QCOMPARE(cell.format().toTableCellFormat().rightPadding(), qreal(15)); |
1952 | QCOMPARE(cell.format().toTableCellFormat().topPadding(), qreal(15)); |
1953 | QCOMPARE(cell.format().toTableCellFormat().bottomPadding(), qreal(15)); |
1954 | } |
1955 | |
1956 | void tst_QTextDocumentFragment::css_whiteSpace_data() |
1957 | { |
1958 | QTest::addColumn<QString>(name: "htmlText" ); |
1959 | QTest::addColumn<bool>(name: "nowrap" ); |
1960 | |
1961 | QTest::newRow(dataTag: "default" ) << QString("<p>Normal Text</p>" ) << false; |
1962 | QTest::newRow(dataTag: "white-space:nowrap" ) << QString("<p style=white-space:nowrap>Normal Text</p>" ) << true; |
1963 | QTest::newRow(dataTag: "white-space:pre" ) << QString("<p style=white-space:pre>Normal Text</p>" ) << true; |
1964 | } |
1965 | |
1966 | void tst_QTextDocumentFragment::css_whiteSpace() |
1967 | { |
1968 | QFETCH(QString, htmlText); |
1969 | QFETCH(bool, nowrap); |
1970 | |
1971 | doc->setHtml(htmlText); |
1972 | QCOMPARE(doc->blockCount(), 1); |
1973 | QCOMPARE(doc->begin().blockFormat().nonBreakableLines(), nowrap); |
1974 | } |
1975 | |
1976 | void tst_QTextDocumentFragment::html_blockLevelDiv() |
1977 | { |
1978 | const char html[] = "<div align=right><b>Hello World" ; |
1979 | setHtml(html); |
1980 | |
1981 | QCOMPARE(doc->begin().blockFormat().alignment(), Qt::AlignRight|Qt::AlignAbsolute); |
1982 | QCOMPARE(doc->begin().next(), doc->end()); |
1983 | } |
1984 | |
1985 | void tst_QTextDocumentFragment::html_spanNesting() |
1986 | { |
1987 | const char html[] = "<span style=\"color:black\">a<span style=\"color:red\">b<span style=\"color:black\">c</span></span>d</span>" ; |
1988 | setHtml(html); |
1989 | |
1990 | cursor.movePosition(op: QTextCursor::Start); |
1991 | cursor.movePosition(op: QTextCursor::NextCharacter); |
1992 | QVERIFY(cursor.charFormat().foreground() == Qt::black); |
1993 | cursor.movePosition(op: QTextCursor::NextCharacter); |
1994 | QVERIFY(cursor.charFormat().foreground() == Qt::red); |
1995 | cursor.movePosition(op: QTextCursor::NextCharacter); |
1996 | QVERIFY(cursor.charFormat().foreground() == Qt::black); |
1997 | cursor.movePosition(op: QTextCursor::NextCharacter); |
1998 | QVERIFY(cursor.charFormat().foreground() == Qt::black); |
1999 | } |
2000 | |
2001 | void tst_QTextDocumentFragment::html_nestedLists() |
2002 | { |
2003 | const char html[] = "<p><ul><li>Foo<ul><li>In nested list</li></ul></li><li>Last item</li></ul></p>" ; |
2004 | setHtml(html); |
2005 | |
2006 | cursor.movePosition(op: QTextCursor::Start); |
2007 | QTextList *firstList = cursor.currentList(); |
2008 | QVERIFY(firstList); |
2009 | QCOMPARE(firstList->format().indent(), 1); |
2010 | |
2011 | cursor.movePosition(op: QTextCursor::NextBlock); |
2012 | QTextList *secondList = cursor.currentList(); |
2013 | QVERIFY(secondList); |
2014 | QVERIFY(secondList != firstList); |
2015 | QCOMPARE(cursor.currentList()->format().indent(), 2); |
2016 | |
2017 | cursor.movePosition(op: QTextCursor::NextBlock); |
2018 | QTextList *thirdList = cursor.currentList(); |
2019 | QVERIFY(thirdList); |
2020 | QCOMPARE(thirdList, firstList); |
2021 | } |
2022 | |
2023 | void tst_QTextDocumentFragment::noSpecialCharactersInPlainText() |
2024 | { |
2025 | cursor.insertTable(rows: 2, cols: 2); |
2026 | cursor.insertBlock(); |
2027 | cursor.insertText(text: QString(QChar::LineSeparator)); |
2028 | cursor.insertText(text: QString(QChar::Nbsp)); |
2029 | |
2030 | QString plain = doc->toPlainText(); |
2031 | QVERIFY(!plain.contains(QChar::ParagraphSeparator)); |
2032 | QVERIFY(!plain.contains(QChar::Nbsp)); |
2033 | QVERIFY(!plain.contains(QTextBeginningOfFrame)); |
2034 | QVERIFY(!plain.contains(QTextEndOfFrame)); |
2035 | QVERIFY(!plain.contains(QChar::LineSeparator)); |
2036 | |
2037 | plain = QTextDocumentFragment(doc).toPlainText(); |
2038 | QVERIFY(!plain.contains(QChar::ParagraphSeparator)); |
2039 | QVERIFY(!plain.contains(QChar::Nbsp)); |
2040 | QVERIFY(!plain.contains(QTextBeginningOfFrame)); |
2041 | QVERIFY(!plain.contains(QTextEndOfFrame)); |
2042 | QVERIFY(!plain.contains(QChar::LineSeparator)); |
2043 | } |
2044 | |
2045 | void tst_QTextDocumentFragment::html_doNotInheritBackground() |
2046 | { |
2047 | const char html[] = "<html><body bgcolor=\"blue\"><p>Blah</p></body></html>" ; |
2048 | doc->setHtml(html); |
2049 | |
2050 | for (QTextBlock block = doc->begin(); |
2051 | block.isValid(); block = block.next()) { |
2052 | QVERIFY(!block.blockFormat().hasProperty(QTextFormat::BackgroundBrush)); |
2053 | } |
2054 | |
2055 | QVERIFY(doc->rootFrame()->frameFormat().hasProperty(QTextFormat::BackgroundBrush)); |
2056 | QVERIFY(doc->rootFrame()->frameFormat().background().color() == Qt::blue); |
2057 | } |
2058 | |
2059 | void tst_QTextDocumentFragment::html_inheritBackgroundToInlineElements() |
2060 | { |
2061 | const char html[] = "<span style=\"background: blue\">Foo<span>Bar</span></span>" ; |
2062 | doc->setHtml(html); |
2063 | |
2064 | int fragmentCount = 0; |
2065 | |
2066 | QTextBlock block = doc->begin(); |
2067 | for (QTextBlock::Iterator it = block.begin(); |
2068 | !it.atEnd(); ++it, ++fragmentCount) { |
2069 | |
2070 | const QTextFragment fragment = it.fragment(); |
2071 | if (fragmentCount == 0) { |
2072 | QCOMPARE(fragment.text(), QString("FooBar" )); |
2073 | QVERIFY(fragment.charFormat().background().color() == Qt::blue); |
2074 | } |
2075 | } |
2076 | |
2077 | QCOMPARE(fragmentCount, 1); |
2078 | } |
2079 | |
2080 | void tst_QTextDocumentFragment::html_doNotInheritBackgroundFromBlockElements() |
2081 | { |
2082 | const char html[] = "<p style=\"background: blue\"><span>Foo</span></span>" ; |
2083 | doc->setHtml(html); |
2084 | |
2085 | int fragmentCount = 0; |
2086 | |
2087 | QTextBlock block = doc->begin(); |
2088 | for (QTextBlock::Iterator it = block.begin(); |
2089 | !it.atEnd(); ++it, ++fragmentCount) { |
2090 | |
2091 | const QTextFragment fragment = it.fragment(); |
2092 | if (fragmentCount == 0) { |
2093 | QCOMPARE(fragment.text(), QString("Foo" )); |
2094 | QVERIFY(!fragment.charFormat().hasProperty(QTextFormat::BackgroundBrush)); |
2095 | } |
2096 | } |
2097 | |
2098 | QCOMPARE(fragmentCount, 1); |
2099 | } |
2100 | void tst_QTextDocumentFragment::html_nobr() |
2101 | { |
2102 | const QString input = "Blah Foo Bar" ; |
2103 | const QString html = QString::fromLatin1(str: "<html><body><p><nobr>" ) + input + QString::fromLatin1(str: "</nobr></p></body></html>" ); |
2104 | setHtml(html); |
2105 | |
2106 | QString text = doc->begin().begin().fragment().text(); |
2107 | QString expectedText = input; |
2108 | expectedText.replace(re: QRegularExpression("\\s+" ), after: QString(QChar::Nbsp)); |
2109 | QCOMPARE(text, expectedText); |
2110 | } |
2111 | |
2112 | void tst_QTextDocumentFragment::fromPlainText() |
2113 | { |
2114 | QString plainText; |
2115 | plainText = "Hello\nWorld\r\nBlub" ; |
2116 | plainText += QChar::ParagraphSeparator; |
2117 | // TextEdit on OS 10 gives us OS 9 style linefeeds |
2118 | // when copy & pasteing multi-line plaintext. |
2119 | plainText += "OS9IsOldSchool\r" ; |
2120 | plainText += "Last Parag" ; |
2121 | |
2122 | doc->setPlainText(plainText); |
2123 | |
2124 | int blockCount = 0; |
2125 | for (QTextBlock block = doc->begin(); block.isValid(); block = block.next()) { |
2126 | QVERIFY(!block.text().contains(QLatin1Char('\n'))); |
2127 | QVERIFY(!block.text().contains(QLatin1Char('\r'))); |
2128 | QVERIFY(!block.text().contains(QChar::ParagraphSeparator)); |
2129 | |
2130 | if (blockCount == 0) |
2131 | QCOMPARE(block.text(), QString("Hello" )); |
2132 | else if (blockCount == 1) |
2133 | QCOMPARE(block.text(), QString("World" )); |
2134 | else if (blockCount == 2) |
2135 | QCOMPARE(block.text(), QString("Blub" )); |
2136 | else if (blockCount == 3) |
2137 | QCOMPARE(block.text(), QString("OS9IsOldSchool" )); |
2138 | else if (blockCount == 4) |
2139 | QCOMPARE(block.text(), QString("Last Parag" )); |
2140 | |
2141 | |
2142 | ++blockCount; |
2143 | } |
2144 | |
2145 | QCOMPARE(blockCount, 5); |
2146 | } |
2147 | |
2148 | void tst_QTextDocumentFragment::fromPlainText2() |
2149 | { |
2150 | doc->setPlainText("Hello World" ); |
2151 | QCOMPARE(QTextDocumentFragment(doc).toPlainText(), doc->toPlainText()); |
2152 | } |
2153 | |
2154 | void tst_QTextDocumentFragment::html_closingImageTag() |
2155 | { |
2156 | const char html[] = "<span style=\"font-size: 10pt\"><span style=\"font-size: 40pt\">Blah<img src=\"blah\"></img>Foo</span></span>" ; |
2157 | setHtml(html); |
2158 | |
2159 | int fragmentCount = 0; |
2160 | |
2161 | QTextBlock block = doc->begin(); |
2162 | for (QTextBlock::Iterator it = block.begin(); |
2163 | !it.atEnd(); ++it, ++fragmentCount) { |
2164 | |
2165 | const QTextFragment fragment = it.fragment(); |
2166 | if (fragmentCount == 0) { |
2167 | QCOMPARE(fragment.text(), QString("Blah" )); |
2168 | QCOMPARE(fragment.charFormat().fontPointSize(), qreal(40)); |
2169 | } else if (fragmentCount == 1) { |
2170 | QCOMPARE(fragment.text(), QString(QChar::ObjectReplacementCharacter)); |
2171 | } else if (fragmentCount == 2) { |
2172 | QCOMPARE(fragment.text(), QString("Foo" )); |
2173 | QCOMPARE(fragment.charFormat().fontPointSize(), qreal(40)); |
2174 | } |
2175 | } |
2176 | |
2177 | QCOMPARE(fragmentCount, 3); |
2178 | } |
2179 | |
2180 | void tst_QTextDocumentFragment::html_emptyDocument() |
2181 | { |
2182 | const char html[] = "<html><body><p style=\"-qt-paragraph-type:empty;\"></p></body></html>" ; |
2183 | setHtml(html); |
2184 | QCOMPARE(doc->blockCount(), 1); |
2185 | } |
2186 | |
2187 | void tst_QTextDocumentFragment::html_closingTag() |
2188 | { |
2189 | const char html[] = "<i />text" ; |
2190 | setHtml(html); |
2191 | |
2192 | QVERIFY(!cursor.charFormat().fontItalic()); |
2193 | } |
2194 | |
2195 | void tst_QTextDocumentFragment::html_anchorAroundImage() |
2196 | { |
2197 | const char html[] = "<a href=\"http://www.troll.no\"><img src=test.png></a>" ; |
2198 | setHtml(html); |
2199 | |
2200 | cursor.movePosition(op: QTextCursor::Start); |
2201 | cursor.movePosition(op: QTextCursor::NextCharacter); |
2202 | QTextImageFormat fmt = cursor.charFormat().toImageFormat(); |
2203 | QCOMPARE(fmt.name(), QString("test.png" )); |
2204 | QVERIFY(fmt.isAnchor()); |
2205 | QCOMPARE(fmt.anchorHref(), QString("http://www.troll.no" )); |
2206 | } |
2207 | |
2208 | void tst_QTextDocumentFragment::html_floatBorder() |
2209 | { |
2210 | const char html[] = "<table border=1.2><tr><td>Foo" ; |
2211 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
2212 | cursor.movePosition(op: QTextCursor::Start); |
2213 | cursor.movePosition(op: QTextCursor::NextBlock); |
2214 | QVERIFY(cursor.currentTable()); |
2215 | QCOMPARE(cursor.currentTable()->format().border(), qreal(1.2)); |
2216 | } |
2217 | |
2218 | void tst_QTextDocumentFragment::html_frameImport() |
2219 | { |
2220 | QTextFrameFormat ffmt; |
2221 | ffmt.setBorder(1); |
2222 | ffmt.setPosition(QTextFrameFormat::FloatRight); |
2223 | ffmt.setMargin(2); |
2224 | ffmt.setWidth(100); |
2225 | ffmt.setHeight(50); |
2226 | ffmt.setBackground(QColor("#00ff00" )); |
2227 | cursor.insertFrame(format: ffmt); |
2228 | cursor.insertText(text: "Hello World" ); |
2229 | |
2230 | QTextDocumentFragment frag(doc); |
2231 | cleanup(); |
2232 | init(); |
2233 | frag = QTextDocumentFragment::fromHtml(html: frag.toHtml()); |
2234 | cursor.insertFragment(fragment: frag); |
2235 | |
2236 | QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); |
2237 | QCOMPARE(childFrames.count(), 1); |
2238 | QTextFrame *frame = childFrames.first(); |
2239 | QCOMPARE(frame->frameFormat().margin(), ffmt.margin()); |
2240 | QCOMPARE(frame->frameFormat().border(), ffmt.border()); |
2241 | } |
2242 | |
2243 | void tst_QTextDocumentFragment::html_frameImport2() |
2244 | { |
2245 | QTextFrameFormat ffmt; |
2246 | ffmt.setBorder(1); |
2247 | ffmt.setPosition(QTextFrameFormat::FloatRight); |
2248 | ffmt.setLeftMargin(200); |
2249 | ffmt.setTopMargin(100); |
2250 | ffmt.setBottomMargin(50); |
2251 | ffmt.setRightMargin(250); |
2252 | ffmt.setWidth(100); |
2253 | ffmt.setHeight(50); |
2254 | ffmt.setBackground(QColor("#00ff00" )); |
2255 | cursor.insertFrame(format: ffmt); |
2256 | cursor.insertText(text: "Hello World" ); |
2257 | |
2258 | QTextDocumentFragment frag(doc); |
2259 | cleanup(); |
2260 | init(); |
2261 | frag = QTextDocumentFragment::fromHtml(html: frag.toHtml()); |
2262 | cursor.insertFragment(fragment: frag); |
2263 | |
2264 | QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); |
2265 | QCOMPARE(childFrames.count(), 1); |
2266 | QTextFrame *frame = childFrames.first(); |
2267 | QCOMPARE(frame->frameFormat().topMargin(), ffmt.topMargin()); |
2268 | QCOMPARE(frame->frameFormat().bottomMargin(), ffmt.bottomMargin()); |
2269 | QCOMPARE(frame->frameFormat().leftMargin(), ffmt.leftMargin()); |
2270 | QCOMPARE(frame->frameFormat().rightMargin(), ffmt.rightMargin()); |
2271 | QCOMPARE(frame->frameFormat().border(), ffmt.border()); |
2272 | } |
2273 | |
2274 | void tst_QTextDocumentFragment::html_dontAddMarginsAcrossTableCells() |
2275 | { |
2276 | const char html[] = "<table style=\"margin-left: 100px;\"><tr><td><p style=\"margin-left:50px;\">Foo</p></td></tr></table>" ; |
2277 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
2278 | |
2279 | QList<QTextFrame *> childFrames = doc->rootFrame()->childFrames(); |
2280 | QCOMPARE(childFrames.count(), 1); |
2281 | QTextFrame *frame = childFrames.first(); |
2282 | cursor = frame->firstCursorPosition(); |
2283 | QCOMPARE(cursor.blockFormat().leftMargin(), qreal(50.0)); |
2284 | } |
2285 | |
2286 | void tst_QTextDocumentFragment::html_dontMergeCenterBlocks() |
2287 | { |
2288 | const char html[] = "<center>This should be centered</center>And this should not be centered anymore" ; |
2289 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
2290 | |
2291 | QCOMPARE(doc->blockCount(), 2); |
2292 | QTextBlock blk = doc->begin(); |
2293 | QCOMPARE(blk.blockFormat().alignment(), Qt::AlignCenter); |
2294 | blk = blk.next(); |
2295 | QVERIFY(blk.blockFormat().alignment() != Qt::AlignCenter); |
2296 | } |
2297 | |
2298 | void tst_QTextDocumentFragment::html_tableCellBgColor() |
2299 | { |
2300 | const char html[] = "<table><tr><td bgcolor=\"blue\">Test<p>Second Parag</p></td></tr></table>" ; |
2301 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
2302 | |
2303 | cursor.movePosition(op: QTextCursor::Start); |
2304 | cursor.movePosition(op: QTextCursor::NextBlock); |
2305 | QTextTable *table = cursor.currentTable(); |
2306 | QVERIFY(table); |
2307 | |
2308 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
2309 | QVERIFY(cell.format().background().color() == Qt::blue); |
2310 | } |
2311 | |
2312 | void tst_QTextDocumentFragment::html_tableCellBgColor2() |
2313 | { |
2314 | const char html[] = "<table><tr><td bgcolor=\"blue\"><table><tr><td>Blah</td></tr></table></td></tr></table>" ; |
2315 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
2316 | |
2317 | cursor.movePosition(op: QTextCursor::Start); |
2318 | cursor.movePosition(op: QTextCursor::NextBlock); |
2319 | QTextTable *table = cursor.currentTable(); |
2320 | QVERIFY(table); |
2321 | |
2322 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
2323 | QVERIFY(cell.format().background().color() == Qt::blue); |
2324 | |
2325 | QTextFrame::Iterator it = cell.begin(); |
2326 | QVERIFY(!it.atEnd()); |
2327 | QVERIFY(!it.currentFrame()); |
2328 | QVERIFY(it.currentBlock().isValid()); |
2329 | |
2330 | ++it; |
2331 | QVERIFY(!it.atEnd()); |
2332 | QVERIFY(it.currentFrame() != 0); |
2333 | QVERIFY(!it.currentBlock().isValid()); |
2334 | |
2335 | ++it; |
2336 | QVERIFY(!it.atEnd()); |
2337 | QVERIFY(!it.currentFrame()); |
2338 | QVERIFY(it.currentBlock().isValid()); |
2339 | QCOMPARE(it.currentBlock().blockFormat().background(), QBrush(Qt::NoBrush)); |
2340 | |
2341 | ++it; |
2342 | QVERIFY(it.atEnd()); |
2343 | } |
2344 | |
2345 | void tst_QTextDocumentFragment::html_cellSkip() |
2346 | { |
2347 | const char html[] = "" |
2348 | "<table border>" |
2349 | " <tr>" |
2350 | " <td>First Cell</td>" |
2351 | " </tr>" |
2352 | " <tr>" |
2353 | " <td>Second Cell</td>" |
2354 | " <td>Third Cell</td>" |
2355 | " </tr>" |
2356 | "</table>" ; |
2357 | |
2358 | setHtml(html); |
2359 | cursor.movePosition(op: QTextCursor::Start); |
2360 | cursor.movePosition(op: QTextCursor::NextBlock); |
2361 | QTextTable *table = cursor.currentTable(); |
2362 | QVERIFY(table); |
2363 | QVERIFY(table->columns() == 2 && table->rows() == 2); |
2364 | |
2365 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell" )); |
2366 | QVERIFY(table->cellAt(0, 1).firstCursorPosition().block().text().isEmpty()); |
2367 | QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell" )); |
2368 | QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("Third Cell" )); |
2369 | } |
2370 | |
2371 | void tst_QTextDocumentFragment::nonZeroMarginOnImport() |
2372 | { |
2373 | // specify bgcolor so that the html import creates a root frame format |
2374 | setHtml("<html><body bgcolor=\"#00ff00\"><b>Hello World</b></body></html>" ); |
2375 | QVERIFY(doc->rootFrame()->frameFormat().margin() > 0.0); |
2376 | } |
2377 | |
2378 | void tst_QTextDocumentFragment::html_charFormatPropertiesUnset() |
2379 | { |
2380 | setHtml("Hello World" ); |
2381 | QVERIFY(doc->begin().begin().fragment().charFormat().properties().isEmpty()); |
2382 | } |
2383 | |
2384 | void tst_QTextDocumentFragment::html_headings() |
2385 | { |
2386 | setHtml("<h1>foo</h1>bar" ); |
2387 | QCOMPARE(doc->blockCount(), 2); |
2388 | } |
2389 | |
2390 | void tst_QTextDocumentFragment::html_quotedFontFamily_data() |
2391 | { |
2392 | QTest::addColumn<QString>(name: "html" ); |
2393 | QTest::addColumn<QString>(name: "fontFamily" ); |
2394 | QTest::addColumn<QStringList>(name: "fontFamilies" ); |
2395 | |
2396 | const QString fooFamily = QLatin1String("Foo Bar" ); |
2397 | const QString weirdFamily = QLatin1String("'Weird, & font '' name'," ); |
2398 | |
2399 | QTest::newRow(dataTag: "data1" ) << QString("<div style=\"font-family: 'Foo Bar';\">Test</div>" ) |
2400 | << fooFamily << QStringList(fooFamily); |
2401 | QTest::newRow(dataTag: "data2" ) << QString("<div style='font-family: \"Foo Bar\";'>Test</div>" ) |
2402 | << QString("Foo Bar" ) << QStringList("Foo Bar" ); |
2403 | QTest::newRow(dataTag: "data3" ) << QString("<div style='font-family: Foo\n Bar;'>Test</div>" ) |
2404 | << fooFamily << QStringList(fooFamily); |
2405 | QTest::newRow(dataTag: "data4" ) << QString("<div style='font-family: Foo\n Bar, serif, \"bar foo\";'>Test" |
2406 | "</div>" ) |
2407 | << fooFamily << (QStringList() << "Foo Bar" << "serif" << "bar foo" ); |
2408 | QTest::newRow(dataTag: "data5" ) << QString("<div style='font-family: \"\\'Weird, & font \\'\\' name\\'," |
2409 | "\";'>Test</div>" ) |
2410 | << weirdFamily << QStringList(weirdFamily); |
2411 | QTest::newRow(dataTag: "data6" ) << QString("<div style='font-family: \"\\'Weird, & font \\'\\' name\\'," |
2412 | "\";'>Test</div>" ) |
2413 | << weirdFamily << QStringList(weirdFamily); |
2414 | QTest::newRow(dataTag: "data7" ) << QString("<div style='font-family: \"\\'Weird, & font \\'\\' name\\',\", " |
2415 | "serif, \"bar foo\";'>Test</div>" ) |
2416 | << weirdFamily |
2417 | << (QStringList() << weirdFamily << "serif" << "bar foo" ); |
2418 | } |
2419 | |
2420 | void tst_QTextDocumentFragment::html_quotedFontFamily() |
2421 | { |
2422 | QFETCH(QString, html); |
2423 | QFETCH(QString, fontFamily); |
2424 | QFETCH(QStringList, fontFamilies); |
2425 | |
2426 | setHtml(html); |
2427 | QCOMPARE(doc->begin().begin().fragment().charFormat().fontFamily(), fontFamily); |
2428 | QCOMPARE(doc->begin().begin().fragment().charFormat().font().families(), fontFamilies); |
2429 | } |
2430 | |
2431 | void tst_QTextDocumentFragment::defaultFont() |
2432 | { |
2433 | QFont f; |
2434 | f.setFamily("Courier New" ); |
2435 | f.setBold(true); |
2436 | f.setItalic(true); |
2437 | f.setStrikeOut(true); // set here but deliberately ignored for the html export |
2438 | f.setPointSize(100); |
2439 | doc->setDefaultFont(f); |
2440 | doc->setPlainText("Hello World" ); |
2441 | const QString html = doc->toHtml(); |
2442 | QLatin1String str("<body style=\" font-family:'Courier New'; font-size:100pt; font-weight:600; font-style:italic;\">" ); |
2443 | QVERIFY(html.contains(str)); |
2444 | } |
2445 | |
2446 | void tst_QTextDocumentFragment::html_spanBackgroundColor() |
2447 | { |
2448 | setHtml("<span style=\"background-color: blue\">Foo</span>" ); |
2449 | QVERIFY(doc->begin().begin().fragment().charFormat().background().color() == QColor(Qt::blue)); |
2450 | } |
2451 | |
2452 | void tst_QTextDocumentFragment::html_brokenTitle_data() |
2453 | { |
2454 | QTest::addColumn<QString>(name: "html" ); |
2455 | QTest::addColumn<QString>(name: "expectedBody" ); |
2456 | QTest::addColumn<QString>(name: "expectedTitle" ); |
2457 | |
2458 | QTest::newRow(dataTag: "brokentitle" ) << QString("<html><head><title>Foo<b>bar</b></title></head><body>Blah</body></html>" ) |
2459 | << QString("Blah" ) << QString("Foo" ); |
2460 | QTest::newRow(dataTag: "brokentitle2" ) << QString("<html><head><title>Foo<font color=red>i</font>t<font color=red>i</font>Blub</title></head><body>Blah</body></html>" ) |
2461 | << QString("Blah" ) << QString("Foo" ); |
2462 | QTest::newRow(dataTag: "entities" ) << QString("<html><head><title>Foo<bar</title></head><body>Blah</body></html>" ) |
2463 | << QString("Blah" ) << QString("Foo<bar" ); |
2464 | QTest::newRow(dataTag: "unclosedtitle" ) << QString("<html><head><title>Foo</head><body>Blah</body></html>" ) |
2465 | << QString("Blah" ) << QString("Foo" ); |
2466 | } |
2467 | |
2468 | void tst_QTextDocumentFragment::html_brokenTitle() |
2469 | { |
2470 | QFETCH(QString, html); |
2471 | QFETCH(QString, expectedBody); |
2472 | QFETCH(QString, expectedTitle); |
2473 | doc->setHtml(html); |
2474 | QCOMPARE(doc->toPlainText(), expectedBody); |
2475 | QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), expectedTitle); |
2476 | } |
2477 | |
2478 | void tst_QTextDocumentFragment::html_blockVsInline() |
2479 | { |
2480 | { |
2481 | setHtml("<html><body><div><b>Foo<div>Bar" ); |
2482 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
2483 | QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold)); |
2484 | } |
2485 | { |
2486 | setHtml("<html><body><p><b>Foo<p>Bar" ); |
2487 | QVERIFY(cursor.charFormat().fontWeight() != QFont::Bold); |
2488 | QVERIFY(cursor.blockCharFormat().fontWeight() != QFont::Bold); |
2489 | } |
2490 | { |
2491 | setHtml("<html><body><b><center>Foo</center></b>" ); |
2492 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
2493 | QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold)); |
2494 | } |
2495 | { |
2496 | setHtml("<html><body><b><p>Foo" ); |
2497 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
2498 | QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold)); |
2499 | } |
2500 | { |
2501 | setHtml("<html><body><b><p>Foo<p>Bar" ); |
2502 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
2503 | QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold)); |
2504 | } |
2505 | { |
2506 | setHtml("<div><b>Foo<div>Bar" ); |
2507 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
2508 | QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold)); |
2509 | } |
2510 | { |
2511 | setHtml("<p><b>Foo<p>Bar" ); |
2512 | QVERIFY(cursor.charFormat().fontWeight() != QFont::Bold); |
2513 | QVERIFY(cursor.blockCharFormat().fontWeight() != QFont::Bold); |
2514 | } |
2515 | { |
2516 | setHtml("<b><center>Foo</center></b>" ); |
2517 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
2518 | QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold)); |
2519 | } |
2520 | { |
2521 | setHtml("<b><p>Foo" ); |
2522 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
2523 | QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold)); |
2524 | } |
2525 | { |
2526 | setHtml("<b><p>Foo<p>Bar" ); |
2527 | QCOMPARE(cursor.charFormat().fontWeight(), int(QFont::Bold)); |
2528 | QCOMPARE(cursor.blockCharFormat().fontWeight(), int(QFont::Bold)); |
2529 | } |
2530 | } |
2531 | |
2532 | void tst_QTextDocumentFragment::html_tbody() |
2533 | { |
2534 | setHtml("<table><thead><tr><td>First Cell</td></tr></thead><tbody><tr><td>Second Cell</td></tr></tbody></table>" ); |
2535 | cursor.movePosition(op: QTextCursor::Start); |
2536 | cursor.movePosition(op: QTextCursor::NextBlock); |
2537 | QTextTable *table = cursor.currentTable(); |
2538 | QVERIFY(table); |
2539 | QCOMPARE(table->columns(), 1); |
2540 | QCOMPARE(table->rows(), 2); |
2541 | QCOMPARE(table->format().headerRowCount(), 1); |
2542 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell" )); |
2543 | QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell" )); |
2544 | } |
2545 | |
2546 | void tst_QTextDocumentFragment::html_nestedTables() |
2547 | { |
2548 | setHtml("<table>" |
2549 | " <tr><td>" |
2550 | "" |
2551 | " <table>" |
2552 | " <tr><td>Hello</td></tr>" |
2553 | " </table>" |
2554 | "" |
2555 | " <table>" |
2556 | " <tr><td>World</td></tr>" |
2557 | " </table>" |
2558 | "" |
2559 | " </td></tr>" |
2560 | "</table>" |
2561 | ); |
2562 | |
2563 | cursor.movePosition(op: QTextCursor::Start); |
2564 | cursor.movePosition(op: QTextCursor::NextBlock); |
2565 | QTextTable *table = cursor.currentTable(); |
2566 | QVERIFY(table); |
2567 | QCOMPARE(table->rows(), 1); |
2568 | QCOMPARE(table->columns(), 1); |
2569 | |
2570 | cursor = table->cellAt(row: 0, col: 0).firstCursorPosition(); |
2571 | cursor.movePosition(op: QTextCursor::NextBlock); |
2572 | |
2573 | QTextTable *firstNestedTable = cursor.currentTable(); |
2574 | QVERIFY(firstNestedTable); |
2575 | QCOMPARE(firstNestedTable->parentFrame(), table); |
2576 | QCOMPARE(firstNestedTable->rows(), 1); |
2577 | QCOMPARE(firstNestedTable->columns(), 1); |
2578 | QCOMPARE(firstNestedTable->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hello" )); |
2579 | |
2580 | while (cursor.currentTable() == firstNestedTable |
2581 | && cursor.movePosition(op: QTextCursor::NextBlock)) |
2582 | ; |
2583 | |
2584 | QVERIFY(!cursor.isNull()); |
2585 | QCOMPARE(cursor.currentTable(), table); |
2586 | |
2587 | cursor.movePosition(op: QTextCursor::NextBlock); |
2588 | |
2589 | QTextTable *secondNestedTable = cursor.currentTable(); |
2590 | QVERIFY(secondNestedTable); |
2591 | QCOMPARE(secondNestedTable->parentFrame(), table); |
2592 | QCOMPARE(secondNestedTable->rows(), 1); |
2593 | QCOMPARE(secondNestedTable->columns(), 1); |
2594 | QCOMPARE(secondNestedTable->cellAt(0, 0).firstCursorPosition().block().text(), QString("World" )); |
2595 | } |
2596 | |
2597 | void tst_QTextDocumentFragment::html_rowSpans() |
2598 | { |
2599 | setHtml("" |
2600 | "<table border=\"1\" width=\"100%\">" |
2601 | " <tr>" |
2602 | " <td rowspan=\"2\">blah</td>" |
2603 | " <td rowspan=\"2\">foo</td>" |
2604 | " </tr>" |
2605 | " <tr></tr>" |
2606 | " <tr>" |
2607 | " <td rowspan=\"2\">blubb</td>" |
2608 | " <td rowspan=\"2\">baz</td>" |
2609 | " </tr>" |
2610 | " <tr></tr>" |
2611 | "</table>" ); |
2612 | |
2613 | cursor.movePosition(op: QTextCursor::Start); |
2614 | cursor.movePosition(op: QTextCursor::NextBlock); |
2615 | QTextTable *table = cursor.currentTable(); |
2616 | QVERIFY(table); |
2617 | QCOMPARE(table->rows(), 4); |
2618 | QCOMPARE(table->columns(), 2); |
2619 | |
2620 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("blah" )); |
2621 | QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("foo" )); |
2622 | |
2623 | QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("blah" )); |
2624 | QCOMPARE(table->cellAt(1, 1).firstCursorPosition().block().text(), QString("foo" )); |
2625 | |
2626 | QCOMPARE(table->cellAt(2, 0).firstCursorPosition().block().text(), QString("blubb" )); |
2627 | QCOMPARE(table->cellAt(2, 1).firstCursorPosition().block().text(), QString("baz" )); |
2628 | |
2629 | QCOMPARE(table->cellAt(3, 0).firstCursorPosition().block().text(), QString("blubb" )); |
2630 | QCOMPARE(table->cellAt(3, 1).firstCursorPosition().block().text(), QString("baz" )); |
2631 | } |
2632 | |
2633 | void tst_QTextDocumentFragment::html_rowSpans2() |
2634 | { |
2635 | setHtml("" |
2636 | "<html><body>" |
2637 | "<table border=\"1\">" |
2638 | "<tr>" |
2639 | "<td>Row 1 col 1</td>" |
2640 | "</tr>" |
2641 | "<tr>" |
2642 | "<td rowspan=\"3\">Row 2 col 1, rowspan 3</td>" |
2643 | "<td>Row 2 col 2</td>" |
2644 | "</tr>" |
2645 | "<tr>" |
2646 | "<td rowspan=\"2\">Row 3 col 2, rowspan 2</td>" |
2647 | "</tr>" |
2648 | "<tr>" |
2649 | "</tr>" |
2650 | "</table>" |
2651 | "</body></html>" ); |
2652 | |
2653 | cursor.movePosition(op: QTextCursor::Start); |
2654 | cursor.movePosition(op: QTextCursor::NextBlock); |
2655 | QTextTable *table = cursor.currentTable(); |
2656 | QVERIFY(table); |
2657 | QCOMPARE(table->rows(), 4); |
2658 | QCOMPARE(table->columns(), 2); |
2659 | QCOMPARE(table->cellAt(0, 1).rowSpan(), 1); |
2660 | QCOMPARE(table->cellAt(1, 0).rowSpan(), 3); |
2661 | QCOMPARE(table->cellAt(2, 1).rowSpan(), 2); |
2662 | } |
2663 | |
2664 | void tst_QTextDocumentFragment::html_implicitParagraphs() |
2665 | { |
2666 | setHtml("<p>foo</p>bar" ); |
2667 | QCOMPARE(doc->blockCount(), 2); |
2668 | } |
2669 | |
2670 | void tst_QTextDocumentFragment::html_missingCloseTag() |
2671 | { |
2672 | setHtml("<font color=\"red\"><span style=\"color:blue\">blue</span></span> red</font>" ); |
2673 | cursor.movePosition(op: QTextCursor::Start); |
2674 | cursor.movePosition(op: QTextCursor::NextCharacter); |
2675 | QVERIFY(cursor.charFormat().foreground().color() == Qt::blue); |
2676 | cursor.movePosition(op: QTextCursor::NextWord); |
2677 | cursor.movePosition(op: QTextCursor::NextCharacter); |
2678 | QVERIFY(cursor.charFormat().foreground().color() == Qt::red); |
2679 | } |
2680 | |
2681 | void tst_QTextDocumentFragment::html_anchorColor() |
2682 | { |
2683 | setHtml("<span style=\"color: red;\">Red</span>" ); |
2684 | cursor.movePosition(op: QTextCursor::Start); |
2685 | cursor.movePosition(op: QTextCursor::NextCharacter); |
2686 | QVERIFY(cursor.charFormat().foreground().color() == Qt::red); |
2687 | |
2688 | setHtml("<span style=\"color: red;\"><a href=\"http://www.kde.org/\">Blue</a></span>" ); |
2689 | cursor.movePosition(op: QTextCursor::Start); |
2690 | cursor.movePosition(op: QTextCursor::NextCharacter); |
2691 | QCOMPARE(cursor.charFormat().foreground().color(), QGuiApplication::palette().link().color()); |
2692 | |
2693 | setHtml("<span style=\"color: red;\"><a href=\"http://www.kde.org/\" style=\"color: yellow;\">Green</a></span>" ); |
2694 | cursor.movePosition(op: QTextCursor::Start); |
2695 | cursor.movePosition(op: QTextCursor::NextCharacter); |
2696 | QVERIFY(cursor.charFormat().foreground().color() == Qt::yellow); |
2697 | } |
2698 | |
2699 | void tst_QTextDocumentFragment::html_lastParagraphClosing() |
2700 | { |
2701 | setHtml("<p>Foo<b>Bar</b>Baz" ); |
2702 | QCOMPARE(doc->blockCount(), 1); |
2703 | } |
2704 | |
2705 | void tst_QTextDocumentFragment::html_tableHeaderBodyFootParent() |
2706 | { |
2707 | // don't get confused by strange tags, keep tbody/thead/tfoot children of |
2708 | // the table tag |
2709 | setHtml("<table><col><col><col><tbody><tr><td>Hey</td></tr></tbody></table>" ); |
2710 | |
2711 | cursor.movePosition(op: QTextCursor::Start); |
2712 | cursor.movePosition(op: QTextCursor::NextBlock); |
2713 | QTextTable *table = cursor.currentTable(); |
2714 | QVERIFY(table); |
2715 | QCOMPARE(table->columns(), 1); |
2716 | QCOMPARE(table->rows(), 1); |
2717 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey" )); |
2718 | |
2719 | setHtml("<table><col><col><col><thead><tr><td>Hey</td></tr></thead></table>" ); |
2720 | |
2721 | cursor.movePosition(op: QTextCursor::Start); |
2722 | cursor.movePosition(op: QTextCursor::NextBlock); |
2723 | table = cursor.currentTable(); |
2724 | QVERIFY(table); |
2725 | QCOMPARE(table->columns(), 1); |
2726 | QCOMPARE(table->rows(), 1); |
2727 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey" )); |
2728 | |
2729 | setHtml("<table><col><col><col><tfoot><tr><td>Hey</td></tr></tfoot></table>" ); |
2730 | |
2731 | cursor.movePosition(op: QTextCursor::Start); |
2732 | cursor.movePosition(op: QTextCursor::NextBlock); |
2733 | table = cursor.currentTable(); |
2734 | QVERIFY(table); |
2735 | QCOMPARE(table->columns(), 1); |
2736 | QCOMPARE(table->rows(), 1); |
2737 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("Hey" )); |
2738 | } |
2739 | |
2740 | void tst_QTextDocumentFragment::html_columnWidths() |
2741 | { |
2742 | setHtml("<table>" |
2743 | " <tr>" |
2744 | " <td colspan=\"2\">Foo</td>" |
2745 | " </tr>" |
2746 | " <tr>" |
2747 | " <td>Bar</td>" |
2748 | " <td width=\"1%\">Baz</td>" |
2749 | " </tr>" |
2750 | "</table>" ); |
2751 | |
2752 | cursor.movePosition(op: QTextCursor::Start); |
2753 | cursor.movePosition(op: QTextCursor::NextBlock); |
2754 | QTextTable *table = cursor.currentTable(); |
2755 | QVERIFY(table); |
2756 | QCOMPARE(table->columns(), 2); |
2757 | QCOMPARE(table->rows(), 2); |
2758 | QTextTableFormat fmt = table->format(); |
2759 | |
2760 | const QVector<QTextLength> columnWidths = fmt.columnWidthConstraints(); |
2761 | QCOMPARE(columnWidths.count(), 2); |
2762 | QCOMPARE(columnWidths.at(0).type(), QTextLength::VariableLength); |
2763 | QCOMPARE(columnWidths.at(1).type(), QTextLength::PercentageLength); |
2764 | QCOMPARE(columnWidths.at(1).rawValue(), qreal(1)); |
2765 | } |
2766 | |
2767 | void tst_QTextDocumentFragment::css_fontWeight() |
2768 | { |
2769 | setHtml("<p style=\"font-weight:bold\">blah</p>" ); |
2770 | QCOMPARE(doc->begin().charFormat().fontWeight(), int(QFont::Bold)); |
2771 | setHtml("<p style=\"font-weight:600\">blah</p>" ); |
2772 | QCOMPARE(doc->begin().charFormat().fontWeight(), int(QFont::Bold)); |
2773 | |
2774 | } |
2775 | |
2776 | void tst_QTextDocumentFragment::css_float() |
2777 | { |
2778 | setHtml("<img src=\"foo\" style=\"float: right\">" ); |
2779 | QTextCharFormat fmt = doc->begin().begin().fragment().charFormat(); |
2780 | QVERIFY(fmt.isImageFormat()); |
2781 | QTextObject *o = doc->objectForFormat(fmt); |
2782 | QVERIFY(o); |
2783 | QTextFormat f = o->format(); |
2784 | QVERIFY(f.isFrameFormat()); |
2785 | QCOMPARE(f.toFrameFormat().position(), QTextFrameFormat::FloatRight); |
2786 | |
2787 | setHtml("<img src=\"foo\" align=right>" ); |
2788 | fmt = doc->begin().begin().fragment().charFormat(); |
2789 | QVERIFY(fmt.isImageFormat()); |
2790 | o = doc->objectForFormat(fmt); |
2791 | QVERIFY(o); |
2792 | f = o->format(); |
2793 | QVERIFY(f.isFrameFormat()); |
2794 | QCOMPARE(f.toFrameFormat().position(), QTextFrameFormat::FloatRight); |
2795 | |
2796 | setHtml("<img src=\"foo\" align=left>" ); |
2797 | fmt = doc->begin().begin().fragment().charFormat(); |
2798 | QVERIFY(fmt.isImageFormat()); |
2799 | o = doc->objectForFormat(fmt); |
2800 | QVERIFY(o); |
2801 | f = o->format(); |
2802 | QVERIFY(f.isFrameFormat()); |
2803 | QCOMPARE(f.toFrameFormat().position(), QTextFrameFormat::FloatLeft); |
2804 | } |
2805 | |
2806 | void tst_QTextDocumentFragment::css_textIndent() |
2807 | { |
2808 | setHtml("<p style=\"text-indent: 42px\">foo</p>" ); |
2809 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
2810 | QCOMPARE(fmt.textIndent(), qreal(42)); |
2811 | } |
2812 | |
2813 | void tst_QTextDocumentFragment::css_inline() |
2814 | { |
2815 | setHtml("" |
2816 | "<style>" |
2817 | " p { background-color: green;}" |
2818 | "</style>" |
2819 | "<p>test</p>" |
2820 | ); |
2821 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
2822 | QCOMPARE(fmt.background().color(), QColor("green" )); |
2823 | } |
2824 | |
2825 | void tst_QTextDocumentFragment::css_external() |
2826 | { |
2827 | doc->addResource(type: QTextDocument::StyleSheetResource, name: QUrl("test.css" ), resource: QString("p { background-color: green; }" )); |
2828 | doc->setHtml("" |
2829 | "<link href=\"test.css\" type=\"text/css\" />" |
2830 | "<p>test</p>" |
2831 | ); |
2832 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
2833 | QCOMPARE(fmt.background().color(), QColor("green" )); |
2834 | } |
2835 | |
2836 | void tst_QTextDocumentFragment::css_import() |
2837 | { |
2838 | const QColor green("green" ); |
2839 | doc->addResource(type: QTextDocument::StyleSheetResource, name: QUrl("test.css" ), resource: QString("@import \"other.css\";" )); |
2840 | doc->addResource(type: QTextDocument::StyleSheetResource, name: QUrl("other.css" ), resource: QString("@import url(\"other2.css\");" )); |
2841 | doc->addResource(type: QTextDocument::StyleSheetResource, name: QUrl("other2.css" ), resource: QString("p { background-color: green; }" )); |
2842 | doc->setHtml("" |
2843 | "<link href=\"test.css\" type=\"text/css\" />" |
2844 | "<p>test</p>" |
2845 | ); |
2846 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
2847 | QCOMPARE(fmt.background().color(), green); |
2848 | |
2849 | doc->setHtml("" |
2850 | "<style>@import \"test.css\" screen;</style>" |
2851 | "<p>test</p>" |
2852 | ); |
2853 | fmt = doc->begin().blockFormat(); |
2854 | QCOMPARE(fmt.background().color(), green); |
2855 | } |
2856 | |
2857 | void tst_QTextDocumentFragment::css_selectors_data() |
2858 | { |
2859 | QTest::addColumn<bool>(name: "match" ); |
2860 | QTest::addColumn<QString>(name: "selector" ); |
2861 | QTest::addColumn<QString>(name: "attributes" ); |
2862 | |
2863 | QTest::newRow(dataTag: "plain" ) << true << QString() << QString(); |
2864 | |
2865 | QTest::newRow(dataTag: "class" ) << true << QString(".foo" ) << QString("class=foo" ); |
2866 | QTest::newRow(dataTag: "notclass" ) << false << QString(".foo" ) << QString("class=bar" ); |
2867 | |
2868 | QTest::newRow(dataTag: "attrset" ) << true << QString("[justset]" ) << QString("justset" ); |
2869 | QTest::newRow(dataTag: "notattrset" ) << false << QString("[justset]" ) << QString("otherattribute" ); |
2870 | |
2871 | QTest::newRow(dataTag: "attrmatch" ) << true << QString("[foo=bar]" ) << QString("foo=bar" ); |
2872 | QTest::newRow(dataTag: "noattrmatch" ) << false << QString("[foo=bar]" ) << QString("foo=xyz" ); |
2873 | |
2874 | QTest::newRow(dataTag: "contains" ) << true << QString("[foo~=bar]" ) << QString("foo=\"baz bleh bar\"" ); |
2875 | QTest::newRow(dataTag: "notcontains" ) << false << QString("[foo~=bar]" ) << QString("foo=\"test\"" ); |
2876 | |
2877 | QTest::newRow(dataTag: "beingswith" ) << true << QString("[foo|=bar]" ) << QString("foo=\"bar-bleh\"" ); |
2878 | QTest::newRow(dataTag: "notbeingswith" ) << false << QString("[foo|=bar]" ) << QString("foo=\"bleh-bar\"" ); |
2879 | |
2880 | QTest::newRow(dataTag: "attr2" ) << true << QString("[bar=foo]" ) << QString("bleh=bar bar=foo" ); |
2881 | } |
2882 | |
2883 | void tst_QTextDocumentFragment::css_selectors() |
2884 | { |
2885 | QFETCH(bool, match); |
2886 | QFETCH(QString, selector); |
2887 | QFETCH(QString, attributes); |
2888 | |
2889 | QString html = QString("" |
2890 | "<style>" |
2891 | " p { background-color: green }" |
2892 | " p%1 { background-color: red }" |
2893 | "</style>" |
2894 | "<p %2>test</p>" |
2895 | ).arg(a: selector).arg(a: attributes); |
2896 | setHtml(html); |
2897 | |
2898 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
2899 | if (match) |
2900 | QCOMPARE(fmt.background().color(), QColor("red" )); |
2901 | else |
2902 | QCOMPARE(fmt.background().color(), QColor("green" )); |
2903 | } |
2904 | |
2905 | void tst_QTextDocumentFragment::css_nodeNameCaseInsensitivity() |
2906 | { |
2907 | setHtml("<style>" |
2908 | "P { background-color: green }" |
2909 | "</style>" |
2910 | "<p>test</p>" ); |
2911 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
2912 | QCOMPARE(fmt.background().color(), QColor("green" )); |
2913 | } |
2914 | |
2915 | void tst_QTextDocumentFragment::css_textUnderlineStyle_data() |
2916 | { |
2917 | QTest::addColumn<QString>(name: "styleName" ); |
2918 | QTest::addColumn<int>(name: "expectedStyle" ); |
2919 | |
2920 | QTest::newRow(dataTag: "none" ) << QString("none" ) << int(QTextCharFormat::NoUnderline); |
2921 | QTest::newRow(dataTag: "solid" ) << QString("solid" ) << int(QTextCharFormat::SingleUnderline); |
2922 | QTest::newRow(dataTag: "dash" ) << QString("dashed" ) << int(QTextCharFormat::DashUnderline); |
2923 | QTest::newRow(dataTag: "dot" ) << QString("dotted" ) << int(QTextCharFormat::DotLine); |
2924 | QTest::newRow(dataTag: "dashdot" ) << QString("dot-dash" ) << int(QTextCharFormat::DashDotLine); |
2925 | QTest::newRow(dataTag: "dashdotdot" ) << QString("dot-dot-dash" ) << int(QTextCharFormat::DashDotDotLine); |
2926 | QTest::newRow(dataTag: "wave" ) << QString("wave" ) << int(QTextCharFormat::WaveUnderline); |
2927 | } |
2928 | |
2929 | void tst_QTextDocumentFragment::css_textUnderlineStyle() |
2930 | { |
2931 | QFETCH(QString, styleName); |
2932 | QFETCH(int, expectedStyle); |
2933 | |
2934 | QString html = QString::fromLatin1(str: "<span style=\"text-underline-style: %1\">Blah</span>" ).arg(a: styleName); |
2935 | doc->setHtml(html); |
2936 | |
2937 | QTextFragment fragment = doc->begin().begin().fragment(); |
2938 | QVERIFY(fragment.isValid()); |
2939 | QCOMPARE(int(fragment.charFormat().underlineStyle()), expectedStyle); |
2940 | } |
2941 | |
2942 | void tst_QTextDocumentFragment::css_textUnderlineStyleAndDecoration() |
2943 | { |
2944 | doc->setHtml("<span style=\"text-decoration: overline; text-underline-style: solid\">Test</span>" ); |
2945 | |
2946 | QTextFragment fragment = doc->begin().begin().fragment(); |
2947 | QVERIFY(fragment.isValid()); |
2948 | QCOMPARE(fragment.charFormat().underlineStyle(), QTextCharFormat::SingleUnderline); |
2949 | QVERIFY(fragment.charFormat().fontOverline()); |
2950 | |
2951 | doc->setHtml("<span style=\"text-underline-style: solid; text-decoration: overline\">Test</span>" ); |
2952 | |
2953 | fragment = doc->begin().begin().fragment(); |
2954 | QVERIFY(fragment.isValid()); |
2955 | QCOMPARE(fragment.charFormat().underlineStyle(), QTextCharFormat::SingleUnderline); |
2956 | QVERIFY(fragment.charFormat().fontOverline()); |
2957 | } |
2958 | |
2959 | void tst_QTextDocumentFragment::css_listStyleType() |
2960 | { |
2961 | doc->setHtml("<ol style=\"list-style-type: disc\"><li>Blah</li></ol>" ); |
2962 | cursor.movePosition(op: QTextCursor::End); |
2963 | QVERIFY(cursor.currentList()); |
2964 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListDisc); |
2965 | |
2966 | doc->setHtml("<ul style=\"list-style-type: square\"><li>Blah</li></ul>" ); |
2967 | cursor.movePosition(op: QTextCursor::End); |
2968 | QVERIFY(cursor.currentList()); |
2969 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListSquare); |
2970 | |
2971 | doc->setHtml("<ul style=\"list-style-type: circle\"><li>Blah</li></ul>" ); |
2972 | cursor.movePosition(op: QTextCursor::End); |
2973 | QVERIFY(cursor.currentList()); |
2974 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListCircle); |
2975 | |
2976 | doc->setHtml("<ul style=\"list-style-type: decimal\"><li>Blah</li></ul>" ); |
2977 | cursor.movePosition(op: QTextCursor::End); |
2978 | QVERIFY(cursor.currentList()); |
2979 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListDecimal); |
2980 | |
2981 | doc->setHtml("<ul style=\"list-style-type: lower-alpha\"><li>Blah</li></ul>" ); |
2982 | cursor.movePosition(op: QTextCursor::End); |
2983 | QVERIFY(cursor.currentList()); |
2984 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListLowerAlpha); |
2985 | |
2986 | doc->setHtml("<ul style=\"list-style-type: upper-alpha\"><li>Blah</li></ul>" ); |
2987 | cursor.movePosition(op: QTextCursor::End); |
2988 | QVERIFY(cursor.currentList()); |
2989 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListUpperAlpha); |
2990 | |
2991 | doc->setHtml("<ul style=\"list-style-type: upper-roman\"><li>Blah</li></ul>" ); |
2992 | cursor.movePosition(op: QTextCursor::End); |
2993 | QVERIFY(cursor.currentList()); |
2994 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListUpperRoman); |
2995 | |
2996 | doc->setHtml("<ul style=\"list-style-type: lower-roman\"><li>Blah</li></ul>" ); |
2997 | cursor.movePosition(op: QTextCursor::End); |
2998 | QVERIFY(cursor.currentList()); |
2999 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListLowerRoman); |
3000 | |
3001 | // ignore the unsupported list-style-position inside the list-style shorthand property |
3002 | doc->setHtml("<ul style=\"list-style: outside decimal\"><li>Blah</li></ul>" ); |
3003 | cursor.movePosition(op: QTextCursor::End); |
3004 | QVERIFY(cursor.currentList()); |
3005 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListDecimal); |
3006 | } |
3007 | |
3008 | void tst_QTextDocumentFragment::css_linkPseudo() |
3009 | { |
3010 | doc->setHtml("<a href=\"foobar\">Blah</a>" ); |
3011 | QVERIFY(doc->begin().begin().fragment().charFormat().fontUnderline()); |
3012 | |
3013 | doc->setHtml("<style>a { text-decoration: none; }</style><a href=\"foobar\">Blah</a>" ); |
3014 | QVERIFY(!doc->begin().begin().fragment().charFormat().fontUnderline()); |
3015 | |
3016 | doc->setHtml("<style>a:link { text-decoration: none; }</style><a href=\"foobar\">Blah</a>" ); |
3017 | QVERIFY(!doc->begin().begin().fragment().charFormat().fontUnderline()); |
3018 | } |
3019 | |
3020 | void tst_QTextDocumentFragment::css_pageBreaks() |
3021 | { |
3022 | doc->setHtml("<p>Foo</p>" ); |
3023 | QCOMPARE(doc->begin().blockFormat().pageBreakPolicy(), QTextFormat::PageBreak_Auto); |
3024 | |
3025 | doc->setHtml("<p style=\" page-break-before:always;\">Foo</p>" ); |
3026 | QCOMPARE(doc->begin().blockFormat().pageBreakPolicy(), QTextFormat::PageBreak_AlwaysBefore); |
3027 | |
3028 | doc->setHtml("<p style=\" page-break-after:always;\">Foo</p>" ); |
3029 | QCOMPARE(doc->begin().blockFormat().pageBreakPolicy(), QTextFormat::PageBreak_AlwaysAfter); |
3030 | |
3031 | doc->setHtml("<p style=\" page-break-before:always; page-break-after:always;\">Foo</p>" ); |
3032 | QVERIFY(doc->begin().blockFormat().pageBreakPolicy() == (QTextFormat::PageBreak_AlwaysAfter | QTextFormat::PageBreak_AlwaysBefore)); |
3033 | } |
3034 | |
3035 | void tst_QTextDocumentFragment::universalSelectors_data() |
3036 | { |
3037 | QTest::addColumn<bool>(name: "match" ); |
3038 | QTest::addColumn<QString>(name: "selector" ); |
3039 | QTest::addColumn<QString>(name: "attributes" ); |
3040 | |
3041 | QTest::newRow(dataTag: "1" ) << true << QString("*" ) << QString(); |
3042 | QTest::newRow(dataTag: "2" ) << false << QString() << QString(); // invalid totally empty selector |
3043 | |
3044 | QTest::newRow(dataTag: "3" ) << false << QString("*[foo=bar]" ) << QString("foo=bleh" ); |
3045 | QTest::newRow(dataTag: "4" ) << true << QString("*[foo=bar]" ) << QString("foo=bar" ); |
3046 | |
3047 | QTest::newRow(dataTag: "5" ) << false << QString("[foo=bar]" ) << QString("foo=bleh" ); |
3048 | QTest::newRow(dataTag: "6" ) << true << QString("[foo=bar]" ) << QString("foo=bar" ); |
3049 | |
3050 | QTest::newRow(dataTag: "7" ) << true << QString(".charfmt1" ) << QString("class=charfmt1" ); |
3051 | } |
3052 | |
3053 | void tst_QTextDocumentFragment::universalSelectors() |
3054 | { |
3055 | QFETCH(bool, match); |
3056 | QFETCH(QString, selector); |
3057 | QFETCH(QString, attributes); |
3058 | |
3059 | QString html = QString("" |
3060 | "<style>" |
3061 | "%1 { background-color: green }" |
3062 | "</style>" |
3063 | "<p %2>test</p>" |
3064 | ).arg(a: selector).arg(a: attributes); |
3065 | |
3066 | setHtml(html); |
3067 | |
3068 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
3069 | if (match) |
3070 | QCOMPARE(fmt.background().color(), QColor("green" )); |
3071 | else |
3072 | QVERIFY(!fmt.hasProperty(QTextFormat::BackgroundBrush)); |
3073 | } |
3074 | |
3075 | void tst_QTextDocumentFragment::screenMedia() |
3076 | { |
3077 | const QColor green("green" ); |
3078 | setHtml("<style>" |
3079 | "@media screen {" |
3080 | "p { background-color: green }" |
3081 | "}" |
3082 | "</style>" |
3083 | "<p>test</p>" |
3084 | "" ); |
3085 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
3086 | QCOMPARE(fmt.background().color(), green); |
3087 | |
3088 | setHtml("<style>" |
3089 | "@media foobar {" |
3090 | "p { background-color: green }" |
3091 | "}" |
3092 | "</style>" |
3093 | "<p>test</p>" |
3094 | "" ); |
3095 | fmt = doc->begin().blockFormat(); |
3096 | QVERIFY(fmt.background().color() != green); |
3097 | |
3098 | setHtml("<style>" |
3099 | "@media sCrEeN {" |
3100 | "p { background-color: green }" |
3101 | "}" |
3102 | "</style>" |
3103 | "<p>test</p>" |
3104 | "" ); |
3105 | fmt = doc->begin().blockFormat(); |
3106 | QCOMPARE(fmt.background().color(), green); |
3107 | } |
3108 | |
3109 | void tst_QTextDocumentFragment::htmlResourceLoading() |
3110 | { |
3111 | const QString html("<link href=\"test.css\" type=\"text/css\" />" |
3112 | "<p>test</p>" ); |
3113 | |
3114 | QTextDocument tmp; |
3115 | tmp.addResource(type: QTextDocument::StyleSheetResource, name: QUrl("test.css" ), resource: QString("p { background-color: green; }" )); |
3116 | QTextDocumentFragment frag = QTextDocumentFragment::fromHtml(html, resourceProvider: &tmp); |
3117 | doc->clear(); |
3118 | QTextCursor(doc).insertFragment(fragment: frag); |
3119 | QTextBlockFormat fmt = doc->begin().blockFormat(); |
3120 | QCOMPARE(fmt.background().color(), QColor("green" )); |
3121 | } |
3122 | |
3123 | void tst_QTextDocumentFragment::someCaseInsensitiveAttributeValues() |
3124 | { |
3125 | const char html1[] = "<ul type=sQUarE><li>Blah</li></ul>" ; |
3126 | setHtml(QString::fromLatin1(str: html1)); |
3127 | cursor.movePosition(op: QTextCursor::End); |
3128 | QVERIFY(cursor.currentList()); |
3129 | QCOMPARE(cursor.currentList()->format().style(), QTextListFormat::ListSquare); |
3130 | |
3131 | const char html2[] = "<div align=ceNTeR><b>Hello World" ; |
3132 | setHtml(html2); |
3133 | |
3134 | QCOMPARE(doc->begin().blockFormat().alignment(), Qt::AlignHCenter); |
3135 | |
3136 | const char html3[] = "<p dir=rTL><b>Hello World" ; |
3137 | setHtml(html3); |
3138 | |
3139 | QCOMPARE(doc->begin().blockFormat().layoutDirection(), Qt::RightToLeft); |
3140 | } |
3141 | |
3142 | class TestDocument : public QTextDocument |
3143 | { |
3144 | public: |
3145 | inline TestDocument() {} |
3146 | |
3147 | QPixmap testPixmap; |
3148 | |
3149 | virtual QVariant loadResource(int type, const QUrl &name) { |
3150 | if (name.toString() == QLatin1String("testPixmap" )) { |
3151 | return testPixmap; |
3152 | } |
3153 | return QTextDocument::loadResource(type, name); |
3154 | } |
3155 | }; |
3156 | |
3157 | void tst_QTextDocumentFragment::backgroundImage() |
3158 | { |
3159 | TestDocument doc; |
3160 | doc.testPixmap = QPixmap(100, 100); |
3161 | doc.testPixmap.fill(fillColor: Qt::blue); |
3162 | doc.setHtml("<p style=\"background-image: url(testPixmap)\">Hello</p>" ); |
3163 | QBrush bg = doc.begin().blockFormat().background(); |
3164 | QCOMPARE(bg.style(), Qt::TexturePattern); |
3165 | QCOMPARE(bg.texture().cacheKey(), doc.testPixmap.cacheKey()); |
3166 | } |
3167 | |
3168 | void tst_QTextDocumentFragment::dontMergePreAndNonPre() |
3169 | { |
3170 | doc->setHtml("<pre>Pre text</pre>Text that should be wrapped" ); |
3171 | QCOMPARE(doc->blockCount(), 2); |
3172 | QCOMPARE(doc->begin().text(), QString("Pre text" )); |
3173 | QCOMPARE(doc->begin().next().text(), QString("Text that should be wrapped" )); |
3174 | } |
3175 | |
3176 | void tst_QTextDocumentFragment::leftMarginInsideHtml() |
3177 | { |
3178 | doc->setHtml("<html><dl><dd>Blah" ); |
3179 | QCOMPARE(doc->blockCount(), 1); |
3180 | QVERIFY(doc->begin().blockFormat().leftMargin() > 0); |
3181 | } |
3182 | |
3183 | void tst_QTextDocumentFragment::html_margins() |
3184 | { |
3185 | doc->setHtml("<p style=\"margin-left: 42px\">Test" ); |
3186 | QCOMPARE(doc->blockCount(), 1); |
3187 | QCOMPARE(doc->begin().blockFormat().topMargin(), 12.); |
3188 | QCOMPARE(doc->begin().blockFormat().bottomMargin(), 12.); |
3189 | QCOMPARE(doc->begin().blockFormat().leftMargin(), 42.); |
3190 | } |
3191 | |
3192 | void tst_QTextDocumentFragment::newlineInsidePreShouldBecomeNewParagraph() |
3193 | { |
3194 | // rationale: we used to map newlines inside <pre> to QChar::LineSeparator, but |
3195 | // if you display a lot of text inside pre it all ended up inside one single paragraph, |
3196 | // which doesn't scale very well with our text engine. Paragraphs spanning thousands of |
3197 | // lines are not a common use-case otherwise. |
3198 | |
3199 | doc->setHtml("<pre>Foo\nBar</pre>" ); |
3200 | QCOMPARE(doc->blockCount(), 2); |
3201 | QTextBlock block = doc->begin(); |
3202 | QCOMPARE(block.blockFormat().topMargin(), qreal(12)); |
3203 | QVERIFY(qIsNull(block.blockFormat().bottomMargin())); |
3204 | |
3205 | block = block.next(); |
3206 | |
3207 | QVERIFY(qIsNull(block.blockFormat().topMargin())); |
3208 | QCOMPARE(block.blockFormat().bottomMargin(), qreal(12)); |
3209 | |
3210 | doc->setHtml("<pre style=\"margin-top: 32px; margin-bottom: 45px; margin-left: 50px\">Foo\nBar</pre>" ); |
3211 | QCOMPARE(doc->blockCount(), 2); |
3212 | block = doc->begin(); |
3213 | QCOMPARE(block.blockFormat().topMargin(), qreal(32)); |
3214 | QVERIFY(qIsNull(block.blockFormat().bottomMargin())); |
3215 | QCOMPARE(block.blockFormat().leftMargin(), qreal(50)); |
3216 | |
3217 | block = block.next(); |
3218 | |
3219 | QVERIFY(qIsNull(block.blockFormat().topMargin())); |
3220 | QCOMPARE(block.blockFormat().bottomMargin(), qreal(45)); |
3221 | QCOMPARE(block.blockFormat().leftMargin(), qreal(50)); |
3222 | |
3223 | } |
3224 | |
3225 | void tst_QTextDocumentFragment::invalidColspan() |
3226 | { |
3227 | doc->setHtml("<table><tr rowspan=-1><td colspan=-1>Blah</td></tr></table>" ); |
3228 | |
3229 | cursor.movePosition(op: QTextCursor::Start); |
3230 | cursor.movePosition(op: QTextCursor::NextBlock); |
3231 | QTextTable *table = cursor.currentTable(); |
3232 | QVERIFY(table); |
3233 | QCOMPARE(table->columns(), 1); |
3234 | QCOMPARE(table->rows(), 1); |
3235 | } |
3236 | |
3237 | void tst_QTextDocumentFragment::html_brokenTableWithJustTr() |
3238 | { |
3239 | doc->setHtml("<tr><td>First Cell</td><tr><td>Second Cell" ); |
3240 | cursor.movePosition(op: QTextCursor::Start); |
3241 | cursor.movePosition(op: QTextCursor::NextBlock); |
3242 | QTextTable *table = cursor.currentTable(); |
3243 | QVERIFY(table); |
3244 | QCOMPARE(table->rows(), 2); |
3245 | QCOMPARE(table->columns(), 1); |
3246 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell" )); |
3247 | QCOMPARE(table->cellAt(1, 0).firstCursorPosition().block().text(), QString("Second Cell" )); |
3248 | |
3249 | doc->setHtml("" |
3250 | "<col width=286 style='mso-width-source:userset;mso-width-alt:10459;width:215pt'>" |
3251 | "<col width=64 span=3 style='width:48pt'>" |
3252 | "<tr height=17 style='height:12.75pt'>" |
3253 | "<td height=17 width=286 style='height:12.75pt;width:215pt'>1a</td>" |
3254 | "<td width=64 style='width:48pt'>1b</td>" |
3255 | "<td width=64 style='width:48pt'>1c</td>" |
3256 | "<td width=64 style='width:48pt'>1d</td>" |
3257 | "</tr>" |
3258 | "<tr height=17 style='height:12.75pt'>" |
3259 | "<td height=17 style='height:12.75pt'>|2a</td>" |
3260 | "<td>2b</td>" |
3261 | "<td>2c</td>" |
3262 | "<td>2d</td>" |
3263 | "</tr>" ); |
3264 | cursor.movePosition(op: QTextCursor::Start); |
3265 | cursor.movePosition(op: QTextCursor::NextBlock); |
3266 | table = cursor.currentTable(); |
3267 | QVERIFY(table); |
3268 | QCOMPARE(table->rows(), 2); |
3269 | QCOMPARE(table->columns(), 4); |
3270 | } |
3271 | |
3272 | void tst_QTextDocumentFragment::html_brokenTableWithJustTd() |
3273 | { |
3274 | doc->setHtml("<td>First Cell</td><td>Second Cell" ); |
3275 | cursor.movePosition(op: QTextCursor::Start); |
3276 | cursor.movePosition(op: QTextCursor::NextBlock); |
3277 | QTextTable *table = cursor.currentTable(); |
3278 | QVERIFY(table); |
3279 | QCOMPARE(table->rows(), 1); |
3280 | QCOMPARE(table->columns(), 2); |
3281 | QCOMPARE(table->cellAt(0, 0).firstCursorPosition().block().text(), QString("First Cell" )); |
3282 | QCOMPARE(table->cellAt(0, 1).firstCursorPosition().block().text(), QString("Second Cell" )); |
3283 | |
3284 | doc->setHtml("<td height=17 width=286 style='height:12.75pt;width:215pt'>1a</td>" |
3285 | "<td width=64 style='width:48pt'>1b</td>" |
3286 | "<td width=64 style='width:48pt'>1c</td>" |
3287 | "<td width=64 style='width:48pt'>1d</td>" ); |
3288 | cursor.movePosition(op: QTextCursor::Start); |
3289 | cursor.movePosition(op: QTextCursor::NextBlock); |
3290 | table = cursor.currentTable(); |
3291 | QVERIFY(table); |
3292 | QCOMPARE(table->rows(), 1); |
3293 | QCOMPARE(table->columns(), 4); |
3294 | } |
3295 | |
3296 | void tst_QTextDocumentFragment::html_preNewlineHandling_data() |
3297 | { |
3298 | QTest::addColumn<QString>(name: "html" ); |
3299 | QTest::addColumn<QString>(name: "expectedPlainText" ); |
3300 | |
3301 | QTest::newRow(dataTag: "pre1" ) << QString("Foo<pre>Bar" ) |
3302 | << QString("Foo\nBar" ); |
3303 | QTest::newRow(dataTag: "pre2" ) << QString("Foo<pre>\nBar" ) |
3304 | << QString("Foo\nBar" ); |
3305 | QTest::newRow(dataTag: "pre3" ) << QString("Foo<pre>\n\nBar" ) |
3306 | << QString("Foo\n\nBar" ); |
3307 | QTest::newRow(dataTag: "pre4" ) << QString("<html>Foo<pre>\nBar" ) |
3308 | << QString("Foo\nBar" ); |
3309 | QTest::newRow(dataTag: "pre5" ) << QString("<pre>Foo\n</pre>\nBar" ) |
3310 | << QString("Foo\nBar" ); |
3311 | QTest::newRow(dataTag: "pre6" ) << QString("<pre>Foo<b>Bar</b>Blah\n</pre>\nMooh" ) |
3312 | << QString("FooBarBlah\nMooh" ); |
3313 | QTest::newRow(dataTag: "pre7" ) << QString("<pre>\nPara1\n</pre>\n<pre>\nPara2\n</pre>" ) |
3314 | << QString("Para1\nPara2" ); |
3315 | } |
3316 | |
3317 | void tst_QTextDocumentFragment::html_preNewlineHandling() |
3318 | { |
3319 | QFETCH(QString, html); |
3320 | |
3321 | doc->setHtml(html); |
3322 | QTEST(doc->toPlainText(), "expectedPlainText" ); |
3323 | } |
3324 | |
3325 | void tst_QTextDocumentFragment::html_br() |
3326 | { |
3327 | doc->setHtml("Foo<br><br><br>Blah" ); |
3328 | QCOMPARE(doc->toPlainText(), QString("Foo\n\n\nBlah" )); |
3329 | } |
3330 | |
3331 | void tst_QTextDocumentFragment::html_dl() |
3332 | { |
3333 | doc->setHtml("<dl><dt>term<dd>data</dl>Text afterwards" ); |
3334 | QCOMPARE(doc->toPlainText(), QString("term\ndata\nText afterwards" )); |
3335 | } |
3336 | |
3337 | void tst_QTextDocumentFragment::html_tableStrangeNewline() |
3338 | { |
3339 | doc->setHtml("<table><tr><td>Foo</td></tr>\n</table>" ); |
3340 | cursor.movePosition(op: QTextCursor::Start); |
3341 | cursor.movePosition(op: QTextCursor::NextBlock); |
3342 | QTextTable *table = cursor.currentTable(); |
3343 | QVERIFY(table); |
3344 | QCOMPARE(table->rows(), 1); |
3345 | QCOMPARE(table->columns(), 1); |
3346 | const QTextTableCell cell = table->cellAt(row: 0, col: 0); |
3347 | QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo" )); |
3348 | QCOMPARE(cell.firstCursorPosition().block(), cell.lastCursorPosition().block()); |
3349 | } |
3350 | |
3351 | void tst_QTextDocumentFragment::html_tableStrangeNewline2() |
3352 | { |
3353 | doc->setHtml("<table><tr><td>Foo</td></tr><tr>\n<td/></tr></table>" ); |
3354 | cursor.movePosition(op: QTextCursor::Start); |
3355 | cursor.movePosition(op: QTextCursor::NextBlock); |
3356 | QTextTable *table = cursor.currentTable(); |
3357 | QVERIFY(table); |
3358 | QCOMPARE(table->rows(), 2); |
3359 | QCOMPARE(table->columns(), 1); |
3360 | const QTextTableCell cell = table->cellAt(row: 0, col: 0); |
3361 | QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo" )); |
3362 | QCOMPARE(cell.firstCursorPosition().block(), cell.lastCursorPosition().block()); |
3363 | } |
3364 | |
3365 | void tst_QTextDocumentFragment::html_tableStrangeNewline3() |
3366 | { |
3367 | doc->setHtml("<table border>" |
3368 | "<tr>" |
3369 | "<td>" |
3370 | "<ul>" |
3371 | "<li>Meh</li>" |
3372 | "</ul>" |
3373 | "</td>" |
3374 | "<td>\n" |
3375 | "<ul>" |
3376 | "<li>Foo</li>" |
3377 | "</ul>" |
3378 | "</td>" |
3379 | "</tr>" |
3380 | "</table>" ); |
3381 | |
3382 | cursor.movePosition(op: QTextCursor::Start); |
3383 | cursor.movePosition(op: QTextCursor::NextBlock); |
3384 | QTextTable *table = cursor.currentTable(); |
3385 | QVERIFY(table); |
3386 | QCOMPARE(table->rows(), 1); |
3387 | QCOMPARE(table->columns(), 2); |
3388 | |
3389 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
3390 | QCOMPARE(cell.firstCursorPosition().block().text(), QString("Meh" )); |
3391 | QCOMPARE(cell.firstCursorPosition().block(), cell.lastCursorPosition().block()); |
3392 | |
3393 | cell = table->cellAt(row: 0, col: 1); |
3394 | QCOMPARE(cell.firstCursorPosition().block().text(), QString("Foo" )); |
3395 | QCOMPARE(cell.firstCursorPosition().block(), cell.lastCursorPosition().block()); |
3396 | } |
3397 | |
3398 | void tst_QTextDocumentFragment::html_caption() |
3399 | { |
3400 | doc->setHtml("<table border align=center>" |
3401 | "<caption>This <b> is a</b> Caption!</caption>" |
3402 | "<tr><td>Blah</td></tr>" |
3403 | "</table>" ); |
3404 | |
3405 | cursor.movePosition(op: QTextCursor::Start); |
3406 | cursor.movePosition(op: QTextCursor::NextBlock); |
3407 | |
3408 | QCOMPARE(cursor.block().text(), QString("This is a Caption!" )); |
3409 | QCOMPARE(cursor.blockFormat().alignment(), Qt::AlignHCenter); |
3410 | |
3411 | cursor.movePosition(op: QTextCursor::NextBlock); |
3412 | QTextTable *table = cursor.currentTable(); |
3413 | QVERIFY(table); |
3414 | QCOMPARE(table->rows(), 1); |
3415 | QCOMPARE(table->columns(), 1); |
3416 | |
3417 | QTextTableCell cell = table->cellAt(row: 0, col: 0); |
3418 | QCOMPARE(cell.firstCursorPosition().block().text(), QString("Blah" )); |
3419 | } |
3420 | |
3421 | static const uint windowsLatin1ExtendedCharacters[0xA0 - 0x80] = { |
3422 | 0x20ac, // 0x80 |
3423 | 0x0081, // 0x81 direct mapping |
3424 | 0x201a, // 0x82 |
3425 | 0x0192, // 0x83 |
3426 | 0x201e, // 0x84 |
3427 | 0x2026, // 0x85 |
3428 | 0x2020, // 0x86 |
3429 | 0x2021, // 0x87 |
3430 | 0x02C6, // 0x88 |
3431 | 0x2030, // 0x89 |
3432 | 0x0160, // 0x8A |
3433 | 0x2039, // 0x8B |
3434 | 0x0152, // 0x8C |
3435 | 0x008D, // 0x8D direct mapping |
3436 | 0x017D, // 0x8E |
3437 | 0x008F, // 0x8F directmapping |
3438 | 0x0090, // 0x90 directmapping |
3439 | 0x2018, // 0x91 |
3440 | 0x2019, // 0x92 |
3441 | 0x201C, // 0x93 |
3442 | 0X201D, // 0x94 |
3443 | 0x2022, // 0x95 |
3444 | 0x2013, // 0x96 |
3445 | 0x2014, // 0x97 |
3446 | 0x02DC, // 0x98 |
3447 | 0x2122, // 0x99 |
3448 | 0x0161, // 0x9A |
3449 | 0x203A, // 0x9B |
3450 | 0x0153, // 0x9C |
3451 | 0x009D, // 0x9D direct mapping |
3452 | 0x017E, // 0x9E |
3453 | 0x0178 // 0x9F |
3454 | }; |
3455 | |
3456 | void tst_QTextDocumentFragment::html_windowsEntities() |
3457 | { |
3458 | for (uint i = 0; i < sizeof(windowsLatin1ExtendedCharacters)/sizeof(windowsLatin1ExtendedCharacters[0]); ++i) { |
3459 | QString html = QString::number(i + 0x80); |
3460 | html.prepend(s: "<p>&#" ); |
3461 | html.append(s: ";" ); |
3462 | doc->setHtml(html); |
3463 | QCOMPARE(doc->toPlainText(), QString(QChar(windowsLatin1ExtendedCharacters[i]))); |
3464 | } |
3465 | } |
3466 | |
3467 | void tst_QTextDocumentFragment::html_eatenText() |
3468 | { |
3469 | doc->setHtml("<h1>Test1</h1>\nTest2<h1>Test3</h1>" ); |
3470 | cursor.movePosition(op: QTextCursor::Start); |
3471 | QCOMPARE(cursor.block().text(), QString("Test1" )); |
3472 | cursor.movePosition(op: QTextCursor::NextBlock); |
3473 | QCOMPARE(cursor.block().text(), QString("Test2" )); |
3474 | cursor.movePosition(op: QTextCursor::NextBlock); |
3475 | QCOMPARE(cursor.block().text(), QString("Test3" )); |
3476 | } |
3477 | |
3478 | void tst_QTextDocumentFragment::html_hr() |
3479 | { |
3480 | doc->setHtml("<hr />" ); |
3481 | QCOMPARE(doc->blockCount(), 1); |
3482 | QVERIFY(doc->begin().blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)); |
3483 | } |
3484 | |
3485 | void tst_QTextDocumentFragment::html_hrMargins() |
3486 | { |
3487 | doc->setHtml("<p>Test<hr/>Blah" ); |
3488 | QCOMPARE(doc->blockCount(), 3); |
3489 | |
3490 | cursor.movePosition(op: QTextCursor::Start); |
3491 | QTextBlock block = cursor.block(); |
3492 | QCOMPARE(block.text(), QString("Test" )); |
3493 | QVERIFY(block.blockFormat().bottomMargin() <= qreal(12.)); |
3494 | QTextBlock first = block; |
3495 | |
3496 | cursor.movePosition(op: QTextCursor::NextBlock); |
3497 | block = cursor.block(); |
3498 | QVERIFY(qMax(first.blockFormat().bottomMargin(), block.blockFormat().topMargin()) > 0); |
3499 | |
3500 | cursor.movePosition(op: QTextCursor::NextBlock); |
3501 | block = cursor.block(); |
3502 | |
3503 | QCOMPARE(block.text(), QString("Blah" )); |
3504 | } |
3505 | |
3506 | void tst_QTextDocumentFragment::html_blockQuoteMargins() |
3507 | { |
3508 | doc->setHtml("<blockquote>Bar</blockquote>" ); |
3509 | QCOMPARE(doc->blockCount(), 1); |
3510 | cursor.movePosition(op: QTextCursor::Start); |
3511 | QTextBlock block = cursor.block(); |
3512 | QCOMPARE(block.text(), QString("Bar" )); |
3513 | QCOMPARE(block.blockFormat().leftMargin(), qreal(40.)); |
3514 | QCOMPARE(block.blockFormat().rightMargin(), qreal(40.)); |
3515 | QCOMPARE(block.blockFormat().topMargin(), qreal(12.)); |
3516 | QCOMPARE(block.blockFormat().bottomMargin(), qreal(12.)); |
3517 | } |
3518 | |
3519 | void tst_QTextDocumentFragment::html_definitionListMargins() |
3520 | { |
3521 | doc->setHtml("Foo<dl><dt>tag<dd>data</dl>Bar" ); |
3522 | QCOMPARE(doc->blockCount(), 4); |
3523 | |
3524 | cursor.movePosition(op: QTextCursor::Start); |
3525 | QTextBlock block = cursor.block(); |
3526 | QCOMPARE(block.text(), QString("Foo" )); |
3527 | |
3528 | block = block.next(); |
3529 | QCOMPARE(block.text(), QString("tag" )); |
3530 | QCOMPARE(block.blockFormat().topMargin(), qreal(8.)); |
3531 | |
3532 | block = block.next(); |
3533 | QCOMPARE(block.text(), QString("data" )); |
3534 | QCOMPARE(block.blockFormat().bottomMargin(), qreal(8.)); |
3535 | |
3536 | block = block.next(); |
3537 | QCOMPARE(block.text(), QString("Bar" )); |
3538 | } |
3539 | |
3540 | void tst_QTextDocumentFragment::html_listMargins() |
3541 | { |
3542 | doc->setHtml("Foo<ol><li>First<li>Second</ol>Bar" ); |
3543 | QCOMPARE(doc->blockCount(), 4); |
3544 | |
3545 | cursor.movePosition(op: QTextCursor::Start); |
3546 | QTextBlock block = cursor.block(); |
3547 | QCOMPARE(block.text(), QString("Foo" )); |
3548 | |
3549 | block = block.next(); |
3550 | QCOMPARE(block.text(), QString("First" )); |
3551 | QCOMPARE(block.blockFormat().topMargin(), qreal(12.)); |
3552 | |
3553 | block = block.next(); |
3554 | QCOMPARE(block.text(), QString("Second" )); |
3555 | QCOMPARE(block.blockFormat().bottomMargin(), qreal(12.)); |
3556 | |
3557 | block = block.next(); |
3558 | QCOMPARE(block.text(), QString("Bar" )); |
3559 | } |
3560 | |
3561 | void tst_QTextDocumentFragment::html_titleAttribute() |
3562 | { |
3563 | doc->setHtml("<span title=\"this is my title\">Test</span>" ); |
3564 | cursor.movePosition(op: QTextCursor::Start); |
3565 | cursor.movePosition(op: QTextCursor::NextCharacter); |
3566 | QCOMPARE(cursor.charFormat().toolTip(), QString("this is my title" )); |
3567 | } |
3568 | |
3569 | void tst_QTextDocumentFragment::html_compressDivs() |
3570 | { |
3571 | doc->setHtml("<p/><div/><div/><div/><div/>Test" ); |
3572 | QCOMPARE(doc->blockCount(), 1); |
3573 | QCOMPARE(doc->begin().text(), QString("Test" )); |
3574 | } |
3575 | |
3576 | void tst_QTextDocumentFragment::completeToPlainText() |
3577 | { |
3578 | doc->setPlainText("Hello\nWorld" ); |
3579 | QCOMPARE(doc->toPlainText(), QString("Hello\nWorld" )); |
3580 | QTextDocumentFragment fragment(doc); |
3581 | QCOMPARE(fragment.toPlainText(), QString("Hello\nWorld" )); |
3582 | } |
3583 | |
3584 | void tst_QTextDocumentFragment::copyContents() |
3585 | { |
3586 | doc->setPlainText("Hello" ); |
3587 | QFont f; |
3588 | doc->setDefaultFont(f); |
3589 | QTextFragment fragment = doc->begin().begin().fragment(); |
3590 | QCOMPARE(fragment.text(), QString("Hello" )); |
3591 | QCOMPARE(fragment.charFormat().font().pointSize(), f.pointSize()); |
3592 | |
3593 | QTextDocumentFragment frag(doc); |
3594 | doc->clear(); |
3595 | f.setPointSize(48); |
3596 | doc->setDefaultFont(f); |
3597 | QTextCursor(doc).insertFragment(fragment: QTextDocumentFragment::fromHtml(html: frag.toHtml())); |
3598 | fragment = doc->begin().begin().fragment(); |
3599 | QCOMPARE(fragment.text(), QString("Hello" )); |
3600 | QCOMPARE(fragment.charFormat().font().pointSize(), f.pointSize()); |
3601 | } |
3602 | |
3603 | void tst_QTextDocumentFragment::html_textAfterHr() |
3604 | { |
3605 | doc->setHtml("<hr><nobr><b>After the centered text</b></nobr>" ); |
3606 | QCOMPARE(doc->blockCount(), 2); |
3607 | QTextBlock block = doc->begin(); |
3608 | QVERIFY(block.text().isEmpty()); |
3609 | QVERIFY(block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)); |
3610 | block = block.next(); |
3611 | |
3612 | QString txt("After the centered text" ); |
3613 | txt.replace(before: QLatin1Char(' '), after: QChar::Nbsp); |
3614 | QCOMPARE(block.text(), txt); |
3615 | QVERIFY(!block.blockFormat().hasProperty(QTextFormat::BlockTrailingHorizontalRulerWidth)); |
3616 | } |
3617 | |
3618 | void tst_QTextDocumentFragment::blockTagClosing() |
3619 | { |
3620 | doc->setHtml("<p>foo<p>bar<span>baz</span>" ); |
3621 | QCOMPARE(doc->blockCount(), 2); |
3622 | QTextBlock block = doc->begin(); |
3623 | QCOMPARE(block.text(), QString("foo" )); |
3624 | block = block.next(); |
3625 | QCOMPARE(block.text(), QString("barbaz" )); |
3626 | } |
3627 | |
3628 | void tst_QTextDocumentFragment::isEmpty() |
3629 | { |
3630 | QTextDocumentFragment frag; |
3631 | QVERIFY(frag.isEmpty()); |
3632 | frag = QTextDocumentFragment::fromHtml(html: "test" ); |
3633 | QVERIFY(!frag.isEmpty()); |
3634 | frag = QTextDocumentFragment::fromHtml(html: "<hr />" ); |
3635 | QVERIFY(!frag.isEmpty()); |
3636 | } |
3637 | |
3638 | void tst_QTextDocumentFragment::html_alignmentInheritance() |
3639 | { |
3640 | doc->setHtml("<center>Centered text<hr></center><b>After the centered text</b>" ); |
3641 | QCOMPARE(doc->blockCount(), 3); |
3642 | QTextBlock block = doc->begin(); |
3643 | QVERIFY(block.blockFormat().alignment() & Qt::AlignHCenter); |
3644 | block = block.next(); |
3645 | QVERIFY(block.blockFormat().alignment() & Qt::AlignHCenter); |
3646 | block = block.next(); |
3647 | QVERIFY(!(block.blockFormat().alignment() & Qt::AlignHCenter)); |
3648 | } |
3649 | |
3650 | void tst_QTextDocumentFragment::html_ignoreEmptyDivs() |
3651 | { |
3652 | doc->setHtml("<p><div/><b>Foo</b>" ); |
3653 | QCOMPARE(doc->blockCount(), 1); |
3654 | QCOMPARE(doc->begin().text(), QString("Foo" )); |
3655 | } |
3656 | |
3657 | void tst_QTextDocumentFragment::html_dontInheritAlignmentForFloatingImages() |
3658 | { |
3659 | doc->setHtml("<p align=right><img align=unknownignored src=\"foo\" /></p>" ); |
3660 | QTextCharFormat fmt = doc->begin().begin().fragment().charFormat(); |
3661 | QVERIFY(fmt.isImageFormat()); |
3662 | QTextObject *o = doc->objectForFormat(fmt); |
3663 | QVERIFY(o); |
3664 | QTextFormat f = o->format(); |
3665 | QVERIFY(f.isFrameFormat()); |
3666 | QCOMPARE(f.toFrameFormat().position(), QTextFrameFormat::InFlow); |
3667 | } |
3668 | |
3669 | void tst_QTextDocumentFragment::html_verticalImageAlignment() |
3670 | { |
3671 | doc->setHtml("<img src=\"foo\"/>" ); |
3672 | cursor.movePosition(op: QTextCursor::Start); |
3673 | cursor.movePosition(op: QTextCursor::NextCharacter); |
3674 | QVERIFY(cursor.charFormat().isImageFormat()); |
3675 | QTextImageFormat fmt = cursor.charFormat().toImageFormat(); |
3676 | QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignNormal); |
3677 | |
3678 | doc->setHtml("<img src=\"foo\" align=middle />" ); |
3679 | cursor.movePosition(op: QTextCursor::Start); |
3680 | cursor.movePosition(op: QTextCursor::NextCharacter); |
3681 | QVERIFY(cursor.charFormat().isImageFormat()); |
3682 | fmt = cursor.charFormat().toImageFormat(); |
3683 | QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignMiddle); |
3684 | |
3685 | doc->setHtml("<img src=\"foo\" style=\"vertical-align: middle\" />" ); |
3686 | cursor.movePosition(op: QTextCursor::Start); |
3687 | cursor.movePosition(op: QTextCursor::NextCharacter); |
3688 | QVERIFY(cursor.charFormat().isImageFormat()); |
3689 | fmt = cursor.charFormat().toImageFormat(); |
3690 | QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignMiddle); |
3691 | |
3692 | doc->setHtml("<img src=\"foo\" align=top />" ); |
3693 | cursor.movePosition(op: QTextCursor::Start); |
3694 | cursor.movePosition(op: QTextCursor::NextCharacter); |
3695 | QVERIFY(cursor.charFormat().isImageFormat()); |
3696 | fmt = cursor.charFormat().toImageFormat(); |
3697 | QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignTop); |
3698 | |
3699 | doc->setHtml("<img src=\"foo\" style=\"vertical-align: top\" />" ); |
3700 | cursor.movePosition(op: QTextCursor::Start); |
3701 | cursor.movePosition(op: QTextCursor::NextCharacter); |
3702 | QVERIFY(cursor.charFormat().isImageFormat()); |
3703 | fmt = cursor.charFormat().toImageFormat(); |
3704 | QCOMPARE(fmt.verticalAlignment(), QTextCharFormat::AlignTop); |
3705 | } |
3706 | |
3707 | void tst_QTextDocumentFragment::html_verticalCellAlignment() |
3708 | { |
3709 | const char *alt[] = |
3710 | { |
3711 | // vertical-align property |
3712 | "<table>" |
3713 | "<tr>" |
3714 | "<td style=\"vertical-align: middle\"></td>" |
3715 | "<td style=\"vertical-align: top\"></td>" |
3716 | "<td style=\"vertical-align: bottom\"></td>" |
3717 | "</tr>" |
3718 | "</table>" , |
3719 | // valign property |
3720 | "<table>" |
3721 | "<tr>" |
3722 | "<td valign=\"middle\"></td>" |
3723 | "<td valign=\"top\"></td>" |
3724 | "<td valign=\"bottom\"></td>" |
3725 | "</tr>" |
3726 | "</table>" , |
3727 | // test td override of tr property |
3728 | "<table>" |
3729 | "<tr valign=\"bottom\">" |
3730 | "<td valign=\"middle\"></td>" |
3731 | "<td valign=\"top\"></td>" |
3732 | "<td></td>" |
3733 | "</tr>" |
3734 | "</table>" |
3735 | }; |
3736 | |
3737 | const int numTestCases = sizeof(alt) / sizeof(*alt); |
3738 | for (int i = 0; i < numTestCases; ++i) { |
3739 | doc->setHtml(alt[i]); |
3740 | |
3741 | QTextTable *table = qobject_cast<QTextTable *>(object: doc->rootFrame()->childFrames().at(i: 0)); |
3742 | QVERIFY(table); |
3743 | |
3744 | QCOMPARE(table->cellAt(0, 0).format().verticalAlignment(), QTextCharFormat::AlignMiddle); |
3745 | QCOMPARE(table->cellAt(0, 1).format().verticalAlignment(), QTextCharFormat::AlignTop); |
3746 | QCOMPARE(table->cellAt(0, 2).format().verticalAlignment(), QTextCharFormat::AlignBottom); |
3747 | } |
3748 | } |
3749 | |
3750 | void tst_QTextDocumentFragment::html_borderColor() |
3751 | { |
3752 | const char html[] = "<table border=1 style=\"border-color:#0000ff;\"><tr><td>Foo</td></tr></table>" ; |
3753 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
3754 | cursor.movePosition(op: QTextCursor::Start); |
3755 | cursor.movePosition(op: QTextCursor::NextBlock); |
3756 | QVERIFY(cursor.currentTable()); |
3757 | QCOMPARE(cursor.currentTable()->format().borderStyle(), QTextFrameFormat::BorderStyle_Outset); |
3758 | QCOMPARE(cursor.currentTable()->format().borderBrush(), QBrush(QColor("#0000ff" ))); |
3759 | } |
3760 | |
3761 | void tst_QTextDocumentFragment::html_borderStyle() |
3762 | { |
3763 | const char html[] = "<table border=1 style=\"border-style:solid;\"><tr><td>Foo</td></tr></table>" ; |
3764 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
3765 | cursor.movePosition(op: QTextCursor::Start); |
3766 | cursor.movePosition(op: QTextCursor::NextBlock); |
3767 | QVERIFY(cursor.currentTable()); |
3768 | QCOMPARE(cursor.currentTable()->format().borderStyle(), QTextFrameFormat::BorderStyle_Solid); |
3769 | QCOMPARE(cursor.currentTable()->format().borderBrush(), QBrush(Qt::darkGray)); |
3770 | } |
3771 | |
3772 | void tst_QTextDocumentFragment::html_borderWidth() |
3773 | { |
3774 | const char *html[2] = { "<table style=\"border-width:2;\"><tr><td>Foo</td></tr></table>" , |
3775 | "<table style=\"border-width:2px;\"><tr><td>Foo</td></tr></table>" }; |
3776 | |
3777 | for (int i = 0; i < 2; ++i) { |
3778 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html[i]))); |
3779 | cursor.movePosition(op: QTextCursor::Start); |
3780 | cursor.movePosition(op: QTextCursor::NextBlock); |
3781 | QVERIFY(cursor.currentTable()); |
3782 | QCOMPARE(cursor.currentTable()->format().border(), qreal(2)); |
3783 | } |
3784 | } |
3785 | |
3786 | void tst_QTextDocumentFragment::html_userState() |
3787 | { |
3788 | const char html[] = "<p style=\"-qt-user-state:42;\">A</p><p style=\"-qt-user-state:0;\">B</p><p>C</p>" ; |
3789 | cursor.insertFragment(fragment: QTextDocumentFragment::fromHtml(html: QString::fromLatin1(str: html))); |
3790 | QTextBlock block = doc->begin(); |
3791 | QCOMPARE(block.userState(), 42); |
3792 | QCOMPARE(block.next().userState(), 0); |
3793 | QCOMPARE(block.next().next().userState(), -1); |
3794 | } |
3795 | |
3796 | void tst_QTextDocumentFragment::html_rootFrameProperties() |
3797 | { |
3798 | const char html[] = "<table border=1 style=\"-qt-table-type:root; margin-top:10px;\"><tr><td>Foo</tr></td>" ; |
3799 | doc->setHtml(html); |
3800 | |
3801 | QCOMPARE(doc->rootFrame()->childFrames().size(), 0); |
3802 | |
3803 | QTextFrameFormat fmt = doc->rootFrame()->frameFormat(); |
3804 | QCOMPARE(fmt.topMargin(), qreal(10)); |
3805 | QCOMPARE(fmt.bottomMargin(), qreal(0)); |
3806 | QCOMPARE(fmt.leftMargin(), qreal(0)); |
3807 | QCOMPARE(fmt.rightMargin(), qreal(0)); |
3808 | QCOMPARE(fmt.border(), qreal(1)); |
3809 | |
3810 | QString normalFrameHtml = QLatin1String(html); |
3811 | normalFrameHtml.replace(before: QLatin1String("root" ), after: QLatin1String("frame" )); |
3812 | |
3813 | doc->setHtml(normalFrameHtml); |
3814 | QCOMPARE(doc->rootFrame()->childFrames().size(), 1); |
3815 | } |
3816 | |
3817 | void tst_QTextDocumentFragment::html_appendList() |
3818 | { |
3819 | appendHtml(html: "<p>foo</p>" ); |
3820 | appendHtml(html: "<ul><li>Line 1</li><li>Line 2</li></ul>" ); |
3821 | |
3822 | QCOMPARE(doc->blockCount(), 3); |
3823 | QVERIFY(doc->begin().next().textList() != 0); |
3824 | } |
3825 | |
3826 | void tst_QTextDocumentFragment::html_appendList2() |
3827 | { |
3828 | appendHtml(html: "1" ); |
3829 | appendHtml(html: "<ul><li><img src=\"/foo/bar\" /></li></ul>" ); |
3830 | |
3831 | QCOMPARE(doc->blockCount(), 2); |
3832 | QVERIFY(doc->begin().next().textList() != 0); |
3833 | } |
3834 | |
3835 | void tst_QTextDocumentFragment::html_alignmentPropertySet() |
3836 | { |
3837 | const char html[] = "<p>Test</p>" ; |
3838 | setHtml(QString::fromLatin1(str: html)); |
3839 | QVERIFY(!doc->begin().blockFormat().hasProperty(QTextFormat::BlockAlignment)); |
3840 | } |
3841 | |
3842 | void tst_QTextDocumentFragment::html_qt3RichtextWhitespaceMode() |
3843 | { |
3844 | setHtml(QString::fromLatin1(str: "<html><head><meta name=\"qrichtext\" content=\"1\" /></head><p> line with whitespace</p><p> another line with whitespace</p></body></html>" )); |
3845 | QCOMPARE(doc->blockCount(), 2); |
3846 | |
3847 | QTextBlock block = doc->begin(); |
3848 | QVERIFY(block.text().startsWith(" " )); |
3849 | |
3850 | block = block.next(); |
3851 | QVERIFY(block.text().startsWith(" " )); |
3852 | } |
3853 | |
3854 | void tst_QTextDocumentFragment::html_brAfterHr() |
3855 | { |
3856 | setHtml(QString::fromLatin1(str: "Text A<br><hr><br>Text B<hr>" )); |
3857 | |
3858 | QCOMPARE(doc->blockCount(), 4); |
3859 | |
3860 | QTextBlock block = doc->begin(); |
3861 | QCOMPARE(block.text(), QString("Text A" ) + QChar(QChar::LineSeparator)); |
3862 | |
3863 | block = block.next(); |
3864 | QVERIFY(block.text().isEmpty()); |
3865 | |
3866 | block = block.next(); |
3867 | QCOMPARE(block.text(), QChar(QChar::LineSeparator) + QString("Text B" )); |
3868 | |
3869 | block = block.next(); |
3870 | QVERIFY(block.text().isEmpty()); |
3871 | } |
3872 | |
3873 | void tst_QTextDocumentFragment::html_unclosedHead() |
3874 | { |
3875 | doc->setHtml(QString::fromLatin1(str: "<html><head><title>Test</title><body>Blah</body></html>" )); |
3876 | QCOMPARE(doc->metaInformation(QTextDocument::DocumentTitle), QString::fromLatin1("Test" )); |
3877 | QCOMPARE(doc->toPlainText(), QString::fromLatin1("Blah" )); |
3878 | } |
3879 | |
3880 | // duplicated from qtexthtmlparser.cpp |
3881 | #define MAX_ENTITY 258 |
3882 | static const struct { const char *name; quint16 code; } entities[MAX_ENTITY]= { |
3883 | { .name: "AElig" , .code: 0x00c6 }, |
3884 | { .name: "Aacute" , .code: 0x00c1 }, |
3885 | { .name: "Acirc" , .code: 0x00c2 }, |
3886 | { .name: "Agrave" , .code: 0x00c0 }, |
3887 | { .name: "Alpha" , .code: 0x0391 }, |
3888 | { .name: "AMP" , .code: 38 }, |
3889 | { .name: "Aring" , .code: 0x00c5 }, |
3890 | { .name: "Atilde" , .code: 0x00c3 }, |
3891 | { .name: "Auml" , .code: 0x00c4 }, |
3892 | { .name: "Beta" , .code: 0x0392 }, |
3893 | { .name: "Ccedil" , .code: 0x00c7 }, |
3894 | { .name: "Chi" , .code: 0x03a7 }, |
3895 | { .name: "Dagger" , .code: 0x2021 }, |
3896 | { .name: "Delta" , .code: 0x0394 }, |
3897 | { .name: "ETH" , .code: 0x00d0 }, |
3898 | { .name: "Eacute" , .code: 0x00c9 }, |
3899 | { .name: "Ecirc" , .code: 0x00ca }, |
3900 | { .name: "Egrave" , .code: 0x00c8 }, |
3901 | { .name: "Epsilon" , .code: 0x0395 }, |
3902 | { .name: "Eta" , .code: 0x0397 }, |
3903 | { .name: "Euml" , .code: 0x00cb }, |
3904 | { .name: "Gamma" , .code: 0x0393 }, |
3905 | { .name: "GT" , .code: 62 }, |
3906 | { .name: "Iacute" , .code: 0x00cd }, |
3907 | { .name: "Icirc" , .code: 0x00ce }, |
3908 | { .name: "Igrave" , .code: 0x00cc }, |
3909 | { .name: "Iota" , .code: 0x0399 }, |
3910 | { .name: "Iuml" , .code: 0x00cf }, |
3911 | { .name: "Kappa" , .code: 0x039a }, |
3912 | { .name: "Lambda" , .code: 0x039b }, |
3913 | { .name: "LT" , .code: 60 }, |
3914 | { .name: "Mu" , .code: 0x039c }, |
3915 | { .name: "Ntilde" , .code: 0x00d1 }, |
3916 | { .name: "Nu" , .code: 0x039d }, |
3917 | { .name: "OElig" , .code: 0x0152 }, |
3918 | { .name: "Oacute" , .code: 0x00d3 }, |
3919 | { .name: "Ocirc" , .code: 0x00d4 }, |
3920 | { .name: "Ograve" , .code: 0x00d2 }, |
3921 | { .name: "Omega" , .code: 0x03a9 }, |
3922 | { .name: "Omicron" , .code: 0x039f }, |
3923 | { .name: "Oslash" , .code: 0x00d8 }, |
3924 | { .name: "Otilde" , .code: 0x00d5 }, |
3925 | { .name: "Ouml" , .code: 0x00d6 }, |
3926 | { .name: "Phi" , .code: 0x03a6 }, |
3927 | { .name: "Pi" , .code: 0x03a0 }, |
3928 | { .name: "Prime" , .code: 0x2033 }, |
3929 | { .name: "Psi" , .code: 0x03a8 }, |
3930 | { .name: "QUOT" , .code: 34 }, |
3931 | { .name: "Rho" , .code: 0x03a1 }, |
3932 | { .name: "Scaron" , .code: 0x0160 }, |
3933 | { .name: "Sigma" , .code: 0x03a3 }, |
3934 | { .name: "THORN" , .code: 0x00de }, |
3935 | { .name: "Tau" , .code: 0x03a4 }, |
3936 | { .name: "Theta" , .code: 0x0398 }, |
3937 | { .name: "Uacute" , .code: 0x00da }, |
3938 | { .name: "Ucirc" , .code: 0x00db }, |
3939 | { .name: "Ugrave" , .code: 0x00d9 }, |
3940 | { .name: "Upsilon" , .code: 0x03a5 }, |
3941 | { .name: "Uuml" , .code: 0x00dc }, |
3942 | { .name: "Xi" , .code: 0x039e }, |
3943 | { .name: "Yacute" , .code: 0x00dd }, |
3944 | { .name: "Yuml" , .code: 0x0178 }, |
3945 | { .name: "Zeta" , .code: 0x0396 }, |
3946 | { .name: "aacute" , .code: 0x00e1 }, |
3947 | { .name: "acirc" , .code: 0x00e2 }, |
3948 | { .name: "acute" , .code: 0x00b4 }, |
3949 | { .name: "aelig" , .code: 0x00e6 }, |
3950 | { .name: "agrave" , .code: 0x00e0 }, |
3951 | { .name: "alefsym" , .code: 0x2135 }, |
3952 | { .name: "alpha" , .code: 0x03b1 }, |
3953 | { .name: "amp" , .code: 38 }, |
3954 | { .name: "and" , .code: 0x22a5 }, |
3955 | { .name: "ang" , .code: 0x2220 }, |
3956 | { .name: "apos" , .code: 0x0027 }, |
3957 | { .name: "aring" , .code: 0x00e5 }, |
3958 | { .name: "asymp" , .code: 0x2248 }, |
3959 | { .name: "atilde" , .code: 0x00e3 }, |
3960 | { .name: "auml" , .code: 0x00e4 }, |
3961 | { .name: "bdquo" , .code: 0x201e }, |
3962 | { .name: "beta" , .code: 0x03b2 }, |
3963 | { .name: "brvbar" , .code: 0x00a6 }, |
3964 | { .name: "bull" , .code: 0x2022 }, |
3965 | { .name: "cap" , .code: 0x2229 }, |
3966 | { .name: "ccedil" , .code: 0x00e7 }, |
3967 | { .name: "cedil" , .code: 0x00b8 }, |
3968 | { .name: "cent" , .code: 0x00a2 }, |
3969 | { .name: "chi" , .code: 0x03c7 }, |
3970 | { .name: "circ" , .code: 0x02c6 }, |
3971 | { .name: "clubs" , .code: 0x2663 }, |
3972 | { .name: "cong" , .code: 0x2245 }, |
3973 | { .name: "copy" , .code: 0x00a9 }, |
3974 | { .name: "crarr" , .code: 0x21b5 }, |
3975 | { .name: "cup" , .code: 0x222a }, |
3976 | { .name: "curren" , .code: 0x00a4 }, |
3977 | { .name: "dArr" , .code: 0x21d3 }, |
3978 | { .name: "dagger" , .code: 0x2020 }, |
3979 | { .name: "darr" , .code: 0x2193 }, |
3980 | { .name: "deg" , .code: 0x00b0 }, |
3981 | { .name: "delta" , .code: 0x03b4 }, |
3982 | { .name: "diams" , .code: 0x2666 }, |
3983 | { .name: "divide" , .code: 0x00f7 }, |
3984 | { .name: "eacute" , .code: 0x00e9 }, |
3985 | { .name: "ecirc" , .code: 0x00ea }, |
3986 | { .name: "egrave" , .code: 0x00e8 }, |
3987 | { .name: "empty" , .code: 0x2205 }, |
3988 | { .name: "emsp" , .code: 0x2003 }, |
3989 | { .name: "ensp" , .code: 0x2002 }, |
3990 | { .name: "epsilon" , .code: 0x03b5 }, |
3991 | { .name: "equiv" , .code: 0x2261 }, |
3992 | { .name: "eta" , .code: 0x03b7 }, |
3993 | { .name: "eth" , .code: 0x00f0 }, |
3994 | { .name: "euml" , .code: 0x00eb }, |
3995 | { .name: "euro" , .code: 0x20ac }, |
3996 | { .name: "exist" , .code: 0x2203 }, |
3997 | { .name: "fnof" , .code: 0x0192 }, |
3998 | { .name: "forall" , .code: 0x2200 }, |
3999 | { .name: "frac12" , .code: 0x00bd }, |
4000 | { .name: "frac14" , .code: 0x00bc }, |
4001 | { .name: "frac34" , .code: 0x00be }, |
4002 | { .name: "frasl" , .code: 0x2044 }, |
4003 | { .name: "gamma" , .code: 0x03b3 }, |
4004 | { .name: "ge" , .code: 0x2265 }, |
4005 | { .name: "gt" , .code: 62 }, |
4006 | { .name: "hArr" , .code: 0x21d4 }, |
4007 | { .name: "harr" , .code: 0x2194 }, |
4008 | { .name: "hearts" , .code: 0x2665 }, |
4009 | { .name: "hellip" , .code: 0x2026 }, |
4010 | { .name: "iacute" , .code: 0x00ed }, |
4011 | { .name: "icirc" , .code: 0x00ee }, |
4012 | { .name: "iexcl" , .code: 0x00a1 }, |
4013 | { .name: "igrave" , .code: 0x00ec }, |
4014 | { .name: "image" , .code: 0x2111 }, |
4015 | { .name: "infin" , .code: 0x221e }, |
4016 | { .name: "int" , .code: 0x222b }, |
4017 | { .name: "iota" , .code: 0x03b9 }, |
4018 | { .name: "iquest" , .code: 0x00bf }, |
4019 | { .name: "isin" , .code: 0x2208 }, |
4020 | { .name: "iuml" , .code: 0x00ef }, |
4021 | { .name: "kappa" , .code: 0x03ba }, |
4022 | { .name: "lArr" , .code: 0x21d0 }, |
4023 | { .name: "lambda" , .code: 0x03bb }, |
4024 | { .name: "lang" , .code: 0x2329 }, |
4025 | { .name: "laquo" , .code: 0x00ab }, |
4026 | { .name: "larr" , .code: 0x2190 }, |
4027 | { .name: "lceil" , .code: 0x2308 }, |
4028 | { .name: "ldquo" , .code: 0x201c }, |
4029 | { .name: "le" , .code: 0x2264 }, |
4030 | { .name: "lfloor" , .code: 0x230a }, |
4031 | { .name: "lowast" , .code: 0x2217 }, |
4032 | { .name: "loz" , .code: 0x25ca }, |
4033 | { .name: "lrm" , .code: 0x200e }, |
4034 | { .name: "lsaquo" , .code: 0x2039 }, |
4035 | { .name: "lsquo" , .code: 0x2018 }, |
4036 | { .name: "lt" , .code: 60 }, |
4037 | { .name: "macr" , .code: 0x00af }, |
4038 | { .name: "mdash" , .code: 0x2014 }, |
4039 | { .name: "micro" , .code: 0x00b5 }, |
4040 | { .name: "middot" , .code: 0x00b7 }, |
4041 | { .name: "minus" , .code: 0x2212 }, |
4042 | { .name: "mu" , .code: 0x03bc }, |
4043 | { .name: "nabla" , .code: 0x2207 }, |
4044 | { .name: "nbsp" , .code: 0x00a0 }, |
4045 | { .name: "ndash" , .code: 0x2013 }, |
4046 | { .name: "ne" , .code: 0x2260 }, |
4047 | { .name: "ni" , .code: 0x220b }, |
4048 | { .name: "not" , .code: 0x00ac }, |
4049 | { .name: "notin" , .code: 0x2209 }, |
4050 | { .name: "nsub" , .code: 0x2284 }, |
4051 | { .name: "ntilde" , .code: 0x00f1 }, |
4052 | { .name: "nu" , .code: 0x03bd }, |
4053 | { .name: "oacute" , .code: 0x00f3 }, |
4054 | { .name: "ocirc" , .code: 0x00f4 }, |
4055 | { .name: "oelig" , .code: 0x0153 }, |
4056 | { .name: "ograve" , .code: 0x00f2 }, |
4057 | { .name: "oline" , .code: 0x203e }, |
4058 | { .name: "omega" , .code: 0x03c9 }, |
4059 | { .name: "omicron" , .code: 0x03bf }, |
4060 | { .name: "oplus" , .code: 0x2295 }, |
4061 | { .name: "or" , .code: 0x22a6 }, |
4062 | { .name: "ordf" , .code: 0x00aa }, |
4063 | { .name: "ordm" , .code: 0x00ba }, |
4064 | { .name: "oslash" , .code: 0x00f8 }, |
4065 | { .name: "otilde" , .code: 0x00f5 }, |
4066 | { .name: "otimes" , .code: 0x2297 }, |
4067 | { .name: "ouml" , .code: 0x00f6 }, |
4068 | { .name: "para" , .code: 0x00b6 }, |
4069 | { .name: "part" , .code: 0x2202 }, |
4070 | { .name: "percnt" , .code: 0x0025 }, |
4071 | { .name: "permil" , .code: 0x2030 }, |
4072 | { .name: "perp" , .code: 0x22a5 }, |
4073 | { .name: "phi" , .code: 0x03c6 }, |
4074 | { .name: "pi" , .code: 0x03c0 }, |
4075 | { .name: "piv" , .code: 0x03d6 }, |
4076 | { .name: "plusmn" , .code: 0x00b1 }, |
4077 | { .name: "pound" , .code: 0x00a3 }, |
4078 | { .name: "prime" , .code: 0x2032 }, |
4079 | { .name: "prod" , .code: 0x220f }, |
4080 | { .name: "prop" , .code: 0x221d }, |
4081 | { .name: "psi" , .code: 0x03c8 }, |
4082 | { .name: "quot" , .code: 34 }, |
4083 | { .name: "rArr" , .code: 0x21d2 }, |
4084 | { .name: "radic" , .code: 0x221a }, |
4085 | { .name: "rang" , .code: 0x232a }, |
4086 | { .name: "raquo" , .code: 0x00bb }, |
4087 | { .name: "rarr" , .code: 0x2192 }, |
4088 | { .name: "rceil" , .code: 0x2309 }, |
4089 | { .name: "rdquo" , .code: 0x201d }, |
4090 | { .name: "real" , .code: 0x211c }, |
4091 | { .name: "reg" , .code: 0x00ae }, |
4092 | { .name: "rfloor" , .code: 0x230b }, |
4093 | { .name: "rho" , .code: 0x03c1 }, |
4094 | { .name: "rlm" , .code: 0x200f }, |
4095 | { .name: "rsaquo" , .code: 0x203a }, |
4096 | { .name: "rsquo" , .code: 0x2019 }, |
4097 | { .name: "sbquo" , .code: 0x201a }, |
4098 | { .name: "scaron" , .code: 0x0161 }, |
4099 | { .name: "sdot" , .code: 0x22c5 }, |
4100 | { .name: "sect" , .code: 0x00a7 }, |
4101 | { .name: "shy" , .code: 0x00ad }, |
4102 | { .name: "sigma" , .code: 0x03c3 }, |
4103 | { .name: "sigmaf" , .code: 0x03c2 }, |
4104 | { .name: "sim" , .code: 0x223c }, |
4105 | { .name: "spades" , .code: 0x2660 }, |
4106 | { .name: "sub" , .code: 0x2282 }, |
4107 | { .name: "sube" , .code: 0x2286 }, |
4108 | { .name: "sum" , .code: 0x2211 }, |
4109 | { .name: "sup1" , .code: 0x00b9 }, |
4110 | { .name: "sup2" , .code: 0x00b2 }, |
4111 | { .name: "sup3" , .code: 0x00b3 }, |
4112 | { .name: "sup" , .code: 0x2283 }, |
4113 | { .name: "supe" , .code: 0x2287 }, |
4114 | { .name: "szlig" , .code: 0x00df }, |
4115 | { .name: "tau" , .code: 0x03c4 }, |
4116 | { .name: "there4" , .code: 0x2234 }, |
4117 | { .name: "theta" , .code: 0x03b8 }, |
4118 | { .name: "thetasym" , .code: 0x03d1 }, |
4119 | { .name: "thinsp" , .code: 0x2009 }, |
4120 | { .name: "thorn" , .code: 0x00fe }, |
4121 | { .name: "tilde" , .code: 0x02dc }, |
4122 | { .name: "times" , .code: 0x00d7 }, |
4123 | { .name: "trade" , .code: 0x2122 }, |
4124 | { .name: "uArr" , .code: 0x21d1 }, |
4125 | { .name: "uacute" , .code: 0x00fa }, |
4126 | { .name: "uarr" , .code: 0x2191 }, |
4127 | { .name: "ucirc" , .code: 0x00fb }, |
4128 | { .name: "ugrave" , .code: 0x00f9 }, |
4129 | { .name: "uml" , .code: 0x00a8 }, |
4130 | { .name: "upsih" , .code: 0x03d2 }, |
4131 | { .name: "upsilon" , .code: 0x03c5 }, |
4132 | { .name: "uuml" , .code: 0x00fc }, |
4133 | { .name: "weierp" , .code: 0x2118 }, |
4134 | { .name: "xi" , .code: 0x03be }, |
4135 | { .name: "yacute" , .code: 0x00fd }, |
4136 | { .name: "yen" , .code: 0x00a5 }, |
4137 | { .name: "yuml" , .code: 0x00ff }, |
4138 | { .name: "zeta" , .code: 0x03b6 }, |
4139 | { .name: "zwj" , .code: 0x200d }, |
4140 | { .name: "zwnj" , .code: 0x200c } |
4141 | }; |
4142 | |
4143 | void tst_QTextDocumentFragment::html_entities_data() |
4144 | { |
4145 | QTest::addColumn<QString>(name: "html" ); |
4146 | QTest::addColumn<quint16>(name: "code" ); |
4147 | |
4148 | for (int i = 0; i < MAX_ENTITY; ++i) { |
4149 | QTest::newRow(dataTag: entities[i].name) << QString("<pre>&" ) + QString::fromLatin1(str: entities[i].name) + QString(";</pre>" ) |
4150 | << entities[i].code; |
4151 | } |
4152 | } |
4153 | |
4154 | void tst_QTextDocumentFragment::html_entities() |
4155 | { |
4156 | QFETCH(QString, html); |
4157 | QFETCH(quint16, code); |
4158 | |
4159 | setHtml(html); |
4160 | QCOMPARE(doc->blockCount(), 1); |
4161 | QString txt = doc->begin().text(); |
4162 | QCOMPARE(txt.length(), 1); |
4163 | QCOMPARE(txt.at(0).unicode(), code); |
4164 | } |
4165 | |
4166 | void tst_QTextDocumentFragment::html_ignore_script() |
4167 | { |
4168 | doc->setHtml(QString::fromLatin1(str: "<html><script>Test</script><body>Blah</body></html>" )); |
4169 | QCOMPARE(doc->toPlainText(), QString("Blah" )); |
4170 | } |
4171 | |
4172 | void tst_QTextDocumentFragment::html_directionWithHtml() |
4173 | { |
4174 | doc->setHtml(QString::fromLatin1(str: "<html><body><p>Test<p dir=rtl>RTL<p dir=ltr>LTR" )); |
4175 | QCOMPARE(doc->blockCount(), 3); |
4176 | |
4177 | QTextBlock block = doc->firstBlock(); |
4178 | QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); |
4179 | QVERIFY(block.blockFormat().layoutDirection() == Qt::LeftToRight); // HTML default |
4180 | |
4181 | block = block.next(); |
4182 | QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); |
4183 | QCOMPARE(block.blockFormat().layoutDirection(), Qt::RightToLeft); |
4184 | |
4185 | block = block.next(); |
4186 | QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); |
4187 | QCOMPARE(block.blockFormat().layoutDirection(), Qt::LeftToRight); |
4188 | } |
4189 | |
4190 | void tst_QTextDocumentFragment::html_directionWithRichText() |
4191 | { |
4192 | doc->setHtml(QString::fromLatin1(str: "<p>Test<p dir=rtl>RTL<p dir=ltr>LTR" )); |
4193 | QCOMPARE(doc->blockCount(), 3); |
4194 | |
4195 | QTextBlock block = doc->firstBlock(); |
4196 | QVERIFY(!block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); |
4197 | |
4198 | block = block.next(); |
4199 | QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); |
4200 | QCOMPARE(block.blockFormat().layoutDirection(), Qt::RightToLeft); |
4201 | |
4202 | block = block.next(); |
4203 | QVERIFY(block.blockFormat().hasProperty(QTextFormat::LayoutDirection)); |
4204 | QCOMPARE(block.blockFormat().layoutDirection(), Qt::LeftToRight); |
4205 | } |
4206 | |
4207 | void tst_QTextDocumentFragment::html_metaInBody() |
4208 | { |
4209 | setHtml("<body>Hello<meta>World</body>" ); |
4210 | QCOMPARE(doc->toPlainText(), QString("HelloWorld" )); |
4211 | } |
4212 | |
4213 | void tst_QTextDocumentFragment::html_importImageWithoutAspectRatio() |
4214 | { |
4215 | doc->setHtml("<img src=\"foo\" width=\"100%\" height=\"43\">" ); |
4216 | cursor.movePosition(op: QTextCursor::Start); |
4217 | cursor.movePosition(op: QTextCursor::NextCharacter); |
4218 | QVERIFY(cursor.charFormat().isImageFormat()); |
4219 | QTextImageFormat fmt = cursor.charFormat().toImageFormat(); |
4220 | // qDebug() << fmt.width() << fmt.height(); |
4221 | QVERIFY (fmt.hasProperty(QTextFormat::ImageWidth)); |
4222 | QCOMPARE (fmt.height(), 43.); |
4223 | |
4224 | doc->setHtml("<img src=\"foo\" height=\"43\">" ); |
4225 | cursor.movePosition(op: QTextCursor::Start); |
4226 | cursor.movePosition(op: QTextCursor::NextCharacter); |
4227 | QVERIFY(cursor.charFormat().isImageFormat()); |
4228 | fmt = cursor.charFormat().toImageFormat(); |
4229 | QVERIFY (! fmt.hasProperty(QTextFormat::ImageWidth)); |
4230 | QCOMPARE (fmt.height(), 43.); |
4231 | |
4232 | doc->setHtml("<img src=\"foo\" width=\"200\">" ); |
4233 | cursor.movePosition(op: QTextCursor::Start); |
4234 | cursor.movePosition(op: QTextCursor::NextCharacter); |
4235 | QVERIFY(cursor.charFormat().isImageFormat()); |
4236 | fmt = cursor.charFormat().toImageFormat(); |
4237 | QVERIFY (! fmt.hasProperty(QTextFormat::ImageHeight)); |
4238 | QCOMPARE (fmt.width(), 200.); |
4239 | } |
4240 | |
4241 | void tst_QTextDocumentFragment::html_fromFirefox() |
4242 | { |
4243 | // if you have a html loaded in firefox like <html>Test\nText</html> then selecting all and copying will |
4244 | // result in the following text on the clipboard (for text/html) |
4245 | doc->setHtml(QString::fromLatin1(str: "<!--StartFragment-->Test\nText\n\n<!--EndFragment-->" )); |
4246 | QCOMPARE(doc->toPlainText(), QString::fromLatin1("Test Text " )); |
4247 | } |
4248 | |
4249 | void tst_QTextDocumentFragment::html_emptyInlineInsideBlock() |
4250 | { |
4251 | doc->setHtml(QString::fromLatin1(str: "<!--StartFragment--><blockquote><span/>Foobar</blockquote><!--EndFragment-->" )); |
4252 | QVERIFY(doc->firstBlock().blockFormat().leftMargin() > 0); |
4253 | } |
4254 | |
4255 | void tst_QTextDocumentFragment::css_fontAndWordSpacing() |
4256 | { |
4257 | { |
4258 | const char html[] = "<body style=\"letter-spacing:13px; word-spacing:15px;\">Foo</span>" ; |
4259 | doc->setHtml(html); |
4260 | cursor.movePosition(op: QTextCursor::Start); |
4261 | cursor.movePosition(op: QTextCursor::NextCharacter); |
4262 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontLetterSpacing).toInt(), 13); |
4263 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontLetterSpacingType).toUInt(), |
4264 | (uint)(QFont::AbsoluteSpacing)); |
4265 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontWordSpacing).toInt(), 15); |
4266 | } |
4267 | { |
4268 | const char html[] = "<body style=\"letter-spacing:1em; word-spacing:0px;\">Foo</span>" ; |
4269 | doc->setHtml(html); |
4270 | cursor.movePosition(op: QTextCursor::Start); |
4271 | cursor.movePosition(op: QTextCursor::NextCharacter); |
4272 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontLetterSpacing).toInt(), 200); |
4273 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontLetterSpacingType).toUInt(), |
4274 | (uint)(QFont::PercentageSpacing)); |
4275 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontWordSpacing).toInt(), 0); |
4276 | } |
4277 | { |
4278 | const char html[] = "<body style=\"letter-spacing:0em;\">Foo</span>" ; |
4279 | doc->setHtml(html); |
4280 | cursor.movePosition(op: QTextCursor::Start); |
4281 | cursor.movePosition(op: QTextCursor::NextCharacter); |
4282 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontLetterSpacing).toInt(), 100); |
4283 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontLetterSpacingType).toUInt(), |
4284 | (uint)(QFont::PercentageSpacing)); |
4285 | } |
4286 | { |
4287 | const char html[] = "<body style=\"letter-spacing:-0.5em;\">Foo</span>" ; |
4288 | doc->setHtml(html); |
4289 | cursor.movePosition(op: QTextCursor::Start); |
4290 | cursor.movePosition(op: QTextCursor::NextCharacter); |
4291 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontLetterSpacing).toInt(), 50); |
4292 | QCOMPARE(cursor.charFormat().property(QTextFormat::FontLetterSpacingType).toUInt(), |
4293 | (uint)(QFont::PercentageSpacing)); |
4294 | } |
4295 | } |
4296 | |
4297 | QTEST_MAIN(tst_QTextDocumentFragment) |
4298 | #include "tst_qtextdocumentfragment.moc" |
4299 | |