Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qtexthtmlparser.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtexthtmlparser_p.h"
5
6#include <qbytearray.h>
7#include <qstack.h>
8#include <qdebug.h>
9#include <qthread.h>
10#include <qguiapplication.h>
11
12#include "qtextdocument.h"
13#include "qtextformat_p.h"
14#include "qtextdocument_p.h"
15#include "qtextcursor.h"
16#include "qfont_p.h"
17
18#include <algorithm>
19
20#ifndef QT_NO_TEXTHTMLPARSER
21
23
24using namespace Qt::StringLiterals;
25
26// see also tst_qtextdocumentfragment.cpp
27#define MAX_ENTITY 258
28static const struct QTextHtmlEntity { const char name[9]; char16_t code; } entities[]= {
29 { "AElig", 0x00c6 },
30 { "AMP", 38 },
31 { "Aacute", 0x00c1 },
32 { "Acirc", 0x00c2 },
33 { "Agrave", 0x00c0 },
34 { "Alpha", 0x0391 },
35 { "Aring", 0x00c5 },
36 { "Atilde", 0x00c3 },
37 { "Auml", 0x00c4 },
38 { "Beta", 0x0392 },
39 { "Ccedil", 0x00c7 },
40 { "Chi", 0x03a7 },
41 { "Dagger", 0x2021 },
42 { "Delta", 0x0394 },
43 { "ETH", 0x00d0 },
44 { "Eacute", 0x00c9 },
45 { "Ecirc", 0x00ca },
46 { "Egrave", 0x00c8 },
47 { "Epsilon", 0x0395 },
48 { "Eta", 0x0397 },
49 { "Euml", 0x00cb },
50 { "GT", 62 },
51 { "Gamma", 0x0393 },
52 { "Iacute", 0x00cd },
53 { "Icirc", 0x00ce },
54 { "Igrave", 0x00cc },
55 { "Iota", 0x0399 },
56 { "Iuml", 0x00cf },
57 { "Kappa", 0x039a },
58 { "LT", 60 },
59 { "Lambda", 0x039b },
60 { "Mu", 0x039c },
61 { "Ntilde", 0x00d1 },
62 { "Nu", 0x039d },
63 { "OElig", 0x0152 },
64 { "Oacute", 0x00d3 },
65 { "Ocirc", 0x00d4 },
66 { "Ograve", 0x00d2 },
67 { "Omega", 0x03a9 },
68 { "Omicron", 0x039f },
69 { "Oslash", 0x00d8 },
70 { "Otilde", 0x00d5 },
71 { "Ouml", 0x00d6 },
72 { "Phi", 0x03a6 },
73 { "Pi", 0x03a0 },
74 { "Prime", 0x2033 },
75 { "Psi", 0x03a8 },
76 { "QUOT", 34 },
77 { "Rho", 0x03a1 },
78 { "Scaron", 0x0160 },
79 { "Sigma", 0x03a3 },
80 { "THORN", 0x00de },
81 { "Tau", 0x03a4 },
82 { "Theta", 0x0398 },
83 { "Uacute", 0x00da },
84 { "Ucirc", 0x00db },
85 { "Ugrave", 0x00d9 },
86 { "Upsilon", 0x03a5 },
87 { "Uuml", 0x00dc },
88 { "Xi", 0x039e },
89 { "Yacute", 0x00dd },
90 { "Yuml", 0x0178 },
91 { "Zeta", 0x0396 },
92 { "aacute", 0x00e1 },
93 { "acirc", 0x00e2 },
94 { "acute", 0x00b4 },
95 { "aelig", 0x00e6 },
96 { "agrave", 0x00e0 },
97 { "alefsym", 0x2135 },
98 { "alpha", 0x03b1 },
99 { "amp", 38 },
100 { "and", 0x22a5 },
101 { "ang", 0x2220 },
102 { "apos", 0x0027 },
103 { "aring", 0x00e5 },
104 { "asymp", 0x2248 },
105 { "atilde", 0x00e3 },
106 { "auml", 0x00e4 },
107 { "bdquo", 0x201e },
108 { "beta", 0x03b2 },
109 { "brvbar", 0x00a6 },
110 { "bull", 0x2022 },
111 { "cap", 0x2229 },
112 { "ccedil", 0x00e7 },
113 { "cedil", 0x00b8 },
114 { "cent", 0x00a2 },
115 { "chi", 0x03c7 },
116 { "circ", 0x02c6 },
117 { "clubs", 0x2663 },
118 { "cong", 0x2245 },
119 { "copy", 0x00a9 },
120 { "crarr", 0x21b5 },
121 { "cup", 0x222a },
122 { "curren", 0x00a4 },
123 { "dArr", 0x21d3 },
124 { "dagger", 0x2020 },
125 { "darr", 0x2193 },
126 { "deg", 0x00b0 },
127 { "delta", 0x03b4 },
128 { "diams", 0x2666 },
129 { "divide", 0x00f7 },
130 { "eacute", 0x00e9 },
131 { "ecirc", 0x00ea },
132 { "egrave", 0x00e8 },
133 { "empty", 0x2205 },
134 { "emsp", 0x2003 },
135 { "ensp", 0x2002 },
136 { "epsilon", 0x03b5 },
137 { "equiv", 0x2261 },
138 { "eta", 0x03b7 },
139 { "eth", 0x00f0 },
140 { "euml", 0x00eb },
141 { "euro", 0x20ac },
142 { "exist", 0x2203 },
143 { "fnof", 0x0192 },
144 { "forall", 0x2200 },
145 { "frac12", 0x00bd },
146 { "frac14", 0x00bc },
147 { "frac34", 0x00be },
148 { "frasl", 0x2044 },
149 { "gamma", 0x03b3 },
150 { "ge", 0x2265 },
151 { "gt", 62 },
152 { "hArr", 0x21d4 },
153 { "harr", 0x2194 },
154 { "hearts", 0x2665 },
155 { "hellip", 0x2026 },
156 { "iacute", 0x00ed },
157 { "icirc", 0x00ee },
158 { "iexcl", 0x00a1 },
159 { "igrave", 0x00ec },
160 { "image", 0x2111 },
161 { "infin", 0x221e },
162 { "int", 0x222b },
163 { "iota", 0x03b9 },
164 { "iquest", 0x00bf },
165 { "isin", 0x2208 },
166 { "iuml", 0x00ef },
167 { "kappa", 0x03ba },
168 { "lArr", 0x21d0 },
169 { "lambda", 0x03bb },
170 { "lang", 0x2329 },
171 { "laquo", 0x00ab },
172 { "larr", 0x2190 },
173 { "lceil", 0x2308 },
174 { "ldquo", 0x201c },
175 { "le", 0x2264 },
176 { "lfloor", 0x230a },
177 { "lowast", 0x2217 },
178 { "loz", 0x25ca },
179 { "lrm", 0x200e },
180 { "lsaquo", 0x2039 },
181 { "lsquo", 0x2018 },
182 { "lt", 60 },
183 { "macr", 0x00af },
184 { "mdash", 0x2014 },
185 { "micro", 0x00b5 },
186 { "middot", 0x00b7 },
187 { "minus", 0x2212 },
188 { "mu", 0x03bc },
189 { "nabla", 0x2207 },
190 { "nbsp", 0x00a0 },
191 { "ndash", 0x2013 },
192 { "ne", 0x2260 },
193 { "ni", 0x220b },
194 { "not", 0x00ac },
195 { "notin", 0x2209 },
196 { "nsub", 0x2284 },
197 { "ntilde", 0x00f1 },
198 { "nu", 0x03bd },
199 { "oacute", 0x00f3 },
200 { "ocirc", 0x00f4 },
201 { "oelig", 0x0153 },
202 { "ograve", 0x00f2 },
203 { "oline", 0x203e },
204 { "omega", 0x03c9 },
205 { "omicron", 0x03bf },
206 { "oplus", 0x2295 },
207 { "or", 0x22a6 },
208 { "ordf", 0x00aa },
209 { "ordm", 0x00ba },
210 { "oslash", 0x00f8 },
211 { "otilde", 0x00f5 },
212 { "otimes", 0x2297 },
213 { "ouml", 0x00f6 },
214 { "para", 0x00b6 },
215 { "part", 0x2202 },
216 { "percnt", 0x0025 },
217 { "permil", 0x2030 },
218 { "perp", 0x22a5 },
219 { "phi", 0x03c6 },
220 { "pi", 0x03c0 },
221 { "piv", 0x03d6 },
222 { "plusmn", 0x00b1 },
223 { "pound", 0x00a3 },
224 { "prime", 0x2032 },
225 { "prod", 0x220f },
226 { "prop", 0x221d },
227 { "psi", 0x03c8 },
228 { "quot", 34 },
229 { "rArr", 0x21d2 },
230 { "radic", 0x221a },
231 { "rang", 0x232a },
232 { "raquo", 0x00bb },
233 { "rarr", 0x2192 },
234 { "rceil", 0x2309 },
235 { "rdquo", 0x201d },
236 { "real", 0x211c },
237 { "reg", 0x00ae },
238 { "rfloor", 0x230b },
239 { "rho", 0x03c1 },
240 { "rlm", 0x200f },
241 { "rsaquo", 0x203a },
242 { "rsquo", 0x2019 },
243 { "sbquo", 0x201a },
244 { "scaron", 0x0161 },
245 { "sdot", 0x22c5 },
246 { "sect", 0x00a7 },
247 { "shy", 0x00ad },
248 { "sigma", 0x03c3 },
249 { "sigmaf", 0x03c2 },
250 { "sim", 0x223c },
251 { "spades", 0x2660 },
252 { "sub", 0x2282 },
253 { "sube", 0x2286 },
254 { "sum", 0x2211 },
255 { "sup", 0x2283 },
256 { "sup1", 0x00b9 },
257 { "sup2", 0x00b2 },
258 { "sup3", 0x00b3 },
259 { "supe", 0x2287 },
260 { "szlig", 0x00df },
261 { "tau", 0x03c4 },
262 { "there4", 0x2234 },
263 { "theta", 0x03b8 },
264 { "thetasym", 0x03d1 },
265 { "thinsp", 0x2009 },
266 { "thorn", 0x00fe },
267 { "tilde", 0x02dc },
268 { "times", 0x00d7 },
269 { "trade", 0x2122 },
270 { "uArr", 0x21d1 },
271 { "uacute", 0x00fa },
272 { "uarr", 0x2191 },
273 { "ucirc", 0x00fb },
274 { "ugrave", 0x00f9 },
275 { "uml", 0x00a8 },
276 { "upsih", 0x03d2 },
277 { "upsilon", 0x03c5 },
278 { "uuml", 0x00fc },
279 { "weierp", 0x2118 },
280 { "xi", 0x03be },
281 { "yacute", 0x00fd },
282 { "yen", 0x00a5 },
283 { "yuml", 0x00ff },
284 { "zeta", 0x03b6 },
285 { "zwj", 0x200d },
286 { "zwnj", 0x200c }
288static_assert(MAX_ENTITY == sizeof entities / sizeof *entities);
289
290#if defined(Q_CC_MSVC_ONLY) && _MSC_VER < 1600
291bool operator<(const QTextHtmlEntity &entity1, const QTextHtmlEntity &entity2)
292{
293 return QLatin1StringView(entity1.name) < QLatin1StringView(entity2.name);
294}
295#endif
296
297static bool operator<(QStringView entityStr, const QTextHtmlEntity &entity)
298{
299 return entityStr < QLatin1StringView(entity.name);
300}
301
302static bool operator<(const QTextHtmlEntity &entity, QStringView entityStr)
303{
304 return QLatin1StringView(entity.name) < entityStr;
305}
306
308{
309 const QTextHtmlEntity *start = &entities[0];
311 const QTextHtmlEntity *e = std::lower_bound(start, end, entity);
312 if (e == end || (entity < *e))
313 return QChar();
314 return e->code;
315}
316
317static const ushort windowsLatin1ExtendedCharacters[0xA0 - 0x80] = {
318 0x20ac, // 0x80
319 0x0081, // 0x81 direct mapping
320 0x201a, // 0x82
321 0x0192, // 0x83
322 0x201e, // 0x84
323 0x2026, // 0x85
324 0x2020, // 0x86
325 0x2021, // 0x87
326 0x02C6, // 0x88
327 0x2030, // 0x89
328 0x0160, // 0x8A
329 0x2039, // 0x8B
330 0x0152, // 0x8C
331 0x008D, // 0x8D direct mapping
332 0x017D, // 0x8E
333 0x008F, // 0x8F directmapping
334 0x0090, // 0x90 directmapping
335 0x2018, // 0x91
336 0x2019, // 0x92
337 0x201C, // 0x93
338 0X201D, // 0x94
339 0x2022, // 0x95
340 0x2013, // 0x96
341 0x2014, // 0x97
342 0x02DC, // 0x98
343 0x2122, // 0x99
344 0x0161, // 0x9A
345 0x203A, // 0x9B
346 0x0153, // 0x9C
347 0x009D, // 0x9D direct mapping
348 0x017E, // 0x9E
349 0x0178 // 0x9F
350};
351
352// the displayMode value is according to the what are blocks in the piecetable, not
353// what the w3c defines.
392 { "qt", Html_body /*deliberate mapping*/, QTextHtmlElement::DisplayBlock },
414};
415
416static bool operator<(const QString &str, const QTextHtmlElement &e)
417{
418 return str < QLatin1StringView(e.name);
419}
420
421static bool operator<(const QTextHtmlElement &e, const QString &str)
422{
423 return QLatin1StringView(e.name) < str;
424}
425
426static const QTextHtmlElement *lookupElementHelper(const QString &element)
427{
428 const QTextHtmlElement *start = &elements[0];
430 const QTextHtmlElement *e = std::lower_bound(start, end, element);
431 if ((e == end) || (element < *e))
432 return nullptr;
433 return e;
434}
435
437{
438 const QTextHtmlElement *e = lookupElementHelper(element);
439 if (!e)
440 return -1;
441 return e->id;
442}
443
444// quotes newlines as "\\n"
446{
447 QString n = s;
448 n.replace(u'\n', "\\n"_L1);
449 return n;
450}
451
453 : parent(0), id(Html_unknown),
454 cssFloat(QTextFrameFormat::InFlow), hasOwnListStyle(false), hasOwnLineHeightType(false), hasLineHeightMultiplier(false),
455 hasCssListIndent(false), isEmptyParagraph(false), isTextFrame(false), isRootFrame(false),
456 displayMode(QTextHtmlElement::DisplayInline), hasHref(false),
457 listStyle(QTextListFormat::ListStyleUndefined), imageWidth(-1), imageHeight(-1), tableBorder(0),
458 tableCellRowSpan(1), tableCellColSpan(1), tableCellSpacing(2), tableCellPadding(0),
459 borderBrush(Qt::darkGray), borderStyle(QTextFrameFormat::BorderStyle_Outset),
460 borderCollapse(false),
461 userState(-1), cssListIndent(0), wsm(WhiteSpaceModeUndefined)
462{
467
468 for (int i = 0; i < 4; ++i) {
470 tableCellBorder[i] = 0;
472 }
473}
474
476{
477 for (int i = 0; i < count(); ++i) {
478 qDebug().nospace() << qPrintable(QString(depth(i) * 4, u' '))
479 << qPrintable(at(i).tag) << ':'
480 << quoteNewline(at(i).text);
481 }
482}
483
485{
486 QTextHtmlParserNode *lastNode = nodes.last();
487 QTextHtmlParserNode *newNode = nullptr;
488
489 bool reuseLastNode = true;
490
491 if (nodes.size() == 1) {
492 reuseLastNode = false;
493 } else if (lastNode->tag.isEmpty()) {
494
495 if (lastNode->text.isEmpty()) {
496 reuseLastNode = true;
497 } else { // last node is a text node (empty tag) with some text
498
499 if (lastNode->text.size() == 1 && lastNode->text.at(0).isSpace()) {
500
501 int lastSibling = count() - 2;
502 while (lastSibling
503 && at(lastSibling).parent != lastNode->parent
504 && at(lastSibling).displayMode == QTextHtmlElement::DisplayInline) {
505 lastSibling = at(lastSibling).parent;
506 }
507
508 if (at(lastSibling).displayMode == QTextHtmlElement::DisplayInline) {
509 reuseLastNode = false;
510 } else {
511 reuseLastNode = true;
512 }
513 } else {
514 // text node with real (non-whitespace) text -> nothing to re-use
515 reuseLastNode = false;
516 }
517
518 }
519
520 } else {
521 // last node had a proper tag -> nothing to re-use
522 reuseLastNode = false;
523 }
524
525 if (reuseLastNode) {
526 newNode = lastNode;
527 newNode->tag.clear();
528 newNode->text.clear();
530 } else {
532 newNode = nodes.last();
533 }
534
536 return newNode;
537}
538
539void QTextHtmlParser::parse(const QString &text, const QTextDocument *_resourceProvider)
540{
542 nodes.clear();
544 txt = text;
545 pos = 0;
546 len = txt.size();
547 textEditMode = false;
548 resourceProvider = _resourceProvider;
549 parse();
550 //dumpHtml();
551}
552
554{
555 int depth = 0;
556 while (i) {
557 i = at(i).parent;
558 ++depth;
559 }
560 return depth;
561}
562
563int QTextHtmlParser::margin(int i, int mar) const {
564 int m = 0;
565 const QTextHtmlParserNode *node;
566 if (mar == MarginLeft
567 || mar == MarginRight) {
568 while (i) {
569 node = &at(i);
570 if (!node->isBlock() && node->id != Html_table)
571 break;
572 if (node->isTableCell())
573 break;
574 m += node->margin[mar];
575 i = node->parent;
576 }
577 }
578 return m;
579}
580
582{
583 if (!i)
584 return 0;
585 return at(i).margin[MarginTop];
586}
587
589{
590 if (!i)
591 return 0;
592 return at(i).margin[MarginBottom];
593}
594
596{
597 while (pos < len && txt.at(pos).isSpace() && txt.at(pos) != QChar::ParagraphSeparator)
598 pos++;
599}
600
602{
603 while (pos < len) {
604 QChar c = txt.at(pos++);
605 if (c == u'<') {
606 parseTag();
607 } else if (c == u'&') {
608 nodes.last()->text += parseEntity();
609 } else {
610 nodes.last()->text += c;
611 }
612 }
613}
614
615// parses a tag after "<"
617{
618 eatSpace();
619
620 // handle comments and other exclamation mark declarations
621 if (hasPrefix(u'!')) {
625 && !textEditMode)
626 eatSpace();
627 return;
628 }
629
630 // if close tag just close
631 if (hasPrefix(u'/')) {
632 if (nodes.last()->id == Html_style) {
633#ifndef QT_NO_CSSPARSER
634 QCss::Parser parser(nodes.constLast()->text);
635 QCss::StyleSheet sheet;
637 parser.parse(&sheet, Qt::CaseInsensitive);
638 inlineStyleSheets.append(sheet);
639 resolveStyleSheetImports(sheet);
640#endif
641 }
643 return;
644 }
645
646 int p = last();
647 while (p && at(p).tag.size() == 0)
648 p = at(p).parent;
649
651
652 // parse tag name
653 node->tag = parseWord().toLower();
654
655 const QTextHtmlElement *elem = lookupElementHelper(node->tag);
656 if (elem) {
657 node->id = elem->id;
658 node->displayMode = elem->displayMode;
659 } else {
660 node->id = Html_unknown;
661 }
662
663 node->attributes.clear();
664 // _need_ at least one space after the tag name, otherwise there can't be attributes
665 if (pos < len && txt.at(pos).isSpace())
666 node->attributes = parseAttributes();
667
668 // resolveParent() may have to change the order in the tree and
669 // insert intermediate nodes for buggy HTML, so re-initialize the 'node'
670 // pointer through the return value
671 node = resolveParent();
672 resolveNode();
673
674#ifndef QT_NO_CSSPARSER
675 const int nodeIndex = nodes.size() - 1; // this new node is always the last
676 node->applyCssDeclarations(declarationsForNode(nodeIndex), resourceProvider);
677#endif
679
680 // finish tag
681 bool tagClosed = false;
682 while (pos < len && txt.at(pos) != u'>') {
683 if (txt.at(pos) == u'/')
684 tagClosed = true;
685
686 pos++;
687 }
688 pos++;
689
690 // in a white-space preserving environment strip off a initial newline
691 // since the element itself already generates a newline
695 && node->isBlock()) {
696 if (pos < len - 1 && txt.at(pos) == u'\n')
697 ++pos;
698 }
699
700 if (node->mayNotHaveChildren() || tagClosed) {
701 newNode(node->parent);
702 resolveNode();
703 }
704}
705
706// parses a tag beginning with "/"
708{
709 ++pos;
711 while (pos < len) {
712 QChar c = txt.at(pos++);
713 if (c == u'>')
714 break;
715 }
716
717 // find corresponding open node
718 int p = last();
719 if (p > 0
720 && at(p - 1).tag == tag
721 && at(p - 1).mayNotHaveChildren())
722 p--;
723
724 while (p && at(p).tag != tag)
725 p = at(p).parent;
726
727 // simply ignore the tag if we can't find
728 // a corresponding open node, for broken
729 // html such as <font>blah</font></font>
730 if (!p)
731 return;
732
733 // in a white-space preserving environment strip off a trailing newline
734 // since the closing of the opening block element will automatically result
735 // in a new block for elements following the <pre>
736 // ...foo\n</pre><p>blah -> foo</pre><p>blah
740 && at(p).isBlock()) {
741 if (at(last()).text.endsWith(u'\n'))
742 nodes[last()]->text.chop(1);
743 }
744
745 newNode(at(p).parent);
746 resolveNode();
747}
748
749// parses a tag beginning with "!"
751{
752 ++pos;
753 if (hasPrefix(u'-') && hasPrefix(u'-', 1)) {
754 pos += 2;
755 // eat comments
756 int end = txt.indexOf("-->"_L1, pos);
757 pos = (end >= 0 ? end + 3 : len);
758 } else {
759 // eat internal tags
760 while (pos < len) {
761 QChar c = txt.at(pos++);
762 if (c == u'>')
763 break;
764 }
765 }
766}
767
769{
770 QChar resolved = resolveEntity(entity);
771 if (!resolved.isNull())
772 return QString(resolved);
773
774 if (entity.size() > 1 && entity.at(0) == u'#') {
775 entity = entity.mid(1); // removing leading #
776
777 int base = 10;
778 bool ok = false;
779
780 if (entity.at(0).toLower() == u'x') { // hex entity?
781 entity = entity.mid(1);
782 base = 16;
783 }
784
785 uint uc = entity.toUInt(&ok, base);
786 if (ok) {
787 if (uc >= 0x80 && uc < 0x80 + (sizeof(windowsLatin1ExtendedCharacters)/sizeof(windowsLatin1ExtendedCharacters[0])))
788 uc = windowsLatin1ExtendedCharacters[uc - 0x80];
789 return QStringView{QChar::fromUcs4(uc)}.toString();
790 }
791 }
792 return {};
793}
794
795// parses an entity after "&", and returns it
797{
798 const int recover = pos;
799 int entityLen = 0;
800 while (pos < len) {
801 QChar c = txt.at(pos++);
802 if (c.isSpace() || pos - recover > 9) {
803 goto error;
804 }
805 if (c == u';')
806 break;
807 ++entityLen;
808 }
809 if (entityLen) {
810 const QStringView entity = QStringView(txt).mid(recover, entityLen);
811 QString parsedEntity = parseEntity(entity);
812 if (!parsedEntity.isNull()) {
813 return parsedEntity;
814 }
815 }
816error:
817 pos = recover;
818 return "&"_L1;
819}
820
821// parses one word, possibly quoted, and returns it
823{
824 QString word;
825 if (hasPrefix(u'\"')) { // double quotes
826 ++pos;
827 while (pos < len) {
828 QChar c = txt.at(pos++);
829 if (c == u'\"')
830 break;
831 else if (c == u'&')
832 word += parseEntity();
833 else
834 word += c;
835 }
836 } else if (hasPrefix(u'\'')) { // single quotes
837 ++pos;
838 while (pos < len) {
839 QChar c = txt.at(pos++);
840 // Allow for escaped single quotes as they may be part of the string
841 if (c == u'\'' && (txt.size() > 1 && txt.at(pos - 2) != u'\\'))
842 break;
843 else
844 word += c;
845 }
846 } else { // normal text
847 while (pos < len) {
848 QChar c = txt.at(pos++);
849 if (c == u'>' || (c == u'/' && hasPrefix(u'>'))
850 || c == u'<' || c == u'=' || c.isSpace()) {
851 --pos;
852 break;
853 }
854 if (c == u'&')
855 word += parseEntity();
856 else
857 word += c;
858 }
859 }
860 return word;
861}
862
863// gives the new node the right parent
865{
867
868 int p = node->parent;
869
870 // Excel gives us buggy HTML with just tr without surrounding table tags
871 // or with just td tags
872
873 if (node->id == Html_td) {
874 int n = p;
875 while (n && at(n).id != Html_tr)
876 n = at(n).parent;
877
878 if (!n) {
881
883 table->parent = p;
884 table->id = Html_table;
885 table->tag = "table"_L1;
886 table->children.append(nodes.size() - 2); // add row as child
887
889 row->parent = nodes.size() - 3; // table as parent
890 row->id = Html_tr;
891 row->tag = "tr"_L1;
892
893 p = nodes.size() - 2;
894 node = nodes.last(); // re-initialize pointer
895 }
896 }
897
898 if (node->id == Html_tr) {
899 int n = p;
900 while (n && at(n).id != Html_table)
901 n = at(n).parent;
902
903 if (!n) {
906 table->parent = p;
907 table->id = Html_table;
908 table->tag = "table"_L1;
909 p = nodes.size() - 2;
910 node = nodes.last(); // re-initialize pointer
911 }
912 }
913
914 // permit invalid html by letting block elements be children
915 // of inline elements with the exception of paragraphs:
916 //
917 // a new paragraph closes parent inline elements (while loop),
918 // unless they themselves are children of a non-paragraph block
919 // element (if statement)
920 //
921 // For example:
922 //
923 // <body><p><b>Foo<p>Bar <-- second <p> implicitly closes <b> that
924 // belongs to the first <p>. The self-nesting
925 // check further down prevents the second <p>
926 // from nesting into the first one then.
927 // so Bar is not bold.
928 //
929 // <body><b><p>Foo <-- Foo should be bold.
930 //
931 // <body><b><p>Foo<p>Bar <-- Foo and Bar should be bold.
932 //
933 if (node->id == Html_p) {
934 while (p && !at(p).isBlock())
935 p = at(p).parent;
936
937 if (!p || at(p).id != Html_p)
938 p = node->parent;
939 }
940
941 // some elements are not self nesting
942 if (node->id == at(p).id
943 && node->isNotSelfNesting())
944 p = at(p).parent;
945
946 // some elements are not allowed in certain contexts
947 while ((p && !node->allowedInContext(at(p).id))
948 // ### make new styles aware of empty tags
949 || at(p).mayNotHaveChildren()
950 ) {
951 p = at(p).parent;
952 }
953
954 node->parent = p;
955
956 // makes it easier to traverse the tree, later
957 nodes[p]->children.append(nodes.size() - 1);
958 return node;
959}
960
961// sets all properties on the new node
963{
965 const QTextHtmlParserNode *parent = nodes.at(node->parent);
966 node->initializeProperties(parent, this);
967}
968
970{
971 if (!isListStart())
972 return false;
973
974 int p = parent;
975 while (p) {
976 if (parser->at(p).isListStart())
977 return true;
978 p = parser->at(p).parent;
979 }
980 return false;
981}
982
984{
985 // inherit properties from parent element
986 charFormat = parent->charFormat;
987
988 if (id == Html_html)
990 else if (parent->blockFormat.hasProperty(QTextFormat::LayoutDirection))
991 blockFormat.setLayoutDirection(parent->blockFormat.layoutDirection());
992
993 if (parent->displayMode == QTextHtmlElement::DisplayNone)
995
996 if (parent->id != Html_table || id == Html_caption) {
997 if (parent->blockFormat.hasProperty(QTextFormat::BlockAlignment))
998 blockFormat.setAlignment(parent->blockFormat.alignment());
999 else
1001 }
1002 // we don't paint per-row background colors, yet. so as an
1003 // exception inherit the background color here
1004 // we also inherit the background between inline elements
1005 // we also inherit from non-body block elements since we merge them together
1006 if ((parent->id != Html_tr || !isTableCell())
1009 ) {
1011 }
1012
1013 listStyle = parent->listStyle;
1014 // makes no sense to inherit that property, a named anchor is a single point
1015 // in the document, which is set by the DocumentFragment
1017 wsm = parent->wsm;
1018
1019 // initialize remaining properties
1025
1026 for (int i = 0; i < 4; ++i)
1027 padding[i] = -1;
1028
1029 // set element specific attributes
1030 switch (id) {
1031 case Html_a:
1032 for (int i = 0; i < attributes.size(); i += 2) {
1033 const QString key = attributes.at(i);
1034 if (key.compare("href"_L1, Qt::CaseInsensitive) == 0
1035 && !attributes.at(i + 1).isEmpty()) {
1036 hasHref = true;
1037 }
1038 }
1039 charFormat.setAnchor(true);
1040 break;
1041 case Html_big:
1043 break;
1044 case Html_small:
1046 break;
1047 case Html_h1:
1051 break;
1052 case Html_h2:
1056 break;
1057 case Html_h3:
1061 break;
1062 case Html_h4:
1066 break;
1067 case Html_h5:
1071 break;
1072 case Html_p:
1075 break;
1076 case Html_ul:
1077 // nested lists don't have margins, except for the toplevel one
1078 if (!isNestedList(parser)) {
1081 }
1082 // no left margin as we use indenting instead
1083 break;
1084 case Html_ol:
1085 // nested lists don't have margins, except for the toplevel one
1086 if (!isNestedList(parser)) {
1089 }
1090 // no left margin as we use indenting instead
1091 break;
1092 case Html_br:
1094 break;
1095 case Html_pre:
1098 break;
1099 case Html_blockquote:
1105 break;
1106 case Html_dl:
1109 break;
1110 case Html_dd:
1112 break;
1113 default: break;
1114 }
1115}
1116
1117#ifndef QT_NO_CSSPARSER
1118void QTextHtmlParserNode::setListStyle(const QList<QCss::Value> &cssValues)
1119{
1120 for (int i = 0; i < cssValues.size(); ++i) {
1121 if (cssValues.at(i).type == QCss::Value::KnownIdentifier) {
1122 switch (static_cast<QCss::KnownValue>(cssValues.at(i).variant.toInt())) {
1132 default: break;
1133 }
1134 }
1135 }
1136 // allow individual list items to override the style
1137 if (id == Html_li && hasOwnListStyle)
1139}
1140
1142{
1143 switch (cssStyle) {
1169 break;
1170 // Intentionally no "default" to allow a compiler warning when extending the enum
1171 // without updating this here. clang gives such a warning.
1172 }
1173 // Must not happen, intentionally trigger undefined behavior which sanitizers will detect.
1174 // Having all cases covered in switch is not sufficient:
1175 // MSVC would warn when there is no "default".
1176 return static_cast<QTextFrameFormat::BorderStyle>(-1);
1177}
1178
1179void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &declarations, const QTextDocument *resourceProvider)
1180{
1181 QCss::ValueExtractor extractor(declarations);
1182 extractor.extractBox(margin, padding);
1183
1184 if (id == Html_td || id == Html_th) {
1185 QCss::BorderStyle cssStyles[4];
1186 int cssBorder[4];
1187 QSize cssRadii[4]; // unused
1188 for (int i = 0; i < 4; ++i) {
1189 cssStyles[i] = QCss::BorderStyle_None;
1190 cssBorder[i] = 0;
1191 }
1192 // this will parse (and cache) "border-width" as a list so the
1193 // QCss::BorderWidth parsing below which expects a single value
1194 // will not work as expected - which in this case does not matter
1195 // because tableBorder is not relevant for cells.
1196 extractor.extractBorder(cssBorder, tableCellBorderBrush, cssStyles, cssRadii);
1197 for (int i = 0; i < 4; ++i) {
1199 tableCellBorder[i] = static_cast<qreal>(cssBorder[i]);
1200 }
1201 }
1202
1203 for (int i = 0; i < declarations.size(); ++i) {
1204 const QCss::Declaration &decl = declarations.at(i);
1205 if (decl.d->values.isEmpty()) continue;
1206
1208 if (decl.d->values.first().type == QCss::Value::KnownIdentifier)
1209 identifier = static_cast<QCss::KnownValue>(decl.d->values.first().variant.toInt());
1210
1211 switch (decl.d->propertyId) {
1212 case QCss::BorderColor: borderBrush = QBrush(decl.colorValue()); break;
1213 case QCss::BorderStyles:
1215 borderStyle = static_cast<QTextFrameFormat::BorderStyle>(decl.styleValue() - 1);
1216 break;
1217 case QCss::BorderWidth: {
1218 int borders[4];
1219 extractor.lengthValues(decl, borders);
1220 tableBorder = borders[0];
1221 }
1222 break;
1225 break;
1226 case QCss::Color: charFormat.setForeground(decl.colorValue()); break;
1227 case QCss::Float:
1229 switch (identifier) {
1232 default: break;
1233 }
1234 break;
1236 blockFormat.setIndent(decl.d->values.first().variant.toInt());
1237 break;
1239 QString lineHeightTypeName = decl.d->values.first().variant.toString();
1240 QTextBlockFormat::LineHeightTypes lineHeightType;
1241 if (lineHeightTypeName.compare("proportional"_L1, Qt::CaseInsensitive) == 0)
1242 lineHeightType = QTextBlockFormat::ProportionalHeight;
1243 else if (lineHeightTypeName.compare("fixed"_L1, Qt::CaseInsensitive) == 0)
1244 lineHeightType = QTextBlockFormat::FixedHeight;
1245 else if (lineHeightTypeName.compare("minimum"_L1, Qt::CaseInsensitive) == 0)
1246 lineHeightType = QTextBlockFormat::MinimumHeight;
1247 else if (lineHeightTypeName.compare("line-distance"_L1, Qt::CaseInsensitive) == 0)
1248 lineHeightType = QTextBlockFormat::LineDistanceHeight;
1249 else
1250 lineHeightType = QTextBlockFormat::SingleHeight;
1251
1253 qreal lineHeight = blockFormat.lineHeight() / 100.0;
1255 }
1256
1258 hasOwnLineHeightType = true;
1259 }
1260 break;
1261 case QCss::LineHeight: {
1262 qreal lineHeight;
1263 QTextBlockFormat::LineHeightTypes lineHeightType;
1264 if (decl.realValue(&lineHeight, "px")) {
1265 lineHeightType = QTextBlockFormat::MinimumHeight;
1266 } else {
1267 bool ok;
1268 QCss::Value cssValue = decl.d->values.first();
1269 QString value = cssValue.toString();
1270 lineHeight = value.toDouble(&ok);
1271 if (ok) {
1272 if (!hasOwnLineHeightType && cssValue.type == QCss::Value::Number) {
1273 lineHeight *= 100.0;
1275 }
1276 lineHeightType = QTextBlockFormat::ProportionalHeight;
1277 } else {
1278 lineHeight = 0.0;
1279 lineHeightType = QTextBlockFormat::SingleHeight;
1280 }
1281 }
1282
1283 // Only override line height type if specified in same node
1286
1287 blockFormat.setLineHeight(lineHeight, lineHeightType);
1288 break;
1289 }
1290 case QCss::TextIndent: {
1291 qreal indent = 0;
1292 if (decl.realValue(&indent, "px"))
1293 blockFormat.setTextIndent(indent);
1294 break; }
1295 case QCss::QtListIndent:
1296 if (decl.intValue(&cssListIndent))
1297 hasCssListIndent = true;
1298 break;
1300 if (decl.d->values.first().variant.toString().compare("empty"_L1, Qt::CaseInsensitive) == 0)
1301 isEmptyParagraph = true;
1302 break;
1303 case QCss::QtTableType:
1304 if (decl.d->values.first().variant.toString().compare("frame"_L1, Qt::CaseInsensitive) == 0)
1305 isTextFrame = true;
1306 else if (decl.d->values.first().variant.toString().compare("root"_L1, Qt::CaseInsensitive) == 0) {
1307 isTextFrame = true;
1308 isRootFrame = true;
1309 }
1310 break;
1311 case QCss::QtUserState:
1312 userState = decl.d->values.first().variant.toInt();
1313 break;
1314 case QCss::Whitespace:
1315 switch (identifier) {
1321 default: break;
1322 }
1323 break;
1325 switch (identifier) {
1332 }
1333 break;
1335 switch (identifier) {
1338 default: break;
1339 }
1340 break;
1342 switch (identifier) {
1345 default: break;
1346 }
1347 break;
1349 switch (identifier) {
1357 default: break;
1358 }
1359 break;
1362 case QCss::ListStyle:
1363 setListStyle(decl.d->values);
1364 break;
1366 textListNumberPrefix = decl.d->values.first().variant.toString();
1367 break;
1369 textListNumberSuffix = decl.d->values.first().variant.toString();
1370 break;
1372 switch (identifier) {
1376 default: break;
1377 }
1378 break;
1379
1381 {
1382 if (resourceProvider != nullptr && QTextDocumentPrivate::get(resourceProvider) != nullptr) {
1383 bool ok;
1384 qint64 searchKey = decl.d->values.first().variant.toLongLong(&ok);
1385 if (ok)
1386 applyForegroundImage(searchKey, resourceProvider);
1387 }
1388 break;
1389 }
1390 default: break;
1391 }
1392 }
1393
1394 QFont f;
1395 int adjustment = -255;
1396 extractor.extractFont(&f, &adjustment);
1397 if (f.pixelSize() > INT32_MAX / 2)
1398 f.setPixelSize(INT32_MAX / 2); // avoid even more extreme values
1400
1401 if (adjustment >= -1)
1403
1404 {
1405 Qt::Alignment ignoredAlignment;
1406 QCss::Repeat ignoredRepeat;
1407 QString bgImage;
1408 QBrush bgBrush;
1409 QCss::Origin ignoredOrigin, ignoredClip;
1410 QCss::Attachment ignoredAttachment;
1411 extractor.extractBackground(&bgBrush, &bgImage, &ignoredRepeat, &ignoredAlignment,
1412 &ignoredOrigin, &ignoredAttachment, &ignoredClip);
1413
1414 if (!bgImage.isEmpty() && resourceProvider) {
1415 applyBackgroundImage(bgImage, resourceProvider);
1416 } else if (bgBrush.style() != Qt::NoBrush) {
1417 charFormat.setBackground(bgBrush);
1418 if (id == Html_hr)
1420 }
1421 }
1422}
1423
1424#endif // QT_NO_CSSPARSER
1425
1427{
1428 const QTextDocumentPrivate *priv = QTextDocumentPrivate::get(resourceProvider);
1429 for (int i = 0; i < priv->formats.numFormats(); ++i) {
1430 QTextCharFormat format = priv->formats.charFormat(i);
1431 if (format.isValid()) {
1432 QBrush brush = format.foreground();
1433 if (brush.style() == Qt::TexturePattern) {
1434 const bool isPixmap = qHasPixmapTexture(brush);
1435
1436 if (isPixmap && QCoreApplication::instance()->thread() != QThread::currentThread()) {
1437 qWarning("Can't apply QPixmap outside of GUI thread");
1438 return;
1439 }
1440
1441 const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();
1442 if (cacheKey == searchKey) {
1443 QBrush b;
1444 if (isPixmap)
1445 b.setTexture(brush.texture());
1446 else
1447 b.setTextureImage(brush.textureImage());
1448 b.setStyle(Qt::TexturePattern);
1450 }
1451 }
1452 }
1453 }
1454
1455}
1456
1458{
1459 if (!url.isEmpty() && resourceProvider) {
1461
1463 // must use images in non-GUI threads
1464 if (val.userType() == QMetaType::QImage) {
1465 QImage image = qvariant_cast<QImage>(val);
1467 } else if (val.userType() == QMetaType::QByteArray) {
1468 QImage image;
1469 if (image.loadFromData(val.toByteArray())) {
1471 }
1472 }
1473 } else {
1474 if (val.userType() == QMetaType::QImage || val.userType() == QMetaType::QPixmap) {
1475 charFormat.setBackground(qvariant_cast<QPixmap>(val));
1476 } else if (val.userType() == QMetaType::QByteArray) {
1477 QPixmap pm;
1478 if (pm.loadFromData(val.toByteArray())) {
1480 }
1481 }
1482 }
1483 }
1484 if (!url.isEmpty())
1486}
1487
1489{
1490 for (int i = 0; i < text.size(); ++i)
1491 if (!text.at(i).isSpace() || text.at(i) == QChar::LineSeparator)
1492 return false;
1493 return true;
1494}
1495
1496static bool setIntAttribute(int *destination, const QString &value)
1497{
1498 bool ok = false;
1499 int val = value.toInt(&ok);
1500 if (ok)
1501 *destination = val;
1502
1503 return ok;
1504}
1505
1507{
1508 bool ok = false;
1509 qreal val = value.toDouble(&ok);
1510 if (ok)
1511 *destination = val;
1512
1513 return ok;
1514}
1515
1516static void setWidthAttribute(QTextLength *width, const QString &valueStr)
1517{
1518 bool ok = false;
1519 qreal realVal = valueStr.toDouble(&ok);
1520 if (ok) {
1522 } else {
1523 auto value = QStringView(valueStr).trimmed();
1524 if (!value.isEmpty() && value.endsWith(u'%')) {
1525 value.truncate(value.size() - 1);
1526 realVal = value.toDouble(&ok);
1527 if (ok)
1529 }
1530 }
1531}
1532
1533#ifndef QT_NO_CSSPARSER
1535{
1536 const QString css = "* {"_L1 + value + u'}';
1537 QCss::Parser parser(css);
1538 QCss::StyleSheet sheet;
1539 parser.parse(&sheet, Qt::CaseInsensitive);
1540 if (sheet.styleRules.size() != 1) return;
1541 applyCssDeclarations(sheet.styleRules.at(0).declarations, resourceProvider);
1542}
1543#endif
1544
1546{
1548
1549 while (pos < len) {
1550 eatSpace();
1551 if (hasPrefix(u'>') || hasPrefix(u'/'))
1552 break;
1554 QString value = "1"_L1;
1555 if (key.size() == 0)
1556 break;
1557 eatSpace();
1558 if (hasPrefix(u'=')){
1559 pos++;
1560 eatSpace();
1561 value = parseWord();
1562 }
1563 if (value.size() == 0)
1564 continue;
1565 attrs << key << value;
1566 }
1567
1568 return attrs;
1569}
1570
1572{
1573 // local state variable for qt3 textedit mode
1574 bool seenQt3Richtext = false;
1575 QString linkHref;
1576 QString linkType;
1577
1578 if (attributes.size() % 2 == 1)
1579 return;
1580
1581 QTextHtmlParserNode *node = nodes.last();
1582
1583 for (int i = 0; i < attributes.size(); i += 2) {
1584 QString key = attributes.at(i);
1585 QString value = attributes.at(i + 1);
1586
1587 switch (node->id) {
1588 case Html_font:
1589 // the infamous font tag
1590 if (key == "size"_L1 && value.size()) {
1591 int n = value.toInt();
1592 if (value.at(0) != u'+' && value.at(0) != u'-')
1593 n -= 3;
1595 } else if (key == "face"_L1) {
1596 if (value.contains(u',')) {
1597 const QStringList values = value.split(u',');
1598 QStringList families;
1599 for (const QString &family : values)
1600 families << family.trimmed();
1601 node->charFormat.setFontFamilies(families);
1602 } else {
1604 }
1605 } else if (key == "color"_L1) {
1607 if (!c.isValid())
1608 qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
1609 node->charFormat.setForeground(c);
1610 }
1611 break;
1612 case Html_ol:
1613 case Html_ul:
1614 if (key == "type"_L1) {
1615 node->hasOwnListStyle = true;
1616 if (value == "1"_L1) {
1618 } else if (value == "a"_L1) {
1620 } else if (value == "A"_L1) {
1622 } else if (value == "i"_L1) {
1624 } else if (value == "I"_L1) {
1626 } else {
1627 value = std::move(value).toLower();
1628 if (value == "square"_L1)
1630 else if (value == "disc"_L1)
1632 else if (value == "circle"_L1)
1634 else if (value == "none"_L1)
1636 }
1637 } else if (key == "start"_L1) {
1639 }
1640 break;
1641 case Html_li:
1642 if (key == "class"_L1) {
1643 if (value == "unchecked"_L1)
1645 else if (value == "checked"_L1)
1647 }
1648 break;
1649 case Html_a:
1650 if (key == "href"_L1)
1652 else if (key == "name"_L1)
1654 break;
1655 case Html_img:
1656 if (key == "src"_L1 || key == "source"_L1) {
1657 node->imageName = value;
1658 } else if (key == "width"_L1) {
1659 node->imageWidth = -2; // register that there is a value for it.
1661 } else if (key == "height"_L1) {
1662 node->imageHeight = -2; // register that there is a value for it.
1664 } else if (key == "alt"_L1) {
1665 node->imageAlt = value;
1666 } else if (key == "title"_L1) {
1667 node->text = value;
1668 }
1669 break;
1670 case Html_tr:
1671 case Html_body:
1672 if (key == "bgcolor"_L1) {
1674 if (!c.isValid())
1675 qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
1676 node->charFormat.setBackground(c);
1677 } else if (key == "background"_L1) {
1679 }
1680 break;
1681 case Html_th:
1682 case Html_td:
1683 if (key == "width"_L1) {
1684 setWidthAttribute(&node->width, value);
1685 } else if (key == "bgcolor"_L1) {
1687 if (!c.isValid())
1688 qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
1689 node->charFormat.setBackground(c);
1690 } else if (key == "background"_L1) {
1692 } else if (key == "rowspan"_L1) {
1694 node->tableCellRowSpan = qMax(1, node->tableCellRowSpan);
1695 } else if (key == "colspan"_L1) {
1697 node->tableCellColSpan = qBound(1, node->tableCellColSpan, 20480);
1698 }
1699 break;
1700 case Html_table:
1701 if (key == "border"_L1) {
1703 } else if (key == "bgcolor"_L1) {
1705 if (!c.isValid())
1706 qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
1707 node->charFormat.setBackground(c);
1708 } else if (key == "bordercolor"_L1) {
1710 if (!c.isValid())
1711 qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
1712 node->borderBrush = c;
1713 } else if (key == "background"_L1) {
1715 } else if (key == "cellspacing"_L1) {
1717 } else if (key == "cellpadding"_L1) {
1719 } else if (key == "width"_L1) {
1720 setWidthAttribute(&node->width, value);
1721 } else if (key == "height"_L1) {
1723 }
1724 break;
1725 case Html_meta:
1726 if (key == "name"_L1 && value == "qrichtext"_L1)
1727 seenQt3Richtext = true;
1728
1729 if (key == "content"_L1 && value == "1"_L1 && seenQt3Richtext)
1730 textEditMode = true;
1731 break;
1732 case Html_hr:
1733 if (key == "width"_L1)
1734 setWidthAttribute(&node->width, value);
1735 break;
1736 case Html_link:
1737 if (key == "href"_L1)
1738 linkHref = value;
1739 else if (key == "type"_L1)
1740 linkType = value;
1741 break;
1742 case Html_pre:
1743 if (key == "class"_L1 && value.startsWith("language-"_L1))
1745 break;
1746 default:
1747 break;
1748 }
1749
1750 if (key == "style"_L1) {
1751#ifndef QT_NO_CSSPARSER
1753#endif
1754 } else if (key == "align"_L1) {
1755 value = std::move(value).toLower();
1756 bool alignmentSet = true;
1757
1758 if (value == "left"_L1)
1760 else if (value == "right"_L1)
1762 else if (value == "center"_L1)
1764 else if (value == "justify"_L1)
1766 else
1767 alignmentSet = false;
1768
1769 if (node->id == Html_img) {
1770 // HTML4 compat
1771 if (alignmentSet) {
1772 if (node->blockFormat.alignment() & Qt::AlignLeft)
1774 else if (node->blockFormat.alignment() & Qt::AlignRight)
1776 } else if (value == "middle"_L1) {
1778 } else if (value == "top"_L1) {
1780 }
1781 }
1782 } else if (key == "valign"_L1) {
1783 value = std::move(value).toLower();
1784 if (value == "top"_L1)
1786 else if (value == "middle"_L1)
1788 else if (value == "bottom"_L1)
1790 } else if (key == "dir"_L1) {
1791 value = std::move(value).toLower();
1792 if (value == "ltr"_L1)
1794 else if (value == "rtl"_L1)
1796 } else if (key == "title"_L1) {
1798 } else if (key == "id"_L1) {
1799 node->charFormat.setAnchor(true);
1801 }
1802 }
1803
1804#ifndef QT_NO_CSSPARSER
1805 if (resourceProvider && !linkHref.isEmpty() && linkType == "text/css"_L1)
1806 importStyleSheet(linkHref);
1807#endif
1808}
1809
1810#ifndef QT_NO_CSSPARSER
1812{
1813public:
1815 : parser(parser) { nameCaseSensitivity = Qt::CaseInsensitive; }
1816
1817 QStringList nodeNames(NodePtr node) const override;
1818 QString attributeValue(NodePtr node, const QCss::AttributeSelector &aSelector) const override;
1819 bool hasAttributes(NodePtr node) const override;
1820 bool isNullNode(NodePtr node) const override;
1821 NodePtr parentNode(NodePtr node) const override;
1822 NodePtr previousSiblingNode(NodePtr node) const override;
1823 NodePtr duplicateNode(NodePtr node) const override;
1824 void freeNode(NodePtr node) const override;
1825
1826private:
1827 const QTextHtmlParser *parser;
1828};
1829
1831{
1832 return QStringList(parser->at(node.id).tag.toLower());
1833}
1834
1835#endif // QT_NO_CSSPARSER
1836
1837#ifndef QT_NO_CSSPARSER
1838
1839static inline int findAttribute(const QStringList &attributes, const QString &name)
1840{
1841 int idx = -1;
1842 do {
1843 idx = attributes.indexOf(name, idx + 1);
1844 } while (idx != -1 && (idx % 2 == 1));
1845 return idx;
1846}
1847
1849{
1850 const QStringList &attributes = parser->at(node.id).attributes;
1851 const int idx = findAttribute(attributes, aSelector.name);
1852 if (idx == -1)
1853 return QString();
1854 return attributes.at(idx + 1);
1855}
1856
1858{
1859 const QStringList &attributes = parser->at(node.id).attributes;
1860 return !attributes.isEmpty();
1861}
1862
1864{
1865 return node.id == 0;
1866}
1867
1869{
1871 parent.id = 0;
1872 if (node.id) {
1873 parent.id = parser->at(node.id).parent;
1874 }
1875 return parent;
1876}
1877
1879{
1880 return node;
1881}
1882
1884{
1885 NodePtr sibling;
1886 sibling.id = 0;
1887 if (!node.id)
1888 return sibling;
1889 int parent = parser->at(node.id).parent;
1890 if (!parent)
1891 return sibling;
1892 const int childIdx = parser->at(parent).children.indexOf(node.id);
1893 if (childIdx <= 0)
1894 return sibling;
1895 sibling.id = parser->at(parent).children.at(childIdx - 1);
1896 return sibling;
1897}
1898
1900{
1901}
1902
1903void QTextHtmlParser::resolveStyleSheetImports(const QCss::StyleSheet &sheet)
1904{
1905 for (int i = 0; i < sheet.importRules.size(); ++i) {
1906 const QCss::ImportRule &rule = sheet.importRules.at(i);
1907 if (rule.media.isEmpty() || rule.media.contains("screen"_L1, Qt::CaseInsensitive))
1908 importStyleSheet(rule.href);
1909 }
1910}
1911
1912void QTextHtmlParser::importStyleSheet(const QString &href)
1913{
1914 if (!resourceProvider)
1915 return;
1916 for (int i = 0; i < externalStyleSheets.size(); ++i)
1917 if (externalStyleSheets.at(i).url == href)
1918 return;
1919
1921 QString css;
1922 if (res.userType() == QMetaType::QString) {
1923 css = res.toString();
1924 } else if (res.userType() == QMetaType::QByteArray) {
1925 // #### detect @charset
1926 css = QString::fromUtf8(res.toByteArray());
1927 }
1928 if (!css.isEmpty()) {
1929 QCss::Parser parser(css);
1930 QCss::StyleSheet sheet;
1931 parser.parse(&sheet, Qt::CaseInsensitive);
1932 externalStyleSheets.append(ExternalStyleSheet(href, sheet));
1933 resolveStyleSheetImports(sheet);
1934 }
1935}
1936
1938{
1940 QCss::Declaration decl;
1942 switch (node.id) {
1943 case Html_a:
1944 case Html_u: {
1945 bool needsUnderline = (node.id == Html_u) ? true : false;
1946 if (node.id == Html_a) {
1947 for (int i = 0; i < node.attributes.size(); i += 2) {
1948 const QString key = node.attributes.at(i);
1949 if (key.compare("href"_L1, Qt::CaseInsensitive) == 0
1950 && !node.attributes.at(i + 1).isEmpty()) {
1951 needsUnderline = true;
1952 decl.d->property = "color"_L1;
1953 decl.d->propertyId = QCss::Color;
1955 val.variant = QStringList() << "palette"_L1 << "link"_L1;
1956 decl.d->values = QList<QCss::Value> { val };
1957 decl.d->inheritable = true;
1958 decls << decl;
1959 break;
1960 }
1961 }
1962 }
1963 if (needsUnderline) {
1964 decl = QCss::Declaration();
1965 decl.d->property = "text-decoration"_L1;
1966 decl.d->propertyId = QCss::TextDecoration;
1969 decl.d->values = QList<QCss::Value> { val };
1970 decl.d->inheritable = true;
1971 decls << decl;
1972 }
1973 break;
1974 }
1975 case Html_b:
1976 case Html_strong:
1977 case Html_h1:
1978 case Html_h2:
1979 case Html_h3:
1980 case Html_h4:
1981 case Html_h5:
1982 case Html_th:
1983 decl = QCss::Declaration();
1984 decl.d->property = "font-weight"_L1;
1985 decl.d->propertyId = QCss::FontWeight;
1987 val.variant = QVariant(QCss::Value_Bold);
1988 decl.d->values = QList<QCss::Value> { val };
1989 decl.d->inheritable = true;
1990 decls << decl;
1991 if (node.id == Html_b || node.id == Html_strong)
1992 break;
1993 Q_FALLTHROUGH();
1994 case Html_big:
1995 case Html_small:
1996 if (node.id != Html_th) {
1997 decl = QCss::Declaration();
1998 decl.d->property = "font-size"_L1;
1999 decl.d->propertyId = QCss::FontSize;
2000 decl.d->inheritable = false;
2002 switch (node.id) {
2003 case Html_h1: val.variant = QVariant(QCss::Value_XXLarge); break;
2004 case Html_h2: val.variant = QVariant(QCss::Value_XLarge); break;
2005 case Html_h3: case Html_big: val.variant = QVariant(QCss::Value_Large); break;
2006 case Html_h4: val.variant = QVariant(QCss::Value_Medium); break;
2007 case Html_h5: case Html_small: val.variant = QVariant(QCss::Value_Small); break;
2008 default: break;
2009 }
2010 decl.d->values = QList<QCss::Value> { val };
2011 decls << decl;
2012 break;
2013 }
2014 Q_FALLTHROUGH();
2015 case Html_center:
2016 case Html_td:
2017 decl = QCss::Declaration();
2018 decl.d->property = "text-align"_L1;
2019 decl.d->propertyId = QCss::TextAlignment;
2022 decl.d->values = QList<QCss::Value> { val };
2023 decl.d->inheritable = true;
2024 decls << decl;
2025 break;
2026 case Html_s:
2027 decl = QCss::Declaration();
2028 decl.d->property = "text-decoration"_L1;
2029 decl.d->propertyId = QCss::TextDecoration;
2032 decl.d->values = QList<QCss::Value> { val };
2033 decl.d->inheritable = true;
2034 decls << decl;
2035 break;
2036 case Html_em:
2037 case Html_i:
2038 case Html_cite:
2039 case Html_address:
2040 case Html_var:
2041 case Html_dfn:
2042 decl = QCss::Declaration();
2043 decl.d->property = "font-style"_L1;
2044 decl.d->propertyId = QCss::FontStyle;
2046 val.variant = QVariant(QCss::Value_Italic);
2047 decl.d->values = QList<QCss::Value> { val };
2048 decl.d->inheritable = true;
2049 decls << decl;
2050 break;
2051 case Html_sub:
2052 case Html_sup:
2053 decl = QCss::Declaration();
2054 decl.d->property = "vertical-align"_L1;
2055 decl.d->propertyId = QCss::VerticalAlignment;
2058 decl.d->values = QList<QCss::Value> { val };
2059 decl.d->inheritable = true;
2060 decls << decl;
2061 break;
2062 case Html_ul:
2063 case Html_ol:
2064 decl = QCss::Declaration();
2065 decl.d->property = "list-style"_L1;
2066 decl.d->propertyId = QCss::ListStyle;
2069 decl.d->values = QList<QCss::Value> { val };
2070 decl.d->inheritable = true;
2071 decls << decl;
2072 break;
2073 case Html_code:
2074 case Html_tt:
2075 case Html_kbd:
2076 case Html_samp:
2077 case Html_pre: {
2078 decl = QCss::Declaration();
2079 decl.d->property = "font-family"_L1;
2080 decl.d->propertyId = QCss::FontFamily;
2082 val.type = QCss::Value::String;
2084 values << val;
2085 decl.d->values = values;
2086 decl.d->inheritable = true;
2087 decls << decl;
2088 }
2089 if (node.id != Html_pre)
2090 break;
2091 Q_FALLTHROUGH();
2092 case Html_br:
2093 case Html_nobr:
2094 decl = QCss::Declaration();
2095 decl.d->property = "whitespace"_L1;
2096 decl.d->propertyId = QCss::Whitespace;
2098 switch (node.id) {
2099 case Html_br: val.variant = QVariant(QCss::Value_PreWrap); break;
2100 case Html_nobr: val.variant = QVariant(QCss::Value_NoWrap); break;
2101 case Html_pre: val.variant = QVariant(QCss::Value_Pre); break;
2102 default: break;
2103 }
2104 decl.d->values = QList<QCss::Value> { val };
2105 decl.d->inheritable = true;
2106 decls << decl;
2107 break;
2108 default:
2109 break;
2110 }
2111 return decls;
2112}
2113
2114QList<QCss::Declaration> QTextHtmlParser::declarationsForNode(int node) const
2115{
2117
2119
2120 int idx = 0;
2121 selector.styleSheets.resize((resourceProvider ? 1 : 0)
2122 + externalStyleSheets.size()
2123 + inlineStyleSheets.size());
2124 if (resourceProvider)
2126
2127 for (int i = 0; i < externalStyleSheets.size(); ++i, ++idx)
2128 selector.styleSheets[idx] = externalStyleSheets.at(i).sheet;
2129
2130 for (int i = 0; i < inlineStyleSheets.size(); ++i, ++idx)
2131 selector.styleSheets[idx] = inlineStyleSheets.at(i);
2132
2134
2136 n.id = node;
2137
2138 const char *extraPseudo = nullptr;
2139 if (nodes.at(node)->id == Html_a && nodes.at(node)->hasHref)
2140 extraPseudo = "link";
2141 // Ensure that our own style is taken into consideration
2142 decls = standardDeclarationForNode(*nodes.at(node));
2143 decls += selector.declarationsForNode(n, extraPseudo);
2144 n = selector.parentNode(n);
2145 while (!selector.isNullNode(n)) {
2146 QList<QCss::Declaration> inheritedDecls;
2147 inheritedDecls = selector.declarationsForNode(n, extraPseudo);
2148 for (int i = 0; i < inheritedDecls.size(); ++i) {
2149 const QCss::Declaration &decl = inheritedDecls.at(i);
2150 if (decl.d->inheritable)
2151 decls.prepend(decl);
2152 }
2153 n = selector.parentNode(n);
2154 }
2155 return decls;
2156}
2157
2159{
2160 while (i) {
2161 if (at(i).id == id)
2162 return true;
2163 i = at(i).parent;
2164 }
2165 return false;
2166}
2167
2169#endif // QT_NO_CSSPARSER
2170
2171#endif // QT_NO_TEXTHTMLPARSER
\inmodule QtGui
Definition qbrush.h:30
Qt::BrushStyle style() const
Returns the brush style.
Definition qbrush.h:120
\inmodule QtCore
Definition qchar.h:48
@ ParagraphSeparator
Definition qchar.h:63
@ LineSeparator
Definition qchar.h:64
QChar toLower() const noexcept
Returns the lowercase equivalent if the character is uppercase or titlecase; otherwise returns the ch...
Definition qchar.h:448
static constexpr auto fromUcs4(char32_t c) noexcept
constexpr bool isNull() const noexcept
Returns true if the character is the Unicode character 0x0000 ('\0'); otherwise returns false.
Definition qchar.h:463
constexpr bool isSpace() const noexcept
Returns true if the character is a separator character (Separator_* categories or certain code points...
Definition qchar.h:466
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
static QColor fromString(QAnyStringView name) noexcept
Definition qcolor.cpp:980
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
bool parse(StyleSheet *styleSheet, Qt::CaseSensitivity nameCaseSensitivity=Qt::CaseSensitive)
Qt::CaseSensitivity nameCaseSensitivity
static QFont systemFont(SystemFont type)
\reentrant
Definition qfont.h:20
QStringList families() const
Definition qfont.cpp:2469
\inmodule QtGui
Definition qimage.h:37
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
T & last()
Definition qlist.h:631
const T & constLast() const noexcept
Definition qlist.h:633
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:471
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void prepend(rvalue_ref t)
Definition qlist.h:456
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
bool loadFromData(const uchar *buf, uint len, const char *format=nullptr, Qt::ImageConversionFlags flags=Qt::AutoColor)
Loads a pixmap from the len first bytes of the given binary data.
Definition qpixmap.cpp:765
\inmodule QtCore
Definition qsize.h:25
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
constexpr void truncate(qsizetype n) noexcept
Truncates this string view to length length.
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
constexpr QChar at(qsizetype n) const noexcept
Returns the character at position n in this string view.
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
QStringView trimmed() const noexcept
Strips leading and trailing whitespace and returns the result.
uint toUInt(bool *ok=nullptr, int base=10) const
Returns the string view converted to an {unsigned int} using base base, which is 10 by default and mu...
Definition qstring.h:1027
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
double toDouble(bool *ok=nullptr) const
Returns the string converted to a double value.
Definition qstring.cpp:7642
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6498
QString toLower() const &
Definition qstring.h:368
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString trimmed() const &
Definition qstring.h:380
Qt::Alignment alignment() const
Returns the paragraph's alignment.
void setPageBreakPolicy(PageBreakFlags flags)
void setAlignment(Qt::Alignment alignment)
Sets the paragraph's alignment.
void setMarker(MarkerType marker)
void setLineHeight(qreal height, int heightType)
PageBreakFlags pageBreakPolicy() const
void setIndent(int indent)
Sets the paragraph's indentation.
qreal lineHeight(qreal scriptLineHeight, qreal scaling) const
int lineHeightType() const
void setTextIndent(qreal aindent)
Sets the indent for the first line in the block.
void setFontFamilies(const QStringList &families)
void setUnderlineStyle(UnderlineStyle style)
void setVerticalAlignment(VerticalAlignment alignment)
Sets the vertical alignment used for the characters with this format to the alignment specified.
void setAnchor(bool anchor)
If anchor is true, text with this format represents an anchor, and is formatted in the appropriate wa...
void setAnchorNames(const QStringList &names)
void setToolTip(const QString &tip)
void setUnderlineColor(const QColor &color)
Sets the color used to draw underlines, overlines and strikeouts on the characters with this format t...
void setAnchorHref(const QString &value)
Sets the hypertext link for the text format to the given value.
void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior=FontPropertiesAll)
QCss::StyleSheet parsedDefaultStyleSheet
static const QTextDocumentPrivate * get(const QTextDocument *document)
\reentrant \inmodule QtGui
QVariant resource(int type, const QUrl &name) const
Returns data of the specified type from the resource with the given name.
QString metaInformation(MetaInformation info) const
Returns meta information about the document of the type specified by info.
void setForeground(const QBrush &brush)
Sets the foreground brush to the specified brush.
void setBackground(const QBrush &brush)
Sets the brush use to paint the document's background to the brush specified.
void setProperty(int propertyId, const QVariant &value)
Sets the property specified by the propertyId to the given value.
void setLayoutDirection(Qt::LayoutDirection direction)
Sets the document's layout direction to the specified direction.
void clearProperty(int propertyId)
Clears the value of the property given by propertyId.
@ PageBreak_AlwaysBefore
@ PageBreak_AlwaysAfter
bool hasPrefix(QChar c, int lookahead=0) const
bool nodeIsChildOf(int i, QTextHTMLElements id) const
QList< QTextHtmlParserNode * > nodes
QTextHtmlParserNode * resolveParent()
void applyAttributes(const QStringList &attributes)
int margin(int i, int mar) const
int topMargin(int i) const
static int lookupElement(const QString &element)
const QTextHtmlParserNode & at(int i) const
int depth(int i) const
QStringList parseAttributes()
int bottomMargin(int i) const
const QTextDocument * resourceProvider
QTextHtmlParserNode * newNode(int parent)
NodePtr previousSiblingNode(NodePtr node) const override
bool isNullNode(NodePtr node) const override
QString attributeValue(NodePtr node, const QCss::AttributeSelector &aSelector) const override
bool hasAttributes(NodePtr node) const override
NodePtr duplicateNode(NodePtr node) const override
QTextHtmlStyleSelector(const QTextHtmlParser *parser)
void freeNode(NodePtr node) const override
NodePtr parentNode(NodePtr node) const override
QStringList nodeNames(NodePtr node) const override
\reentrant
Definition qtextformat.h:45
static QThread * currentThread()
Definition qthread.cpp:966
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1888
\inmodule QtCore
Definition qvariant.h:64
QString str
[2]
QString text
qDeleteAll(list.begin(), list.end())
double e
@ Value_Disc
@ Value_Bottom
@ Value_Wave
@ Value_UpperRoman
@ Value_XXLarge
@ Value_Decimal
@ Value_PreWrap
@ Value_Left
@ Value_Circle
@ Value_Medium
@ Value_Pre
@ Value_Normal
@ Value_LineThrough
@ Value_DotDotDash
@ Value_Square
@ Value_Small
@ Value_LowerAlpha
@ Value_Solid
@ Value_Super
@ Value_NoWrap
@ Value_LowerRoman
@ Value_Top
@ Value_None
@ Value_Bold
@ UnknownValue
@ Value_Center
@ Value_Right
@ Value_Sub
@ Value_PreLine
@ Value_Underline
@ Value_DotDash
@ Value_Auto
@ Value_Large
@ Value_XLarge
@ Value_UpperAlpha
@ Value_Dashed
@ Value_Always
@ Value_Dotted
@ Value_Middle
@ Value_Italic
@ Whitespace
@ QtTableType
@ TextUnderlineStyle
@ QtListIndent
@ QtListNumberPrefix
@ PageBreakAfter
@ FontWeight
@ QtForegroundTextureCacheKey
@ TextIndent
@ BorderColor
@ QtUserState
@ BorderCollapse
@ QtBlockIndent
@ FontStyle
@ FontFamily
@ BorderWidth
@ VerticalAlignment
@ LineHeight
@ QtParagraphType
@ BorderStyles
@ TextDecoration
@ ListStyleType
@ ListStyle
@ TextAlignment
@ TextDecorationColor
@ QtListNumberSuffix
@ FontSize
@ PageBreakBefore
@ QtLineHeightType
@ StyleSheetOrigin_Author
@ BorderStyle_Dotted
@ BorderStyle_Solid
@ BorderStyle_Double
@ BorderStyle_DotDash
@ BorderStyle_Ridge
@ BorderStyle_Unknown
@ BorderStyle_Dashed
@ BorderStyle_Outset
@ BorderStyle_Groove
@ BorderStyle_Native
@ NumKnownBorderStyles
@ BorderStyle_None
@ BorderStyle_DotDotDash
@ BorderStyle_Inset
Combined button and popup list for selecting options.
@ AlignRight
Definition qnamespace.h:145
@ AlignJustify
Definition qnamespace.h:148
@ AlignHCenter
Definition qnamespace.h:147
@ AlignCenter
Definition qnamespace.h:162
@ AlignAbsolute
Definition qnamespace.h:149
@ AlignLeft
Definition qnamespace.h:143
@ LeftToRight
@ RightToLeft
@ CaseInsensitive
@ TexturePattern
@ NoBrush
Definition brush.cpp:5
Definition image.cpp:4
bool Q_GUI_EXPORT qHasPixmapTexture(const QBrush &brush)
Definition qbrush.cpp:202
#define Q_FALLTHROUGH()
AudioChannelLayoutTag tag
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char * destination
DBusConnection const char * rule
DBusConnection const char DBusError * error
static struct AttrInfo attrs[]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
static const QMetaObjectPrivate * priv(const uint *data)
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum GLsizei GLsizei GLint * values
[15]
GLboolean GLboolean GLboolean b
GLint GLenum GLsizei GLsizei GLsizei depth
const GLfloat * m
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLuint id
[7]
GLfloat GLfloat f
GLint GLsizei width
GLuint start
GLuint name
GLfloat n
GLint GLsizei GLsizei GLenum format
GLuint res
const GLubyte * c
GLuint GLfloat * val
GLenum GLsizei len
GLenum GLenum GLsizei void * row
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLenum GLenum GLsizei void * table
#define qPrintable(string)
Definition qstring.h:1391
static int findAttribute(const QStringList &attributes, const QString &name)
static bool operator<(QStringView entityStr, const QTextHtmlEntity &entity)
static const struct QTextHtmlEntity entities[]
QList< QCss::Declaration > standardDeclarationForNode(const QTextHtmlParserNode &node)
static bool setFloatAttribute(qreal *destination, const QString &value)
static QTextFrameFormat::BorderStyle toQTextFrameFormat(QCss::BorderStyle cssStyle)
static const QTextHtmlElement elements[Html_NumElements]
static void setWidthAttribute(QTextLength *width, const QString &valueStr)
static const ushort windowsLatin1ExtendedCharacters[0xA0 - 0x80]
static bool setIntAttribute(int *destination, const QString &value)
#define MAX_ENTITY
static QChar resolveEntity(QStringView entity)
static const QTextHtmlElement * lookupElementHelper(const QString &element)
static QString quoteNewline(const QString &s)
QTextHTMLElements
@ Html_h2
@ Html_dl
@ Html_meta
@ Html_samp
@ Html_em
@ Html_code
@ Html_th
@ Html_dd
@ Html_tr
@ Html_NumElements
@ Html_tbody
@ Html_nobr
@ Html_tfoot
@ Html_b
@ Html_h4
@ Html_a
@ Html_caption
@ Html_h5
@ Html_big
@ Html_title
@ Html_table
@ Html_address
@ Html_div
@ Html_var
@ Html_i
@ Html_u
@ Html_tt
@ Html_font
@ Html_p
@ Html_ol
@ Html_blockquote
@ Html_head
@ Html_ul
@ Html_span
@ Html_br
@ Html_script
@ Html_thead
@ Html_kbd
@ Html_pre
@ Html_body
@ Html_cite
@ Html_link
@ Html_s
@ Html_unknown
@ Html_dfn
@ Html_sub
@ Html_td
@ Html_hr
@ Html_li
@ Html_img
@ Html_html
@ Html_h6
@ Html_h1
@ Html_small
@ Html_sup
@ Html_h3
@ Html_dt
@ Html_center
@ Html_strong
@ Html_style
unsigned int uint
Definition qtypes.h:29
long long qint64
Definition qtypes.h:55
unsigned short ushort
Definition qtypes.h:28
double qreal
Definition qtypes.h:92
QFileSelector selector
[1]
QUrl url("example.com")
[constructor-url-reference]
QAction * at
bool realValue(qreal *r, const char *unit=nullptr) const
QExplicitlySharedDataPointer< DeclarationData > d
QColor colorValue(const QPalette &=QPalette()) const
bool intValue(int *i, const char *unit=nullptr) const
BorderStyle styleValue() const
bool borderCollapseValue() const
QList< StyleRule > styleRules
StyleSheetOrigin origin
QList< ImportRule > importRules
Q_GUI_EXPORT QString toString() const
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
Definition qlist.h:955
enum QTextHtmlElement::DisplayMode displayMode
QTextHTMLElements id
const char name[9]
bool isNotSelfNesting() const
void initializeProperties(const QTextHtmlParserNode *parent, const QTextHtmlParser *parser)
void parseStyleAttribute(const QString &value, const QTextDocument *resourceProvider)
QTextListFormat::Style listStyle
QTextFrameFormat::BorderStyle borderStyle
QTextCharFormat charFormat
QTextHTMLElements id
bool isNestedList(const QTextHtmlParser *parser) const
bool allowedInContext(int parentId) const
void applyBackgroundImage(const QString &url, const QTextDocument *resourceProvider)
void applyForegroundImage(qint64 cacheKey, const QTextDocument *resourceProvider)
QTextFrameFormat::BorderStyle tableCellBorderStyle[4]
QTextBlockFormat blockFormat
bool mayNotHaveChildren() const
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent