1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtGui module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #ifndef QTEXTENGINE_P_H
|
---|
43 | #define QTEXTENGINE_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 for the convenience
|
---|
50 | // of other Qt classes. 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/qglobal.h"
|
---|
57 | #include "QtCore/qstring.h"
|
---|
58 | #include "QtCore/qvarlengtharray.h"
|
---|
59 | #include "QtCore/qnamespace.h"
|
---|
60 | #include "QtGui/qtextlayout.h"
|
---|
61 | #include "private/qtextformat_p.h"
|
---|
62 | #include "private/qfont_p.h"
|
---|
63 | #include "QtCore/qvector.h"
|
---|
64 | #include "QtGui/qpaintengine.h"
|
---|
65 | #include "QtGui/qtextobject.h"
|
---|
66 | #include "QtGui/qtextoption.h"
|
---|
67 | #include "QtCore/qset.h"
|
---|
68 | #include "QtCore/qdebug.h"
|
---|
69 | #ifndef QT_BUILD_COMPAT_LIB
|
---|
70 | #include "private/qtextdocument_p.h"
|
---|
71 | #endif
|
---|
72 | #include "private/qharfbuzz_p.h"
|
---|
73 | #include "private/qfixed_p.h"
|
---|
74 |
|
---|
75 | #include <stdlib.h>
|
---|
76 |
|
---|
77 | QT_BEGIN_NAMESPACE
|
---|
78 |
|
---|
79 | class QFontPrivate;
|
---|
80 | class QFontEngine;
|
---|
81 |
|
---|
82 | class QString;
|
---|
83 | class QPainter;
|
---|
84 |
|
---|
85 | class QAbstractTextDocumentLayout;
|
---|
86 |
|
---|
87 |
|
---|
88 | // this uses the same coordinate system as Qt, but a different one to freetype.
|
---|
89 | // * y is usually negative, and is equal to the ascent.
|
---|
90 | // * negative yoff means the following stuff is drawn higher up.
|
---|
91 | // the characters bounding rect is given by QRect(x,y,width,height), its advance by
|
---|
92 | // xoo and yoff
|
---|
93 | struct glyph_metrics_t
|
---|
94 | {
|
---|
95 | inline glyph_metrics_t()
|
---|
96 | : x(100000), y(100000) {}
|
---|
97 | inline glyph_metrics_t(QFixed _x, QFixed _y, QFixed _width, QFixed _height, QFixed _xoff, QFixed _yoff)
|
---|
98 | : x(_x),
|
---|
99 | y(_y),
|
---|
100 | width(_width),
|
---|
101 | height(_height),
|
---|
102 | xoff(_xoff),
|
---|
103 | yoff(_yoff)
|
---|
104 | {}
|
---|
105 | QFixed x;
|
---|
106 | QFixed y;
|
---|
107 | QFixed width;
|
---|
108 | QFixed height;
|
---|
109 | QFixed xoff;
|
---|
110 | QFixed yoff;
|
---|
111 |
|
---|
112 | glyph_metrics_t transformed(const QTransform &xform) const;
|
---|
113 | };
|
---|
114 | Q_DECLARE_TYPEINFO(glyph_metrics_t, Q_PRIMITIVE_TYPE);
|
---|
115 |
|
---|
116 | struct Q_AUTOTEST_EXPORT QScriptAnalysis
|
---|
117 | {
|
---|
118 | enum Flags {
|
---|
119 | None = 0,
|
---|
120 | Lowercase = 1,
|
---|
121 | Uppercase = 2,
|
---|
122 | SmallCaps = 3,
|
---|
123 | LineOrParagraphSeparator = 4,
|
---|
124 | Space = 5,
|
---|
125 | SpaceTabOrObject = Space,
|
---|
126 | Tab = 6,
|
---|
127 | TabOrObject = Tab,
|
---|
128 | Object = 7
|
---|
129 | };
|
---|
130 | unsigned short script : 8;
|
---|
131 | unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61)
|
---|
132 | unsigned short flags : 3;
|
---|
133 | inline bool operator == (const QScriptAnalysis &other) const {
|
---|
134 | return script == other.script && bidiLevel == other.bidiLevel && flags == other.flags;
|
---|
135 | }
|
---|
136 | };
|
---|
137 | Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE);
|
---|
138 |
|
---|
139 | struct QGlyphJustification
|
---|
140 | {
|
---|
141 | inline QGlyphJustification()
|
---|
142 | : type(0), nKashidas(0), space_18d6(0)
|
---|
143 | {}
|
---|
144 |
|
---|
145 | enum JustificationType {
|
---|
146 | JustifyNone,
|
---|
147 | JustifySpace,
|
---|
148 | JustifyKashida
|
---|
149 | };
|
---|
150 |
|
---|
151 | uint type :2;
|
---|
152 | uint nKashidas : 6; // more do not make sense...
|
---|
153 | uint space_18d6 : 24;
|
---|
154 | };
|
---|
155 | Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE);
|
---|
156 |
|
---|
157 | struct QGlyphLayoutInstance
|
---|
158 | {
|
---|
159 | QFixedPoint offset;
|
---|
160 | QFixedPoint advance;
|
---|
161 | HB_Glyph glyph;
|
---|
162 | QGlyphJustification justification;
|
---|
163 | HB_GlyphAttributes attributes;
|
---|
164 | };
|
---|
165 |
|
---|
166 | struct QGlyphLayout
|
---|
167 | {
|
---|
168 | // init to 0 not needed, done when shaping
|
---|
169 | QFixedPoint *offsets; // 8 bytes per element
|
---|
170 | HB_Glyph *glyphs; // 4 bytes per element
|
---|
171 | QFixed *advances_x; // 4 bytes per element
|
---|
172 | QFixed *advances_y; // 4 bytes per element
|
---|
173 | QGlyphJustification *justifications; // 4 bytes per element
|
---|
174 | HB_GlyphAttributes *attributes; // 2 bytes per element
|
---|
175 |
|
---|
176 | int numGlyphs;
|
---|
177 |
|
---|
178 | inline QGlyphLayout() : numGlyphs(0) {}
|
---|
179 |
|
---|
180 | inline explicit QGlyphLayout(char *address, int totalGlyphs)
|
---|
181 | {
|
---|
182 | offsets = reinterpret_cast<QFixedPoint *>(address);
|
---|
183 | int offset = totalGlyphs * sizeof(HB_FixedPoint);
|
---|
184 | glyphs = reinterpret_cast<HB_Glyph *>(address + offset);
|
---|
185 | offset += totalGlyphs * sizeof(HB_Glyph);
|
---|
186 | advances_x = reinterpret_cast<QFixed *>(address + offset);
|
---|
187 | offset += totalGlyphs * sizeof(QFixed);
|
---|
188 | advances_y = reinterpret_cast<QFixed *>(address + offset);
|
---|
189 | offset += totalGlyphs * sizeof(QFixed);
|
---|
190 | justifications = reinterpret_cast<QGlyphJustification *>(address + offset);
|
---|
191 | offset += totalGlyphs * sizeof(QGlyphJustification);
|
---|
192 | attributes = reinterpret_cast<HB_GlyphAttributes *>(address + offset);
|
---|
193 | numGlyphs = totalGlyphs;
|
---|
194 | }
|
---|
195 |
|
---|
196 | inline QGlyphLayout mid(int position, int n = -1) const {
|
---|
197 | QGlyphLayout copy = *this;
|
---|
198 | copy.glyphs += position;
|
---|
199 | copy.advances_x += position;
|
---|
200 | copy.advances_y += position;
|
---|
201 | copy.offsets += position;
|
---|
202 | copy.justifications += position;
|
---|
203 | copy.attributes += position;
|
---|
204 | if (n == -1)
|
---|
205 | copy.numGlyphs -= position;
|
---|
206 | else
|
---|
207 | copy.numGlyphs = n;
|
---|
208 | return copy;
|
---|
209 | }
|
---|
210 |
|
---|
211 | static inline int spaceNeededForGlyphLayout(int totalGlyphs) {
|
---|
212 | return totalGlyphs * (sizeof(HB_Glyph) + sizeof(HB_GlyphAttributes)
|
---|
213 | + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
|
---|
214 | + sizeof(QGlyphJustification));
|
---|
215 | }
|
---|
216 |
|
---|
217 | inline QFixed effectiveAdvance(int item) const
|
---|
218 | { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
|
---|
219 |
|
---|
220 | inline QGlyphLayoutInstance instance(int position) const {
|
---|
221 | QGlyphLayoutInstance g;
|
---|
222 | g.offset.x = offsets[position].x;
|
---|
223 | g.offset.y = offsets[position].y;
|
---|
224 | g.glyph = glyphs[position];
|
---|
225 | g.advance.x = advances_x[position];
|
---|
226 | g.advance.y = advances_y[position];
|
---|
227 | g.justification = justifications[position];
|
---|
228 | g.attributes = attributes[position];
|
---|
229 | return g;
|
---|
230 | }
|
---|
231 |
|
---|
232 | inline void setInstance(int position, const QGlyphLayoutInstance &g) {
|
---|
233 | offsets[position].x = g.offset.x;
|
---|
234 | offsets[position].y = g.offset.y;
|
---|
235 | glyphs[position] = g.glyph;
|
---|
236 | advances_x[position] = g.advance.x;
|
---|
237 | advances_y[position] = g.advance.y;
|
---|
238 | justifications[position] = g.justification;
|
---|
239 | attributes[position] = g.attributes;
|
---|
240 | }
|
---|
241 |
|
---|
242 | inline void clear(int first = 0, int last = -1) {
|
---|
243 | if (last == -1)
|
---|
244 | last = numGlyphs;
|
---|
245 | if (first == 0 && last == numGlyphs
|
---|
246 | && reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) {
|
---|
247 | memset(offsets, 0, spaceNeededForGlyphLayout(numGlyphs));
|
---|
248 | } else {
|
---|
249 | const int num = last - first;
|
---|
250 | memset(offsets + first, 0, num * sizeof(QFixedPoint));
|
---|
251 | memset(glyphs + first, 0, num * sizeof(HB_Glyph));
|
---|
252 | memset(advances_x + first, 0, num * sizeof(QFixed));
|
---|
253 | memset(advances_y + first, 0, num * sizeof(QFixed));
|
---|
254 | memset(justifications + first, 0, num * sizeof(QGlyphJustification));
|
---|
255 | memset(attributes + first, 0, num * sizeof(HB_GlyphAttributes));
|
---|
256 | }
|
---|
257 | }
|
---|
258 |
|
---|
259 | inline char *data() {
|
---|
260 | return reinterpret_cast<char *>(offsets);
|
---|
261 | }
|
---|
262 |
|
---|
263 | void grow(char *address, int totalGlyphs);
|
---|
264 | };
|
---|
265 |
|
---|
266 | class QVarLengthGlyphLayoutArray : private QVarLengthArray<void *>, public QGlyphLayout
|
---|
267 | {
|
---|
268 | private:
|
---|
269 | typedef QVarLengthArray<void *> Array;
|
---|
270 | public:
|
---|
271 | QVarLengthGlyphLayoutArray(int totalGlyphs)
|
---|
272 | : Array(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1)
|
---|
273 | , QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs)
|
---|
274 | {
|
---|
275 | memset(Array::data(), 0, Array::size() * sizeof(void *));
|
---|
276 | }
|
---|
277 |
|
---|
278 | void resize(int totalGlyphs)
|
---|
279 | {
|
---|
280 | Array::resize(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1);
|
---|
281 |
|
---|
282 | *((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs);
|
---|
283 | memset(Array::data(), 0, Array::size() * sizeof(void *));
|
---|
284 | }
|
---|
285 | };
|
---|
286 |
|
---|
287 | template <int N> struct QGlyphLayoutArray : public QGlyphLayout
|
---|
288 | {
|
---|
289 | public:
|
---|
290 | QGlyphLayoutArray()
|
---|
291 | : QGlyphLayout(reinterpret_cast<char *>(buffer), N)
|
---|
292 | {
|
---|
293 | memset(buffer, 0, sizeof(buffer));
|
---|
294 | }
|
---|
295 |
|
---|
296 | private:
|
---|
297 | void *buffer[(N * (sizeof(HB_Glyph) + sizeof(HB_GlyphAttributes)
|
---|
298 | + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
|
---|
299 | + sizeof(QGlyphJustification)))
|
---|
300 | / sizeof(void *) + 1];
|
---|
301 | };
|
---|
302 |
|
---|
303 | struct QScriptItem;
|
---|
304 | /// Internal QTextItem
|
---|
305 | class QTextItemInt : public QTextItem
|
---|
306 | {
|
---|
307 | public:
|
---|
308 | inline QTextItemInt()
|
---|
309 | : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(0),
|
---|
310 | logClusters(0), f(0), fontEngine(0)
|
---|
311 | {}
|
---|
312 | QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
|
---|
313 |
|
---|
314 | /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
|
---|
315 | /// the width of the returned QTextItemInt is not adjusted, for speed reasons
|
---|
316 | QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const;
|
---|
317 |
|
---|
318 | QFixed descent;
|
---|
319 | QFixed ascent;
|
---|
320 | QFixed width;
|
---|
321 |
|
---|
322 | RenderFlags flags;
|
---|
323 | bool justified;
|
---|
324 | QTextCharFormat::UnderlineStyle underlineStyle;
|
---|
325 | const QTextCharFormat charFormat;
|
---|
326 | int num_chars;
|
---|
327 | const QChar *chars;
|
---|
328 | const unsigned short *logClusters;
|
---|
329 | const QFont *f;
|
---|
330 |
|
---|
331 | QGlyphLayout glyphs;
|
---|
332 | QFontEngine *fontEngine;
|
---|
333 | };
|
---|
334 |
|
---|
335 | inline bool qIsControlChar(ushort uc)
|
---|
336 | {
|
---|
337 | return uc >= 0x200b && uc <= 0x206f
|
---|
338 | && (uc <= 0x200f /* ZW Space, ZWNJ, ZWJ, LRM and RLM */
|
---|
339 | || (uc >= 0x2028 && uc <= 0x202f /* LS, PS, LRE, RLE, PDF, LRO, RLO, NNBSP */)
|
---|
340 | || uc >= 0x206a /* ISS, ASS, IAFS, AFS, NADS, NODS */);
|
---|
341 | }
|
---|
342 |
|
---|
343 | struct Q_AUTOTEST_EXPORT QScriptItem
|
---|
344 | {
|
---|
345 | inline QScriptItem()
|
---|
346 | : position(0),
|
---|
347 | num_glyphs(0), descent(-1), ascent(-1), width(-1),
|
---|
348 | glyph_data_offset(0) {}
|
---|
349 | inline QScriptItem(int p, const QScriptAnalysis &a)
|
---|
350 | : position(p), analysis(a),
|
---|
351 | num_glyphs(0), descent(-1), ascent(-1), width(-1),
|
---|
352 | glyph_data_offset(0) {}
|
---|
353 |
|
---|
354 | int position;
|
---|
355 | QScriptAnalysis analysis;
|
---|
356 | unsigned short num_glyphs;
|
---|
357 | QFixed descent;
|
---|
358 | QFixed ascent;
|
---|
359 | QFixed width;
|
---|
360 | int glyph_data_offset;
|
---|
361 | QFixed height() const { return ascent + descent + 1; }
|
---|
362 | };
|
---|
363 |
|
---|
364 |
|
---|
365 | Q_DECLARE_TYPEINFO(QScriptItem, Q_MOVABLE_TYPE);
|
---|
366 |
|
---|
367 | typedef QVector<QScriptItem> QScriptItemArray;
|
---|
368 |
|
---|
369 | struct Q_AUTOTEST_EXPORT QScriptLine
|
---|
370 | {
|
---|
371 | // created and filled in QTextLine::layout_helper
|
---|
372 | QScriptLine()
|
---|
373 | : from(0), length(0),
|
---|
374 | justified(0), gridfitted(0),
|
---|
375 | hasTrailingSpaces(0) {}
|
---|
376 | QFixed descent;
|
---|
377 | QFixed ascent;
|
---|
378 | QFixed x;
|
---|
379 | QFixed y;
|
---|
380 | QFixed width;
|
---|
381 | QFixed textWidth;
|
---|
382 | int from;
|
---|
383 | signed int length : 29;
|
---|
384 | mutable uint justified : 1;
|
---|
385 | mutable uint gridfitted : 1;
|
---|
386 | uint hasTrailingSpaces : 1;
|
---|
387 | QFixed height() const { return ascent + descent + 1; }
|
---|
388 | void setDefaultHeight(QTextEngine *eng);
|
---|
389 | void operator+=(const QScriptLine &other);
|
---|
390 | };
|
---|
391 | Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
|
---|
392 |
|
---|
|
---|