QtBase  v6.3.1
qtextdocument.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qtextdocument.h"
41 #include <qtextformat.h>
42 #include "qtextcursor_p.h"
43 #include "qtextdocument_p.h"
44 #include "qtextdocumentlayout_p.h"
45 #include "qtextdocumentfragment.h"
47 #include "qtexttable.h"
48 #include "qtextlist.h"
49 #include <qdebug.h>
50 #if QT_CONFIG(regularexpression)
51 #include <qregularexpression.h>
52 #endif
53 #include <qvarlengtharray.h>
54 #include <qthread.h>
55 #include <qcoreapplication.h>
56 #include <qmetaobject.h>
57 
58 #include "qtexthtmlparser_p.h"
59 #include "qpainter.h"
60 #include <qfile.h>
61 #include <qfileinfo.h>
62 #include <qdir.h>
63 #include "qfont_p.h"
64 #include "private/qdataurl_p.h"
65 
66 #include "qtextdocument_p.h"
67 #include <private/qabstracttextdocumentlayout_p.h>
68 #include "qpagedpaintdevice.h"
69 #include "private/qpagedpaintdevice_p.h"
70 #if QT_CONFIG(textmarkdownreader)
71 #include <private/qtextmarkdownimporter_p.h>
72 #endif
73 #if QT_CONFIG(textmarkdownwriter)
74 #include <private/qtextmarkdownwriter_p.h>
75 #endif
76 
77 #include <limits.h>
78 
80 
81 Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n);
82 
83 namespace {
84  QTextDocument::ResourceProvider qt_defaultResourceProvider;
85 };
86 
99 {
100  if (text.isEmpty())
101  return false;
102  int start = 0;
103 
104  while (start < text.length() && text.at(start).isSpace())
105  ++start;
106 
107  // skip a leading <?xml ... ?> as for example with xhtml
108  if (QStringView{text}.mid(start, 5).compare(QLatin1String("<?xml")) == 0) {
109  while (start < text.length()) {
110  if (text.at(start) == QLatin1Char('?')
111  && start + 2 < text.length()
112  && text.at(start + 1) == QLatin1Char('>')) {
113  start += 2;
114  break;
115  }
116  ++start;
117  }
118 
119  while (start < text.length() && text.at(start).isSpace())
120  ++start;
121  }
122 
124  return true;
125  int open = start;
126  while (open < text.length() && text.at(open) != QLatin1Char('<')
127  && text.at(open) != QLatin1Char('\n')) {
128  if (text.at(open) == QLatin1Char('&') && QStringView{text}.mid(open + 1, 3) == QLatin1String("lt;"))
129  return true; // support desperate attempt of user to see <...>
130  ++open;
131  }
132  if (open < text.length() && text.at(open) == QLatin1Char('<')) {
133  const int close = text.indexOf(QLatin1Char('>'), open);
134  if (close > -1) {
135  QString tag;
136  for (int i = open+1; i < close; ++i) {
137  if (text[i].isDigit() || text[i].isLetter())
138  tag += text[i];
139  else if (!tag.isEmpty() && text[i].isSpace())
140  break;
141  else if (!tag.isEmpty() && text[i] == QLatin1Char('/') && i + 1 == close)
142  break;
143  else if (!text[i].isSpace() && (!tag.isEmpty() || text[i] != QLatin1Char('!')))
144  return false; // that's not a tag
145  }
146 #ifndef QT_NO_TEXTHTMLPARSER
147  return QTextHtmlParser::lookupElement(std::move(tag).toLower()) != -1;
148 #else
149  return false;
150 #endif // QT_NO_TEXTHTMLPARSER
151  }
152  }
153  return false;
154 }
155 
167 {
168  int col = 0;
169  QString rich;
170  rich += QLatin1String("<p>");
171  for (int i = 0; i < plain.length(); ++i) {
172  if (plain[i] == QLatin1Char('\n')){
173  int c = 1;
174  while (i+1 < plain.length() && plain[i+1] == QLatin1Char('\n')) {
175  i++;
176  c++;
177  }
178  if (c == 1)
179  rich += QLatin1String("<br>\n");
180  else {
181  rich += QLatin1String("</p>\n");
182  while (--c > 1)
183  rich += QLatin1String("<br>\n");
184  rich += QLatin1String("<p>");
185  }
186  col = 0;
187  } else {
188  if (mode == Qt::WhiteSpacePre && plain[i] == QLatin1Char('\t')){
189  rich += QChar::Nbsp;
190  ++col;
191  while (col % 8) {
192  rich += QChar::Nbsp;
193  ++col;
194  }
195  }
196  else if (mode == Qt::WhiteSpacePre && plain[i].isSpace())
197  rich += QChar::Nbsp;
198  else if (plain[i] == QLatin1Char('<'))
199  rich += QLatin1String("&lt;");
200  else if (plain[i] == QLatin1Char('>'))
201  rich += QLatin1String("&gt;");
202  else if (plain[i] == QLatin1Char('&'))
203  rich += QLatin1String("&amp;");
204  else
205  rich += plain[i];
206  ++col;
207  }
208  }
209  if (col != 0)
210  rich += QLatin1String("</p>");
211  return rich;
212 }
213 
294 {
295  Q_D(QTextDocument);
296  d->init();
297 }
298 
305 {
306  Q_D(QTextDocument);
307  d->init();
308  QTextCursor(this).insertText(text);
309 }
310 
315  : QObject(dd, parent)
316 {
317  Q_D(QTextDocument);
318  d->init();
319 }
320 
325 {
326 }
327 
328 
334 {
335  Q_D(const QTextDocument);
336  QTextDocument *doc = new QTextDocument(parent);
337  if (isEmpty()) {
338  const QTextCursor thisCursor(const_cast<QTextDocument *>(this));
339 
340  const auto blockFormat = thisCursor.blockFormat();
341  if (blockFormat.isValid() && !blockFormat.isEmpty())
342  QTextCursor(doc).setBlockFormat(blockFormat);
343 
344  const auto blockCharFormat = thisCursor.blockCharFormat();
345  if (blockCharFormat.isValid() && !blockCharFormat.isEmpty())
346  QTextCursor(doc).setBlockCharFormat(blockCharFormat);
347  } else {
349  }
350  doc->rootFrame()->setFrameFormat(rootFrame()->frameFormat());
351  QTextDocumentPrivate *priv = doc->d_func();
352  priv->title = d->title;
353  priv->url = d->url;
354  priv->cssMedia = d->cssMedia;
355  priv->pageSize = d->pageSize;
356  priv->indentWidth = d->indentWidth;
357  priv->defaultTextOption = d->defaultTextOption;
358  priv->setDefaultFont(d->defaultFont());
359  priv->resources = d->resources;
360  priv->cachedResources.clear();
361  priv->resourceProvider = d->resourceProvider;
362 #ifndef QT_NO_CSSPARSER
363  priv->defaultStyleSheet = d->defaultStyleSheet;
364  priv->parsedDefaultStyleSheet = d->parsedDefaultStyleSheet;
365 #endif
366  return doc;
367 }
368 
373 {
374  Q_D(const QTextDocument);
375  /* because if we're empty we still have one single paragraph as
376  * one single fragment */
377  return d->length() <= 1;
378 }
379 
384 {
385  Q_D(QTextDocument);
386  d->clear();
387  d->resources.clear();
388 }
389 
403 {
404  Q_D(QTextDocument);
405  const int pos = d->undoRedo(true);
406  if (cursor && pos >= 0) {
407  *cursor = QTextCursor(this);
408  cursor->setPosition(pos);
409  }
410 }
411 
420 {
421  Q_D(QTextDocument);
422  const int pos = d->undoRedo(false);
423  if (cursor && pos >= 0) {
424  *cursor = QTextCursor(this);
425  cursor->setPosition(pos);
426  }
427 }
428 
448 {
449  Q_D(QTextDocument);
450  d->clearUndoRedoStacks(stacksToClear, true);
451 }
452 
458 {
459  Q_D(QTextDocument);
460  d->undoRedo(true);
461 }
462 
468 {
469  Q_D(QTextDocument);
470  d->undoRedo(false);
471 }
472 
479 {
480  Q_D(QTextDocument);
481  d->appendUndoItem(item);
482 }
483 
492 {
493  Q_D(QTextDocument);
494  d->enableUndoRedo(enable);
495 }
496 
498 {
499  Q_D(const QTextDocument);
500  return d->isUndoRedoEnabled();
501 }
502 
525 {
526  Q_D(const QTextDocument);
527  return d->maximumBlockCount;
528 }
529 
531 {
532  Q_D(QTextDocument);
533  d->maximumBlockCount = maximum;
534  d->ensureMaximumBlockCount();
535  setUndoRedoEnabled(false);
536 }
537 
546 {
547  Q_D(const QTextDocument);
548  return d->defaultTextOption;
549 }
550 
557 {
558  Q_D(QTextDocument);
559  d->defaultTextOption = option;
560  if (d->lout)
561  d->lout->documentChanged(0, 0, d->length());
562 }
563 
581 {
582  Q_D(const QTextDocument);
583  return d->baseUrl;
584 }
585 
587 {
588  Q_D(QTextDocument);
589  if (d->baseUrl != url) {
590  d->baseUrl = url;
591  if (d->lout)
592  d->lout->documentChanged(0, 0, d->length());
594  }
595 }
596 
604 {
605  Q_D(const QTextDocument);
606  return d->defaultCursorMoveStyle;
607 }
608 
615 {
616  Q_D(QTextDocument);
617  d->defaultCursorMoveStyle = style;
618 }
619 
628 {
629  Q_D(QTextDocument);
630  d->documentChange(from, length);
631  if (!d->inContentsChange) {
632  if (d->lout) {
633  d->lout->documentChanged(d->docChangeFrom, d->docChangeOldLength, d->docChangeLength);
634  d->docChangeFrom = -1;
635  }
636  }
637 }
638 
656 {
657  Q_D(QTextDocument);
658  if (b == d->defaultTextOption.useDesignMetrics())
659  return;
660  d->defaultTextOption.setUseDesignMetrics(b);
661  if (d->lout)
662  d->lout->documentChanged(0, 0, d->length());
663 }
664 
666 {
667  Q_D(const QTextDocument);
668  return d->defaultTextOption.useDesignMetrics();
669 }
670 
678 {
679  p->save();
681  if (rect.isValid()) {
682  p->setClipRect(rect);
683  ctx.clip = rect;
684  }
685  documentLayout()->draw(p, ctx);
686  p->restore();
687 }
688 
711 {
712  Q_D(QTextDocument);
713  QSizeF sz = d->pageSize;
714  sz.setWidth(width);
715  sz.setHeight(-1);
716  setPageSize(sz);
717 }
718 
720 {
721  Q_D(const QTextDocument);
722  return d->pageSize.width();
723 }
724 
734 {
735  if (QTextDocumentLayout *lout = qobject_cast<QTextDocumentLayout *>(documentLayout()))
736  return lout->idealWidth();
737  return textWidth();
738 }
739 
747 {
748  Q_D(const QTextDocument);
749  return d->documentMargin;
750 }
751 
753 {
754  Q_D(QTextDocument);
755  if (d->documentMargin != margin) {
756  d->documentMargin = margin;
757 
758  QTextFrame* root = rootFrame();
760  format.setMargin(margin);
761  root->setFrameFormat(format);
762 
763  if (d->lout)
764  d->lout->documentChanged(0, 0, d->length());
765  }
766 }
767 
768 
779 {
780  Q_D(const QTextDocument);
781  return d->indentWidth;
782 }
783 
784 
796 {
797  Q_D(QTextDocument);
798  if (d->indentWidth != width) {
799  d->indentWidth = width;
800  if (d->lout)
801  d->lout->documentChanged(0, 0, d->length());
802  }
803 }
804 
805 
806 
807 
816 {
817  // Pull this private function in from qglobal.cpp
818  QFont f = defaultFont();
819  QFontMetrics fm(f);
820  int mw = fm.horizontalAdvance(QLatin1Char('x')) * 80;
821  int w = mw;
822  setTextWidth(w);
824  if (size.width() != 0) {
825  w = qt_int_sqrt((uint)(5 * size.height() * size.width() / 3));
826  setTextWidth(qMin(w, mw));
827 
829  if (w*3 < 5*size.height()) {
830  w = qt_int_sqrt((uint)(2 * size.height() * size.width()));
831  setTextWidth(qMin(w, mw));
832  }
833  }
835 }
836 
855 {
856  return documentLayout()->documentSize();
857 }
858 
871 {
872  Q_D(const QTextDocument);
873  return d->blockMap().numNodes();
874 }
875 
876 
886 {
887  Q_D(const QTextDocument);
888  return d->blockMap().length(2);
889 }
890 
902 {
903  Q_D(const QTextDocument);
904  return d->length();
905 }
906 
916 {
917  Q_D(const QTextDocument);
918  if (pos < 0 || pos >= d->length())
919  return QChar();
921  const QTextFragmentData * const frag = fragIt.value();
922  const int offsetInFragment = qMax(0, pos - fragIt.position());
923  return d->text.at(frag->stringPosition + offsetInFragment);
924 }
925 
926 
942 #ifndef QT_NO_CSSPARSER
944 {
945  Q_D(QTextDocument);
946  d->defaultStyleSheet = sheet;
947  QCss::Parser parser(sheet);
948  d->parsedDefaultStyleSheet = QCss::StyleSheet();
949  d->parsedDefaultStyleSheet.origin = QCss::StyleSheetOrigin_UserAgent;
950  parser.parse(&d->parsedDefaultStyleSheet);
951 }
952 
954 {
955  Q_D(const QTextDocument);
956  return d->defaultStyleSheet;
957 }
958 #endif // QT_NO_CSSPARSER
959 
1042 {
1043  Q_D(const QTextDocument);
1044  return d->isUndoAvailable();
1045 }
1046 
1053 {
1054  Q_D(const QTextDocument);
1055  return d->isRedoAvailable();
1056 }
1057 
1065 {
1066  Q_D(const QTextDocument);
1067  return d->availableUndoSteps();
1068 }
1069 
1077 {
1078  Q_D(const QTextDocument);
1079  return d->availableRedoSteps();
1080 }
1081 
1092 {
1093  Q_D(const QTextDocument);
1094  return d->revision;
1095 }
1096 
1097 
1098 
1106 {
1107  Q_D(QTextDocument);
1108  d->setLayout(layout);
1109 }
1110 
1115 {
1116  Q_D(const QTextDocument);
1117  if (!d->lout) {
1118  QTextDocument *that = const_cast<QTextDocument *>(this);
1119  that->d_func()->setLayout(new QTextDocumentLayout(that));
1120  }
1121  return d->lout;
1122 }
1123 
1124 
1132 {
1133  Q_D(const QTextDocument);
1134  switch (info) {
1135  case DocumentTitle:
1136  return d->title;
1137  case DocumentUrl:
1138  return d->url;
1139  case CssMedia:
1140  return d->cssMedia;
1141  }
1142  return QString();
1143 }
1144 
1152 {
1153  Q_D(QTextDocument);
1154  switch (info) {
1155  case DocumentTitle:
1156  d->title = string;
1157  break;
1158  case DocumentUrl:
1159  d->url = string;
1160  break;
1161  case CssMedia:
1162  d->cssMedia = string;
1163  break;
1164  }
1165 }
1166 
1176 {
1177  Q_D(const QTextDocument);
1178  return d->plainText();
1179 }
1180 
1199 {
1200  Q_D(const QTextDocument);
1201  QString txt = d->plainText();
1202 
1203  QChar *uc = txt.data();
1204  QChar *e = uc + txt.size();
1205 
1206  for (; uc != e; ++uc) {
1207  switch (uc->unicode()) {
1208  case 0xfdd0: // QTextBeginningOfFrame
1209  case 0xfdd1: // QTextEndOfFrame
1211  case QChar::LineSeparator:
1212  *uc = QLatin1Char('\n');
1213  break;
1214  case QChar::Nbsp:
1215  *uc = QLatin1Char(' ');
1216  break;
1217  default:
1218  ;
1219  }
1220  }
1221  return txt;
1222 }
1223 
1231 {
1232  Q_D(QTextDocument);
1233  bool previousState = d->isUndoRedoEnabled();
1234  d->enableUndoRedo(false);
1235  d->beginEditBlock();
1236  d->clear();
1237  QTextCursor(this).insertText(text);
1238  d->endEditBlock();
1239  d->enableUndoRedo(previousState);
1240 }
1241 
1261 #ifndef QT_NO_TEXTHTMLPARSER
1262 
1264 {
1265  Q_D(QTextDocument);
1266  bool previousState = d->isUndoRedoEnabled();
1267  d->enableUndoRedo(false);
1268  d->beginEditBlock();
1269  d->clear();
1271  d->endEditBlock();
1272  d->enableUndoRedo(previousState);
1273 }
1274 
1275 #endif // QT_NO_TEXTHTMLPARSER
1276 
1305 static bool findInBlock(const QTextBlock &block, const QString &expression, int offset,
1306  QTextDocument::FindFlags options, QTextCursor *cursor)
1307 {
1308  QString text = block.text();
1311  int idx = -1;
1312 
1313  while (offset >= 0 && offset <= text.length()) {
1314  idx = (options & QTextDocument::FindBackward) ?
1315  text.lastIndexOf(expression, offset, sensitivity) : text.indexOf(expression, offset, sensitivity);
1316  if (idx == -1)
1317  return false;
1318 
1319  if (options & QTextDocument::FindWholeWords) {
1320  const int start = idx;
1321  const int end = start + expression.length();
1322  if ((start != 0 && text.at(start - 1).isLetterOrNumber())
1323  || (end != text.length() && text.at(end).isLetterOrNumber())) {
1324  //if this is not a whole word, continue the search in the string
1325  offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;
1326  idx = -1;
1327  continue;
1328  }
1329  }
1330  //we have a hit, return the cursor for that.
1332  block.position() + idx);
1333  cursor->setPosition(cursor->position() + expression.length(), QTextCursor::KeepAnchor);
1334  return true;
1335  }
1336  return false;
1337 }
1338 
1355 QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags options) const
1356 {
1357  Q_D(const QTextDocument);
1358 
1359  if (subString.isEmpty())
1360  return QTextCursor();
1361 
1362  int pos = from;
1363  //the cursor is positioned between characters, so for a backward search
1364  //do not include the character given in the position.
1365  if (options & FindBackward) {
1366  --pos ;
1367  if (pos < 0)
1368  return QTextCursor();
1369  }
1370 
1372  QTextBlock block = d->blocksFind(pos);
1373  int blockOffset = pos - block.position();
1374 
1375  if (!(options & FindBackward)) {
1376  while (block.isValid()) {
1377  if (findInBlock(block, subString, blockOffset, options, &cursor))
1378  return cursor;
1379  block = block.next();
1380  blockOffset = 0;
1381  }
1382  } else {
1383  if (blockOffset == block.length() - 1)
1384  --blockOffset; // make sure to skip end-of-paragraph character
1385  while (block.isValid()) {
1386  if (findInBlock(block, subString, blockOffset, options, &cursor))
1387  return cursor;
1388  block = block.previous();
1389  blockOffset = block.length() - 2;
1390  }
1391  }
1392 
1393  return QTextCursor();
1394 }
1395 
1411 QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cursor, FindFlags options) const
1412 {
1413  int pos = 0;
1414  if (!cursor.isNull()) {
1415  if (options & QTextDocument::FindBackward)
1416  pos = cursor.selectionStart();
1417  else
1418  pos = cursor.selectionEnd();
1419  }
1420 
1421  return find(subString, pos, options);
1422 }
1423 
1424 #if QT_CONFIG(regularexpression)
1425 static bool findInBlock(const QTextBlock &block, const QRegularExpression &expr, int offset,
1426  QTextDocument::FindFlags options, QTextCursor *cursor)
1427 {
1428  QString text = block.text();
1431  int idx = -1;
1432 
1433  while (offset >= 0 && offset <= text.length()) {
1434  idx = (options & QTextDocument::FindBackward) ?
1435  text.lastIndexOf(expr, offset, &match) : text.indexOf(expr, offset, &match);
1436  if (idx == -1)
1437  return false;
1438 
1439  if (options & QTextDocument::FindWholeWords) {
1440  const int start = idx;
1441  const int end = start + match.capturedLength();
1442  if ((start != 0 && text.at(start - 1).isLetterOrNumber())
1443  || (end != text.length() && text.at(end).isLetterOrNumber())) {
1444  //if this is not a whole word, continue the search in the string
1445  offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1;
1446  idx = -1;
1447  continue;
1448  }
1449  }
1450  //we have a hit, return the cursor for that.
1452  block.position() + idx);
1453  cursor->setPosition(cursor->position() + match.capturedLength(), QTextCursor::KeepAnchor);
1454  return true;
1455  }
1456  return false;
1457 }
1458 
1475 QTextCursor QTextDocument::find(const QRegularExpression &expr, int from, FindFlags options) const
1476 {
1477  Q_D(const QTextDocument);
1478 
1479  if (!expr.isValid())
1480  return QTextCursor();
1481 
1482  int pos = from;
1483  //the cursor is positioned between characters, so for a backward search
1484  //do not include the character given in the position.
1485  if (options & FindBackward) {
1486  --pos ;
1487  if (pos < 0)
1488  return QTextCursor();
1489  }
1490 
1492  QTextBlock block = d->blocksFind(pos);
1493  int blockOffset = pos - block.position();
1494 
1495  QRegularExpression expression(expr);
1496  if (!(options & QTextDocument::FindCaseSensitively))
1497  expression.setPatternOptions(expr.patternOptions() | QRegularExpression::CaseInsensitiveOption);
1498  else
1499  expression.setPatternOptions(expr.patternOptions() & ~QRegularExpression::CaseInsensitiveOption);
1500 
1501  if (!(options & FindBackward)) {
1502  while (block.isValid()) {
1503  if (findInBlock(block, expression, blockOffset, options, &cursor))
1504  return cursor;
1505  block = block.next();
1506  blockOffset = 0;
1507  }
1508  } else {
1509  while (block.isValid()) {
1510  if (findInBlock(block, expression, blockOffset, options, &cursor))
1511  return cursor;
1512  block = block.previous();
1513  blockOffset = block.length() - 1;
1514  }
1515  }
1516 
1517  return QTextCursor();
1518 }
1519 
1539 QTextCursor QTextDocument::find(const QRegularExpression &expr, const QTextCursor &cursor, FindFlags options) const
1540 {
1541  int pos = 0;
1542  if (!cursor.isNull()) {
1543  if (options & QTextDocument::FindBackward)
1544  pos = cursor.selectionStart();
1545  else
1546  pos = cursor.selectionEnd();
1547  }
1548  return find(expr, pos, options);
1549 }
1550 #endif // QT_CONFIG(regularexpression)
1551 
1562 {
1563  QTextObject *obj = nullptr;
1564  if (f.isListFormat())
1565  obj = new QTextList(this);
1566  else if (f.isTableFormat())
1567  obj = new QTextTable(this);
1568  else if (f.isFrameFormat())
1569  obj = new QTextFrame(this);
1570 
1571  return obj;
1572 }
1573 
1580 {
1581  Q_D(const QTextDocument);
1582  return d->frameAt(pos);
1583 }
1584 
1589 {
1590  Q_D(const QTextDocument);
1591  return d->rootFrame();
1592 }
1593 
1597 QTextObject *QTextDocument::object(int objectIndex) const
1598 {
1599  Q_D(const QTextDocument);
1600  return d->objectForIndex(objectIndex);
1601 }
1602 
1607 {
1608  Q_D(const QTextDocument);
1609  return d->objectForFormat(f);
1610 }
1611 
1612 
1617 {
1618  Q_D(const QTextDocument);
1619  return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(pos));
1620 }
1621 
1629 {
1630  Q_D(const QTextDocument);
1631  return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(blockNumber, 1));
1632 }
1633 
1641 {
1642  Q_D(const QTextDocument);
1643  return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().findNode(lineNumber, 2));
1644 }
1645 
1652 {
1653  Q_D(const QTextDocument);
1654  return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().begin().n);
1655 }
1656 
1670 {
1671  Q_D(const QTextDocument);
1672  return QTextBlock(const_cast<QTextDocumentPrivate *>(d), 0);
1673 }
1674 
1680 {
1681  Q_D(const QTextDocument);
1682  return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().begin().n);
1683 }
1684 
1690 {
1691  Q_D(const QTextDocument);
1692  return QTextBlock(const_cast<QTextDocumentPrivate *>(d), d->blockMap().last().n);
1693 }
1694 
1710 {
1711  Q_D(QTextDocument);
1712  d->pageSize = size;
1713  if (d->lout)
1714  d->lout->documentChanged(0, 0, d->length());
1715 }
1716 
1718 {
1719  Q_D(const QTextDocument);
1720  return d->pageSize;
1721 }
1722 
1727 {
1728  return documentLayout()->pageCount();
1729 }
1730 
1735 {
1736  Q_D(QTextDocument);
1737  d->setDefaultFont(font);
1738  if (d->lout)
1739  d->lout->documentChanged(0, 0, d->length());
1740 }
1741 
1746 {
1747  Q_D(const QTextDocument);
1748  return d->defaultFont();
1749 }
1750 
1761 {
1762  Q_D(QTextDocument);
1763  d->formats.setSuperScriptBaseline(baseline);
1764 }
1765 
1775 {
1776  Q_D(const QTextDocument);
1777  return d->formats.defaultTextFormat().superScriptBaseline();
1778 }
1779 
1790 {
1791  Q_D(QTextDocument);
1792  d->formats.setSubScriptBaseline(baseline);
1793 }
1794 
1804 {
1805  Q_D(const QTextDocument);
1806  return d->formats.defaultTextFormat().subScriptBaseline();
1807 }
1808 
1820 {
1821  Q_D(QTextDocument);
1822  d->formats.setBaselineOffset(baseline);
1823 }
1824 
1834 {
1835  Q_D(const QTextDocument);
1836  return d->formats.defaultTextFormat().baselineOffset();
1837 }
1838 
1863 {
1864  Q_D(const QTextDocument);
1865  return d->isModified();
1866 }
1867 
1869 {
1870  Q_D(QTextDocument);
1871  d->setModified(m);
1872 }
1873 
1874 #ifndef QT_NO_PRINTER
1875 static void printPage(int index, QPainter *painter, const QTextDocument *doc, const QRectF &body, const QPointF &pageNumberPos)
1876 {
1877  painter->save();
1878  painter->translate(body.left(), body.top() - (index - 1) * body.height());
1879  QRectF view(0, (index - 1) * body.height(), body.width(), body.height());
1880 
1883 
1885  ctx.clip = view;
1886 
1887  // don't use the system palette text as default text color, on HP/UX
1888  // for example that's white, and white text on white paper doesn't
1889  // look that nice
1891 
1892  layout->draw(painter, ctx);
1893 
1894  if (!pageNumberPos.isNull()) {
1895  painter->setClipping(false);
1896  painter->setFont(QFont(doc->defaultFont()));
1897  const QString pageString = QString::number(index);
1898 
1899  painter->drawText(qRound(pageNumberPos.x() - painter->fontMetrics().horizontalAdvance(pageString)),
1900  qRound(pageNumberPos.y() + view.top()),
1901  pageString);
1902  }
1903 
1904  painter->restore();
1905 }
1906 
1926 {
1927  Q_D(const QTextDocument);
1928 
1929  if (!printer)
1930  return;
1931 
1932  bool documentPaginated = d->pageSize.isValid() && !d->pageSize.isNull()
1933  && d->pageSize.height() != INT_MAX;
1934 
1935  // ### set page size to paginated size?
1937  if (!documentPaginated && m.left() == 0. && m.right() == 0. && m.top() == 0. && m.bottom() == 0.) {
1938  m.setLeft(2);
1939  m.setRight(2);
1940  m.setTop(2);
1941  m.setBottom(2);
1943  }
1944  // ### use the margins correctly
1945 
1946  QPainter p(printer);
1947 
1948  // Check that there is a valid device to print to.
1949  if (!p.isActive())
1950  return;
1951 
1952  const QTextDocument *doc = this;
1954  (void)doc->documentLayout(); // make sure that there is a layout
1955 
1956  QRectF body = QRectF(QPointF(0, 0), d->pageSize);
1957  QPointF pageNumberPos;
1958 
1959  qreal sourceDpiX = qt_defaultDpiX();
1960  qreal sourceDpiY = qt_defaultDpiY();
1961  const qreal dpiScaleX = qreal(printer->logicalDpiX()) / sourceDpiX;
1962  const qreal dpiScaleY = qreal(printer->logicalDpiY()) / sourceDpiY;
1963 
1964  if (documentPaginated) {
1965 
1966  QPaintDevice *dev = doc->documentLayout()->paintDevice();
1967  if (dev) {
1968  sourceDpiX = dev->logicalDpiX();
1969  sourceDpiY = dev->logicalDpiY();
1970  }
1971 
1972  // scale to dpi
1973  p.scale(dpiScaleX, dpiScaleY);
1974 
1975  QSizeF scaledPageSize = d->pageSize;
1976  scaledPageSize.rwidth() *= dpiScaleX;
1977  scaledPageSize.rheight() *= dpiScaleY;
1978 
1979  const QSizeF printerPageSize(printer->width(), printer->height());
1980 
1981  // scale to page
1982  p.scale(printerPageSize.width() / scaledPageSize.width(),
1983  printerPageSize.height() / scaledPageSize.height());
1984  } else {
1985  doc = clone(const_cast<QTextDocument *>(this));
1986  clonedDoc.reset(const_cast<QTextDocument *>(doc));
1987 
1988  for (QTextBlock srcBlock = firstBlock(), dstBlock = clonedDoc->firstBlock();
1989  srcBlock.isValid() && dstBlock.isValid();
1990  srcBlock = srcBlock.next(), dstBlock = dstBlock.next()) {
1991  dstBlock.layout()->setFormats(srcBlock.layout()->formats());
1992  }
1993 
1995  layout->setPaintDevice(p.device());
1996 
1997  // copy the custom object handlers
1998  layout->d_func()->handlers = documentLayout()->d_func()->handlers;
1999 
2000  // 2 cm margins, scaled to device in QTextDocumentLayoutPrivate::layoutFrame
2001  const int horizontalMargin = int((2/2.54)*sourceDpiX);
2002  const int verticalMargin = int((2/2.54)*sourceDpiY);
2003  QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
2004  fmt.setLeftMargin(horizontalMargin);
2005  fmt.setRightMargin(horizontalMargin);
2006  fmt.setTopMargin(verticalMargin);
2007  fmt.setBottomMargin(verticalMargin);
2008  doc->rootFrame()->setFrameFormat(fmt);
2009 
2010  // pageNumberPos must be in device coordinates, so scale to device here
2011  const int dpiy = p.device()->logicalDpiY();
2012  body = QRectF(0, 0, printer->width(), printer->height());
2013  pageNumberPos = QPointF(body.width() - horizontalMargin * dpiScaleX,
2014  body.height() - verticalMargin * dpiScaleY
2015  + QFontMetrics(doc->defaultFont(), p.device()).ascent()
2016  + 5 * dpiy / 72.0);
2017  clonedDoc->setPageSize(body.size());
2018  }
2019 
2020  const QPageRanges pageRanges = printer->pageRanges();
2021  int fromPage = pageRanges.firstPage();
2022  int toPage = pageRanges.lastPage();
2023 
2024  if (fromPage == 0 && toPage == 0) {
2025  fromPage = 1;
2026  toPage = doc->pageCount();
2027  }
2028  // paranoia check
2029  fromPage = qMax(1, fromPage);
2030  toPage = qMin(doc->pageCount(), toPage);
2031 
2032  if (toPage < fromPage) {
2033  // if the user entered a page range outside the actual number
2034  // of printable pages, just return
2035  return;
2036  }
2037 
2038 // bool ascending = true;
2039 // if (printer->pageOrder() == QPrinter::LastPageFirst) {
2040 // int tmp = fromPage;
2041 // fromPage = toPage;
2042 // toPage = tmp;
2043 // ascending = false;
2044 // }
2045 
2046  int page = fromPage;
2047  while (true) {
2048  if (pageRanges.isEmpty() || pageRanges.contains(page))
2049  printPage(page, &p, doc, body, pageNumberPos);
2050 
2051  if (page == toPage)
2052  break;
2053  ++page;
2054  if (!printer->newPage())
2055  return;
2056  }
2057 }
2058 #endif
2059 
2104 {
2105  Q_D(const QTextDocument);
2106  const QUrl url = d->baseUrl.resolved(name);
2107  QVariant r = d->resources.value(url);
2108  if (!r.isValid()) {
2109  r = d->cachedResources.value(url);
2110  if (!r.isValid()) {
2111  r = const_cast<QTextDocument *>(this)->loadResource(type, url);
2112  if (!r.isValid()) {
2113  if (d->resourceProvider)
2114  r = d->resourceProvider(url);
2115  else if (auto defaultProvider = defaultResourceProvider())
2116  r = defaultProvider(url);
2117  }
2118  }
2119  }
2120  return r;
2121 }
2122 
2141 void QTextDocument::addResource(int type, const QUrl &name, const QVariant &resource)
2142 {
2143  Q_UNUSED(type);
2144  Q_D(QTextDocument);
2145  d->resources.insert(name, resource);
2146 }
2147 
2156 {
2157  Q_D(const QTextDocument);
2158  return d->resourceProvider;
2159 }
2160 
2176 {
2177  Q_D(QTextDocument);
2178  d->resourceProvider = provider;
2179 }
2180 
2192 {
2193  qt_defaultResourceProvider = provider;
2194 }
2195 
2204 {
2205  return qt_defaultResourceProvider;
2206 }
2207 
2228 {
2229  Q_D(QTextDocument);
2230  QVariant r;
2231 
2232  QObject *p = parent();
2233  if (p) {
2234  const QMetaObject *me = p->metaObject();
2235  int index = me->indexOfMethod("loadResource(int,QUrl)");
2236  if (index >= 0) {
2237  QMetaMethod loader = me->method(index);
2238  loader.invoke(p, Q_RETURN_ARG(QVariant, r), Q_ARG(int, type), Q_ARG(QUrl, name));
2239  }
2240  }
2241 
2242  // handle data: URLs
2243  if (r.isNull() && name.scheme().compare(QLatin1String("data"), Qt::CaseInsensitive) == 0) {
2244  QString mimetype;
2246  if (qDecodeDataUrl(name, mimetype, payload))
2247  r = payload;
2248  }
2249 
2250  // if resource was not loaded try to load it here
2251  if (!qobject_cast<QTextDocument *>(p) && r.isNull()) {
2252  QUrl resourceUrl = name;
2253 
2254  if (name.isRelative()) {
2255  QUrl currentURL = d->url;
2256  // For the second case QUrl can merge "#someanchor" with "foo.html"
2257  // correctly to "foo.html#someanchor"
2258  if (!(currentURL.isRelative()
2259  || (currentURL.scheme() == QLatin1String("file")
2260  && !QFileInfo(currentURL.toLocalFile()).isAbsolute()))
2261  || (name.hasFragment() && name.path().isEmpty())) {
2262  resourceUrl = currentURL.resolved(name);
2263  } else {
2264  // this is our last resort when current url and new url are both relative
2265  // we try to resolve against the current working directory in the local
2266  // file system.
2267  QFileInfo fi(currentURL.toLocalFile());
2268  if (fi.exists()) {
2269  resourceUrl =
2271  } else if (currentURL.isEmpty()) {
2272  resourceUrl.setScheme(QLatin1String("file"));
2273  }
2274  }
2275  }
2276 
2277  QString s = resourceUrl.toLocalFile();
2278  QFile f(s);
2279  if (!s.isEmpty() && f.open(QFile::ReadOnly)) {
2280  r = f.readAll();
2281  f.close();
2282  }
2283  }
2284 
2285  if (!r.isNull()) {
2286  if (type == ImageResource && r.userType() == QMetaType::QByteArray) {
2287  if (qApp->thread() != QThread::currentThread()) {
2288  // must use images in non-GUI threads
2289  QImage image;
2290  image.loadFromData(r.toByteArray());
2291  if (!image.isNull())
2292  r = image;
2293  } else {
2294  QPixmap pm;
2295  pm.loadFromData(r.toByteArray());
2296  if (!pm.isNull())
2297  r = pm;
2298  }
2299  }
2300  d->cachedResources.insert(name, r);
2301  }
2302  return r;
2303 }
2304 
2305 static QTextFormat formatDifference(const QTextFormat &from, const QTextFormat &to)
2306 {
2307  QTextFormat diff = to;
2308 
2309  const QMap<int, QVariant> props = to.properties();
2310  for (QMap<int, QVariant>::ConstIterator it = props.begin(), end = props.end();
2311  it != end; ++it)
2312  if (it.value() == from.property(it.key()))
2313  diff.clearProperty(it.key());
2314 
2315  return diff;
2316 }
2317 
2318 static QString colorValue(QColor color)
2319 {
2320  QString result;
2321 
2322  if (color.alpha() == 255) {
2323  result = color.name();
2324  } else if (color.alpha()) {
2325  QString alphaValue = QString::number(color.alphaF(), 'f', 6);
2326  while (alphaValue.length() > 1 && alphaValue.at(alphaValue.size() - 1) == QLatin1Char('0'))
2327  alphaValue.chop(1);
2328  if (alphaValue.at(alphaValue.size() - 1) == QLatin1Char('.'))
2329  alphaValue.chop(1);
2330  result = QString::fromLatin1("rgba(%1,%2,%3,%4)").arg(color.red())
2331  .arg(color.green())
2332  .arg(color.blue())
2333  .arg(alphaValue);
2334  } else {
2335  result = QLatin1String("transparent");
2336  }
2337 
2338  return result;
2339 }
2340 
2342  : doc(_doc), fragmentMarkers(false)
2343 {
2344  const QFont defaultFont = doc->defaultFont();
2345  defaultCharFormat.setFont(defaultFont);
2346 }
2347 
2348 static QStringList resolvedFontFamilies(const QTextCharFormat &format)
2349 {
2350  return format.fontFamilies().toStringList();
2351 }
2352 
2359 {
2360  html = QLatin1String("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
2361  "\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
2362  "<html><head><meta name=\"qrichtext\" content=\"1\" />");
2364 
2365  fragmentMarkers = (mode == ExportFragment);
2366 
2367  html += QString::fromLatin1("<meta charset=\"utf-8\" />");
2368 
2370  if (!title.isEmpty())
2371  html += QString::fromLatin1("<title>") + title + QString::fromLatin1("</title>");
2372  html += QLatin1String("<style type=\"text/css\">\n");
2373  html += QLatin1String("p, li { white-space: pre-wrap; }\n");
2374  html += QLatin1String("hr { height: 1px; border-width: 0; }\n");
2375  html += QLatin1String("</style>");
2376  html += QLatin1String("</head><body");
2377 
2378  if (mode == ExportEntireDocument) {
2379  html += QLatin1String(" style=\"");
2380 
2381  emitFontFamily(resolvedFontFamilies(defaultCharFormat));
2382 
2383  if (defaultCharFormat.hasProperty(QTextFormat::FontPointSize)) {
2384  html += QLatin1String(" font-size:");
2385  html += QString::number(defaultCharFormat.fontPointSize());
2386  html += QLatin1String("pt;");
2387  } else if (defaultCharFormat.hasProperty(QTextFormat::FontPixelSize)) {
2388  html += QLatin1String(" font-size:");
2389  html += QString::number(defaultCharFormat.intProperty(QTextFormat::FontPixelSize));
2390  html += QLatin1String("px;");
2391  }
2392 
2393  html += QLatin1String(" font-weight:");
2394  html += QString::number(defaultCharFormat.fontWeight());
2395  html += QLatin1Char(';');
2396 
2397  html += QLatin1String(" font-style:");
2398  html += (defaultCharFormat.fontItalic() ? QLatin1String("italic") : QLatin1String("normal"));
2399  html += QLatin1Char(';');
2400 
2401  const bool percentSpacing = (defaultCharFormat.fontLetterSpacingType() == QFont::PercentageSpacing);
2402  if (defaultCharFormat.hasProperty(QTextFormat::FontLetterSpacing) &&
2403  (!percentSpacing || defaultCharFormat.fontLetterSpacing() != 0.0)) {
2404  html += QLatin1String(" letter-spacing:");
2405  qreal value = defaultCharFormat.fontLetterSpacing();
2406  if (percentSpacing) // Map to em (100% == 0em)
2407  value = (value / 100) - 1;
2408  html += QString::number(value);
2409  html += percentSpacing ? QLatin1String("em;") : QLatin1String("px;");
2410  }
2411 
2412  if (defaultCharFormat.hasProperty(QTextFormat::FontWordSpacing) &&
2413  defaultCharFormat.fontWordSpacing() != 0.0) {
2414  html += QLatin1String(" word-spacing:");
2415  html += QString::number(defaultCharFormat.fontWordSpacing());
2416  html += QLatin1String("px;");
2417  }
2418 
2419  QString decorationTag(QLatin1String(" text-decoration:"));
2420  bool atLeastOneDecorationSet = false;
2421  if (defaultCharFormat.hasProperty(QTextFormat::FontUnderline) || defaultCharFormat.hasProperty(QTextFormat::TextUnderlineStyle)) {
2422  if (defaultCharFormat.fontUnderline()) {
2423  decorationTag += QLatin1String(" underline");
2424  atLeastOneDecorationSet = true;
2425  }
2426  }
2427  if (defaultCharFormat.hasProperty(QTextFormat::FontOverline)) {
2428  if (defaultCharFormat.fontOverline()) {
2429  decorationTag += QLatin1String(" overline");
2430  atLeastOneDecorationSet = true;
2431  }
2432  }
2433  if (defaultCharFormat.hasProperty(QTextFormat::FontStrikeOut)) {
2434  if (defaultCharFormat.fontStrikeOut()) {
2435  decorationTag += QLatin1String(" line-through");
2436  atLeastOneDecorationSet = true;
2437  }
2438  }
2439  if (atLeastOneDecorationSet)
2440  html += decorationTag + QLatin1Char(';');
2441 
2442  html += QLatin1Char('\"');
2443 
2444  const QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
2445  emitBackgroundAttribute(fmt);
2446 
2447  } else {
2448  defaultCharFormat = QTextCharFormat();
2449  }
2450  html += QLatin1Char('>');
2451 
2452  QTextFrameFormat rootFmt = doc->rootFrame()->frameFormat();
2454 
2455  QTextFrameFormat defaultFmt;
2456  defaultFmt.setMargin(doc->documentMargin());
2457 
2458  if (rootFmt == defaultFmt)
2459  emitFrame(doc->rootFrame()->begin());
2460  else
2461  emitTextFrame(doc->rootFrame());
2462 
2463  html += QLatin1String("</body></html>");
2464  return html;
2465 }
2466 
2467 void QTextHtmlExporter::emitAttribute(const char *attribute, const QString &value)
2468 {
2469  html += QLatin1Char(' ');
2470  html += QLatin1String(attribute);
2471  html += QLatin1String("=\"");
2472  html += value.toHtmlEscaped();
2473  html += QLatin1Char('"');
2474 }
2475 
2476 bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
2477 {
2478  bool attributesEmitted = false;
2479 
2480  {
2481  const QStringList families = resolvedFontFamilies(format);
2482  if (!families.isEmpty() && families != resolvedFontFamilies(defaultCharFormat)) {
2483  emitFontFamily(families);
2484  attributesEmitted = true;
2485  }
2486  }
2487 
2488  if (format.hasProperty(QTextFormat::FontPointSize)
2489  && format.fontPointSize() != defaultCharFormat.fontPointSize()) {
2490  html += QLatin1String(" font-size:");
2491  html += QString::number(format.fontPointSize());
2492  html += QLatin1String("pt;");
2493  attributesEmitted = true;
2494  } else if (format.hasProperty(QTextFormat::FontSizeAdjustment)) {
2495  static const char sizeNameData[] =
2496  "small" "\0"
2497  "medium" "\0"
2498  "xx-large" ;
2499  static const quint8 sizeNameOffsets[] = {
2500  0, // "small"
2501  sizeof("small"), // "medium"
2502  sizeof("small") + sizeof("medium") + 3, // "large" )
2503  sizeof("small") + sizeof("medium") + 1, // "x-large" )> compressed into "xx-large"
2504  sizeof("small") + sizeof("medium"), // "xx-large" )
2505  };
2506  const char *name = nullptr;
2507  const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1;
2508  if (idx >= 0 && idx <= 4) {
2509  name = sizeNameData + sizeNameOffsets[idx];
2510  }
2511  if (name) {
2512  html += QLatin1String(" font-size:");
2513  html += QLatin1String(name);
2514  html += QLatin1Char(';');
2515  attributesEmitted = true;
2516  }
2517  } else if (format.hasProperty(QTextFormat::FontPixelSize)) {
2518  html += QLatin1String(" font-size:");
2519  html += QString::number(format.intProperty(QTextFormat::FontPixelSize));
2520  html += QLatin1String("px;");
2521  attributesEmitted = true;
2522  }
2523 
2524  if (format.hasProperty(QTextFormat::FontWeight)
2525  && format.fontWeight() != defaultCharFormat.fontWeight()) {
2526  html += QLatin1String(" font-weight:");
2527  html += QString::number(format.fontWeight());
2528  html += QLatin1Char(';');
2529  attributesEmitted = true;
2530  }
2531 
2532  if (format.hasProperty(QTextFormat::FontItalic)
2533  && format.fontItalic() != defaultCharFormat.fontItalic()) {
2534  html += QLatin1String(" font-style:");
2535  html += (format.fontItalic() ? QLatin1String("italic") : QLatin1String("normal"));
2536  html += QLatin1Char(';');
2537  attributesEmitted = true;
2538  }
2539 
2540  QLatin1String decorationTag(" text-decoration:");
2541  html += decorationTag;
2542  bool hasDecoration = false;
2543  bool atLeastOneDecorationSet = false;
2544 
2545  if ((format.hasProperty(QTextFormat::FontUnderline) || format.hasProperty(QTextFormat::TextUnderlineStyle))
2546  && format.fontUnderline() != defaultCharFormat.fontUnderline()) {
2547  hasDecoration = true;
2548  if (format.fontUnderline()) {
2549  html += QLatin1String(" underline");
2550  atLeastOneDecorationSet = true;
2551  }
2552  }
2553 
2554  if (format.hasProperty(QTextFormat::FontOverline)
2555  && format.fontOverline() != defaultCharFormat.fontOverline()) {
2556  hasDecoration = true;
2557  if (format.fontOverline()) {
2558  html += QLatin1String(" overline");
2559  atLeastOneDecorationSet = true;
2560  }
2561  }
2562 
2563  if (format.hasProperty(QTextFormat::FontStrikeOut)
2564  && format.fontStrikeOut() != defaultCharFormat.fontStrikeOut()) {
2565  hasDecoration = true;
2566  if (format.fontStrikeOut()) {
2567  html += QLatin1String(" line-through");
2568  atLeastOneDecorationSet = true;
2569  }
2570  }
2571 
2572  if (hasDecoration) {
2573  if (!atLeastOneDecorationSet)
2574  html += QLatin1String("none");
2575  html += QLatin1Char(';');
2576  if (format.hasProperty(QTextFormat::TextUnderlineColor)) {
2577  html += QLatin1String(" text-decoration-color:");
2578  html += colorValue(format.underlineColor());
2579  html += QLatin1Char(';');
2580  }
2581  attributesEmitted = true;
2582  } else {
2583  html.chop(decorationTag.size());
2584  }
2585 
2586  if (format.foreground() != defaultCharFormat.foreground()
2587  && format.foreground().style() != Qt::NoBrush) {
2588  QBrush brush = format.foreground();
2589  if (brush.style() == Qt::TexturePattern) {
2590  const bool isPixmap = qHasPixmapTexture(brush);
2591  const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();
2592 
2593  html += QLatin1String(" -qt-fg-texture-cachekey:");
2594  html += QString::number(cacheKey);
2595  html += QLatin1String(";");
2596  } else {
2597  html += QLatin1String(" color:");
2598  html += colorValue(brush.color());
2599  html += QLatin1Char(';');
2600  }
2601  attributesEmitted = true;
2602  }
2603 
2604  if (format.background() != defaultCharFormat.background()
2605  && format.background().style() == Qt::SolidPattern) {
2606  html += QLatin1String(" background-color:");
2607  html += colorValue(format.background().color());
2608  html += QLatin1Char(';');
2609  attributesEmitted = true;
2610  }
2611 
2612  if (format.verticalAlignment() != defaultCharFormat.verticalAlignment()
2613  && format.verticalAlignment() != QTextCharFormat::AlignNormal)
2614  {
2615  html += QLatin1String(" vertical-align:");
2616 
2617  QTextCharFormat::VerticalAlignment valign = format.verticalAlignment();
2618  if (valign == QTextCharFormat::AlignSubScript)
2619  html += QLatin1String("sub");
2620  else if (valign == QTextCharFormat::AlignSuperScript)
2621  html += QLatin1String("super");
2622  else if (valign == QTextCharFormat::AlignMiddle)
2623  html += QLatin1String("middle");
2624  else if (valign == QTextCharFormat::AlignTop)
2625  html += QLatin1String("top");
2626  else if (valign == QTextCharFormat::AlignBottom)
2627  html += QLatin1String("bottom");
2628 
2629  html += QLatin1Char(';');
2630  attributesEmitted = true;
2631  }
2632 
2633  if (format.fontCapitalization() != QFont::MixedCase) {
2634  const QFont::Capitalization caps = format.fontCapitalization();
2635  if (caps == QFont::AllUppercase)
2636  html += QLatin1String(" text-transform:uppercase;");
2637  else if (caps == QFont::AllLowercase)
2638  html += QLatin1String(" text-transform:lowercase;");
2639  else if (caps == QFont::SmallCaps)
2640  html += QLatin1String(" font-variant:small-caps;");
2641  attributesEmitted = true;
2642  }
2643 
2644  if (format.fontWordSpacing() != 0.0) {
2645  html += QLatin1String(" word-spacing:");
2646  html += QString::number(format.fontWordSpacing());
2647  html += QLatin1String("px;");
2648  attributesEmitted = true;
2649  }
2650 
2651  return attributesEmitted;
2652 }
2653 
2654 void QTextHtmlExporter::emitTextLength(const char *attribute, const QTextLength &length)
2655 {
2656  if (length.type() == QTextLength::VariableLength) // default
2657  return;
2658 
2659  html += QLatin1Char(' ');
2660  html += QLatin1String(attribute);
2661  html += QLatin1String("=\"");
2662  html += QString::number(length.rawValue());
2663 
2664  if (length.type() == QTextLength::PercentageLength)
2665  html += QLatin1String("%\"");
2666  else
2667  html += QLatin1Char('\"');
2668 }
2669 
2670 void QTextHtmlExporter::emitAlignment(Qt::Alignment align)
2671 {
2672  if (align & Qt::AlignLeft)
2673  return;
2674  else if (align & Qt::AlignRight)
2675  html += QLatin1String(" align=\"right\"");
2676  else if (align & Qt::AlignHCenter)
2677  html += QLatin1String(" align=\"center\"");
2678  else if (align & Qt::AlignJustify)
2679  html += QLatin1String(" align=\"justify\"");
2680 }
2681 
2682 void QTextHtmlExporter::emitFloatStyle(QTextFrameFormat::Position pos, StyleMode mode)
2683 {
2685  return;
2686 
2687  if (mode == EmitStyleTag)
2688  html += QLatin1String(" style=\"float:");
2689  else
2690  html += QLatin1String(" float:");
2691 
2693  html += QLatin1String(" left;");
2694  else if (pos == QTextFrameFormat::FloatRight)
2695  html += QLatin1String(" right;");
2696  else
2697  Q_ASSERT_X(0, "QTextHtmlExporter::emitFloatStyle()", "pos should be a valid enum type");
2698 
2699  if (mode == EmitStyleTag)
2700  html += QLatin1Char('\"');
2701 }
2702 
2703 static QLatin1String richtextBorderStyleToHtmlBorderStyle(QTextFrameFormat::BorderStyle style)
2704 {
2705  switch (style) {
2707  return QLatin1String("none");
2709  return QLatin1String("dotted");
2711  return QLatin1String("dashed");
2713  return QLatin1String("solid");
2715  return QLatin1String("double");
2717  return QLatin1String("dot-dash");
2719  return QLatin1String("dot-dot-dash");
2721  return QLatin1String("groove");
2723  return QLatin1String("ridge");
2725  return QLatin1String("inset");
2727  return QLatin1String("outset");
2728  default:
2729  Q_UNREACHABLE();
2730  };
2731  return QLatin1String("");
2732 }
2733 
2734 void QTextHtmlExporter::emitBorderStyle(QTextFrameFormat::BorderStyle style)
2735 {
2737 
2738  html += QLatin1String(" border-style:");
2739  html += richtextBorderStyleToHtmlBorderStyle(style);
2740  html += QLatin1Char(';');
2741 }
2742 
2743 void QTextHtmlExporter::emitPageBreakPolicy(QTextFormat::PageBreakFlags policy)
2744 {
2746  html += QLatin1String(" page-break-before:always;");
2747 
2749  html += QLatin1String(" page-break-after:always;");
2750 }
2751 
2752 void QTextHtmlExporter::emitFontFamily(const QStringList &families)
2753 {
2754  html += QLatin1String(" font-family:");
2755 
2756  bool first = true;
2757  for (const QString &family : families) {
2758  QLatin1String quote("\'");
2759  if (family.contains(QLatin1Char('\'')))
2760  quote = QLatin1String("&quot;");
2761 
2762  if (!first)
2763  html += QLatin1String(",");
2764  else
2765  first = false;
2766  html += quote;
2767  html += family.toHtmlEscaped();
2768  html += quote;
2769  }
2770  html += QLatin1Char(';');
2771 }
2772 
2773 void QTextHtmlExporter::emitMargins(const QString &top, const QString &bottom, const QString &left, const QString &right)
2774 {
2775  html += QLatin1String(" margin-top:");
2776  html += top;
2777  html += QLatin1String("px;");
2778 
2779  html += QLatin1String(" margin-bottom:");
2780  html += bottom;
2781  html += QLatin1String("px;");
2782 
2783  html += QLatin1String(" margin-left:");
2784  html += left;
2785  html += QLatin1String("px;");
2786 
2787  html += QLatin1String(" margin-right:");
2788  html += right;
2789  html += QLatin1String("px;");
2790 }
2791 
2792 void QTextHtmlExporter::emitFragment(const QTextFragment &fragment)
2793 {
2794  const QTextCharFormat format = fragment.charFormat();
2795 
2796  bool closeAnchor = false;
2797 
2798  if (format.isAnchor()) {
2799  const auto names = format.anchorNames();
2800  if (!names.isEmpty()) {
2801  html += QLatin1String("<a name=\"");
2802  html += names.constFirst().toHtmlEscaped();
2803  html += QLatin1String("\"></a>");
2804  }
2805  const QString href = format.anchorHref();
2806  if (!href.isEmpty()) {
2807  html += QLatin1String("<a href=\"");
2808  html += href.toHtmlEscaped();
2809  html += QLatin1String("\">");
2810  closeAnchor = true;
2811  }
2812  }
2813 
2814  QString txt = fragment.text();
2815  const bool isObject = txt.contains(QChar::ObjectReplacementCharacter);
2816  const bool isImage = isObject && format.isImageFormat();
2817 
2818  QLatin1String styleTag("<span style=\"");
2819  html += styleTag;
2820 
2821  bool attributesEmitted = false;
2822  if (!isImage)
2823  attributesEmitted = emitCharFormatStyle(format);
2824  if (attributesEmitted)
2825  html += QLatin1String("\">");
2826  else
2827  html.chop(styleTag.size());
2828 
2829  if (isObject) {
2830  for (int i = 0; isImage && i < txt.length(); ++i) {
2832 
2833  html += QLatin1String("<img");
2834 
2835  if (imgFmt.hasProperty(QTextFormat::ImageName))
2836  emitAttribute("src", imgFmt.name());
2837 
2839  emitAttribute("alt", imgFmt.stringProperty(QTextFormat::ImageAltText));
2840 
2842  emitAttribute("title", imgFmt.stringProperty(QTextFormat::ImageTitle));
2843 
2845  emitAttribute("width", QString::number(imgFmt.width()));
2846 
2848  emitAttribute("height", QString::number(imgFmt.height()));
2849 
2851  html += QLatin1String(" style=\"vertical-align: middle;\"");
2852  else if (imgFmt.verticalAlignment() == QTextCharFormat::AlignTop)
2853  html += QLatin1String(" style=\"vertical-align: top;\"");
2854 
2855  if (QTextFrame *imageFrame = qobject_cast<QTextFrame *>(doc->objectForFormat(imgFmt)))
2856  emitFloatStyle(imageFrame->frameFormat().position());
2857 
2858  html += QLatin1String(" />");
2859  }
2860  } else {
2862 
2863  txt = txt.toHtmlEscaped();
2864 
2865  // split for [\n{LineSeparator}]
2866  // space in BR on purpose for compatibility with old-fashioned browsers
2867  txt.replace(QLatin1Char('\n'), QLatin1String("<br />"));
2868  txt.replace(QChar::LineSeparator, QLatin1String("<br />"));
2869  html += txt;
2870  }
2871 
2872  if (attributesEmitted)
2873  html += QLatin1String("</span>");
2874 
2875  if (closeAnchor)
2876  html += QLatin1String("</a>");
2877 }
2878 
2879 static bool isOrderedList(int style)
2880 {
2885  ;
2886 }
2887 
2888 void QTextHtmlExporter::emitBlockAttributes(const QTextBlock &block)
2889 {
2890  QTextBlockFormat format = block.blockFormat();
2891  emitAlignment(format.alignment());
2892 
2893  // assume default to not bloat the html too much
2894  // html += QLatin1String(" dir='ltr'");
2895  if (block.textDirection() == Qt::RightToLeft)
2896  html += QLatin1String(" dir='rtl'");
2897 
2898  QLatin1String style(" style=\"");
2899  html += style;
2900 
2901  const bool emptyBlock = block.begin().atEnd();
2902  if (emptyBlock) {
2903  html += QLatin1String("-qt-paragraph-type:empty;");
2904  }
2905 
2906  emitMargins(QString::number(format.topMargin()),
2907  QString::number(format.bottomMargin()),
2908  QString::number(format.leftMargin()),
2909  QString::number(format.rightMargin()));
2910 
2911  html += QLatin1String(" -qt-block-indent:");
2912  html += QString::number(format.indent());
2913  html += QLatin1Char(';');
2914 
2915  html += QLatin1String(" text-indent:");
2916  html += QString::number(format.textIndent());
2917  html += QLatin1String("px;");
2918 
2919  if (block.userState() != -1) {
2920  html += QLatin1String(" -qt-user-state:");
2921  html += QString::number(block.userState());
2922  html += QLatin1Char(';');
2923  }
2924 
2925  if (format.lineHeightType() != QTextBlockFormat::SingleHeight) {
2926  html += QLatin1String(" line-height:")
2927  + QString::number(format.lineHeight());
2928  switch (format.lineHeightType()) {
2930  html += QLatin1String("%;");
2931  break;
2933  html += QLatin1String("; -qt-line-height-type: fixed;");
2934  break;
2936  html += QLatin1String("px;");
2937  break;
2939  html += QLatin1String("; -qt-line-height-type: line-distance;");
2940  break;
2941  default:
2942  html += QLatin1String(";");
2943  break; // Should never reach here
2944  }
2945  }
2946 
2947  emitPageBreakPolicy(format.pageBreakPolicy());
2948 
2949  QTextCharFormat diff;
2950  if (emptyBlock) { // only print character properties when we don't expect them to be repeated by actual text in the parag
2951  const QTextCharFormat blockCharFmt = block.charFormat();
2952  diff = formatDifference(defaultCharFormat, blockCharFmt).toCharFormat();
2953  }
2954 
2956  if (format.hasProperty(QTextFormat::BackgroundBrush)) {
2957  QBrush bg = format.background();
2958  if (bg.style() != Qt::NoBrush)
2960  }
2961 
2962  if (!diff.properties().isEmpty())
2963  emitCharFormatStyle(diff);
2964 
2965  html += QLatin1Char('"');
2966 
2967 }
2968 
2969 void QTextHtmlExporter::emitBlock(const QTextBlock &block)
2970 {
2971  if (block.begin().atEnd()) {
2972  // ### HACK, remove once QTextFrame::Iterator is fixed
2973  int p = block.position();
2974  if (p > 0)
2975  --p;
2976 
2978  QChar ch = QTextDocumentPrivate::get(doc)->buffer().at(frag->stringPosition);
2979  if (ch == QTextBeginningOfFrame
2980  || ch == QTextEndOfFrame)
2981  return;
2982  }
2983 
2984  html += QLatin1Char('\n');
2985 
2986  // save and later restore, in case we 'change' the default format by
2987  // emitting block char format information
2988  QTextCharFormat oldDefaultCharFormat = defaultCharFormat;
2989 
2990  QTextList *list = block.textList();
2991  if (list) {
2992  if (list->itemNumber(block) == 0) { // first item? emit <ul> or appropriate
2993  const QTextListFormat format = list->format();
2994  const int style = format.style();
2995  switch (style) {
2996  case QTextListFormat::ListDecimal: html += QLatin1String("<ol"); break;
2997  case QTextListFormat::ListDisc: html += QLatin1String("<ul"); break;
2998  case QTextListFormat::ListCircle: html += QLatin1String("<ul type=\"circle\""); break;
2999  case QTextListFormat::ListSquare: html += QLatin1String("<ul type=\"square\""); break;
3000  case QTextListFormat::ListLowerAlpha: html += QLatin1String("<ol type=\"a\""); break;
3001  case QTextListFormat::ListUpperAlpha: html += QLatin1String("<ol type=\"A\""); break;
3002  case QTextListFormat::ListLowerRoman: html += QLatin1String("<ol type=\"i\""); break;
3003  case QTextListFormat::ListUpperRoman: html += QLatin1String("<ol type=\"I\""); break;
3004  default: html += QLatin1String("<ul"); // ### should not happen
3005  }
3006 
3007  QString styleString = QString::fromLatin1("margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px;");
3008 
3009  if (format.hasProperty(QTextFormat::ListIndent)) {
3010  styleString += QLatin1String(" -qt-list-indent: ");
3011  styleString += QString::number(format.indent());
3012  styleString += QLatin1Char(';');
3013  }
3014 
3015  if (format.hasProperty(QTextFormat::ListNumberPrefix)) {
3016  QString numberPrefix = format.numberPrefix();
3017  numberPrefix.replace(QLatin1Char('"'), QLatin1String("\\22"));
3018  numberPrefix.replace(QLatin1Char('\''), QLatin1String("\\27")); // FIXME: There's a problem in the CSS parser the prevents this from being correctly restored
3019  styleString += QLatin1String(" -qt-list-number-prefix: ");
3020  styleString += QLatin1Char('\'');
3021  styleString += numberPrefix;
3022  styleString += QLatin1Char('\'');
3023  styleString += QLatin1Char(';');
3024  }
3025 
3026  if (format.hasProperty(QTextFormat::ListNumberSuffix)) {
3027  if (format.numberSuffix() != QLatin1String(".")) { // this is our default
3028  QString numberSuffix = format.numberSuffix();
3029  numberSuffix.replace(QLatin1Char('"'), QLatin1String("\\22"));
3030  numberSuffix.replace(QLatin1Char('\''), QLatin1String("\\27")); // see above
3031  styleString += QLatin1String(" -qt-list-number-suffix: ");
3032  styleString += QLatin1Char('\'');
3033  styleString += numberSuffix;
3034  styleString += QLatin1Char('\'');
3035  styleString += QLatin1Char(';');
3036  }
3037  }
3038 
3039  html += QLatin1String(" style=\"");
3040  html += styleString;
3041  html += QLatin1String("\">");
3042  }
3043 
3044  html += QLatin1String("<li");
3045 
3046  const QTextCharFormat blockFmt = formatDifference(defaultCharFormat, block.charFormat()).toCharFormat();
3047  if (!blockFmt.properties().isEmpty()) {
3048  html += QLatin1String(" style=\"");
3049  emitCharFormatStyle(blockFmt);
3050  html += QLatin1Char('\"');
3051 
3052  defaultCharFormat.merge(block.charFormat());
3053  }
3054  }
3055 
3056  const QTextBlockFormat blockFormat = block.blockFormat();
3058  html += QLatin1String("<hr");
3059 
3061  if (width.type() != QTextLength::VariableLength)
3062  emitTextLength("width", width);
3063  html += QLatin1Char(' ');
3064 
3065  if (blockFormat.hasProperty(QTextFormat::BackgroundBrush)) {
3066  html += QLatin1String("style=\"");
3067  html += QLatin1String("background-color:");
3068  html += colorValue(qvariant_cast<QBrush>(blockFormat.property(QTextFormat::BackgroundBrush)).color());
3069  html += QLatin1Char(';');
3070  html += QLatin1Char('\"');
3071  }
3072 
3073  html += QLatin1String("/>");
3074  return;
3075  }
3076 
3077  const bool pre = blockFormat.nonBreakableLines();
3078  if (pre) {
3079  if (list)
3080  html += QLatin1Char('>');
3081  html += QLatin1String("<pre");
3082  } else if (!list) {
3083  int headingLevel = blockFormat.headingLevel();
3084  if (headingLevel > 0 && headingLevel <= 6)
3085  html += QLatin1String("<h") + QString::number(headingLevel);
3086  else
3087  html += QLatin1String("<p");
3088  }
3089 
3090  emitBlockAttributes(block);
3091 
3092  html += QLatin1Char('>');
3093  if (block.begin().atEnd())
3094  html += QLatin1String("<br />");
3095 
3096  QTextBlock::Iterator it = block.begin();
3097  if (fragmentMarkers && !it.atEnd() && block == doc->begin())
3098  html += QLatin1String("<!--StartFragment-->");
3099 
3100  for (; !it.atEnd(); ++it)
3101  emitFragment(it.fragment());
3102 
3103  if (fragmentMarkers && block.position() + block.length() == QTextDocumentPrivate::get(doc)->length())
3104  html += QLatin1String("<!--EndFragment-->");
3105 
3106  QString closeTags;
3107 
3108  if (pre)
3109  html += QLatin1String("</pre>");
3110  else if (list)
3111  closeTags += QLatin1String("</li>");
3112  else {
3113  int headingLevel = blockFormat.headingLevel();
3114  if (headingLevel > 0 && headingLevel <= 6)
3115  html += QLatin1String("</h") + QString::number(headingLevel) + QLatin1Char('>');
3116  else
3117  html += QLatin1String("</p>");
3118  }
3119 
3120  if (list) {
3121  if (list->itemNumber(block) == list->count() - 1) { // last item? close list
3122  if (isOrderedList(list->format().style()))
3123  closeTags += QLatin1String("</ol>");
3124  else
3125  closeTags += QLatin1String("</ul>");
3126  }
3127  const QTextBlock nextBlock = block.next();
3128  // If the next block is the beginning of a new deeper nested list, then we don't
3129  // want to close the current list item just yet. This should be closed when this
3130  // item is fully finished
3131  if (nextBlock.isValid() && nextBlock.textList() &&
3132  nextBlock.textList()->itemNumber(nextBlock) == 0 &&
3133  nextBlock.textList()->format().indent() > list->format().indent()) {
3134  QString lastTag;
3135  if (!closingTags.isEmpty() && list->itemNumber(block) == list->count() - 1)
3136  lastTag = closingTags.takeLast();
3137  lastTag.prepend(closeTags);
3138  closingTags << lastTag;
3139  } else if (list->itemNumber(block) == list->count() - 1) {
3140  // If we are at the end of the list now then we can add in the closing tags for that
3141  // current block
3142  html += closeTags;
3143  if (!closingTags.isEmpty())
3144  html += closingTags.takeLast();
3145  } else {
3146  html += closeTags;
3147  }
3148  }
3149 
3150  defaultCharFormat = oldDefaultCharFormat;
3151 }
3152 
3153 extern bool qHasPixmapTexture(const QBrush& brush);
3154 
3155 QString QTextHtmlExporter::findUrlForImage(const QTextDocument *doc, qint64 cacheKey, bool isPixmap)
3156 {
3157  QString url;
3158  if (!doc)
3159  return url;
3160 
3161  if (QTextDocument *parent = qobject_cast<QTextDocument *>(doc->parent()))
3162  return findUrlForImage(parent, cacheKey, isPixmap);
3163 
3165  Q_ASSERT(priv != nullptr);
3166 
3167  QMap<QUrl, QVariant>::const_iterator it = priv->cachedResources.constBegin();
3168  for (; it != priv->cachedResources.constEnd(); ++it) {
3169 
3170  const QVariant &v = it.value();
3171  if (v.userType() == QMetaType::QImage && !isPixmap) {
3172  if (qvariant_cast<QImage>(v).cacheKey() == cacheKey)
3173  break;
3174  }
3175 
3176  if (v.userType() == QMetaType::QPixmap && isPixmap) {
3177  if (qvariant_cast<QPixmap>(v).cacheKey() == cacheKey)
3178  break;
3179  }
3180  }
3181 
3182  if (it != priv->cachedResources.constEnd())
3183  url = it.key().toString();
3184 
3185  return url;
3186 }
3187 
3189 {
3190  if (!priv)
3191  return;
3192 
3193  cachedResources.insert(priv->cachedResources);
3194 }
3195 
3196 void QTextHtmlExporter::emitBackgroundAttribute(const QTextFormat &format)
3197 {
3198  if (format.hasProperty(QTextFormat::BackgroundImageUrl)) {
3200  emitAttribute("background", url);
3201  } else {
3202  const QBrush &brush = format.background();
3203  if (brush.style() == Qt::SolidPattern) {
3204  emitAttribute("bgcolor", colorValue(brush.color()));
3205  } else if (brush.style() == Qt::TexturePattern) {
3206  const bool isPixmap = qHasPixmapTexture(brush);
3207  const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();
3208 
3209  const QString url = findUrlForImage(doc, cacheKey, isPixmap);
3210 
3211  if (!url.isEmpty())
3212  emitAttribute("background", url);
3213  }
3214  }
3215 }
3216 
3217 void QTextHtmlExporter::emitTable(const QTextTable *table)
3218 {
3219  QTextTableFormat format = table->format();
3220 
3221  html += QLatin1String("\n<table");
3222 
3223  if (format.hasProperty(QTextFormat::FrameBorder))
3224  emitAttribute("border", QString::number(format.border()));
3225 
3226  emitFrameStyle(format, TableFrame);
3227 
3228  emitAlignment(format.alignment());
3229  emitTextLength("width", format.width());
3230 
3231  if (format.hasProperty(QTextFormat::TableCellSpacing))
3232  emitAttribute("cellspacing", QString::number(format.cellSpacing()));
3233  if (format.hasProperty(QTextFormat::TableCellPadding))
3234  emitAttribute("cellpadding", QString::number(format.cellPadding()));
3235 
3236  emitBackgroundAttribute(format);
3237 
3238  html += QLatin1Char('>');
3239 
3240  const int rows = table->rows();
3241  const int columns = table->columns();
3242 
3243  QList<QTextLength> columnWidths = format.columnWidthConstraints();
3244  if (columnWidths.isEmpty()) {
3245  columnWidths.resize(columns);
3246  columnWidths.fill(QTextLength());
3247  }
3248  Q_ASSERT(columnWidths.count() == columns);
3249 
3250  QVarLengthArray<bool> widthEmittedForColumn(columns);
3251  for (int i = 0; i < columns; ++i)
3252  widthEmittedForColumn[i] = false;
3253 
3254  const int headerRowCount = qMin(format.headerRowCount(), rows);
3255  if (headerRowCount > 0)
3256  html += QLatin1String("<thead>");
3257 
3258  for (int row = 0; row < rows; ++row) {
3259  html += QLatin1String("\n<tr>");
3260 
3261  for (int col = 0; col < columns; ++col) {
3262  const QTextTableCell cell = table->cellAt(row, col);
3263 
3264  // for col/rowspans
3265  if (cell.row() != row)
3266  continue;
3267 
3268  if (cell.column() != col)
3269  continue;
3270 
3271  html += QLatin1String("\n<td");
3272 
3273  if (!widthEmittedForColumn[col] && cell.columnSpan() == 1) {
3274  emitTextLength("width", columnWidths.at(col));
3275  widthEmittedForColumn[col] = true;
3276  }
3277 
3278  if (cell.columnSpan() > 1)
3279  emitAttribute("colspan", QString::number(cell.columnSpan()));
3280 
3281  if (cell.rowSpan() > 1)
3282  emitAttribute("rowspan", QString::number(cell.rowSpan()));
3283 
3284  const QTextTableCellFormat cellFormat = cell.format().toTableCellFormat();
3285  emitBackgroundAttribute(cellFormat);
3286 
3287  QTextCharFormat oldDefaultCharFormat = defaultCharFormat;
3288 
3290 
3291  QString styleString;
3292  if (valign >= QTextCharFormat::AlignMiddle && valign <= QTextCharFormat::AlignBottom) {
3293  styleString += QLatin1String(" vertical-align:");
3294  switch (valign) {
3296  styleString += QLatin1String("middle");
3297  break;
3299  styleString += QLatin1String("top");
3300  break;
3302  styleString += QLatin1String("bottom");
3303  break;
3304  default:
3305  break;
3306  }
3307  styleString += QLatin1Char(';');
3308 
3309  QTextCharFormat temp;
3310  temp.setVerticalAlignment(valign);
3311  defaultCharFormat.merge(temp);
3312  }
3313 
3315  styleString += QLatin1String(" padding-left:") + QString::number(cellFormat.leftPadding()) + QLatin1Char(';');
3317  styleString += QLatin1String(" padding-right:") + QString::number(cellFormat.rightPadding()) + QLatin1Char(';');
3319  styleString += QLatin1String(" padding-top:") + QString::number(cellFormat.topPadding()) + QLatin1Char(';');
3321  styleString += QLatin1String(" padding-bottom:") + QString::number(cellFormat.bottomPadding()) + QLatin1Char(';');
3322 
3324  styleString += QLatin1String(" border-top:") + QString::number(cellFormat.topBorder()) + QLatin1String("px;");
3326  styleString += QLatin1String(" border-right:") + QString::number(cellFormat.rightBorder()) + QLatin1String("px;");
3328  styleString += QLatin1String(" border-bottom:") + QString::number(cellFormat.bottomBorder()) + QLatin1String("px;");
3330  styleString += QLatin1String(" border-left:") + QString::number(cellFormat.leftBorder()) + QLatin1String("px;");
3331 
3333  styleString += QLatin1String(" border-top-color:") + cellFormat.topBorderBrush().color().name() + QLatin1Char(';');
3335  styleString += QLatin1String(" border-right-color:") + cellFormat.rightBorderBrush().color().name() + QLatin1Char(';');
3337  styleString += QLatin1String(" border-bottom-color:") + cellFormat.bottomBorderBrush().color().name() + QLatin1Char(';');
3339  styleString += QLatin1String(" border-left-color:") + cellFormat.leftBorderBrush().color().name() + QLatin1Char(';');
3340 
3342  styleString += QLatin1String(" border-top-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.topBorderStyle()) + QLatin1Char(';');
3344  styleString += QLatin1String(" border-right-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.rightBorderStyle()) + QLatin1Char(';');
3346  styleString += QLatin1String(" border-bottom-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.bottomBorderStyle()) + QLatin1Char(';');
3348  styleString += QLatin1String(" border-left-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.leftBorderStyle()) + QLatin1Char(';');
3349 
3350  if (!styleString.isEmpty())
3351  html += QLatin1String(" style=\"") + styleString + QLatin1Char('\"');
3352 
3353  html += QLatin1Char('>');
3354 
3355  emitFrame(cell.begin());
3356 
3357  html += QLatin1String("</td>");
3358 
3359  defaultCharFormat = oldDefaultCharFormat;
3360  }
3361 
3362  html += QLatin1String("</tr>");
3363  if (headerRowCount > 0 && row == headerRowCount - 1)
3364  html += QLatin1String("</thead>");
3365  }
3366 
3367  html += QLatin1String("</table>");
3368 }
3369 
3370 void QTextHtmlExporter::emitFrame(const QTextFrame::Iterator &frameIt)
3371 {
3372  if (!frameIt.atEnd()) {
3373  QTextFrame::Iterator next = frameIt;
3374  ++next;
3375  if (next.atEnd()
3376  && frameIt.currentFrame() == nullptr
3377  && frameIt.parentFrame() != doc->rootFrame()
3378  && frameIt.currentBlock().begin().atEnd())
3379  return;
3380  }
3381 
3382  for (QTextFrame::Iterator it = frameIt;
3383  !it.atEnd(); ++it) {
3384  if (QTextFrame *f = it.currentFrame()) {
3385  if (QTextTable *table = qobject_cast<QTextTable *>(f)) {
3386  emitTable(table);
3387  } else {
3388  emitTextFrame(f);
3389  }
3390  } else if (it.currentBlock().isValid()) {
3391  emitBlock(it.currentBlock());
3392  }
3393  }
3394 }
3395 
3396 void QTextHtmlExporter::emitTextFrame(const QTextFrame *f)
3397 {
3398  FrameType frameType = f->parentFrame() ? TextFrame : RootFrame;
3399 
3400  html += QLatin1String("\n<table");
3401  QTextFrameFormat format = f->frameFormat();
3402 
3403  if (format.hasProperty(QTextFormat::FrameBorder))
3404  emitAttribute("border", QString::number(format.border()));
3405 
3406  emitFrameStyle(format, frameType);
3407 
3408  emitTextLength("width", format.width());
3409  emitTextLength("height", format.height());
3410 
3411  // root frame's bcolor goes in the <body> tag
3412  if (frameType != RootFrame)
3413  emitBackgroundAttribute(format);
3414 
3415  html += QLatin1Char('>');
3416  html += QLatin1String("\n<tr>\n<td style=\"border: none;\">");
3417  emitFrame(f->begin());
3418  html += QLatin1String("</td></tr></table>");
3419 }
3420 
3421 void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType frameType)
3422 {
3423  QLatin1String styleAttribute(" style=\"");
3424  html += styleAttribute;
3425  const int originalHtmlLength = html.length();
3426 
3427  if (frameType == TextFrame)
3428  html += QLatin1String("-qt-table-type: frame;");
3429  else if (frameType == RootFrame)
3430  html += QLatin1String("-qt-table-type: root;");
3431 
3432  const QTextFrameFormat defaultFormat;
3433 
3434  emitFloatStyle(format.position(), OmitStyleTag);
3435  emitPageBreakPolicy(format.pageBreakPolicy());
3436 
3437  if (format.borderBrush() != defaultFormat.borderBrush()) {
3438  html += QLatin1String(" border-color:");
3439  html += colorValue(format.borderBrush().color());
3440  html += QLatin1Char(';');
3441  }
3442 
3443  if (format.borderStyle() != defaultFormat.borderStyle())
3444  emitBorderStyle(format.borderStyle());
3445 
3446  if (format.hasProperty(QTextFormat::FrameMargin)
3447  || format.hasProperty(QTextFormat::FrameLeftMargin)
3448  || format.hasProperty(QTextFormat::FrameRightMargin)
3449  || format.hasProperty(QTextFormat::FrameTopMargin)
3450  || format.hasProperty(QTextFormat::FrameBottomMargin))
3451  emitMargins(QString::number(format.topMargin()),
3452  QString::number(format.bottomMargin()),
3453  QString::number(format.leftMargin()),
3454  QString::number(format.rightMargin()));
3455 
3456  if (format.property(QTextFormat::TableBorderCollapse).toBool())
3457  html += QLatin1String(" border-collapse:collapse;");
3458 
3459  if (html.length() == originalHtmlLength) // nothing emitted?
3460  html.chop(styleAttribute.size());
3461  else
3462  html += QLatin1Char('\"');
3463 }
3464 
3475 #ifndef QT_NO_TEXTHTMLPARSER
3477 {
3478  return QTextHtmlExporter(this).toHtml();
3479 }
3480 #endif // QT_NO_TEXTHTMLPARSER
3481 
3489 #if QT_CONFIG(textmarkdownwriter)
3490 QString QTextDocument::toMarkdown(QTextDocument::MarkdownFeatures features) const
3491 {
3492  QString ret;
3493  QTextStream s(&ret);
3494  QTextMarkdownWriter w(s, features);
3495  if (w.writeAll(this))
3496  return ret;
3497  return QString();
3498 }
3499 #endif
3500 
3531 #if QT_CONFIG(textmarkdownreader)
3532 void QTextDocument::setMarkdown(const QString &markdown, QTextDocument::MarkdownFeatures features)
3533 {
3534  QTextMarkdownImporter(features).import(this, markdown);
3535 }
3536 #endif
3537 
3542 {
3543  Q_D(const QTextDocument);
3544  return d->formatCollection()->formats;
3545 }
3546 
3555 
3556 #include "moc_qtextdocument.cpp"
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
Arabic default style
Definition: afstyles.h:94
const QByteArray payload("Qt rocks!")
FT_UInt idx
Definition: cffcmap.c:135
The QAbstractTextDocumentLayout class is an abstract base class used to implement custom layouts for ...
virtual int pageCount() const =0
virtual void draw(QPainter *painter, const PaintContext &context)=0
virtual QSizeF documentSize() const =0
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:66
const QColor & color() const
Definition: qbrush.h:157
Qt::BrushStyle style() const
Definition: qbrush.h:156
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
constexpr bool isLetterOrNumber() const noexcept
Definition: qchar.h:503
@ ObjectReplacementCharacter
Definition: qchar.h:96
@ Nbsp
Definition: qchar.h:93
@ ParagraphSeparator
Definition: qchar.h:99
@ LineSeparator
Definition: qchar.h:100
constexpr char16_t unicode() const noexcept
Definition: qchar.h:489
constexpr bool isSpace() const noexcept
Definition: qchar.h:497
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
QString name(NameFormat format=HexRgb) const
Definition: qcolor.cpp:864
static QChar separator()
Definition: qdir.h:234
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:94
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:57
QString absolutePath() const
Definition: qfileinfo.cpp:599
bool isAbsolute() const
Definition: qfileinfo.h:151
bool exists() const
Definition: qfileinfo.cpp:697
The QFont class specifies a query for a font used for drawing text.
Definition: qfont.h:56
Capitalization
Definition: qfont.h:130
@ AllLowercase
Definition: qfont.h:133
@ AllUppercase
Definition: qfont.h:132
@ MixedCase
Definition: qfont.h:131
@ SmallCaps
Definition: qfont.h:134
@ PercentageSpacing
Definition: qfont.h:140
The QFontMetrics class provides font metrics information.
Definition: qfontmetrics.h:56
int horizontalAdvance(const QString &, int len=-1) const
int ascent() const
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:73
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
Definition: qlist.h:108
QList< T > & fill(parameter_type t, qsizetype size=-1)
Definition: qlist.h:907
bool isEmpty() const noexcept
Definition: qlist.h:418
const_reference at(qsizetype i) const noexcept
Definition: qlist.h:457
qsizetype count() const noexcept
Definition: qlist.h:415
void resize(qsizetype size)
Definition: qlist.h:420
Definition: qmap.h:222
iterator insert(const Key &key, const T &value)
Definition: qmap.h:719
void clear()
Definition: qmap.h:324
const_iterator constBegin() const
Definition: qmap.h:635
const_iterator constEnd() const
Definition: qmap.h:639
The QMarginsF class defines the four margins of a rectangle.
Definition: qmargins.h:301
constexpr void setLeft(qreal aleft) noexcept
Definition: qmargins.h:404
The QMetaMethod class provides meta-data about a member function.
Definition: qmetaobject.h:54
bool invoke(QObject *object, Qt::ConnectionType connectionType, QGenericReturnArgument returnValue, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument()) const
The QObject class is the base class of all Qt objects.
Definition: qobject.h:125
QObject * parent() const
Definition: qobject.h:409
QMarginsF margins() const
The QPageRanges class represents a collection of page ranges. \inmodule QtGui.
Definition: qpageranges.h:57
bool isEmpty() const
int lastPage() const
int firstPage() const
bool contains(int pageNumber) const
The QPagedPaintDevice class represents a paint device that supports multiple pages.
virtual bool newPage()=0
virtual bool setPageMargins(const QMarginsF &margins, QPageLayout::Unit units=QPageLayout::Millimeter)
QPageRanges pageRanges() const
QPageLayout pageLayout() const
int logicalDpiX() const
Definition: qpaintdevice.h:81
int logicalDpiY() const
Definition: qpaintdevice.h:82
int width() const
Definition: qpaintdevice.h:77
int height() const
Definition: qpaintdevice.h:78
The QPainter class performs low-level painting on widgets and other paint devices.
Definition: qpainter.h:82
void setClipping(bool enable)
Definition: qpainter.cpp:2448
void setClipRect(const QRectF &, Qt::ClipOperation op=Qt::ReplaceClip)
Definition: qpainter.cpp:2717
void restore()
Definition: qpainter.cpp:1611
QFontMetrics fontMetrics() const
Definition: qpainter.cpp:2009
void save()
Definition: qpainter.cpp:1577
void setFont(const QFont &f)
Definition: qpainter.cpp:3866
void drawText(const QPointF &p, const QString &s)
Definition: qpainter.cpp:5444
void translate(const QPointF &offset)
Definition: qpainter.cpp:2993
void setColor(ColorGroup cg, ColorRole cr, const QColor &color)
Definition: qpalette.h:179
@ Text
Definition: qpalette.h:87
The QPixmap class is an off-screen image representation that can be used as a paint device.
Definition: qpixmap.h:63
bool isNull() const
Definition: qpixmap.cpp:491
bool loadFromData(const uchar *buf, uint len, const char *format=nullptr, Qt::ImageConversionFlags flags=Qt::AutoColor)
Definition: qpixmap.cpp:794
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:242
constexpr qreal x() const noexcept
Definition: qpoint.h:361
constexpr qreal y() const noexcept
Definition: qpoint.h:366
bool isNull() const noexcept
Definition: qpoint.h:356
The QRectF class defines a finite rectangle in the plane using floating point precision.
Definition: qrect.h:511
The QRegularExpression class provides pattern matching using regular expressions.
PatternOptions patternOptions() const
The QRegularExpressionMatch class provides the results of a matching a QRegularExpression against a s...
qsizetype capturedLength(int nth=0) const
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon dest...
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
The QSizeF class defines the size of a two-dimensional object using floating point precision.
Definition: qsize.h:235
constexpr qreal & rwidth() noexcept
Definition: qsize.h:373
constexpr void setHeight(qreal h) noexcept
Definition: qsize.h:358
constexpr qreal & rheight() noexcept
Definition: qsize.h:376
constexpr void setWidth(qreal w) noexcept
Definition: qsize.h:355
constexpr qreal width() const noexcept
Definition: qsize.h:349
constexpr qreal height() const noexcept
Definition: qsize.h:352
The QString class provides a Unicode character string.
Definition: qstring.h:388
QString & prepend(QChar c)
Definition: qstring.h:656
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstring.h:514
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition: qstring.cpp:3450
void reserve(qsizetype size)
Definition: qstring.h:1307
void chop(qsizetype n)
Definition: qstring.cpp:5955
static QString fromLatin1(QByteArrayView ba)
Definition: qstring.cpp:5488
qsizetype size() const
Definition: qstring.h:413
QString mid(qsizetype position, qsizetype n=-1) const
Definition: qstring.cpp:4994
const QChar at(qsizetype i) const
Definition: qstring.h:1212
bool isEmpty() const
Definition: qstring.h:1216
QString arg(qlonglong a, int fieldwidth=0, int base=10, QChar fillChar=QLatin1Char(' ')) const
Definition: qstring.cpp:8318
static QString number(int, int base=10)
Definition: qstring.cpp:7538
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:4197
QString toHtmlEscaped() const
Definition: qstring.cpp:10705
qsizetype length() const
Definition: qstring.h:415
The QStringList class provides a list of strings.
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
The QTextBlock::iterator class provides an iterator for reading the contents of a QTextBlock....
Definition: qtextobject.h:246
bool atEnd() const
Definition: qtextobject.h:259
The QTextBlockFormat class provides formatting information for blocks of text in a QTextDocument....
Definition: qtextformat.h:640
int headingLevel() const
Definition: qtextformat.h:695
bool nonBreakableLines() const
Definition: qtextformat.h:708
The QTextBlock class provides a container for text fragments in a QTextDocument. \inmodule QtGui.
Definition: qtextobject.h:193
iterator begin() const
bool isValid() const
QTextList * textList() const
The QTextCharFormat class provides formatting information for characters in a QTextDocument....
Definition: qtextformat.h:416
qreal fontLetterSpacing() const
Definition: qtextformat.h:499
QStringList anchorNames() const
int fontWeight() const
Definition: qtextformat.h:483
qreal fontPointSize() const
Definition: qtextformat.h:478
bool fontStrikeOut() const
Definition: qtextformat.h:517
void setVerticalAlignment(VerticalAlignment alignment)
Definition: qtextformat.h:563
qreal fontWordSpacing() const
Definition: qtextformat.h:503
bool fontOverline() const
Definition: qtextformat.h:512
VerticalAlignment verticalAlignment() const
Definition: qtextformat.h:565
QFont::SpacingType fontLetterSpacingType() const
Definition: qtextformat.h:495
bool fontItalic() const
Definition: qtextformat.h:487
bool fontUnderline() const
void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior=FontPropertiesAll)
The QTextCursor class offers an API to access and modify QTextDocuments.
Definition: qtextcursor.h:67
void setBlockCharFormat(const QTextCharFormat &format)
QTextBlockFormat blockFormat() const
QTextCharFormat blockCharFormat() const
void insertFragment(const QTextDocumentFragment &fragment)
void setBlockFormat(const QTextBlockFormat &format)
void insertText(const QString &text)
static QTextCursor fromPosition(QTextDocumentPrivate *d, int pos)
The QTextDocumentFragment class represents a piece of formatted text from a QTextDocument.
The QTextDocument class holds formatted text.
Definition: qtextdocument.h:93
void setModified(bool m=true)
QString defaultStyleSheet
QTextDocument * clone(QObject *parent=nullptr) const
void setDefaultCursorMoveStyle(Qt::CursorMoveStyle style)
void setSuperScriptBaseline(qreal baseline)
void setBaselineOffset(qreal baseline)
void setIndentWidth(qreal width)
QTextBlock findBlockByLineNumber(int blockNumber) const
int maximumBlockCount
Specifies the limit for blocks in the document.
void setHtml(const QString &html)
bool isEmpty() const
QTextFrame * frameAt(int pos) const
qreal baselineOffset() const
qreal idealWidth() const
int lineCount() const
void setDefaultTextOption(const QTextOption &option)
int availableRedoSteps() const
void setResourceProvider(const ResourceProvider &provider)
QList< QTextFormat > allFormats() const
bool isRedoAvailable() const
QFont defaultFont
the default font used to display the document's text
Definition: qtextdocument.h:99
QString toHtml() const
QTextBlock findBlockByNumber(int blockNumber) const
int availableUndoSteps() const
int blockCount
the number of text blocks in the document.
QAbstractTextDocumentLayout * documentLayout() const
QString toRawText() const
bool useDesignMetrics
whether the document uses design metrics of fonts to improve the accuracy of text layout
QSizeF size
the actual size of the document. This is equivalent to documentLayout()->documentSize();
QSizeF pageSize
the page size that should be used for laying out the document
Definition: qtextdocument.h:98
void appendUndoItem(QAbstractUndoItem *)
bool isModified() const
QTextObject * objectForFormat(const QTextFormat &) const
virtual void clear()
bool isUndoRedoEnabled() const
int revision() const
void baseUrlChanged(const QUrl &url)
int pageCount() const
QTextBlock begin() const
bool isUndoAvailable() const
QTextOption defaultTextOption() const
the default text option will be set on all \l{QTextLayout}s in the document.
qreal documentMargin
void print(QPagedPaintDevice *printer) const
QVariant resource(int type, const QUrl &name) const
void setDefaultFont(const QFont &font)
QChar characterAt(int pos) const
void setPageSize(const QSizeF &size)
QTextDocument(QObject *parent=nullptr)
QTextDocument::ResourceProvider resourceProvider() const
void setDefaultStyleSheet(const QString &sheet)
void setUndoRedoEnabled(bool enable)
QUrl baseUrl
the base URL used to resolve relative resource URLs within the document.
QString toPlainText() const
virtual Q_INVOKABLE QVariant loadResource(int type, const QUrl &name)
QTextObject * object(int objectIndex) const
void clearUndoRedoStacks(Stacks historyToClear=UndoAndRedoStacks)
QTextCursor find(const QString &subString, int from=0, FindFlags options=FindFlags()) const
void setDocumentMargin(qreal margin)
QTextBlock findBlock(int pos) const
qreal subScriptBaseline() const
QTextBlock end() const
QString metaInformation(MetaInformation info) const
Qt::CursorMoveStyle defaultCursorMoveStyle() const
QTextBlock firstBlock() const
static void setDefaultResourceProvider(const ResourceProvider &provider)
void setPlainText(const QString &text)
void setMaximumBlockCount(int maximum)
QTextFrame * rootFrame() const
void setDocumentLayout(QAbstractTextDocumentLayout *layout)
void setMetaInformation(MetaInformation info, const QString &)
qreal superScriptBaseline() const
static QTextDocument::ResourceProvider defaultResourceProvider()
void setBaseUrl(const QUrl &url)
QTextBlock lastBlock() const
void addResource(int type, const QUrl &name, const QVariant &resource)
void setSubScriptBaseline(qreal baseline)
virtual QTextObject * createObject(const QTextFormat &f)
std::function< QVariant(const QUrl &)> ResourceProvider
void markContentsDirty(int from, int length)
void setUseDesignMetrics(bool b)
void setTextWidth(qreal width)
void drawContents(QPainter *painter, const QRectF &rect=QRectF())
int characterCount() const
QCss::StyleSheet parsedDefaultStyleSheet
QString buffer() const
FragmentMap::ConstIterator FragmentIterator
static const QTextDocumentPrivate * get(const QTextDocument *document)
FragmentIterator find(int pos) const
QTextOption defaultTextOption
void mergeCachedResources(const QTextDocumentPrivate *priv)
void setDefaultFont(const QFont &f)
The QTextFormat class provides formatting information for a QTextDocument. \inmodule QtGui.
Definition: qtextformat.h:126
QTextCharFormat toCharFormat() const
QBrush background() const
Definition: qtextformat.h:386
QString stringProperty(int propertyId) const
@ TableCellBottomBorderStyle
Definition: qtextformat.h:262
@ TableCellRightBorder
Definition: qtextformat.h:259
@ TableCellTopBorderStyle
Definition: qtextformat.h:261
@ TableBorderCollapse
Definition: qtextformat.h:245
@ TableCellTopPadding
Definition: qtextformat.h:251
@ TableCellLeftPadding
Definition: qtextformat.h:253
@ TableCellBottomBorderBrush
Definition: qtextformat.h:267
@ TableCellRightBorderStyle
Definition: qtextformat.h:264
@ BlockTrailingHorizontalRulerWidth
Definition: qtextformat.h:165
@ TableCellLeftBorder
Definition: qtextformat.h:258
@ TextUnderlineColor
Definition: qtextformat.h:200
@ FontSizeAdjustment
Definition: qtextformat.h:189
@ TableCellTopBorder
Definition: qtextformat.h:256
@ BackgroundImageUrl
Definition: qtextformat.h:151
@ TableCellTopBorderBrush
Definition: qtextformat.h:266
@ TableCellRightBorderBrush
Definition: qtextformat.h:269
@ TableCellBottomPadding
Definition: qtextformat.h:252
@ TableCellRightPadding
Definition: qtextformat.h:254
@ TextUnderlineStyle
Definition: qtextformat.h:203
@ TableCellBottomBorder
Definition: qtextformat.h:257
@ TableCellLeftBorderStyle
Definition: qtextformat.h:263
@ TableCellLeftBorderBrush
Definition: qtextformat.h:268
QTextLength lengthProperty(int propertyId) const
int intProperty(int propertyId) const
void setProperty(int propertyId, const QVariant &value)
QTextImageFormat toImageFormat() const
QMap< int, QVariant > properties() const
QTextTableCellFormat toTableCellFormat() const
bool hasProperty(int propertyId) const
void clearProperty(int propertyId)
void merge(const QTextFormat &other)
@ PageBreak_AlwaysBefore
Definition: qtextformat.h:308
@ PageBreak_AlwaysAfter
Definition: qtextformat.h:309
QVariant property(int propertyId) const
QBrush foreground() const
Definition: qtextformat.h:393
The QTextFragment class holds a piece of text in a QTextDocument with a single QTextCharFormat....
Definition: qtextobject.h:292
QString text() const
QTextCharFormat charFormat() const
The iterator class provides an iterator for reading the contents of a QTextFrame.
Definition: qtextobject.h:138
QTextFrame * parentFrame() const
Definition: qtextobject.h:153
QTextFrame * currentFrame() const
Definition: qtextobject.h:155
bool atEnd() const
Definition: qtextobject.h:158
Q_GUI_EXPORT QTextBlock currentBlock() const
The QTextFrameFormat class provides formatting information for frames in a QTextDocument....
Definition: qtextformat.h:859
QBrush borderBrush() const
Definition: qtextformat.h:898
void setTopMargin(qreal margin)
Definition: qtextformat.h:965
void setLeftMargin(qreal margin)
Definition: qtextformat.h:971
void setBottomMargin(qreal margin)
Definition: qtextformat.h:968
BorderStyle borderStyle() const
Definition: qtextformat.h:903
void setRightMargin(qreal margin)
Definition: qtextformat.h:974
void setMargin(qreal margin)
The QTextFrame class represents a frame in a QTextDocument. \inmodule QtGui.
Definition: qtextobject.h:117
void setFrameFormat(const QTextFrameFormat &format)
Definition: qtextobject.h:184
QTextFrameFormat frameFormat() const
Definition: qtextobject.h:125
iterator begin() const
QString toHtml(ExportMode mode=ExportEntireDocument)
QTextHtmlExporter(const QTextDocument *_doc)
static int lookupElement(const QString &element)
The QTextImageFormat class provides formatting information for images in a QTextDocument....
Definition: qtextformat.h:811
qreal width() const
Definition: qtextformat.h:822
qreal height() const
Definition: qtextformat.h:826
QString name() const
Definition: qtextformat.h:818
The QTextLength class encapsulates the different types of length used in a QTextDocument....
Definition: qtextformat.h:81
@ PercentageLength
Definition: qtextformat.h:83
The QTextListFormat class provides formatting information for lists in a QTextDocument....
Definition: qtextformat.h:757
int indent() const
Definition: qtextformat.h:780
The QTextList class provides a decorated list of items in a QTextDocument. \inmodule QtGui.
Definition: qtextlist.h:54
int itemNumber(const QTextBlock &) const
Definition: qtextlist.cpp:157
QTextListFormat format() const
Definition: qtextlist.h:73
void import(QTextDocument *doc, const QString &markdown)
The QTextObject class is a base class for different kinds of objects that can group parts of a QTextD...
Definition: qtextobject.h:61
The QTextOption class provides a description of general rich text properties. \inmodule QtGui.
Definition: qtextoption.h:54
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:62
The QTextTableCellFormat class provides formatting information for table cells in a QTextDocument....
Definition: qtextformat.h:1041
QBrush leftBorderBrush() const
Definition: qtextformat.h:1117
QTextFrameFormat::BorderStyle bottomBorderStyle() const
Definition: qtextformat.h:1090
QTextFrameFormat::BorderStyle rightBorderStyle() const
Definition: qtextformat.h:1100
QBrush rightBorderBrush() const
Definition: qtextformat.h:1122
qreal rightBorder() const
Definition: qtextformat.h:1078
qreal leftBorder() const
Definition: qtextformat.h:1073
qreal topPadding() const
Definition: qtextformat.h:1141
QBrush topBorderBrush() const
Definition: qtextformat.h:1107
qreal bottomBorder() const
Definition: qtextformat.h:1068
qreal leftPadding() const
Definition: qtextformat.h:1161
qreal rightPadding() const
Definition: qtextformat.h:1171
QBrush bottomBorderBrush() const
Definition: qtextformat.h:1112
QTextFrameFormat::BorderStyle leftBorderStyle() const
Definition: qtextformat.h:1095
qreal bottomPadding() const
Definition: qtextformat.h:1151
QTextFrameFormat::BorderStyle topBorderStyle() const
Definition: qtextformat.h:1085
qreal topBorder() const
Definition: qtextformat.h:1063
The QTextTableCell class represents the properties of a cell in a QTextTable. \inmodule QtGui.
Definition: qtexttable.h:55
QTextCharFormat format() const
Definition: qtexttable.cpp:138
int columnSpan() const
Definition: qtexttable.cpp:210
int row() const
Definition: qtexttable.cpp:166
int rowSpan() const
Definition: qtexttable.cpp:200
int column() const
Definition: qtexttable.cpp:183
QTextFrame::iterator begin() const
Definition: qtexttable.cpp:279
The QTextTableFormat class provides formatting information for tables in a QTextDocument....
Definition: qtextformat.h:978
The QTextTable class represents a table in a QTextDocument. \inmodule QtGui.
Definition: qtexttable.h:99
static QThread * currentThread()
Definition: qthread.cpp:879
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:130
static QUrl fromLocalFile(const QString &localfile)
Definition: qurl.cpp:3373
QUrl resolved(const QUrl &relative) const
Definition: qurl.cpp:2745
bool isRelative() const
Definition: qurl.cpp:2820
bool isEmpty() const
Definition: qurl.cpp:1911
QString scheme() const
Definition: qurl.cpp:2006
void setScheme(const QString &scheme)
Definition: qurl.cpp:1982
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Definition: qurl.cpp:2851
QString toLocalFile() const
Definition: qurl.cpp:3430
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:95
QString text
[meta data]
QCursor cursor
double e
rect
[4]
union Alignment_ Alignment
backing_store_ptr info
[4]
Definition: jmemsys.h:161
JOCTET JCOEFPTR block
Definition: jsimd.h:109
short next
Definition: keywords.cpp:454
std::string toLower(std::string const &s)
@ StyleSheetOrigin_UserAgent
Definition: qcssparser_p.h:630
@ AlignRight
Definition: qnamespace.h:171
@ AlignJustify
Definition: qnamespace.h:174
@ AlignHCenter
Definition: qnamespace.h:173
@ AlignLeft
Definition: qnamespace.h:169
Q_GUI_EXPORT QString convertFromPlainText(const QString &plain, WhiteSpaceMode mode=WhiteSpacePre)
@ RightToLeft
Definition: qnamespace.h:1464
@ black
Definition: qnamespace.h:61
WhiteSpaceMode
Definition: qnamespace.h:221
@ WhiteSpacePre
Definition: qnamespace.h:223
CaseSensitivity
Definition: qnamespace.h:1282
@ CaseInsensitive
Definition: qnamespace.h:1283
@ CaseSensitive
Definition: qnamespace.h:1284
@ SolidPattern
Definition: qnamespace.h:1141
@ TexturePattern
Definition: qnamespace.h:1158
@ NoBrush
Definition: qnamespace.h:1140
CursorMoveStyle
Definition: qnamespace.h:1684
Q_GUI_EXPORT bool mightBeRichText(const QString &)
Definition: brush.cpp:52
parser
Definition: devices.py:74
Definition: image.cpp:51
#define QString()
Definition: parse-defines.h:51
void
Definition: png.h:1080
#define Q_DECL_CONST_FUNCTION
#define Q_UNREACHABLE()
#define qApp
QT_BEGIN_NAMESPACE Q_CORE_EXPORT bool qDecodeDataUrl(const QUrl &uri, QString &mimeType, QByteArray &payload)
Definition: qdataurl.cpp:52
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
EGLOutputLayerEXT EGLint attribute
int qRound(qfloat16 d) noexcept
Definition: qfloat16.h:227
Q_GUI_EXPORT int qt_defaultDpiX()
Definition: qfont.cpp:141
Q_GUI_EXPORT int qt_defaultDpiY()
Definition: qfont.cpp:156
QT_END_INCLUDE_NAMESPACE typedef double qreal
Definition: qglobal.h:341
unsigned int uint
Definition: qglobal.h:334
long long qint64
Definition: qglobal.h:298
unsigned char quint8
Definition: qglobal.h:284
@ text
#define Q_ARG(type, data)
Definition: qobjectdefs.h:98
#define Q_RETURN_ARG(type, data)
Definition: qobjectdefs.h:99
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLenum type
Definition: qopengl.h:270
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLenum mode
const GLfloat * m
GLboolean r
[2]
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLdouble GLdouble GLdouble GLdouble top
GLdouble GLdouble right
GLfloat GLfloat f
GLint GLsizei width
GLuint color
[2]
GLint left
GLint GLint bottom
GLboolean enable
GLenum GLuint GLsizei const GLenum * props
GLuint start
GLenum GLuint GLintptr offset
GLuint name
GLint first
GLfloat n
GLint GLsizei GLsizei GLenum format
GLeglImageOES image
GLhandleARB obj
[2]
Definition: qopenglext.h:4164
const GLubyte * c
Definition: qopenglext.h:12701
GLuint GLuint * names
Definition: qopenglext.h:5654
GLenum GLenum GLsizei void * row
Definition: qopenglext.h:2747
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLuint GLenum option
Definition: qopenglext.h:5929
GLenum GLenum GLsizei void * table
Definition: qopenglext.h:2745
GLsizei const GLchar *const * string
[0]
Definition: qopenglext.h:694
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define Q_ASSERT_X(cond, x, msg)
Definition: qrandom.cpp:85
QT_BEGIN_NAMESPACE Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
Definition: qglobal.cpp:3321
bool qHasPixmapTexture(const QBrush &brush)
Definition: qbrush.cpp:235
#define QTextBeginningOfFrame
#define QTextEndOfFrame
#define emit
Definition: qtmetamacros.h:85
Q_UNUSED(salary)
[21]
file open(QIODevice::ReadOnly)
QFileInfo fi("c:/temp/foo")
[newstuff]
QUrl url("http://www.example.com/List of holidays.xml")
[0]
QVBoxLayout * layout
QString title
[35]
QByteArray page
[45]
Text files * txt
QGraphicsItem * item
QPainter painter(this)
[7]
QSizePolicy policy
content text html
QQuickView * view
[0]
QStringList::Iterator it
QStringList list
[0]
The QAbstractTextDocumentLayout::PaintContext class is a convenience class defining the parameters us...
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
The QMetaObject class contains meta-information about Qt objects.
Definition: qobjectdefs.h:165
int indexOfMethod(const char *method) const
QMetaMethod method(int index) const
void compare(Input input, FnUnderTest fn_under_test, const QByteArray &output)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
XmlOutput::xml_output tag(const QString &name)
Definition: xmloutput.h:154