1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the 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 #ifndef QTEXTHTMLPARSER_P_H
41 #define QTEXTHTMLPARSER_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtGui/private/qtguiglobal_p.h>
55 #include "QtCore/qvector.h"
56 #include "QtGui/qbrush.h"
57 #include "QtGui/qcolor.h"
58 #include "QtGui/qfont.h"
59 #include "QtGui/qtextdocument.h"
60 #include "QtGui/qtextcursor.h"
61 #include "private/qtextformat_p.h"
62 #include "private/qtextdocument_p.h"
63 #include "private/qcssparser_p.h"
64 
65 #ifndef QT_NO_TEXTHTMLPARSER
66 
67 QT_BEGIN_NAMESPACE
68 
69 enum QTextHTMLElements {
70     Html_unknown = -1,
71     Html_qt = 0,
72     Html_body,
73 
74     Html_a,
75     Html_em,
76     Html_i,
77     Html_big,
78     Html_small,
79     Html_strong,
80     Html_b,
81     Html_cite,
82     Html_address,
83     Html_var,
84     Html_dfn,
85 
86     Html_h1,
87     Html_h2,
88     Html_h3,
89     Html_h4,
90     Html_h5,
91     Html_h6,
92     Html_p,
93     Html_center,
94 
95     Html_font,
96 
97     Html_ul,
98     Html_ol,
99     Html_li,
100 
101     Html_code,
102     Html_tt,
103     Html_kbd,
104     Html_samp,
105 
106     Html_img,
107     Html_br,
108     Html_hr,
109 
110     Html_sub,
111     Html_sup,
112 
113     Html_pre,
114     Html_blockquote,
115     Html_head,
116     Html_div,
117     Html_span,
118     Html_dl,
119     Html_dt,
120     Html_dd,
121     Html_u,
122     Html_s,
123     Html_nobr,
124 
125     // tables
126     Html_table,
127     Html_tr,
128     Html_td,
129     Html_th,
130     Html_thead,
131     Html_tbody,
132     Html_tfoot,
133     Html_caption,
134 
135     // misc...
136     Html_html,
137     Html_style,
138     Html_title,
139     Html_meta,
140     Html_link,
141     Html_script,
142 
143     Html_NumElements
144 };
145 
146 struct QTextHtmlElement
147 {
148     const char name[11];
149     QTextHTMLElements id;
150     enum DisplayMode { DisplayBlock, DisplayInline, DisplayTable, DisplayNone } displayMode;
151 };
152 
153 class QTextHtmlParser;
154 
155 struct QTextHtmlParserNode {
156     enum WhiteSpaceMode {
157         WhiteSpaceNormal,
158         WhiteSpacePre,
159         WhiteSpaceNoWrap,
160         WhiteSpacePreWrap,
161         WhiteSpacePreLine,
162         WhiteSpaceModeUndefined = -1
163     };
164 
165     QTextHtmlParserNode();
166     QString tag;
167     QString text;
168     QStringList attributes;
169     int parent;
170     QVector<int> children;
171     QTextHTMLElements id;
172     QTextCharFormat charFormat;
173     QTextBlockFormat blockFormat;
174     uint cssFloat : 2;
175     uint hasOwnListStyle : 1;
176     uint hasOwnLineHeightType : 1;
177     uint hasLineHeightMultiplier : 1;
178     uint hasCssListIndent : 1;
179     uint isEmptyParagraph : 1;
180     uint isTextFrame : 1;
181     uint isRootFrame : 1;
182     uint displayMode : 3; // QTextHtmlElement::DisplayMode
183     uint hasHref : 1;
184     QTextListFormat::Style listStyle;
185     QString textListNumberPrefix;
186     QString textListNumberSuffix;
187     QString imageName;
188     QString imageAlt;
189     qreal imageWidth;
190     qreal imageHeight;
191     QTextLength width;
192     QTextLength height;
193     qreal tableBorder;
194     int tableCellRowSpan;
195     int tableCellColSpan;
196     qreal tableCellSpacing;
197     qreal tableCellPadding;
198     qreal tableCellBorder[4];
199     QBrush tableCellBorderBrush[4];
200     QTextFrameFormat::BorderStyle tableCellBorderStyle[4];
201     QBrush borderBrush;
202     QTextFrameFormat::BorderStyle borderStyle;
203     bool borderCollapse;
204     int userState;
205 
206     int cssListIndent;
207 
208     WhiteSpaceMode wsm;
209 
isListStartQTextHtmlParserNode210     inline bool isListStart() const
211     { return id == Html_ol || id == Html_ul; }
isTableCellQTextHtmlParserNode212     inline bool isTableCell() const
213     { return id == Html_td || id == Html_th; }
isBlockQTextHtmlParserNode214     inline bool isBlock() const
215     { return displayMode == QTextHtmlElement::DisplayBlock; }
216 
isNotSelfNestingQTextHtmlParserNode217     inline bool isNotSelfNesting() const
218     { return id == Html_p || id == Html_li; }
219 
allowedInContextQTextHtmlParserNode220     inline bool allowedInContext(int parentId) const
221     {
222         switch (id) {
223             case Html_dd:
224             case Html_dt: return (parentId == Html_dl);
225             case Html_tr: return (parentId == Html_table
226                                   || parentId == Html_thead
227                                   || parentId == Html_tbody
228                                   || parentId == Html_tfoot
229                                  );
230             case Html_th:
231             case Html_td: return (parentId == Html_tr);
232             case Html_thead:
233             case Html_tbody:
234             case Html_tfoot: return (parentId == Html_table);
235             case Html_caption: return (parentId == Html_table);
236             case Html_body: return parentId != Html_head;
237             default: break;
238         }
239         return true;
240     }
241 
mayNotHaveChildrenQTextHtmlParserNode242     inline bool mayNotHaveChildren() const
243     { return id == Html_img || id == Html_hr || id == Html_br || id == Html_meta; }
244 
245     void initializeProperties(const QTextHtmlParserNode *parent, const QTextHtmlParser *parser);
246 
uncollapsedMarginQTextHtmlParserNode247     inline int uncollapsedMargin(int mar) const { return margin[mar]; }
248 
249     bool isNestedList(const QTextHtmlParser *parser) const;
250 
251     void parseStyleAttribute(const QString &value, const QTextDocument *resourceProvider);
252 
253 #if QT_CONFIG(cssparser)
254     void applyCssDeclarations(const QVector<QCss::Declaration> &declarations, const QTextDocument *resourceProvider);
255 
256     void setListStyle(const QVector<QCss::Value> &cssValues);
257 #endif
258 
259     void applyForegroundImage(qint64 cacheKey, const QTextDocument *resourceProvider);
260     void applyBackgroundImage(const QString &url, const QTextDocument *resourceProvider);
261 
262     bool hasOnlyWhitespace() const;
263 
264     int margin[4];
265     int padding[4];
266 
267     friend class QTextHtmlParser;
268 };
269 Q_DECLARE_TYPEINFO(QTextHtmlParserNode, Q_MOVABLE_TYPE);
270 
271 
272 class QTextHtmlParser
273 {
274 public:
275     enum Margin {
276         MarginTop,
277         MarginRight,
278         MarginBottom,
279         MarginLeft
280     };
281 
at(int i)282     inline const QTextHtmlParserNode &at(int i) const { return nodes.at(i); }
283     inline QTextHtmlParserNode &operator[](int i) { return nodes[i]; }
count()284     inline int count() const { return nodes.count(); }
last()285     inline int last() const { return nodes.count()-1; }
286     int depth(int i) const;
287     int topMargin(int i) const;
288     int bottomMargin(int i) const;
leftMargin(int i)289     inline int leftMargin(int i) const { return margin(i, MarginLeft); }
rightMargin(int i)290     inline int rightMargin(int i) const { return margin(i, MarginRight); }
291 
topPadding(int i)292     inline int topPadding(int i) const { return at(i).padding[MarginTop]; }
bottomPadding(int i)293     inline int bottomPadding(int i) const { return at(i).padding[MarginBottom]; }
leftPadding(int i)294     inline int leftPadding(int i) const { return at(i).padding[MarginLeft]; }
rightPadding(int i)295     inline int rightPadding(int i) const { return at(i).padding[MarginRight]; }
296 
tableCellBorder(int i,int edge)297     inline qreal tableCellBorder(int i, int edge) const { return at(i).tableCellBorder[edge]; }
tableCellBorderStyle(int i,int edge)298     inline QTextFrameFormat::BorderStyle tableCellBorderStyle(int i, int edge) const { return at(i).tableCellBorderStyle[edge]; }
tableCellBorderBrush(int i,int edge)299     inline QBrush tableCellBorderBrush(int i, int edge) const { return at(i).tableCellBorderBrush[edge]; }
300 
301     void dumpHtml();
302 
303     void parse(const QString &text, const QTextDocument *resourceProvider);
304 
305     static int lookupElement(const QString &element);
306 protected:
307     QTextHtmlParserNode *newNode(int parent);
308     QVector<QTextHtmlParserNode> nodes;
309     QString txt;
310     int pos, len;
311 
312     bool textEditMode;
313 
314     void parse();
315     void parseTag();
316     void parseCloseTag();
317     void parseExclamationTag();
318     QString parseEntity();
319     QString parseWord();
320     QTextHtmlParserNode *resolveParent();
321     void resolveNode();
322     QStringList parseAttributes();
323     void applyAttributes(const QStringList &attributes);
324     void eatSpace();
325     inline bool hasPrefix(QChar c, int lookahead = 0) const
326         {return pos + lookahead < len && txt.at(pos) == c; }
327     int margin(int i, int mar) const;
328 
329     bool nodeIsChildOf(int i, QTextHTMLElements id) const;
330 
331 
332 #if QT_CONFIG(cssparser)
333     QVector<QCss::Declaration> declarationsForNode(int node) const;
334     void resolveStyleSheetImports(const QCss::StyleSheet &sheet);
335     void importStyleSheet(const QString &href);
336 
337     struct ExternalStyleSheet
338     {
ExternalStyleSheetExternalStyleSheet339         inline ExternalStyleSheet() {}
ExternalStyleSheetExternalStyleSheet340         inline ExternalStyleSheet(const QString &_url, const QCss::StyleSheet &_sheet)
341             : url(_url), sheet(_sheet) {}
342         QString url;
343         QCss::StyleSheet sheet;
344     };
345     friend class QTypeInfo<ExternalStyleSheet>;
346     QVector<ExternalStyleSheet> externalStyleSheets;
347     QVector<QCss::StyleSheet> inlineStyleSheets;
348 #endif
349 
350     const QTextDocument *resourceProvider;
351 };
352 #if QT_CONFIG(cssparser)
353 Q_DECLARE_TYPEINFO(QTextHtmlParser::ExternalStyleSheet, Q_MOVABLE_TYPE);
354 #endif
355 
356 QT_END_NAMESPACE
357 
358 #endif // QT_NO_TEXTHTMLPARSER
359 
360 #endif // QTEXTHTMLPARSER_P_H
361