src/gui/text/qtextengine_p.h
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    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 "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     inline bool isValid() const {return x != 100000 && y != 100000;}
       
   114 };
       
   115 Q_DECLARE_TYPEINFO(glyph_metrics_t, Q_PRIMITIVE_TYPE);
       
   116 
       
   117 struct Q_AUTOTEST_EXPORT QScriptAnalysis
       
   118 {
       
   119     enum Flags {
       
   120         None = 0,
       
   121         Lowercase = 1,
       
   122         Uppercase = 2,
       
   123         SmallCaps = 3,
       
   124         LineOrParagraphSeparator = 4,
       
   125         Space = 5,
       
   126         SpaceTabOrObject = Space,
       
   127         Tab = 6,
       
   128         TabOrObject = Tab,
       
   129         Object = 7
       
   130     };
       
   131     unsigned short script    : 8;
       
   132     unsigned short bidiLevel : 6;  // Unicode Bidi algorithm embedding level (0-61)
       
   133     unsigned short flags     : 3;
       
   134     inline bool operator == (const QScriptAnalysis &other) const {
       
   135         return script == other.script && bidiLevel == other.bidiLevel && flags == other.flags;
       
   136     }
       
   137 };
       
   138 Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE);
       
   139 
       
   140 struct QGlyphJustification
       
   141 {
       
   142     inline QGlyphJustification()
       
   143         : type(0), nKashidas(0), space_18d6(0)
       
   144     {}
       
   145 
       
   146     enum JustificationType {
       
   147         JustifyNone,
       
   148         JustifySpace,
       
   149         JustifyKashida
       
   150     };
       
   151 
       
   152     uint type :2;
       
   153     uint nKashidas : 6; // more do not make sense...
       
   154     uint space_18d6 : 24;
       
   155 };
       
   156 Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE);
       
   157 
       
   158 struct QGlyphLayoutInstance
       
   159 {
       
   160     QFixedPoint offset;
       
   161     QFixedPoint advance;
       
   162     HB_Glyph glyph;
       
   163     QGlyphJustification justification;
       
   164     HB_GlyphAttributes attributes;
       
   165 };
       
   166 
       
   167 struct QGlyphLayout
       
   168 {
       
   169     // init to 0 not needed, done when shaping
       
   170     QFixedPoint *offsets; // 8 bytes per element
       
   171     HB_Glyph *glyphs; // 4 bytes per element
       
   172     QFixed *advances_x; // 4 bytes per element
       
   173     QFixed *advances_y; // 4 bytes per element
       
   174     QGlyphJustification *justifications; // 4 bytes per element
       
   175     HB_GlyphAttributes *attributes; // 2 bytes per element
       
   176 
       
   177     int numGlyphs;
       
   178 
       
   179     inline QGlyphLayout() : numGlyphs(0) {}
       
   180 
       
   181     inline explicit QGlyphLayout(char *address, int totalGlyphs)
       
   182     {
       
   183         offsets = reinterpret_cast<QFixedPoint *>(address);
       
   184         int offset = totalGlyphs * sizeof(HB_FixedPoint);
       
   185         glyphs = reinterpret_cast<HB_Glyph *>(address + offset);
       
   186         offset += totalGlyphs * sizeof(HB_Glyph);
       
   187         advances_x = reinterpret_cast<QFixed *>(address + offset);
       
   188         offset += totalGlyphs * sizeof(QFixed);
       
   189         advances_y = reinterpret_cast<QFixed *>(address + offset);
       
   190         offset += totalGlyphs * sizeof(QFixed);
       
   191         justifications = reinterpret_cast<QGlyphJustification *>(address + offset);
       
   192         offset += totalGlyphs * sizeof(QGlyphJustification);
       
   193         attributes = reinterpret_cast<HB_GlyphAttributes *>(address + offset);
       
   194         numGlyphs = totalGlyphs;
       
   195     }
       
   196 
       
   197     inline QGlyphLayout mid(int position, int n = -1) const {
       
   198         QGlyphLayout copy = *this;
       
   199         copy.glyphs += position;
       
   200         copy.advances_x += position;
       
   201         copy.advances_y += position;
       
   202         copy.offsets += position;
       
   203         copy.justifications += position;
       
   204         copy.attributes += position;
       
   205         if (n == -1)
       
   206             copy.numGlyphs -= position;
       
   207         else
       
   208             copy.numGlyphs = n;
       
   209         return copy;
       
   210     }
       
   211 
       
   212     static inline int spaceNeededForGlyphLayout(int totalGlyphs) {
       
   213         return totalGlyphs * (sizeof(HB_Glyph) + sizeof(HB_GlyphAttributes)
       
   214                 + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
       
   215                 + sizeof(QGlyphJustification));
       
   216     }
       
   217 
       
   218     inline QFixed effectiveAdvance(int item) const
       
   219     { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
       
   220 
       
   221     inline QGlyphLayoutInstance instance(int position) const {
       
   222         QGlyphLayoutInstance g;
       
   223         g.offset.x = offsets[position].x;
       
   224         g.offset.y = offsets[position].y;
       
   225         g.glyph = glyphs[position];
       
   226         g.advance.x = advances_x[position];
       
   227         g.advance.y = advances_y[position];
       
   228         g.justification = justifications[position];
       
   229         g.attributes = attributes[position];
       
   230         return g;
       
   231     }
       
   232 
       
   233     inline void setInstance(int position, const QGlyphLayoutInstance &g) {
       
   234         offsets[position].x = g.offset.x;
       
   235         offsets[position].y = g.offset.y;
       
   236         glyphs[position] = g.glyph;
       
   237         advances_x[position] = g.advance.x;
       
   238         advances_y[position] = g.advance.y;
       
   239         justifications[position] = g.justification;
       
   240         attributes[position] = g.attributes;
       
   241     }
       
   242 
       
   243     inline void clear(int first = 0, int last = -1) {
       
   244         if (last == -1)
       
   245             last = numGlyphs;
       
   246         if (first == 0 && last == numGlyphs
       
   247             && reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) {
       
   248             memset(offsets, 0, spaceNeededForGlyphLayout(numGlyphs));
       
   249         } else {
       
   250             const int num = last - first;
       
   251             memset(offsets + first, 0, num * sizeof(QFixedPoint));
       
   252             memset(glyphs + first, 0, num * sizeof(HB_Glyph));
       
   253             memset(advances_x + first, 0, num * sizeof(QFixed));
       
   254             memset(advances_y + first, 0, num * sizeof(QFixed));
       
   255             memset(justifications + first, 0, num * sizeof(QGlyphJustification));
       
   256             memset(attributes + first, 0, num * sizeof(HB_GlyphAttributes));
       
   257         }
       
   258     }
       
   259 
       
   260     inline char *data() {
       
   261         return reinterpret_cast<char *>(offsets);
       
   262     }
       
   263 
       
   264     void grow(char *address, int totalGlyphs);
       
   265 };
       
   266 
       
   267 class QVarLengthGlyphLayoutArray : private QVarLengthArray<void *>, public QGlyphLayout
       
   268 {
       
   269 private:
       
   270     typedef QVarLengthArray<void *> Array;
       
   271 public:
       
   272     QVarLengthGlyphLayoutArray(int totalGlyphs)
       
   273         : Array(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1)
       
   274         , QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs)
       
   275     {
       
   276         memset(Array::data(), 0, Array::size() * sizeof(void *));
       
   277     }
       
   278 
       
   279     void resize(int totalGlyphs)
       
   280     {
       
   281         Array::resize(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1);
       
   282 
       
   283         *((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs);
       
   284         memset(Array::data(), 0, Array::size() * sizeof(void *));
       
   285     }
       
   286 };
       
   287 
       
   288 template <int N> struct QGlyphLayoutArray : public QGlyphLayout
       
   289 {
       
   290 public:
       
   291     QGlyphLayoutArray()
       
   292         : QGlyphLayout(reinterpret_cast<char *>(buffer), N)
       
   293     {
       
   294         memset(buffer, 0, sizeof(buffer));
       
   295     }
       
   296 
       
   297 private:
       
   298     void *buffer[(N * (sizeof(HB_Glyph) + sizeof(HB_GlyphAttributes)
       
   299                 + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
       
   300                 + sizeof(QGlyphJustification)))
       
   301                     / sizeof(void *) + 1];
       
   302 };
       
   303 
       
   304 struct QScriptItem;
       
   305 /// Internal QTextItem
       
   306 class QTextItemInt : public QTextItem
       
   307 {
       
   308 public:
       
   309     inline QTextItemInt()
       
   310         : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(0),
       
   311           logClusters(0), f(0), fontEngine(0)
       
   312     {}
       
   313     QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
       
   314 
       
   315     /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
       
   316     /// the width of the returned QTextItemInt is not adjusted, for speed reasons
       
   317     QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const;
       
   318 
       
   319     QFixed descent;
       
   320     QFixed ascent;
       
   321     QFixed width;
       
   322 
       
   323     RenderFlags flags;
       
   324     bool justified;
       
   325     QTextCharFormat::UnderlineStyle underlineStyle;
       
   326     const QTextCharFormat charFormat;
       
   327     int num_chars;
       
   328     const QChar *chars;
       
   329     const unsigned short *logClusters;
       
   330     const QFont *f;
       
   331 
       
   332     QGlyphLayout glyphs;
       
   333     QFontEngine *fontEngine;
       
   334 };
       
   335 
       
   336 inline bool qIsControlChar(ushort uc)
       
   337 {
       
   338     return uc >= 0x200b && uc <= 0x206f
       
   339         && (uc <= 0x200f /* ZW Space, ZWNJ, ZWJ, LRM and RLM */
       
   340             || (uc >= 0x2028 && uc <= 0x202f /* LS, PS, LRE, RLE, PDF, LRO, RLO, NNBSP */)
       
   341             || uc >= 0x206a /* ISS, ASS, IAFS, AFS, NADS, NODS */);
       
   342 }
       
   343 
       
   344 struct Q_AUTOTEST_EXPORT QScriptItem
       
   345 {
       
   346     inline QScriptItem()
       
   347         : position(0),
       
   348           num_glyphs(0), descent(-1), ascent(-1), width(-1),
       
   349           glyph_data_offset(0) {}
       
   350     inline QScriptItem(int p, const QScriptAnalysis &a)
       
   351         : position(p), analysis(a),
       
   352           num_glyphs(0), descent(-1), ascent(-1), width(-1),
       
   353           glyph_data_offset(0) {}
       
   354 
       
   355     int position;
       
   356     QScriptAnalysis analysis;
       
   357     unsigned short num_glyphs;
       
   358     QFixed descent;
       
   359     QFixed ascent;
       
   360     QFixed width;
       
   361     int glyph_data_offset;
       
   362     QFixed height() const { return ascent + descent + 1; }
       
   363 };
       
   364 
       
   365 
       
   366 Q_DECLARE_TYPEINFO(QScriptItem, Q_MOVABLE_TYPE);
       
   367 
       
   368 typedef QVector<QScriptItem> QScriptItemArray;
       
   369 
       
   370 struct Q_AUTOTEST_EXPORT QScriptLine
       
   371 {
       
   372     // created and filled in QTextLine::layout_helper
       
   373     QScriptLine()
       
   374         : from(0), length(0),
       
   375         justified(0), gridfitted(0),
       
   376         hasTrailingSpaces(0) {}
       
   377     QFixed descent;
       
   378     QFixed ascent;
       
   379     QFixed x;
       
   380     QFixed y;
       
   381     QFixed width;
       
   382     QFixed textWidth;
       
   383     int from;
       
   384     signed int length : 29;
       
   385     mutable uint justified : 1;
       
   386     mutable uint gridfitted : 1;
       
   387     uint hasTrailingSpaces : 1;
       
   388     QFixed height() const { return ascent + descent + 1; }
       
   389     void setDefaultHeight(QTextEngine *eng);
       
   390     void operator+=(const QScriptLine &other);
       
   391 };
       
   392 Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
       
   393 
       
   394 
       
   395 inline void QScriptLine::operator+=(const QScriptLine &other)
       
   396 {
       
   397     descent = qMax(descent, other.descent);
       
   398     ascent = qMax(ascent, other.ascent);
       
   399     textWidth += other.textWidth;
       
   400     length += other.length;
       
   401 }
       
   402 
       
   403 typedef QVector<QScriptLine> QScriptLineArray;
       
   404 
       
   405 class QFontPrivate;
       
   406 class QTextFormatCollection;
       
   407 
       
   408 class Q_GUI_EXPORT QTextEngine {
       
   409 public:
       
   410     struct LayoutData {
       
   411         LayoutData(const QString &str, void **stack_memory, int mem_size);
       
   412         LayoutData();
       
   413         ~LayoutData();
       
   414         mutable QScriptItemArray items;
       
   415         int allocated;
       
   416         int available_glyphs;
       
   417         void **memory;
       
   418         unsigned short *logClustersPtr;
       
   419         QGlyphLayout glyphLayout;
       
   420         mutable int used;
       
   421         uint hasBidi : 1;
       
   422         uint inLayout : 1;
       
   423         uint memory_on_stack : 1;
       
   424         bool haveCharAttributes;
       
   425         QString string;
       
   426         void reallocate(int totalGlyphs);
       
   427     };
       
   428 
       
   429     QTextEngine(LayoutData *data);
       
   430     QTextEngine();
       
   431     QTextEngine(const QString &str, const QFont &f);
       
   432     ~QTextEngine();
       
   433 
       
   434     enum Mode {
       
   435         WidthOnly = 0x07
       
   436     };
       
   437 
       
   438     // keep in sync with QAbstractFontEngine::TextShapingFlag!!
       
   439     enum ShaperFlag {
       
   440         RightToLeft = 0x0001,
       
   441         DesignMetrics = 0x0002,
       
   442         GlyphIndicesOnly = 0x0004
       
   443     };
       
   444     Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
       
   445 
       
   446     void invalidate();
       
   447     void clearLineData();
       
   448 
       
   449     void validate() const;
       
   450     void itemize() const;
       
   451 
       
   452     static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
       
   453 
       
   454     const HB_CharAttributes *attributes() const;
       
   455 
       
   456     void shape(int item) const;
       
   457 
       
   458     void justify(const QScriptLine &si);
       
   459 
       
   460     QFixed width(int charFrom, int numChars) const;
       
   461     glyph_metrics_t boundingBox(int from,  int len) const;
       
   462     glyph_metrics_t tightBoundingBox(int from,  int len) const;
       
   463 
       
   464     int length(int item) const {
       
   465         const QScriptItem &si = layoutData->items[item];
       
   466         int from = si.position;
       
   467         item++;
       
   468         return (item < layoutData->items.size() ? layoutData->items[item].position : layoutData->string.length()) - from;
       
   469     }
       
   470     int length(const QScriptItem *si) const {
       
   471         int end;
       
   472         if (si + 1 < layoutData->items.constData()+ layoutData->items.size())
       
   473             end = (si+1)->position;
       
   474         else
       
   475             end = layoutData->string.length();
       
   476         return end - si->position;
       
   477     }
       
   478 
       
   479     QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = 0, QFixed *descent = 0) const;
       
   480     QFont font(const QScriptItem &si) const;
       
   481     inline QFont font() const { return fnt; }
       
   482 
       
   483     /**
       
   484      * Returns a pointer to an array of log clusters, offset at the script item.
       
   485      * Each item in the array is a unsigned short.  For each character in the original string there is an entry in the table
       
   486      * so there is a one to one correlation in indexes between the original text and the index in the logcluster.
       
   487      * The value of each item is the position in the glyphs array. Multiple similar pointers in the logclusters array imply
       
   488      * that one glyph is used for more than one character.
       
   489      * \sa glyphs()
       
   490      */
       
   491     inline unsigned short *logClusters(const QScriptItem *si) const
       
   492         { return layoutData->logClustersPtr+si->position; }
       
   493     /**
       
   494      * Returns an array of QGlyphLayout items, offset at the script item.
       
   495      * Each item in the array matches one glyph in the text, storing the advance, position etc.
       
   496      * The returned item's length equals to the number of available glyphs. This may be more
       
   497      * than what was actually shaped.
       
   498      * \sa logClusters()
       
   499      */
       
   500     inline QGlyphLayout availableGlyphs(const QScriptItem *si) const {
       
   501         return layoutData->glyphLayout.mid(si->glyph_data_offset);
       
   502     }
       
   503     /**
       
   504      * Returns an array of QGlyphLayout items, offset at the script item.
       
   505      * Each item in the array matches one glyph in the text, storing the advance, position etc.
       
   506      * The returned item's length equals to the number of shaped glyphs.
       
   507      * \sa logClusters()
       
   508      */
       
   509     inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const {
       
   510         return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs);
       
   511     }
       
   512 
       
   513     inline void ensureSpace(int nGlyphs) const {
       
   514         if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
       
   515             layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
       
   516     }
       
   517 
       
   518     void freeMemory();
       
   519 
       
   520     int findItem(int strPos) const;
       
   521     inline QTextFormatCollection *formats() const {
       
   522 #ifdef QT_BUILD_COMPAT_LIB
       
   523         return 0; // Compat should never reference this symbol
       
   524 #else
       
   525         return block.docHandle()->formatCollection();
       
   526 #endif
       
   527     }
       
   528     QTextCharFormat format(const QScriptItem *si) const;
       
   529     inline QAbstractTextDocumentLayout *docLayout() const {
       
   530 #ifdef QT_BUILD_COMPAT_LIB
       
   531         return 0; // Compat should never reference this symbol
       
   532 #else
       
   533         return block.docHandle()->document()->documentLayout();
       
   534 #endif
       
   535     }
       
   536     int formatIndex(const QScriptItem *si) const;
       
   537 
       
   538     /// returns the width of tab at index (in the tabs array) with the tab-start at position x
       
   539     QFixed calculateTabWidth(int index, QFixed x) const;
       
   540 
       
   541     mutable QScriptLineArray lines;
       
   542 
       
   543     QString text;
       
   544     QFont fnt;
       
   545     QTextBlock block;
       
   546 
       
   547     QTextOption option;
       
   548 
       
   549     QFixed minWidth;
       
   550     QFixed maxWidth;
       
   551     QPointF position;
       
   552     uint ignoreBidi : 1;
       
   553     uint cacheGlyphs : 1;
       
   554     uint stackEngine : 1;
       
   555     uint forceJustification : 1;
       
   556 
       
   557     int *underlinePositions;
       
   558 
       
   559     mutable LayoutData *layoutData;
       
   560 
       
   561     inline bool hasFormats() const { return (block.docHandle() || specialData); }
       
   562 
       
   563     struct SpecialData {
       
   564         int preeditPosition;
       
   565         QString preeditText;
       
   566         QList<QTextLayout::FormatRange> addFormats;
       
   567         QVector<int> addFormatIndices;
       
   568         QVector<int> resolvedFormatIndices;
       
   569     };
       
   570     SpecialData *specialData;
       
   571 
       
   572     bool atWordSeparator(int position) const;
       
   573     bool atSpace(int position) const;
       
   574     void indexAdditionalFormats();
       
   575 
       
   576     QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const;
       
   577 
       
   578     void shapeLine(const QScriptLine &line);
       
   579 
       
   580 private:
       
   581     void setBoundary(int strPos) const;
       
   582     void addRequiredBoundaries() const;
       
   583     void shapeText(int item) const;
       
   584     void shapeTextWithHarfbuzz(int item) const;
       
   585 #if defined(Q_WS_WINCE)
       
   586     void shapeTextWithCE(int item) const;
       
   587 #endif
       
   588 #if defined(Q_WS_MAC)
       
   589     void shapeTextMac(int item) const;
       
   590 #endif
       
   591     void splitItem(int item, int pos) const;
       
   592 
       
   593     void resolveAdditionalFormats() const;
       
   594 };
       
   595 
       
   596 class QStackTextEngine : public QTextEngine {
       
   597 public:
       
   598     enum { MemSize = 256*40/sizeof(void *) };
       
   599     QStackTextEngine(const QString &string, const QFont &f);
       
   600     LayoutData _layoutData;
       
   601     void *_memory[MemSize];
       
   602 };
       
   603 
       
   604 
       
   605 Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEngine::ShaperFlags)
       
   606 
       
   607 QT_END_NAMESPACE
       
   608 
       
   609 #endif // QTEXTENGINE_P_H