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