1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QTEXTENGINE_P_H
41#define QTEXTENGINE_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists for the convenience
48// of other Qt classes. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <QtGui/private/qtguiglobal_p.h>
55#include "QtCore/qstring.h"
56#include "QtCore/qvarlengtharray.h"
57#include "QtCore/qnamespace.h"
58#include "QtGui/qtextlayout.h"
59#include "private/qtextformat_p.h"
60#include "private/qfont_p.h"
61#include "QtCore/qvector.h"
62#include "QtGui/qpaintengine.h"
63#include "QtGui/qtextobject.h"
64#include "QtGui/qtextoption.h"
65#include "QtGui/qtextcursor.h"
66#include "QtCore/qset.h"
67#include "QtCore/qdebug.h"
68#ifndef QT_BUILD_COMPAT_LIB
69#include "private/qtextdocument_p.h"
70#endif
71
72#include "private/qfixed_p.h"
73
74#include <private/qunicodetools_p.h>
75
76#include <stdlib.h>
77#include <vector>
78
79QT_BEGIN_NAMESPACE
80
81class QFontPrivate;
82class QFontEngine;
83
84class QString;
85class QPainter;
86
87class QAbstractTextDocumentLayout;
88
89typedef quint32 glyph_t;
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
96struct 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 inline QFixed leftBearing() const
119 {
120 if (!isValid())
121 return QFixed();
122
123 return x;
124 }
125
126 inline QFixed rightBearing() const
127 {
128 if (!isValid())
129 return QFixed();
130
131 return xoff - x - width;
132 }
133};
134Q_DECLARE_TYPEINFO(glyph_metrics_t, Q_PRIMITIVE_TYPE);
135
136struct Q_AUTOTEST_EXPORT QScriptAnalysis
137{
138 enum Flags {
139 None = 0,
140 Lowercase = 1,
141 Uppercase = 2,
142 SmallCaps = 3,
143 LineOrParagraphSeparator = 4,
144 Space = 5,
145 SpaceTabOrObject = Space,
146 Nbsp = 6,
147 Tab = 7,
148 TabOrObject = Tab,
149 Object = 8
150 };
151 enum BidiFlags {
152 BidiBN = 1,
153 BidiMaybeResetToParagraphLevel = 2,
154 BidiResetToParagraphLevel = 4,
155 BidiMirrored = 8
156 };
157 unsigned short script : 8;
158 unsigned short flags : 4;
159 unsigned short bidiFlags : 4;
160 unsigned short bidiLevel : 8; // Unicode Bidi algorithm embedding level (0-125)
161 QChar::Direction bidiDirection : 8; // used when running the bidi algorithm
162 inline bool operator == (const QScriptAnalysis &other) const {
163 return script == other.script && bidiLevel == other.bidiLevel && flags == other.flags;
164 }
165};
166Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE);
167
168struct QGlyphJustification
169{
170 inline QGlyphJustification()
171 : type(0), nKashidas(0), space_18d6(0)
172 {}
173
174 enum JustificationType {
175 JustifyNone,
176 JustifySpace,
177 JustifyKashida
178 };
179
180 uint type :2;
181 uint nKashidas : 6; // more do not make sense...
182 uint space_18d6 : 24;
183};
184Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE);
185
186struct QGlyphAttributes {
187 uchar clusterStart : 1;
188 uchar dontPrint : 1;
189 uchar justification : 4;
190 uchar reserved : 2;
191};
192Q_STATIC_ASSERT(sizeof(QGlyphAttributes) == 1);
193Q_DECLARE_TYPEINFO(QGlyphAttributes, Q_PRIMITIVE_TYPE);
194
195struct QGlyphLayout
196{
197 enum {
198 SpaceNeeded = sizeof(glyph_t) + sizeof(QFixed) + sizeof(QFixedPoint)
199 + sizeof(QGlyphAttributes) + sizeof(QGlyphJustification)
200 };
201
202 // init to 0 not needed, done when shaping
203 QFixedPoint *offsets; // 8 bytes per element
204 glyph_t *glyphs; // 4 bytes per element
205 QFixed *advances; // 4 bytes per element
206 QGlyphJustification *justifications; // 4 bytes per element
207 QGlyphAttributes *attributes; // 1 byte per element
208
209 int numGlyphs;
210
211 inline QGlyphLayout() : numGlyphs(0) {}
212
213 inline explicit QGlyphLayout(char *address, int totalGlyphs)
214 {
215 offsets = reinterpret_cast<QFixedPoint *>(address);
216 int offset = totalGlyphs * sizeof(QFixedPoint);
217 glyphs = reinterpret_cast<glyph_t *>(address + offset);
218 offset += totalGlyphs * sizeof(glyph_t);
219 advances = reinterpret_cast<QFixed *>(address + offset);
220 offset += totalGlyphs * sizeof(QFixed);
221 justifications = reinterpret_cast<QGlyphJustification *>(address + offset);
222 offset += totalGlyphs * sizeof(QGlyphJustification);
223 attributes = reinterpret_cast<QGlyphAttributes *>(address + offset);
224 numGlyphs = totalGlyphs;
225 }
226
227 inline QGlyphLayout mid(int position, int n = -1) const {
228 QGlyphLayout copy = *this;
229 copy.glyphs += position;
230 copy.advances += position;
231 copy.offsets += position;
232 copy.justifications += position;
233 copy.attributes += position;
234 if (n == -1)
235 copy.numGlyphs -= position;
236 else
237 copy.numGlyphs = n;
238 return copy;
239 }
240
241 inline QFixed effectiveAdvance(int item) const
242 { return (advances[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
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(static_cast<void *>(offsets), 0, (numGlyphs * SpaceNeeded));
250 } else {
251 const int num = last - first;
252 memset(static_cast<void *>(offsets + first), 0, num * sizeof(QFixedPoint));
253 memset(glyphs + first, 0, num * sizeof(glyph_t));
254 memset(static_cast<void *>(advances + first), 0, num * sizeof(QFixed));
255 memset(static_cast<void *>(justifications + first), 0, num * sizeof(QGlyphJustification));
256 memset(attributes + first, 0, num * sizeof(QGlyphAttributes));
257 }
258 }
259
260 inline char *data() {
261 return reinterpret_cast<char *>(offsets);
262 }
263
264 void grow(char *address, int totalGlyphs);
265};
266
267class QVarLengthGlyphLayoutArray : private QVarLengthArray<void *>, public QGlyphLayout
268{
269private:
270 typedef QVarLengthArray<void *> Array;
271public:
272 QVarLengthGlyphLayoutArray(int totalGlyphs)
273 : Array((totalGlyphs * SpaceNeeded) / 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((totalGlyphs * SpaceNeeded) / 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
288template <int N> struct QGlyphLayoutArray : public QGlyphLayout
289{
290public:
291 QGlyphLayoutArray()
292 : QGlyphLayout(reinterpret_cast<char *>(buffer), N)
293 {
294 memset(buffer, 0, sizeof(buffer));
295 }
296
297private:
298 void *buffer[(N * SpaceNeeded) / sizeof(void *) + 1];
299};
300
301struct QScriptItem;
302/// Internal QTextItem
303class QTextItemInt : public QTextItem
304{
305public:
306 inline QTextItemInt()
307 : justified(false), underlineStyle(QTextCharFormat::NoUnderline), num_chars(0), chars(nullptr),
308 logClusters(nullptr), f(nullptr), fontEngine(nullptr)
309 {}
310 QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
311 QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars, int numChars, QFontEngine *fe,
312 const QTextCharFormat &format = QTextCharFormat());
313
314 /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
315 /// the width of the returned QTextItemInt is not adjusted, for speed reasons
316 QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const;
317 void initWithScriptItem(const QScriptItem &si);
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
336struct QScriptItem
337{
338 Q_DECL_CONSTEXPR QScriptItem(int p, QScriptAnalysis a) noexcept
339 : position(p), analysis(a),
340 num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
341 glyph_data_offset(0) {}
342
343 int position;
344 QScriptAnalysis analysis;
345 unsigned short num_glyphs;
346 QFixed descent;
347 QFixed ascent;
348 QFixed leading;
349 QFixed width;
350 int glyph_data_offset;
351 Q_DECL_CONSTEXPR QFixed height() const noexcept { return ascent + descent; }
352private:
353 friend class QVector<QScriptItem>;
354 QScriptItem() {}; // for QVector, don't use
355};
356Q_DECLARE_TYPEINFO(QScriptItem, Q_PRIMITIVE_TYPE);
357
358typedef QVector<QScriptItem> QScriptItemArray;
359
360struct Q_AUTOTEST_EXPORT QScriptLine
361{
362 // created and filled in QTextLine::layout_helper
363 QScriptLine()
364 : from(0), trailingSpaces(0), length(0),
365 justified(0), gridfitted(0),
366 hasTrailingSpaces(0), leadingIncluded(0) {}
367 QFixed descent;
368 QFixed ascent;
369 QFixed leading;
370 QFixed x;
371 QFixed y;
372 QFixed width;
373 QFixed textWidth;
374 QFixed textAdvance;
375 int from;
376 unsigned short trailingSpaces;
377 signed int length : 28;
378 mutable uint justified : 1;
379 mutable uint gridfitted : 1;
380 uint hasTrailingSpaces : 1;
381 uint leadingIncluded : 1;
382 QFixed height() const { return ascent + descent
383 + (leadingIncluded? qMax(QFixed(),leading) : QFixed()); }
384 QFixed base() const { return ascent; }
385 void setDefaultHeight(QTextEngine *eng);
386 void operator+=(const QScriptLine &other);
387};
388Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
389
390
391inline void QScriptLine::operator+=(const QScriptLine &other)
392{
393 leading= qMax(leading + ascent, other.leading + other.ascent) - qMax(ascent, other.ascent);
394 descent = qMax(descent, other.descent);
395 ascent = qMax(ascent, other.ascent);
396 textWidth += other.textWidth;
397 length += other.length;
398}
399
400typedef QVector<QScriptLine> QScriptLineArray;
401
402class QFontPrivate;
403class QTextFormatCollection;
404
405class Q_GUI_EXPORT QTextEngine {
406public:
407 enum LayoutState {
408 LayoutEmpty,
409 InLayout,
410 LayoutFailed
411 };
412 struct Q_GUI_EXPORT LayoutData {
413 LayoutData(const QString &str, void **stack_memory, int mem_size);
414 LayoutData();
415 ~LayoutData();
416 mutable QScriptItemArray items;
417 int allocated;
418 int available_glyphs;
419 void **memory;
420 unsigned short *logClustersPtr;
421 QGlyphLayout glyphLayout;
422 mutable int used;
423 uint hasBidi : 1;
424 uint layoutState : 2;
425 uint memory_on_stack : 1;
426 uint haveCharAttributes : 1;
427 QString string;
428 bool reallocate(int totalGlyphs);
429 };
430
431 struct ItemDecoration {
432 ItemDecoration() {} // for QVector, don't use
433 ItemDecoration(qreal x1, qreal x2, qreal y, const QPen &pen):
434 x1(x1), x2(x2), y(y), pen(pen) {}
435
436 qreal x1;
437 qreal x2;
438 qreal y;
439 QPen pen;
440 };
441
442 typedef QVector<ItemDecoration> ItemDecorationList;
443
444 QTextEngine();
445 QTextEngine(const QString &str, const QFont &f);
446 ~QTextEngine();
447
448 enum Mode {
449 WidthOnly = 0x07
450 };
451
452 void invalidate();
453 void clearLineData();
454
455 void validate() const;
456 void itemize() const;
457
458 bool isRightToLeft() const;
459 static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
460
461 const QCharAttributes *attributes() const;
462
463 void shape(int item) const;
464
465 void justify(const QScriptLine &si);
466 QFixed alignLine(const QScriptLine &line);
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 = nullptr, QFixed *descent = nullptr, QFixed *leading = nullptr) 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 bool ensureSpace(int nGlyphs) const {
522 if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
523 return layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
524 return true;
525 }
526
527 void freeMemory();
528
529 int findItem(int strPos, int firstItem = 0) const;
530 inline QTextFormatCollection *formatCollection() const {
531 if (block.docHandle())
532 return block.docHandle()->formatCollection();
533 return specialData ? specialData->formatCollection.data() : nullptr;
534 }
535 QTextCharFormat format(const QScriptItem *si) const;
536 inline QAbstractTextDocumentLayout *docLayout() const {
537 Q_ASSERT(block.docHandle());
538 return block.docHandle()->document()->documentLayout();
539 }
540 int formatIndex(const QScriptItem *si) const;
541
542 /// returns the width of tab at index (in the tabs array) with the tab-start at position x
543 QFixed calculateTabWidth(int index, QFixed x) const;
544
545 mutable QScriptLineArray lines;
546
547private:
548 struct FontEngineCache {
549 FontEngineCache();
550 mutable QFontEngine *prevFontEngine;
551 mutable QFontEngine *prevScaledFontEngine;
552 mutable int prevScript;
553 mutable int prevPosition;
554 mutable int prevLength;
555 inline void reset() {
556 prevFontEngine = nullptr;
557 prevScaledFontEngine = nullptr;
558 prevScript = -1;
559 prevPosition = -1;
560 prevLength = -1;
561 }
562 };
563 mutable FontEngineCache feCache;
564
565public:
566 QString text;
567 mutable QFont fnt;
568#ifndef QT_NO_RAWFONT
569 QRawFont rawFont;
570#endif
571 QTextBlock block;
572
573 QTextOption option;
574
575 QFixed minWidth;
576 QFixed maxWidth;
577 QPointF position;
578 uint ignoreBidi : 1;
579 uint cacheGlyphs : 1;
580 uint stackEngine : 1;
581 uint forceJustification : 1;
582 uint visualMovement : 1;
583 uint delayDecorations: 1;
584#ifndef QT_NO_RAWFONT
585 uint useRawFont : 1;
586#endif
587
588 mutable LayoutData *layoutData;
589
590 ItemDecorationList underlineList;
591 ItemDecorationList strikeOutList;
592 ItemDecorationList overlineList;
593
594 inline bool visualCursorMovement() const
595 { return visualMovement || (block.docHandle() && block.docHandle()->defaultCursorMoveStyle == Qt::VisualMoveStyle); }
596
597 inline int preeditAreaPosition() const { return specialData ? specialData->preeditPosition : -1; }
598 inline QString preeditAreaText() const { return specialData ? specialData->preeditText : QString(); }
599 void setPreeditArea(int position, const QString &text);
600
601 inline bool hasFormats() const
602 { return block.docHandle() || (specialData && !specialData->formats.isEmpty()); }
603 inline QVector<QTextLayout::FormatRange> formats() const
604 { return specialData ? specialData->formats : QVector<QTextLayout::FormatRange>(); }
605 void setFormats(const QVector<QTextLayout::FormatRange> &formats);
606
607private:
608 static void init(QTextEngine *e);
609
610 struct SpecialData {
611 int preeditPosition;
612 QString preeditText;
613 QVector<QTextLayout::FormatRange> formats;
614 QVector<QTextCharFormat> resolvedFormats;
615 // only used when no docHandle is available
616 QScopedPointer<QTextFormatCollection> formatCollection;
617 };
618 SpecialData *specialData;
619
620 void indexFormats();
621 void resolveFormats() const;
622
623public:
624 bool atWordSeparator(int position) const;
625
626 QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0, int from = 0, int count = -1) const;
627
628 void shapeLine(const QScriptLine &line);
629 QFixed leadingSpaceWidth(const QScriptLine &line);
630
631 QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
632 int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
633 int previousLogicalPosition(int oldPos) const;
634 int nextLogicalPosition(int oldPos) const;
635 int lineNumberForTextPosition(int pos);
636 int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op);
637 std::vector<int> insertionPointsForLine(int lineNum);
638 void resetFontEngineCache();
639
640 void enableDelayDecorations(bool enable = true) { delayDecorations = enable; }
641
642 void addUnderline(QPainter *painter, const QLineF &line);
643 void addStrikeOut(QPainter *painter, const QLineF &line);
644 void addOverline(QPainter *painter, const QLineF &line);
645
646 void drawDecorations(QPainter *painter);
647 void clearDecorations();
648 void adjustUnderlines();
649
650private:
651 void addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList);
652 void adjustUnderlines(ItemDecorationList::iterator start,
653 ItemDecorationList::iterator end,
654 qreal underlinePos, qreal penWidth);
655 void drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList);
656 void setBoundary(int strPos) const;
657 void addRequiredBoundaries() const;
658 void shapeText(int item) const;
659#if QT_CONFIG(harfbuzz)
660 int shapeTextWithHarfbuzzNG(const QScriptItem &si,
661 const ushort *string,
662 int itemLength,
663 QFontEngine *fontEngine,
664 const QVector<uint> &itemBoundaries,
665 bool kerningEnabled,
666 bool hasLetterSpacing) const;
667#endif
668 int shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector<uint> &itemBoundaries, bool kerningEnabled) const;
669
670 int endOfLine(int lineNum);
671 int beginningOfLine(int lineNum);
672 int getClusterLength(unsigned short *logClusters, const QCharAttributes *attributes, int from, int to, int glyph_pos, int *start);
673};
674
675class Q_GUI_EXPORT QStackTextEngine : public QTextEngine {
676public:
677 enum { MemSize = 256*40/sizeof(void *) };
678 QStackTextEngine(const QString &string, const QFont &f);
679 LayoutData _layoutData;
680 void *_memory[MemSize];
681};
682Q_DECLARE_TYPEINFO(QTextEngine::ItemDecoration, Q_MOVABLE_TYPE);
683
684struct QTextLineItemIterator
685{
686 QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(),
687 const QTextLayout::FormatRange *_selection = nullptr);
688
689 inline bool atEnd() const { return logicalItem >= nItems - 1; }
690 inline bool atBeginning() const { return logicalItem <= 0; }
691 QScriptItem &next();
692
693 bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const;
694 inline bool isOutsideSelection() const {
695 QFixed tmp1, tmp2;
696 return !getSelectionBounds(&tmp1, &tmp2);
697 }
698
699 QTextEngine *eng;
700
701 QFixed x;
702 const QScriptLine &line;
703 QScriptItem *si;
704
705 const int lineNum;
706 const int lineEnd;
707 const int firstItem;
708 const int lastItem;
709 const int nItems;
710 int logicalItem;
711 int item;
712 int itemLength;
713
714 int glyphsStart;
715 int glyphsEnd;
716 int itemStart;
717 int itemEnd;
718
719 QFixed itemWidth;
720
721 QVarLengthArray<int> visualOrder;
722
723 const QTextLayout::FormatRange *selection;
724};
725
726QT_END_NAMESPACE
727
728#endif // QTEXTENGINE_P_H
729