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