Support placing cursor in ligature with mouse or touch
[profile/ivi/qtbase.git] / src / gui / text / qtextengine_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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 #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 {
96     inline glyph_metrics_t()
97         : x(100000),  y(100000) {}
98     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;
114     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 {
143     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
180     inline QGlyphLayout() : numGlyphs(0) {}
181
182     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
213     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
219     inline QFixed effectiveAdvance(int item) const
220     { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
221
222     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
234     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
261     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:
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
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:
292     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:
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
317     /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
318     /// the width of the returned QTextItemInt is not adjusted, for speed reasons
319     QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const;
320
321     QFixed descent;
322     QFixed ascent;
323     QFixed width;
324
325     RenderFlags flags;
326     bool justified;
327     QTextCharFormat::UnderlineStyle underlineStyle;
328     const QTextCharFormat charFormat;
329     int num_chars;
330     const QChar *chars;
331     const unsigned short *logClusters;
332     const QFont *f;
333
334     QGlyphLayout glyphs;
335     QFontEngine *fontEngine;
336 };
337
338 inline bool qIsControlChar(ushort uc)
339 {
340     return uc >= 0x200b && uc <= 0x206f
341         && (uc <= 0x200f /* ZW Space, ZWNJ, ZWJ, LRM and RLM */
342             || (uc >= 0x2028 && uc <= 0x202f /* LS, PS, LRE, RLE, PDF, LRO, RLO, NNBSP */)
343             || uc >= 0x206a /* ISS, ASS, IAFS, AFS, NADS, NODS */);
344 }
345
346 struct Q_AUTOTEST_EXPORT QScriptItem
347 {
348     inline QScriptItem()
349         : position(0),
350           num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
351           glyph_data_offset(0) {}
352     inline QScriptItem(int p, const QScriptAnalysis &a)
353         : position(p), analysis(a),
354           num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
355           glyph_data_offset(0) {}
356
357     int position;
358     QScriptAnalysis analysis;
359     unsigned short num_glyphs;
360     QFixed descent;
361     QFixed ascent;
362     QFixed leading;
363     QFixed width;
364     int glyph_data_offset;
365     QFixed height() const { return ascent + descent + 1; }
366 };
367
368
369 Q_DECLARE_TYPEINFO(QScriptItem, Q_MOVABLE_TYPE);
370
371 typedef QVector<QScriptItem> QScriptItemArray;
372
373 struct Q_AUTOTEST_EXPORT QScriptLine
374 {
375     // created and filled in QTextLine::layout_helper
376     QScriptLine()
377         : from(0), length(0),
378         justified(0), gridfitted(0),
379         hasTrailingSpaces(0), leadingIncluded(0) {}
380     QFixed descent;
381     QFixed ascent;
382     QFixed leading;
383     QFixed x;
384     QFixed y;
385     QFixed width;
386     QFixed textWidth;
387     QFixed textAdvance;
388     int from;
389     signed int length : 28;
390     mutable uint justified : 1;
391     mutable uint gridfitted : 1;
392     uint hasTrailingSpaces : 1;
393     uint leadingIncluded : 1;
394     QFixed height() const { return (ascent + descent).ceil() + 1
395                             + (leadingIncluded?  qMax(QFixed(),leading) : QFixed()); }
396     QFixed base() const { return ascent
397                           + (leadingIncluded ? qMax(QFixed(),leading) : QFixed()); }
398     void setDefaultHeight(QTextEngine *eng);
399     void operator+=(const QScriptLine &other);
400 };
401 Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
402
403
404 inline void QScriptLine::operator+=(const QScriptLine &other)
405 {
406     leading= qMax(leading + ascent, other.leading + other.ascent) - qMax(ascent, other.ascent);
407     descent = qMax(descent, other.descent);
408     ascent = qMax(ascent, other.ascent);
409     textWidth += other.textWidth;
410     length += other.length;
411 }
412
413 typedef QVector<QScriptLine> QScriptLineArray;
414
415 class QFontPrivate;
416 class QTextFormatCollection;
417
418 class Q_GUI_EXPORT QTextEngine {
419 public:
420     enum LayoutState {
421         LayoutEmpty,
422         InLayout,
423         LayoutFailed,
424     };
425     struct LayoutData {
426         LayoutData(const QString &str, void **stack_memory, int mem_size);
427         LayoutData();
428         ~LayoutData();
429         mutable QScriptItemArray items;
430         int allocated;
431         int available_glyphs;
432         void **memory;
433         unsigned short *logClustersPtr;
434         QGlyphLayout glyphLayout;
435         mutable int used;
436         uint hasBidi : 1;
437         uint layoutState : 2;
438         uint memory_on_stack : 1;
439         uint haveCharAttributes : 1;
440         QString string;
441         bool reallocate(int totalGlyphs);
442     };
443
444     QTextEngine(LayoutData *data);
445     QTextEngine();
446     QTextEngine(const QString &str, const QFont &f);
447     ~QTextEngine();
448
449     enum Mode {
450         WidthOnly = 0x07
451     };
452
453     // keep in sync with QAbstractFontEngine::TextShapingFlag!!
454     enum ShaperFlag {
455         RightToLeft = 0x0001,
456         DesignMetrics = 0x0002,
457         GlyphIndicesOnly = 0x0004
458     };
459     Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
460
461     void invalidate();
462     void clearLineData();
463
464     void validate() const;
465     void itemize() const;
466
467     bool isRightToLeft() const;
468     static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
469
470     const HB_CharAttributes *attributes() const;
471
472     void shape(int item) const;
473
474     void justify(const QScriptLine &si);
475     QFixed alignLine(const QScriptLine &line);
476
477     QFixed width(int charFrom, int numChars) const;
478     glyph_metrics_t boundingBox(int from,  int len) const;
479     glyph_metrics_t tightBoundingBox(int from,  int len) const;
480
481     int length(int item) const {
482         const QScriptItem &si = layoutData->items[item];
483         int from = si.position;
484         item++;
485         return (item < layoutData->items.size() ? layoutData->items[item].position : layoutData->string.length()) - from;
486     }
487     int length(const QScriptItem *si) const {
488         int end;
489         if (si + 1 < layoutData->items.constData()+ layoutData->items.size())
490             end = (si+1)->position;
491         else
492             end = layoutData->string.length();
493         return end - si->position;
494     }
495
496     QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = 0, QFixed *descent = 0, QFixed *leading = 0) const;
497     QFont font(const QScriptItem &si) const;
498     inline QFont font() const { return fnt; }
499
500     /**
501      * Returns a pointer to an array of log clusters, offset at the script item.
502      * Each item in the array is a unsigned short.  For each character in the original string there is an entry in the table
503      * so there is a one to one correlation in indexes between the original text and the index in the logcluster.
504      * The value of each item is the position in the glyphs array. Multiple similar pointers in the logclusters array imply
505      * that one glyph is used for more than one character.
506      * \sa glyphs()
507      */
508     inline unsigned short *logClusters(const QScriptItem *si) const
509         { return layoutData->logClustersPtr+si->position; }
510     /**
511      * Returns an array of QGlyphLayout items, offset at the script item.
512      * Each item in the array matches one glyph in the text, storing the advance, position etc.
513      * The returned item's length equals to the number of available glyphs. This may be more
514      * than what was actually shaped.
515      * \sa logClusters()
516      */
517     inline QGlyphLayout availableGlyphs(const QScriptItem *si) const {
518         return layoutData->glyphLayout.mid(si->glyph_data_offset);
519     }
520     /**
521      * Returns an array of QGlyphLayout items, offset at the script item.
522      * Each item in the array matches one glyph in the text, storing the advance, position etc.
523      * The returned item's length equals to the number of shaped glyphs.
524      * \sa logClusters()
525      */
526     inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const {
527         return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs);
528     }
529
530     inline bool ensureSpace(int nGlyphs) const {
531         if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
532             return layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
533         return true;
534     }
535
536     void freeMemory();
537
538     int findItem(int strPos) const;
539     inline QTextFormatCollection *formats() const {
540 #ifdef QT_BUILD_COMPAT_LIB
541         return 0; // Compat should never reference this symbol
542 #else
543         return block.docHandle()->formatCollection();
544 #endif
545     }
546     QTextCharFormat format(const QScriptItem *si) const;
547     inline QAbstractTextDocumentLayout *docLayout() const {
548 #ifdef QT_BUILD_COMPAT_LIB
549         return 0; // Compat should never reference this symbol
550 #else
551         return block.docHandle()->document()->documentLayout();
552 #endif
553     }
554     int formatIndex(const QScriptItem *si) const;
555
556     /// returns the width of tab at index (in the tabs array) with the tab-start at position x
557     QFixed calculateTabWidth(int index, QFixed x) const;
558
559     mutable QScriptLineArray lines;
560
561     struct FontEngineCache {
562         FontEngineCache();
563         mutable QFontEngine *prevFontEngine;
564         mutable QFontEngine *prevScaledFontEngine;
565         mutable int prevScript;
566         mutable int prevPosition;
567         mutable int prevLength;
568         inline void reset() {
569             prevFontEngine = 0;
570             prevScaledFontEngine = 0;
571             prevScript = -1;
572             prevPosition = -1;
573             prevLength = -1;
574         }
575     };
576     mutable FontEngineCache feCache;
577
578     QString text;
579     QFont fnt;
580     QTextBlock block;
581
582     QTextOption option;
583
584     QFixed minWidth;
585     QFixed maxWidth;
586     QPointF position;
587     uint ignoreBidi : 1;
588     uint cacheGlyphs : 1;
589     uint stackEngine : 1;
590     uint forceJustification : 1;
591     uint visualMovement : 1;
592
593     int *underlinePositions;
594
595     mutable LayoutData *layoutData;
596
597     inline bool hasFormats() const { return (block.docHandle() || specialData); }
598     inline bool visualCursorMovement() const
599     {
600         return (visualMovement ||
601                 (block.docHandle() ? block.docHandle()->defaultCursorMoveStyle == Qt::VisualMoveStyle : false));
602     }
603
604     struct SpecialData {
605         int preeditPosition;
606         QString preeditText;
607         QList<QTextLayout::FormatRange> addFormats;
608         QVector<int> addFormatIndices;
609         QVector<int> resolvedFormatIndices;
610     };
611     SpecialData *specialData;
612
613     bool atWordSeparator(int position) const;
614     bool atSpace(int position) const;
615     void indexAdditionalFormats();
616
617     QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const;
618
619     void shapeLine(const QScriptLine &line);
620     QFixed leadingSpaceWidth(const QScriptLine &line);
621
622     QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
623     int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
624     int previousLogicalPosition(int oldPos) const;
625     int nextLogicalPosition(int oldPos) const;
626     int lineNumberForTextPosition(int pos);
627     int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op);
628     void insertionPointsForLine(int lineNum, QVector<int> &insertionPoints);
629
630 private:
631     void setBoundary(int strPos) const;
632     void addRequiredBoundaries() const;
633     void shapeText(int item) const;
634     void shapeTextWithHarfbuzz(int item) const;
635 #if defined(Q_WS_WINCE)
636     void shapeTextWithCE(int item) const;
637 #endif
638 #if defined(Q_WS_MAC)
639     void shapeTextMac(int item) const;
640 #endif
641     void splitItem(int item, int pos) const;
642
643     void resolveAdditionalFormats() const;
644     int endOfLine(int lineNum);
645     int beginningOfLine(int lineNum);
646     int getClusterLength(unsigned short *logClusters, const HB_CharAttributes *attributes, int from, int to, int glyph_pos, int *start);
647 };
648
649 class QStackTextEngine : public QTextEngine {
650 public:
651     enum { MemSize = 256*40/sizeof(void *) };
652     QStackTextEngine(const QString &string, const QFont &f);
653     LayoutData _layoutData;
654     void *_memory[MemSize];
655 };
656
657 struct QTextLineItemIterator
658 {
659     QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(),
660                           const QTextLayout::FormatRange *_selection = 0);
661
662     inline bool atEnd() const { return logicalItem >= nItems - 1; }
663     inline bool atBeginning() const { return logicalItem <= 0; }
664     QScriptItem &next();
665
666     bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const;
667     inline bool isOutsideSelection() const {
668         QFixed tmp1, tmp2;
669         return !getSelectionBounds(&tmp1, &tmp2);
670     }
671
672     QTextEngine *eng;
673
674     QFixed x;
675     QFixed pos_x;
676     const QScriptLine &line;
677     QScriptItem *si;
678
679     int lineNum;
680     int lineEnd;
681     int firstItem;
682     int lastItem;
683     int nItems;
684     int logicalItem;
685     int item;
686     int itemLength;
687
688     int glyphsStart;
689     int glyphsEnd;
690     int itemStart;
691     int itemEnd;
692
693     QFixed itemWidth;
694
695     QVarLengthArray<int> visualOrder;
696     QVarLengthArray<uchar> levels;
697
698     const QTextLayout::FormatRange *selection;
699 };
700
701 Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEngine::ShaperFlags)
702
703 QT_END_NAMESPACE
704
705 #endif // QTEXTENGINE_P_H