📄 qtexthtmlparser.cpp
字号:
hasCssBlockIndent(false), hasCssListIndent(false), isEmptyParagraph(false), isTextFrame(false), direction(3), displayMode(QTextHtmlElement::DisplayInline), fontPointSize(-1), fontPixelSize(-1), fontSizeAdjustment(0), fontWeight(-1), alignment(0), verticalAlignment(QTextCharFormat::AlignNormal), listStyle(QTextListFormat::ListStyleUndefined), imageWidth(-1), imageHeight(-1), tableBorder(0), tableCellRowSpan(1), tableCellColSpan(1), tableCellSpacing(2), tableCellPadding(0), cssBlockIndent(0), cssListIndent(0), text_indent(0), wsm(WhiteSpaceModeUndefined){ margin[QTextHtmlParser::MarginLeft] = 0; margin[QTextHtmlParser::MarginRight] = 0; margin[QTextHtmlParser::MarginTop] = 0; margin[QTextHtmlParser::MarginBottom] = 0;}QTextCharFormat QTextHtmlParserNode::charFormat() const{ QTextCharFormat format; if (fontItalic != Unspecified) { format.setFontItalic(fontItalic == On); } if (fontUnderline != Unspecified) { format.setFontUnderline(fontUnderline == On); } if (fontOverline != Unspecified) { format.setFontOverline(fontOverline == On); } if (fontStrikeOut != Unspecified) { format.setFontStrikeOut(fontStrikeOut == On); } if (fontFixedPitch != Unspecified) { format.setFontFixedPitch(fontFixedPitch == On); } if (fontFamily.size()) format.setFontFamily(fontFamily); if (hasFontPointSize) format.setFontPointSize(fontPointSize); else if (hasFontPixelSize) format.setProperty(QTextFormat::FontPixelSize, fontPixelSize); if (hasFontSizeAdjustment) format.setProperty(QTextFormat::FontSizeAdjustment, fontSizeAdjustment); if (fontWeight > 0) format.setFontWeight(fontWeight); if (color.isValid()) format.setForeground(QBrush(color)); if (bgColor.isValid()) format.setBackground(QBrush(bgColor)); if (verticalAlignment != QTextCharFormat::AlignNormal) format.setVerticalAlignment(verticalAlignment); if (isAnchor) { format.setAnchor(true); format.setAnchorHref(anchorHref); format.setAnchorName(anchorName); } return format;}QTextBlockFormat QTextHtmlParserNode::blockFormat() const{ QTextBlockFormat format; if (alignment) format.setAlignment(alignment); if (direction < 2) format.setLayoutDirection(Qt::LayoutDirection(direction)); if (hasCssBlockIndent) format.setIndent(cssBlockIndent); if (text_indent != 0.) format.setTextIndent(text_indent); return format;}void QTextHtmlParser::dumpHtml(){ for (int i = 0; i < count(); ++i) { qDebug().nospace() << qPrintable(QString(depth(i)*4, ' ')) << qPrintable(at(i).tag) << ":" << quoteNewline(at(i).text); ; }}QTextHtmlParserNode *QTextHtmlParser::newNode(int parent){ QTextHtmlParserNode *lastNode = &nodes.last(); QTextHtmlParserNode *newNode = 0; bool reuseLastNode = true; if (nodes.count() == 1) { reuseLastNode = false; } else if (lastNode->tag.isEmpty()) { if (lastNode->text.isEmpty()) { reuseLastNode = true; } else { // last node is a text node (empty tag) with some text if (lastNode->text == QLatin1String(" ")) { int lastSibling = count() - 2; while (lastSibling && at(lastSibling).parent != lastNode->parent && at(lastSibling).displayMode == QTextHtmlElement::DisplayInline) { lastSibling = at(lastSibling).parent; } if (at(lastSibling).displayMode == QTextHtmlElement::DisplayInline) { reuseLastNode = false; } else { reuseLastNode = true; } } else { // text node with real (non-whitespace) text -> nothing to re-use reuseLastNode = false; } } } else { // last node had a proper tag -> nothing to re-use reuseLastNode = false; } if (reuseLastNode) { newNode = lastNode; newNode->tag.clear(); newNode->text.clear(); newNode->id = -1; } else { nodes.resize(nodes.size() + 1); newNode = &nodes.last(); } newNode->parent = parent; return newNode;}void QTextHtmlParser::parse(const QString &text){ nodes.clear(); nodes.resize(1); txt = text; pos = 0; len = txt.length(); textEditMode = false; parse(); //dumpHtml();}int QTextHtmlParser::depth(int i) const{ int depth = 0; while (i) { i = at(i).parent; ++depth; } return depth;}int QTextHtmlParser::margin(int i, int mar) const { int m = 0; const QTextHtmlParserNode *node; if (mar == MarginLeft || mar == MarginRight) { while (i) { node = &at(i); if (!node->isBlock) return 0; if (node->isTableCell) break; m += node->margin[mar]; i = node->parent; } } return m;}int QTextHtmlParser::topMargin(int i) const{ if (!i) return 0; return at(i).margin[MarginTop]; // we do margin collapsing in QTextDocumentFragment#if 0 int m = 0; const QTextHtmlParserNode *node; while (i) { node = &at(i); if (!node->isBlock) return 0; m = qMax(m, node->margin[MarginTop]); // collapsing margins across table cells makes no sense if (node->isTableCell) break; // don't collapse margins across list items // (the top margin of the list is merged as part of the block // merging in documentfragment.cpp) if (node->isListItem) break; // <ul> // .. // <ul> <-- this one should not take the first <ul>'s margin into account if (node->isNestedList(this)) break; // get previous block while (i-1 && !at(i-1).isBlock) --i; if (i && node->parent == at(i).parent) break; i = node->parent; } return m;#endif}int QTextHtmlParser::bottomMargin(int i) const{ if (!i) return 0; return at(i).margin[MarginBottom];#if 0 // we do margin collapsing in QTextDocumentFragment int m = 0; const QTextHtmlParserNode *node; while (i) { node = &at(i); if (!node->isBlock) return 0; m = qMax(m, node->margin[MarginBottom]); // collapsing margins across table cells makes no sense if (node->isTableCell) break; // don't collapse margins across list items if (node->isListItem) break; // <ul> // .. // <ul> <-- this one should not take the first <ul>'s margin into account if (node->isNestedList(this)) break; // get next block while (i+1 < count() && !at(i+1).isBlock) ++i; if (i && node->parent == at(i).parent) break; i = node->parent; } return m;#endif}void QTextHtmlParser::eatSpace(){ while (pos < len && txt.at(pos).isSpace() && txt.at(pos) != QChar::ParagraphSeparator) pos++;}void QTextHtmlParser::parse() { QTextHtmlParserNode::WhiteSpaceMode wsm = QTextHtmlParserNode::WhiteSpaceNormal; while (pos < len) { QChar c = txt.at(pos++); if (c == QLatin1Char('<')) { parseTag(); wsm = nodes.last().wsm; } else if (c == QLatin1Char('&')) { nodes.last().text += parseEntity(); } else { if (c.isSpace() && c != QChar(QChar::Nbsp) && c != QChar::ParagraphSeparator) { if (wsm == QTextHtmlParserNode::WhiteSpacePre || textEditMode) { if (c == QLatin1Char('\n')) c = QChar::LineSeparator; else if (c == QLatin1Char('\r')) continue; if (textEditMode && c == QChar::LineSeparator) continue; } else if (wsm != QTextHtmlParserNode::WhiteSpacePreWrap) { // non-pre mode: collapse whitespace except nbsp while (pos < len && txt.at(pos).isSpace() && txt.at(pos) != QChar::Nbsp) pos++; if (wsm == QTextHtmlParserNode::WhiteSpaceNoWrap) c = QChar::Nbsp; else c = QLatin1Char(' '); } } nodes.last().text += c; } }}// parses a tag after "<"void QTextHtmlParser::parseTag(){ eatSpace(); // handle comments and other exclamation mark declarations if (hasPrefix(QLatin1Char('!'))) { parseExclamationTag(); if (nodes.last().wsm != QTextHtmlParserNode::WhiteSpacePre && nodes.last().wsm != QTextHtmlParserNode::WhiteSpacePreWrap && !textEditMode) eatSpace(); return; } // if close tag just close if (hasPrefix(QLatin1Char('/'))) { parseCloseTag(); return; } int p = last(); while (p && at(p).tag.size() == 0) p = at(p).parent; QTextHtmlParserNode *node = newNode(p); // parse tag name node->tag = parseWord().toLower(); const QTextHtmlElement *elem = ::lookupElement(node->tag); if (elem->name) { node->id = elem->id; node->isBlock = (elem->displayMode == QTextHtmlElement::DisplayBlock); node->displayMode = elem->displayMode; } else { node->id = -1; } node->isListItem = (node->id == Html_li); node->isListStart = (node->id == Html_ol || node->id == Html_ul); node->isTableCell = (node->id == Html_td || node->id == Html_th); resolveParent(); resolveNode(); QColor inheritedNodeColor = node->color; node->color = QColor(); // _need_ at least one space after the tag name, otherwise there can't be attributes if (pos < len && txt.at(pos).isSpace()) parseAttributes(); // special handling for anchors with href attribute (hyperlinks) if (node->isAnchor && !node->anchorHref.isEmpty()) { node->fontUnderline = On; // #### remove 4.2 if (!node->color.isValid()) node->color = Qt::blue; // #### remove 4.2 } else { if (!node->color.isValid()) node->color = inheritedNodeColor; } // finish tag bool tagClosed = false; while (pos < len && txt.at(pos) != QLatin1Char('>')) { if (txt.at(pos) == QLatin1Char('/')) tagClosed = true; pos++; } pos++; if (node->wsm != QTextHtmlParserNode::WhiteSpacePre && node->wsm != QTextHtmlParserNode::WhiteSpacePreWrap && !textEditMode) eatSpace(); if (node->mayNotHaveChildren() || tagClosed) { newNode(node->parent); resolveNode(); }}// parses a tag beginning with "/"void QTextHtmlParser::parseCloseTag(){ ++pos; QString tag = parseWord().toLower().trimmed(); while (pos < len) { QChar c = txt.at(pos++); if (c == QLatin1Char('>')) break; } // find corresponding open node int p = last(); if (p > 0 && at(p - 1).tag == tag && at(p - 1).mayNotHaveChildren()) p--; while (p && at(p).tag != tag) p = at(p).parent; // simply ignore the tag if we can't find // a corresponding open node, for broken // html such as <font>blah</font></font> if (!p) return; newNode(at(p).parent); resolveNode();}// parses a tag beginning with "!"void QTextHtmlParser::parseExclamationTag()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -