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 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 "QtGui/qtextcursor.h"
68 #include "QtCore/qset.h"
69 #include "QtCore/qdebug.h"
70 #ifndef QT_BUILD_COMPAT_LIB
71 #include "private/qtextdocument_p.h"
72 #endif
73 #include "private/qharfbuzz_p.h"
74 #include "private/qfixed_p.h"
75
76 #include <stdlib.h>
77
78 QT_BEGIN_NAMESPACE
79
80 class QFontPrivate;
81 class QFontEngine;
82
83 class QString;
84 class QPainter;
85
86 class QAbstractTextDocumentLayout;
87
88
89 // this uses the same coordinate system as Qt, but a different one to freetype.
90 // * y is usually negative, and is equal to the ascent.
91 // * negative yoff means the following stuff is drawn higher up.
92 // the characters bounding rect is given by QRect(x,y,width,height), its advance by
93 // xoo and yoff
94 struct glyph_metrics_t
95 {
glyph_metrics_tglyph_metrics_t96 inline glyph_metrics_t()
97 : x(100000), y(100000) {}
glyph_metrics_tglyph_metrics_t98 inline glyph_metrics_t(QFixed _x, QFixed _y, QFixed _width, QFixed _height, QFixed _xoff, QFixed _yoff)
99 : x(_x),
100 y(_y),
101 width(_width),
102 height(_height),
103 xoff(_xoff),
104 yoff(_yoff)
105 {}
106 QFixed x;
107 QFixed y;
108 QFixed width;
109 QFixed height;
110 QFixed xoff;
111 QFixed yoff;
112
113 glyph_metrics_t transformed(const QTransform &xform) const;
isValidglyph_metrics_t114 inline bool isValid() const {return x != 100000 && y != 100000;}
115 };
116 Q_DECLARE_TYPEINFO(glyph_metrics_t, Q_PRIMITIVE_TYPE);
117
118 struct Q_AUTOTEST_EXPORT QScriptAnalysis
119 {
120 enum Flags {
121 None = 0,
122 Lowercase = 1,
123 Uppercase = 2,
124 SmallCaps = 3,
125 LineOrParagraphSeparator = 4,
126 Space = 5,
127 SpaceTabOrObject = Space,
128 Tab = 6,
129 TabOrObject = Tab,
130 Object = 7
131 };
132 unsigned short script : 7;
133 unsigned short bidiLevel : 6; // Unicode Bidi algorithm embedding level (0-61)
134 unsigned short flags : 3;
135 inline bool operator == (const QScriptAnalysis &other) const {
136 return script == other.script && bidiLevel == other.bidiLevel && flags == other.flags;
137 }
138 };
139 Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE);
140
141 struct QGlyphJustification
142 {
QGlyphJustificationQGlyphJustification143 inline QGlyphJustification()
144 : type(0), nKashidas(0), space_18d6(0)
145 {}
146
147 enum JustificationType {
148 JustifyNone,
149 JustifySpace,
150 JustifyKashida
151 };
152
153 uint type :2;
154 uint nKashidas : 6; // more do not make sense...
155 uint space_18d6 : 24;
156 };
157 Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE);
158
159 struct QGlyphLayoutInstance
160 {
161 QFixedPoint offset;
162 QFixedPoint advance;
163 HB_Glyph glyph;
164 QGlyphJustification justification;
165 HB_GlyphAttributes attributes;
166 };
167
168 struct QGlyphLayout
169 {
170 // init to 0 not needed, done when shaping
171 QFixedPoint *offsets; // 8 bytes per element
172 HB_Glyph *glyphs; // 4 bytes per element
173 QFixed *advances_x; // 4 bytes per element
174 QFixed *advances_y; // 4 bytes per element
175 QGlyphJustification *justifications; // 4 bytes per element
176 HB_GlyphAttributes *attributes; // 2 bytes per element
177
178 int numGlyphs;
179
QGlyphLayoutQGlyphLayout180 inline QGlyphLayout() : numGlyphs(0) {}
181
QGlyphLayoutQGlyphLayout182 inline explicit QGlyphLayout(char *address, int totalGlyphs)
183 {
184 offsets = reinterpret_cast<QFixedPoint *>(address);
185 int offset = totalGlyphs * sizeof(HB_FixedPoint);
186 glyphs = reinterpret_cast<HB_Glyph *>(address + offset);
187 offset += totalGlyphs * sizeof(HB_Glyph);
188 advances_x = reinterpret_cast<QFixed *>(address + offset);
189 offset += totalGlyphs * sizeof(QFixed);
190 advances_y = reinterpret_cast<QFixed *>(address + offset);
191 offset += totalGlyphs * sizeof(QFixed);
192 justifications = reinterpret_cast<QGlyphJustification *>(address + offset);
193 offset += totalGlyphs * sizeof(QGlyphJustification);
194 attributes = reinterpret_cast<HB_GlyphAttributes *>(address + offset);
195 numGlyphs = totalGlyphs;
196 }
197
198 inline QGlyphLayout mid(int position, int n = -1) const {
199 QGlyphLayout copy = *this;
200 copy.glyphs += position;
201 copy.advances_x += position;
202 copy.advances_y += position;
203 copy.offsets += position;
204 copy.justifications += position;
205 copy.attributes += position;
206 if (n == -1)
207 copy.numGlyphs -= position;
208 else
209 copy.numGlyphs = n;
210 return copy;
211 }
212
spaceNeededForGlyphLayoutQGlyphLayout213 static inline int spaceNeededForGlyphLayout(int totalGlyphs) {
214 return totalGlyphs * (sizeof(HB_Glyph) + sizeof(HB_GlyphAttributes)
215 + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
216 + sizeof(QGlyphJustification));
217 }
218
effectiveAdvanceQGlyphLayout219 inline QFixed effectiveAdvance(int item) const
220 { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
221
instanceQGlyphLayout222 inline QGlyphLayoutInstance instance(int position) const {
223 QGlyphLayoutInstance g;
224 g.offset.x = offsets[position].x;
225 g.offset.y = offsets[position].y;
226 g.glyph = glyphs[position];
227 g.advance.x = advances_x[position];
228 g.advance.y = advances_y[position];
229 g.justification = justifications[position];
230 g.attributes = attributes[position];
231 return g;
232 }
233
setInstanceQGlyphLayout234 inline void setInstance(int position, const QGlyphLayoutInstance &g) {
235 offsets[position].x = g.offset.x;
236 offsets[position].y = g.offset.y;
237 glyphs[position] = g.glyph;
238 advances_x[position] = g.advance.x;
239 advances_y[position] = g.advance.y;
240 justifications[position] = g.justification;
241 attributes[position] = g.attributes;
242 }
243
244 inline void clear(int first = 0, int last = -1) {
245 if (last == -1)
246 last = numGlyphs;
247 if (first == 0 && last == numGlyphs
248 && reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) {
249 memset(offsets, 0, spaceNeededForGlyphLayout(numGlyphs));
250 } else {
251 const int num = last - first;
252 memset(offsets + first, 0, num * sizeof(QFixedPoint));
253 memset(glyphs + first, 0, num * sizeof(HB_Glyph));
254 memset(advances_x + first, 0, num * sizeof(QFixed));
255 memset(advances_y + first, 0, num * sizeof(QFixed));
256 memset(justifications + first, 0, num * sizeof(QGlyphJustification));
257 memset(attributes + first, 0, num * sizeof(HB_GlyphAttributes));
258 }
259 }
260
dataQGlyphLayout261 inline char *data() {
262 return reinterpret_cast<char *>(offsets);
263 }
264
265 void grow(char *address, int totalGlyphs);
266 };
267
268 class QVarLengthGlyphLayoutArray : private QVarLengthArray<void *>, public QGlyphLayout
269 {
270 private:
271 typedef QVarLengthArray<void *> Array;
272 public:
QVarLengthGlyphLayoutArray(int totalGlyphs)273 QVarLengthGlyphLayoutArray(int totalGlyphs)
274 : Array(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1)
275 , QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs)
276 {
277 memset(Array::data(), 0, Array::size() * sizeof(void *));
278 }
279
resize(int totalGlyphs)280 void resize(int totalGlyphs)
281 {
282 Array::resize(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1);
283
284 *((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs);
285 memset(Array::data(), 0, Array::size() * sizeof(void *));
286 }
287 };
288
289 template <int N> struct QGlyphLayoutArray : public QGlyphLayout
290 {
291 public:
QGlyphLayoutArrayQGlyphLayoutArray292 QGlyphLayoutArray()
293 : QGlyphLayout(reinterpret_cast<char *>(buffer), N)
294 {
295 memset(buffer, 0, sizeof(buffer));
296 }
297
298 private:
299 void *buffer[(N * (sizeof(HB_Glyph) + sizeof(HB_GlyphAttributes)
300 + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
301 + sizeof(QGlyphJustification)))
302 / sizeof(void *) + 1];
303 };
304
305 struct QScriptItem;
306 /// Internal QTextItem
307 class QTextItemInt : public QTextItem
308 {
309 public:
QTextItemInt()310 inline QTextItemInt()
311 : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(0),
312 logClusters(0), f(0), fontEngine(0)
313 {}
314 QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
315 QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars, int numChars, QFontEngine *fe,
316 const QTextCharFormat &format = QTextCharFormat());
317
318 /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
319 /// the width of the returned QTextItemInt is not adjusted, for speed reasons
320 QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const;
321 void initWithScriptItem(const QScriptItem &si);
322
323 QFixed descent;
324 QFixed ascent;
325 QFixed width;
326
327 RenderFlags flags;
328 bool justified;
329 QTextCharFormat::UnderlineStyle underlineStyle;
330 const QTextCharFormat charFormat;
331 int num_chars;
332 const QChar *chars;
333 const unsigned short *logClusters;
334 const QFont *f;
335
336 QGlyphLayout glyphs;
337 QFontEngine *fontEngine;
338 };
339
qIsControlChar(ushort uc)340 inline bool qIsControlChar(ushort uc)
341 {
342 return uc >= 0x200b && uc <= 0x206f
343 && (uc <= 0x200f /* ZW Space, ZWNJ, ZWJ, LRM and RLM */
344 || (uc >= 0x2028 && uc <= 0x202f /* LS, PS, LRE, RLE, PDF, LRO, RLO, NNBSP */)
345 || uc >= 0x206a /* ISS, ASS, IAFS, AFS, NADS, NODS */);
346 }
347
348 struct Q_AUTOTEST_EXPORT QScriptItem
349 {
QScriptItemQScriptItem350 inline QScriptItem()
351 : position(0),
352 num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
353 glyph_data_offset(0) {}
QScriptItemQScriptItem354 inline QScriptItem(int p, const QScriptAnalysis &a)
355 : position(p), analysis(a),
356 num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
357 glyph_data_offset(0) {}
358
359 int position;
360 QScriptAnalysis analysis;
361 unsigned short num_glyphs;
362 QFixed descent;
363 QFixed ascent;
364 QFixed leading;
365 QFixed width;
366 int glyph_data_offset;
heightQScriptItem367 QFixed height() const { return ascent + descent + 1; }
368 };
369
370
371 Q_DECLARE_TYPEINFO(QScriptItem, Q_MOVABLE_TYPE);
372
373 typedef QVector<QScriptItem> QScriptItemArray;
374
375 struct Q_AUTOTEST_EXPORT QScriptLine
376 {
377 // created and filled in QTextLine::layout_helper
QScriptLineQScriptLine378 QScriptLine()
379 : from(0), trailingSpaces(0), length(0),
380 justified(0), gridfitted(0),
381 hasTrailingSpaces(0), leadingIncluded(0) {}
382 QFixed descent;
383 QFixed ascent;
384 QFixed leading;
385 QFixed x;
386 QFixed y;
387 QFixed width;
388 QFixed textWidth;
389 QFixed textAdvance;
390 int from;
391 unsigned short trailingSpaces;
392 signed int length : 28;
393 mutable uint justified : 1;
394 mutable uint gridfitted : 1;
395 uint hasTrailingSpaces : 1;
396 uint leadingIncluded : 1;
heightQScriptLine397 QFixed height() const { return (ascent + descent).ceil() + 1
398 + (leadingIncluded? qMax(QFixed(),leading) : QFixed()); }
baseQScriptLine399 QFixed base() const { return ascent
400 + (leadingIncluded ? qMax(QFixed(),leading) : QFixed()); }
401 void setDefaultHeight(QTextEngine *eng);
402 void operator+=(const QScriptLine &other);
403 };
404 Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
405
406
407 inline void QScriptLine::operator+=(const QScriptLine &other)
408 {
409 leading= qMax(leading + ascent, other.leading + other.ascent) - qMax(ascent, other.ascent);
410 descent = qMax(descent, other.descent);
411 ascent = qMax(ascent, other.ascent);
412 textWidth += other.textWidth;
413 length += other.length;
414 }
415
416 typedef QVector<QScriptLine> QScriptLineArray;
417
418 class QFontPrivate;
419 class QTextFormatCollection;
420
421 class Q_GUI_EXPORT QTextEngine {
422 public:
423 enum LayoutState {
424 LayoutEmpty,
425 InLayout,
426 LayoutFailed,
427 };
428 struct LayoutData {
429 LayoutData(const QString &str, void **stack_memory, int mem_size);
430 LayoutData();
431 ~LayoutData();
432 mutable QScriptItemArray items;
433 int allocated;
434 int available_glyphs;
435 void **memory;
436 unsigned short *logClustersPtr;
437 QGlyphLayout glyphLayout;
438 mutable int used;
439 uint hasBidi : 1;
440 uint layoutState : 2;
441 uint memory_on_stack : 1;
442 uint haveCharAttributes : 1;
443 QString string;
444 bool reallocate(int totalGlyphs);
445 };
446
447 QTextEngine(LayoutData *data);
448 QTextEngine();
449 QTextEngine(const QString &str, const QFont &f);
450 ~QTextEngine();
451
452 enum Mode {
453 WidthOnly = 0x07
454 };
455
456 // keep in sync with QAbstractFontEngine::TextShapingFlag!!
457 enum ShaperFlag {
458 RightToLeft = 0x0001,
459 DesignMetrics = 0x0002,
460 GlyphIndicesOnly = 0x0004
461 };
462 Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
463
464 void invalidate();
465 void clearLineData();
466
467 void validate() const;
468 void itemize() const;
469
470 bool isRightToLeft() const;
471 static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
472
473 const HB_CharAttributes *attributes() const;
474
475 void shape(int item) const;
476
477 void justify(const QScriptLine &si);
478 QFixed alignLine(const QScriptLine &line);
479
480 QFixed width(int charFrom, int numChars) const;
481 glyph_metrics_t boundingBox(int from, int len) const;
482 glyph_metrics_t tightBoundingBox(int from, int len) const;
483
length(int item)484 int length(int item) const {
485 const QScriptItem &si = layoutData->items[item];
486 int from = si.position;
487 item++;
488 return (item < layoutData->items.size() ? layoutData->items[item].position : layoutData->string.length()) - from;
489 }
length(const QScriptItem * si)490 int length(const QScriptItem *si) const {
491 int end;
492 if (si + 1 < layoutData->items.constData()+ layoutData->items.size())
493 end = (si+1)->position;
494 else
495 end = layoutData->string.length();
496 return end - si->position;
497 }
498
499 QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = 0, QFixed *descent = 0, QFixed *leading = 0) const;
500 QFont font(const QScriptItem &si) const;
font()501 inline QFont font() const { return fnt; }
502
503 /**
504 * Returns a pointer to an array of log clusters, offset at the script item.
505 * Each item in the array is a unsigned short. For each character in the original string there is an entry in the table
506 * so there is a one to one correlation in indexes between the original text and the index in the logcluster.
507 * The value of each item is the position in the glyphs array. Multiple similar pointers in the logclusters array imply
508 * that one glyph is used for more than one character.
509 * \sa glyphs()
510 */
logClusters(const QScriptItem * si)511 inline unsigned short *logClusters(const QScriptItem *si) const
512 { return layoutData->logClustersPtr+si->position; }
513 /**
514 * Returns an array of QGlyphLayout items, offset at the script item.
515 * Each item in the array matches one glyph in the text, storing the advance, position etc.
516 * The returned item's length equals to the number of available glyphs. This may be more
517 * than what was actually shaped.
518 * \sa logClusters()
519 */
availableGlyphs(const QScriptItem * si)520 inline QGlyphLayout availableGlyphs(const QScriptItem *si) const {
521 return layoutData->glyphLayout.mid(si->glyph_data_offset);
522 }
523 /**
524 * Returns an array of QGlyphLayout items, offset at the script item.
525 * Each item in the array matches one glyph in the text, storing the advance, position etc.
526 * The returned item's length equals to the number of shaped glyphs.
527 * \sa logClusters()
528 */
shapedGlyphs(const QScriptItem * si)529 inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const {
530 return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs);
531 }
532
ensureSpace(int nGlyphs)533 inline bool ensureSpace(int nGlyphs) const {
534 if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
535 return layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
536 return true;
537 }
538
539 void freeMemory();
540
541 int findItem(int strPos) const;
formats()542 inline QTextFormatCollection *formats() const {
543 #ifdef QT_BUILD_COMPAT_LIB
544 return 0; // Compat should never reference this symbol
545 #else
546 return block.docHandle()->formatCollection();
547 #endif
548 }
549 QTextCharFormat format(const QScriptItem *si) const;
docLayout()550 inline QAbstractTextDocumentLayout *docLayout() const {
551 #ifdef QT_BUILD_COMPAT_LIB
552 return 0; // Compat should never reference this symbol
553 #else
554 return block.docHandle()->document()->documentLayout();
555 #endif
556 }
557 int formatIndex(const QScriptItem *si) const;
558
559 /// returns the width of tab at index (in the tabs array) with the tab-start at position x
560 QFixed calculateTabWidth(int index, QFixed x) const;
561
562 mutable QScriptLineArray lines;
563
564 struct FontEngineCache {
565 FontEngineCache();
566 mutable QFontEngine *prevFontEngine;
567 mutable QFontEngine *prevScaledFontEngine;
568 mutable int prevScript;
569 mutable int prevPosition;
570 mutable int prevLength;
resetFontEngineCache571 inline void reset() {
572 prevFontEngine = 0;
573 prevScaledFontEngine = 0;
574 prevScript = -1;
575 prevPosition = -1;
576 prevLength = -1;
577 }
578 };
579 mutable FontEngineCache feCache;
580
581 QString text;
582 QFont fnt;
583 QTextBlock block;
584
585 QTextOption option;
586
587 QFixed minWidth;
588 QFixed maxWidth;
589 QPointF position;
590 uint ignoreBidi : 1;
591 uint cacheGlyphs : 1;
592 uint stackEngine : 1;
593 uint forceJustification : 1;
594 uint visualMovement : 1;
595
596 int *underlinePositions;
597
598 mutable LayoutData *layoutData;
599
hasFormats()600 inline bool hasFormats() const { return (block.docHandle() || specialData); }
visualCursorMovement()601 inline bool visualCursorMovement() const
602 {
603 return (visualMovement ||
604 (block.docHandle() ? block.docHandle()->defaultCursorMoveStyle == Qt::VisualMoveStyle : false));
605 }
606
607 struct SpecialData {
608 int preeditPosition;
609 QString preeditText;
610 QList<QTextLayout::FormatRange> addFormats;
611 QVector<int> addFormatIndices;
612 QVector<int> resolvedFormatIndices;
613 };
614 SpecialData *specialData;
615
616 bool atWordSeparator(int position) const;
617 bool atSpace(int position) const;
618 void indexAdditionalFormats();
619
620 QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const;
621
622 void shapeLine(const QScriptLine &line);
623 QFixed leadingSpaceWidth(const QScriptLine &line);
624
625 QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
626 int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
627 int previousLogicalPosition(int oldPos) const;
628 int nextLogicalPosition(int oldPos) const;
629 int lineNumberForTextPosition(int pos);
630 int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op);
631 void insertionPointsForLine(int lineNum, QVector<int> &insertionPoints);
632 void resetFontEngineCache();
633
634 private:
635 void setBoundary(int strPos) const;
636 void addRequiredBoundaries() const;
637 void shapeText(int item) const;
638 void shapeTextWithHarfbuzz(int item) const;
639 #if defined(Q_WS_WINCE)
640 void shapeTextWithCE(int item) const;
641 #endif
642 #if defined(Q_WS_MAC)
643 void shapeTextMac(int item) const;
644 #endif
645 void splitItem(int item, int pos) const;
646
647 void resolveAdditionalFormats() const;
648 int endOfLine(int lineNum);
649 int beginningOfLine(int lineNum);
650 int getClusterLength(unsigned short *logClusters, const HB_CharAttributes *attributes, int from, int to, int glyph_pos, int *start);
651 };
652
653 class QStackTextEngine : public QTextEngine {
654 public:
655 enum { MemSize = 256*40/sizeof(void *) };
656 QStackTextEngine(const QString &string, const QFont &f);
657 LayoutData _layoutData;
658 void *_memory[MemSize];
659 };
660
661 struct QTextLineItemIterator
662 {
663 QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(),
664 const QTextLayout::FormatRange *_selection = 0);
665
atEndQTextLineItemIterator666 inline bool atEnd() const { return logicalItem >= nItems - 1; }
atBeginningQTextLineItemIterator667 inline bool atBeginning() const { return logicalItem <= 0; }
668 QScriptItem &next();
669
670 bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const;
isOutsideSelectionQTextLineItemIterator671 inline bool isOutsideSelection() const {
672 QFixed tmp1, tmp2;
673 return !getSelectionBounds(&tmp1, &tmp2);
674 }
675
676 QTextEngine *eng;
677
678 QFixed x;
679 QFixed pos_x;
680 const QScriptLine &line;
681 QScriptItem *si;
682
683 int lineNum;
684 int lineEnd;
685 int firstItem;
686 int lastItem;
687 int nItems;
688 int logicalItem;
689 int item;
690 int itemLength;
691
692 int glyphsStart;
693 int glyphsEnd;
694 int itemStart;
695 int itemEnd;
696
697 QFixed itemWidth;
698
699 QVarLengthArray<int> visualOrder;
700 QVarLengthArray<uchar> levels;
701
702 const QTextLayout::FormatRange *selection;
703 };
704
705 Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEngine::ShaperFlags)
706
707 QT_END_NAMESPACE
708
709 #endif // QTEXTENGINE_P_H
710