1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #ifndef QTEXTHTMLPARSER_P_H
43 #define QTEXTHTMLPARSER_P_H
44 
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55 
56 #include "QtCore/qvector.h"
57 #include "QtGui/qbrush.h"
58 #include "QtGui/qcolor.h"
59 #include "QtGui/qfont.h"
60 #include "QtGui/qtextdocument.h"
61 #include "QtGui/qtextcursor.h"
62 #include "private/qtextformat_p.h"
63 #include "private/qtextdocument_p.h"
64 #include "private/qcssparser_p.h"
65 
66 #ifndef QT_NO_TEXTHTMLPARSER
67 
68 QT_BEGIN_NAMESPACE
69 
70 enum QTextHTMLElements {
71     Html_unknown = -1,
72     Html_qt = 0,
73     Html_body,
74 
75     Html_a,
76     Html_em,
77     Html_i,
78     Html_big,
79     Html_small,
80     Html_strong,
81     Html_b,
82     Html_cite,
83     Html_address,
84     Html_var,
85     Html_dfn,
86 
87     Html_h1,
88     Html_h2,
89     Html_h3,
90     Html_h4,
91     Html_h5,
92     Html_h6,
93     Html_p,
94     Html_center,
95 
96     Html_font,
97 
98     Html_ul,
99     Html_ol,
100     Html_li,
101 
102     Html_code,
103     Html_tt,
104     Html_kbd,
105     Html_samp,
106 
107     Html_img,
108     Html_br,
109     Html_hr,
110 
111     Html_sub,
112     Html_sup,
113 
114     Html_pre,
115     Html_blockquote,
116     Html_head,
117     Html_div,
118     Html_span,
119     Html_dl,
120     Html_dt,
121     Html_dd,
122     Html_u,
123     Html_s,
124     Html_nobr,
125 
126     // tables
127     Html_table,
128     Html_tr,
129     Html_td,
130     Html_th,
131     Html_thead,
132     Html_tbody,
133     Html_tfoot,
134     Html_caption,
135 
136     // misc...
137     Html_html,
138     Html_style,
139     Html_title,
140     Html_meta,
141     Html_link,
142     Html_script,
143 
144     Html_NumElements
145 };
146 
147 struct QTextHtmlElement
148 {
149     const char *name;
150     QTextHTMLElements id;
151     enum DisplayMode { DisplayBlock, DisplayInline, DisplayTable, DisplayNone } displayMode;
152 };
153 
154 class QTextHtmlParser;
155 
156 struct QTextHtmlParserNode {
157     enum WhiteSpaceMode {
158         WhiteSpaceNormal,
159         WhiteSpacePre,
160         WhiteSpaceNoWrap,
161         WhiteSpacePreWrap,
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 hasCssListIndent : 1;
177     uint isEmptyParagraph : 1;
178     uint isTextFrame : 1;
179     uint isRootFrame : 1;
180     uint displayMode : 3; // QTextHtmlElement::DisplayMode
181     uint hasHref : 1;
182     QTextListFormat::Style listStyle;
183     QString textListNumberPrefix;
184     QString textListNumberSuffix;
185     QString imageName;
186     qreal imageWidth;
187     qreal imageHeight;
188     QTextLength width;
189     QTextLength height;
190     qreal tableBorder;
191     int tableCellRowSpan;
192     int tableCellColSpan;
193     qreal tableCellSpacing;
194     qreal tableCellPadding;
195     QBrush borderBrush;
196     QTextFrameFormat::BorderStyle borderStyle;
197     int userState;
198 
199     int cssListIndent;
200 
201     WhiteSpaceMode wsm;
202 
isListStartQTextHtmlParserNode203     inline bool isListStart() const
204     { return id == Html_ol || id == Html_ul; }
isTableCellQTextHtmlParserNode205     inline bool isTableCell() const
206     { return id == Html_td || id == Html_th; }
isBlockQTextHtmlParserNode207     inline bool isBlock() const
208     { return displayMode == QTextHtmlElement::DisplayBlock; }
209 
isNotSelfNestingQTextHtmlParserNode210     inline bool isNotSelfNesting() const
211     { return id == Html_p || id == Html_li; }
212 
allowedInContextQTextHtmlParserNode213     inline bool allowedInContext(int parentId) const
214     {
215         switch (id) {
216             case Html_dd:
217             case Html_dt: return (parentId == Html_dl);
218             case Html_tr: return (parentId == Html_table
219                                   || parentId == Html_thead
220                                   || parentId == Html_tbody
221                                   || parentId == Html_tfoot
222                                  );
223             case Html_th:
224             case Html_td: return (parentId == Html_tr);
225             case Html_thead:
226             case Html_tbody:
227             case Html_tfoot: return (parentId == Html_table);
228             case Html_caption: return (parentId == Html_table);
229             case Html_body: return parentId != Html_head;
230             default: break;
231         }
232         return true;
233     }
234 
mayNotHaveChildrenQTextHtmlParserNode235     inline bool mayNotHaveChildren() const
236     { return id == Html_img || id == Html_hr || id == Html_br || id == Html_meta; }
237 
238     void initializeProperties(const QTextHtmlParserNode *parent, const QTextHtmlParser *parser);
239 
uncollapsedMarginQTextHtmlParserNode240     inline int uncollapsedMargin(int mar) const { return margin[mar]; }
241 
242     bool isNestedList(const QTextHtmlParser *parser) const;
243 
244     void parseStyleAttribute(const QString &value, const QTextDocument *resourceProvider);
245 
246 #ifndef QT_NO_CSSPARSER
247     void applyCssDeclarations(const QVector<QCss::Declaration> &declarations, const QTextDocument *resourceProvider);
248 
249     void setListStyle(const QVector<QCss::Value> &cssValues);
250 #endif
251 
252     void applyBackgroundImage(const QString &url, const QTextDocument *resourceProvider);
253 
254     bool hasOnlyWhitespace() const;
255 
256     int margin[4];
257     int padding[4];
258 
259     friend class QTextHtmlParser;
260 };
261 Q_DECLARE_TYPEINFO(QTextHtmlParserNode, Q_MOVABLE_TYPE);
262 
263 
264 class QTextHtmlParser
265 {
266 public:
267     enum Margin {
268         MarginTop,
269         MarginRight,
270         MarginBottom,
271         MarginLeft
272     };
273 
at(int i)274     inline const QTextHtmlParserNode &at(int i) const { return nodes.at(i); }
275     inline QTextHtmlParserNode &operator[](int i) { return nodes[i]; }
count()276     inline int count() const { return nodes.count(); }
last()277     inline int last() const { return nodes.count()-1; }
278     int depth(int i) const;
279     int topMargin(int i) const;
280     int bottomMargin(int i) const;
leftMargin(int i)281     inline int leftMargin(int i) const { return margin(i, MarginLeft); }
rightMargin(int i)282     inline int rightMargin(int i) const { return margin(i, MarginRight); }
283 
topPadding(int i)284     inline int topPadding(int i) const { return at(i).padding[MarginTop]; }
bottomPadding(int i)285     inline int bottomPadding(int i) const { return at(i).padding[MarginBottom]; }
leftPadding(int i)286     inline int leftPadding(int i) const { return at(i).padding[MarginLeft]; }
rightPadding(int i)287     inline int rightPadding(int i) const { return at(i).padding[MarginRight]; }
288 
289     void dumpHtml();
290 
291     void parse(const QString &text, const QTextDocument *resourceProvider);
292 
293     static int lookupElement(const QString &element);
294 protected:
295     QTextHtmlParserNode *newNode(int parent);
296     QVector<QTextHtmlParserNode> nodes;
297     QString txt;
298     int pos, len;
299 
300     bool textEditMode;
301 
302     void parse();
303     void parseTag();
304     void parseCloseTag();
305     void parseExclamationTag();
306     QString parseEntity();
307     QString parseWord();
308     QTextHtmlParserNode *resolveParent();
309     void resolveNode();
310     QStringList parseAttributes();
311     void applyAttributes(const QStringList &attributes);
312     void eatSpace();
313     inline bool hasPrefix(QChar c, int lookahead = 0) const
314         {return pos + lookahead < len && txt.at(pos) == c; }
315     int margin(int i, int mar) const;
316 
317     bool nodeIsChildOf(int i, QTextHTMLElements id) const;
318 
319 
320 #ifndef QT_NO_CSSPARSER
321     QVector<QCss::Declaration> declarationsForNode(int node) const;
322     void resolveStyleSheetImports(const QCss::StyleSheet &sheet);
323     void importStyleSheet(const QString &href);
324 
325     struct ExternalStyleSheet
326     {
ExternalStyleSheetExternalStyleSheet327         inline ExternalStyleSheet() {}
ExternalStyleSheetExternalStyleSheet328         inline ExternalStyleSheet(const QString &_url, const QCss::StyleSheet &_sheet)
329             : url(_url), sheet(_sheet) {}
330         QString url;
331         QCss::StyleSheet sheet;
332     };
333     QVector<ExternalStyleSheet> externalStyleSheets;
334     QVector<QCss::StyleSheet> inlineStyleSheets;
335 #endif
336 
337     const QTextDocument *resourceProvider;
338 };
339 
340 QT_END_NAMESPACE
341 
342 #endif // QT_NO_TEXTHTMLPARSER
343 
344 #endif // QTEXTHTMLPARSER_P_H
345