Back port change d85b149a5c7f3532f8e1a593a79298c9ae38a95f
[qt:kde-qt.git] / src / gui / text / qtextengine_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 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), leading(-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), leading(-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 leading;
361     QFixed width;
362     int glyph_data_offset;
363     QFixed height() const { return ascent + descent + 1; }
364 };
365
366
367 Q_DECLARE_TYPEINFO(QScriptItem, Q_MOVABLE_TYPE);
368
369 typedef QVector<QScriptItem> QScriptItemArray;
370
371 struct Q_AUTOTEST_EXPORT QScriptLine
372 {
373     // created and filled in QTextLine::layout_helper
374     QScriptLine()
375         : from(0), length(0),
376         justified(0), gridfitted(0),
377         hasTrailingSpaces(0), leadingIncluded(0) {}
378     QFixed descent;
379     QFixed ascent;
380     QFixed leading;
381     QFixed x;
382     QFixed y;
383     QFixed width;
384     QFixed textWidth;
385     QFixed textAdvance;
386     int from;
387     signed int length : 29;
388     mutable uint justified : 1;
389     mutable uint gridfitted : 1;
390     uint hasTrailingSpaces : 1;
391     uint leadingIncluded : 1;
392     QFixed height() const { return ascent + descent + 1
393                             + (leadingIncluded?  qMax(QFixed(),leading) : QFixed()); }
394     QFixed base() const { return ascent
395                           + (leadingIncluded ? qMax(QFixed(),leading) : QFixed()); }
396     void setDefaultHeight(QTextEngine *eng);
397     void operator+=(const QScriptLine &other);
398 };
399 Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
400
401
402 inline void QScriptLine::operator+=(const QScriptLine &other)
403 {
404     leading= qMax(leading + ascent, other.leading + other.ascent) - qMax(ascent, other.ascent);
405     descent = qMax(descent, other.descent);
406     ascent = qMax(ascent, other.ascent);
407     textWidth += other.textWidth;
408     length += other.length;
409 }
410
411 typedef QVector<QScriptLine> QScriptLineArray;
412
413 class QFontPrivate;
414 class QTextFormatCollection;
415
416 class Q_GUI_EXPORT QTextEngine {
417 public:
418     struct LayoutData {
419         LayoutData(const QString &str, void **stack_memory, int mem_size);
420         LayoutData();
421         ~LayoutData();
422         mutable QScriptItemArray items;
423         int allocated;
424         int available_glyphs;
425         void **memory;
426         unsigned short *logClustersPtr;
427         QGlyphLayout glyphLayout;
428         mutable int used;
429         uint hasBidi : 1;
430         uint inLayout : 1;
431         uint memory_on_stack : 1;
432         bool haveCharAttributes;
433         QString string;
434         void reallocate(int totalGlyphs);
435     };
436
437     QTextEngine(LayoutData *data);
438     QTextEngine();
439     QTextEngine(const QString &str, const QFont &f);
440     ~QTextEngine();
441
442     enum Mode {
443         WidthOnly = 0x07
444     };
445
446     // keep in sync with QAbstractFontEngine::TextShapingFlag!!
447     enum ShaperFlag {
448         RightToLeft = 0x0001,
449         DesignMetrics = 0x0002,
450         GlyphIndicesOnly = 0x0004
451     };
452     Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
453
454     void invalidate();
455     void clearLineData();
456
457     void validate() const;
458     void itemize() const;
459
460     static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
461
462     const HB_CharAttributes *attributes() const;
463
464     void shape(int item) const;
465
466     void justify(const QScriptLine &si);
467
468     QFixed width(int charFrom, int numChars) const;
469     glyph_metrics_t boundingBox(int from,  int len) const;
470     glyph_metrics_t tightBoundingBox(int from,  int len) const;
471
472     int length(int item) const {
473         const QScriptItem &si = layoutData->items[item];
474         int from = si.position;
475         item++;
476         return (item < layoutData->items.size() ? layoutData->items[item].position : layoutData->string.length()) - from;
477     }
478     int length(const QScriptItem *si) const {
479         int end;
480         if (si + 1 < layoutData->items.constData()+ layoutData->items.size())
481             end = (si+1)->position;
482         else
483             end = layoutData->string.length();
484         return end - si->position;
485     }
486
487     QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = 0, QFixed *descent = 0, QFixed *leading = 0) const;
488     QFont font(const QScriptItem &si) const;
489     inline QFont font() const { return fnt; }
490
491     /**
492      * Returns a pointer to an array of log clusters, offset at the script item.
493      * Each item in the array is a unsigned short.  For each character in the original string there is an entry in the table
494      * so there is a one to one correlation in indexes between the original text and the index in the logcluster.
495      * The value of each item is the position in the glyphs array. Multiple similar pointers in the logclusters array imply
496      * that one glyph is used for more than one character.
497      * \sa glyphs()
498      */
499     inline unsigned short *logClusters(const QScriptItem *si) const
500         { return layoutData->logClustersPtr+si->position; }
501     /**
502      * Returns an array of QGlyphLayout items, offset at the script item.
503      * Each item in the array matches one glyph in the text, storing the advance, position etc.
504      * The returned item's length equals to the number of available glyphs. This may be more
505      * than what was actually shaped.
506      * \sa logClusters()
507      */
508     inline QGlyphLayout availableGlyphs(const QScriptItem *si) const {
509         return layoutData->glyphLayout.mid(si->glyph_data_offset);
510     }
511     /**
512      * Returns an array of QGlyphLayout items, offset at the script item.
513      * Each item in the array matches one glyph in the text, storing the advance, position etc.
514      * The returned item's length equals to the number of shaped glyphs.
515      * \sa logClusters()
516      */
517     inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const {
518         return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs);
519     }
520
521     inline void ensureSpace(int nGlyphs) const {
522         if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
523             layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
524     }
525
526     void freeMemory();
527
528     int findItem(int strPos) const;
529     inline QTextFormatCollection *formats() const {
530 #ifdef QT_BUILD_COMPAT_LIB
531         return 0; // Compat should never reference this symbol
532 #else
533         return block.docHandle()->formatCollection();
534 #endif
535     }
536     QTextCharFormat format(const QScriptItem *si) const;
537     inline QAbstractTextDocumentLayout *docLayout() const {
538 #ifdef QT_BUILD_COMPAT_LIB
539         return 0; // Compat should never reference this symbol
540 #else
541         return block.docHandle()->document()->documentLayout();
542 #endif
543     }
544     int formatIndex(const QScriptItem *si) const;
545
546     /// returns the width of tab at index (in the tabs array) with the tab-start at position x
547     QFixed calculateTabWidth(int index, QFixed x) const;
548
549     mutable QScriptLineArray lines;
550
551     QString text;
552     QFont fnt;
553     QTextBlock block;
554
555     QTextOption option;
556
557     QFixed minWidth;
558     QFixed maxWidth;
559     QPointF position;
560     uint ignoreBidi : 1;
561     uint cacheGlyphs : 1;
562     uint stackEngine : 1;
563     uint forceJustification : 1;
564
565     int *underlinePositions;
566
567     mutable LayoutData *layoutData;
568
569     inline bool hasFormats() const { return (block.docHandle() || specialData); }
570
571     struct SpecialData {
572         int preeditPosition;
573         QString preeditText;
574         QList<QTextLayout::FormatRange> addFormats;
575         QVector<int> addFormatIndices;
576         QVector<int> resolvedFormatIndices;
577     };
578     SpecialData *specialData;
579
580     bool atWordSeparator(int position) const;
581     bool atSpace(int position) const;
582     void indexAdditionalFormats();
583
584     QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const;
585
586     void shapeLine(const QScriptLine &line);
587
588 private:
589     void setBoundary(int strPos) const;
590     void addRequiredBoundaries() const;
591     void shapeText(int item) const;
592     void shapeTextWithHarfbuzz(int item) const;
593 #if defined(Q_WS_WINCE)
594     void shapeTextWithCE(int item) const;
595 #endif
596 #if defined(Q_WS_MAC)
597     void shapeTextMac(int item) const;
598 #endif
599     void splitItem(int item, int pos) const;
600
601     void resolveAdditionalFormats() const;
602 };
603
604 class QStackTextEngine : public QTextEngine {
605 public:
606     enum { MemSize = 256*40/sizeof(void *) };
607     QStackTextEngine(const QString &string, const QFont &f);
608     LayoutData _layoutData;
609     void *_memory[MemSize];
610 };
611
612
613 Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEngine::ShaperFlags)
614
615 QT_END_NAMESPACE
616
617 #endif // QTEXTENGINE_P_H