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() = default;
307 QTextItemInt(const QScriptItem &si, QFont *font, const QTextCharFormat &format = QTextCharFormat());
308 QTextItemInt(const QGlyphLayout &g, QFont *font, const QChar *chars, int numChars, QFontEngine *fe,
309 const QTextCharFormat &format = QTextCharFormat());
310
311 /// copy the structure items, adjusting the glyphs arrays to the right subarrays.
312 /// the width of the returned QTextItemInt is not adjusted, for speed reasons
313 QTextItemInt midItem(QFontEngine *fontEngine, int firstGlyphIndex, int numGlyphs) const;
314 void initWithScriptItem(const QScriptItem &si);
315
316 QFixed descent;
317 QFixed ascent;
318 QFixed width;
319
320 RenderFlags flags;
321 bool justified = false;
322 QTextCharFormat::UnderlineStyle underlineStyle = QTextCharFormat::NoUnderline;
323 const QTextCharFormat charFormat;
324 int num_chars = 0;
325 const QChar *chars = nullptr;
326 const unsigned short *logClusters = nullptr;
327 const QFont *f = nullptr;
328
329 QGlyphLayout glyphs;
330 QFontEngine *fontEngine = nullptr;
331};
332
333struct QScriptItem
334{
335 Q_DECL_CONSTEXPR QScriptItem(int p, QScriptAnalysis a) noexcept
336 : position(p), analysis(a),
337 num_glyphs(0), descent(-1), ascent(-1), leading(-1), width(-1),
338 glyph_data_offset(0) {}
339
340 int position;
341 QScriptAnalysis analysis;
342 unsigned short num_glyphs;
343 QFixed descent;
344 QFixed ascent;
345 QFixed leading;
346 QFixed width;
347 int glyph_data_offset;
348 Q_DECL_CONSTEXPR QFixed height() const noexcept { return ascent + descent; }
349private:
350 friend class QVector<QScriptItem>;
351 QScriptItem() {} // for QVector, don't use
352};
353Q_DECLARE_TYPEINFO(QScriptItem, Q_PRIMITIVE_TYPE);
354
355typedef QVector<QScriptItem> QScriptItemArray;
356
357struct Q_AUTOTEST_EXPORT QScriptLine
358{
359 // created and filled in QTextLine::layout_helper
360 QScriptLine()
361 : from(0), trailingSpaces(0), length(0),
362 justified(0), gridfitted(0),
363 hasTrailingSpaces(0), leadingIncluded(0) {}
364 QFixed descent;
365 QFixed ascent;
366 QFixed leading;
367 QFixed x;
368 QFixed y;
369 QFixed width;
370 QFixed textWidth;
371 QFixed textAdvance;
372 int from;
373 unsigned short trailingSpaces;
374 signed int length : 28;
375 mutable uint justified : 1;
376 mutable uint gridfitted : 1;
377 uint hasTrailingSpaces : 1;
378 uint leadingIncluded : 1;
379 QFixed height() const { return ascent + descent
380 + (leadingIncluded? qMax(QFixed(),leading) : QFixed()); }
381 QFixed base() const { return ascent; }
382 void setDefaultHeight(QTextEngine *eng);
383 void operator+=(const QScriptLine &other);
384};
385Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE);
386
387
388inline void QScriptLine::operator+=(const QScriptLine &other)
389{
390 leading= qMax(leading + ascent, other.leading + other.ascent) - qMax(ascent, other.ascent);
391 descent = qMax(descent, other.descent);
392 ascent = qMax(ascent, other.ascent);
393 textWidth += other.textWidth;
394 length += other.length;
395}
396
397typedef QVector<QScriptLine> QScriptLineArray;
398
399class QFontPrivate;
400class QTextFormatCollection;
401
402class Q_GUI_EXPORT QTextEngine {
403public:
404 enum LayoutState {
405 LayoutEmpty,
406 InLayout,
407 LayoutFailed
408 };
409 struct Q_GUI_EXPORT LayoutData {
410 LayoutData(const QString &str, void **stack_memory, int mem_size);
411 LayoutData();
412 ~LayoutData();
413 mutable QScriptItemArray items;
414 int allocated;
415 int available_glyphs;
416 void **memory;
417 unsigned short *logClustersPtr;
418 QGlyphLayout glyphLayout;
419 mutable int used;
420 uint hasBidi : 1;
421 uint layoutState : 2;
422 uint memory_on_stack : 1;
423 uint haveCharAttributes : 1;
424 QString string;
425 bool reallocate(int totalGlyphs);
426 };
427
428 struct ItemDecoration {
429 ItemDecoration() {} // for QVector, don't use
430 ItemDecoration(qreal x1, qreal x2, qreal y, const QPen &pen):
431 x1(x1), x2(x2), y(y), pen(pen) {}
432
433 qreal x1;
434 qreal x2;
435 qreal y;
436 QPen pen;
437 };
438
439 typedef QVector<ItemDecoration> ItemDecorationList;
440
441 QTextEngine();
442 QTextEngine(const QString &str, const QFont &f);
443 ~QTextEngine();
444
445 enum Mode {
446 WidthOnly = 0x07
447 };
448
449 void invalidate();
450 void clearLineData();
451
452 void validate() const;
453 void itemize() const;
454
455 bool isRightToLeft() const;
456 static void bidiReorder(int numRuns, const quint8 *levels, int *visualOrder);
457
458 const QCharAttributes *attributes() const;
459
460 void shape(int item) const;
461
462 void justify(const QScriptLine &si);
463 QFixed alignLine(const QScriptLine &line);
464
465 QFixed width(int charFrom, int numChars) const;
466 glyph_metrics_t boundingBox(int from, int len) const;
467 glyph_metrics_t tightBoundingBox(int from, int len) const;
468
469 int length(int item) const {
470 const QScriptItem &si = layoutData->items[item];
471 int from = si.position;
472 item++;
473 return (item < layoutData->items.size() ? layoutData->items[item].position : layoutData->string.length()) - from;
474 }
475 int length(const QScriptItem *si) const {
476 int end;
477 if (si + 1 < layoutData->items.constData()+ layoutData->items.size())
478 end = (si+1)->position;
479 else
480 end = layoutData->string.length();
481 return end - si->position;
482 }
483
484 QFontEngine *fontEngine(const QScriptItem &si, QFixed *ascent = nullptr, QFixed *descent = nullptr, QFixed *leading = nullptr) const;
485 QFont font(const QScriptItem &si) const;
486 inline QFont font() const { return fnt; }
487
488 /**
489 * Returns a pointer to an array of log clusters, offset at the script item.
490 * Each item in the array is a unsigned short. For each character in the original string there is an entry in the table
491 * so there is a one to one correlation in indexes between the original text and the index in the logcluster.
492 * The value of each item is the position in the glyphs array. Multiple similar pointers in the logclusters array imply
493 * that one glyph is used for more than one character.
494 * \sa glyphs()
495 */
496 inline unsigned short *logClusters(const QScriptItem *si) const
497 { return layoutData->logClustersPtr+si->position; }
498 /**
499 * Returns an array of QGlyphLayout items, offset at the script item.
500 * Each item in the array matches one glyph in the text, storing the advance, position etc.
501 * The returned item's length equals to the number of available glyphs. This may be more
502 * than what was actually shaped.
503 * \sa logClusters()
504 */
505 inline QGlyphLayout availableGlyphs(const QScriptItem *si) const {
506 return layoutData->glyphLayout.mid(si->glyph_data_offset);
507 }
508 /**
509 * Returns an array of QGlyphLayout items, offset at the script item.
510 * Each item in the array matches one glyph in the text, storing the advance, position etc.
511 * The returned item's length equals to the number of shaped glyphs.
512 * \sa logClusters()
513 */
514 inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const {
515 return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs);
516 }
517
518 inline bool ensureSpace(int nGlyphs) const {
519 if (layoutData->glyphLayout.numGlyphs - layoutData->used < nGlyphs)
520 return layoutData->reallocate((((layoutData->used + nGlyphs)*3/2 + 15) >> 4) << 4);
521 return true;
522 }
523
524 void freeMemory();
525
526 int findItem(int strPos, int firstItem = 0) const;
527 inline QTextFormatCollection *formatCollection() const {
528 if (block.docHandle())
529 return block.docHandle()->formatCollection();
530 return specialData ? specialData->formatCollection.data() : nullptr;
531 }
532 QTextCharFormat format(const QScriptItem *si) const;
533 inline QAbstractTextDocumentLayout *docLayout() const {
534 Q_ASSERT(block.docHandle());
535 return block.docHandle()->document()->documentLayout();
536 }
537 int formatIndex(const QScriptItem *si) const;
538
539 /// returns the width of tab at index (in the tabs array) with the tab-start at position x
540 QFixed calculateTabWidth(int index, QFixed x) const;
541
542 mutable QScriptLineArray lines;
543
544private:
545 struct FontEngineCache {
546 FontEngineCache();
547 mutable QFontEngine *prevFontEngine;
548 mutable QFontEngine *prevScaledFontEngine;
549 mutable int prevScript;
550 mutable int prevPosition;
551 mutable int prevLength;
552 inline void reset() {
553 prevFontEngine = nullptr;
554 prevScaledFontEngine = nullptr;
555 prevScript = -1;
556 prevPosition = -1;
557 prevLength = -1;
558 }
559 };
560 mutable FontEngineCache feCache;
561
562public:
563 QString text;
564 mutable QFont fnt;
565#ifndef QT_NO_RAWFONT
566 QRawFont rawFont;
567#endif
568 QTextBlock block;
569
570 QTextOption option;
571
572 QFixed minWidth;
573 QFixed maxWidth;
574 QPointF position;
575 uint ignoreBidi : 1;
576 uint cacheGlyphs : 1;
577 uint stackEngine : 1;
578 uint forceJustification : 1;
579 uint visualMovement : 1;
580 uint delayDecorations: 1;
581#ifndef QT_NO_RAWFONT
582 uint useRawFont : 1;
583#endif
584
585 mutable LayoutData *layoutData;
586
587 ItemDecorationList underlineList;
588 ItemDecorationList strikeOutList;
589 ItemDecorationList overlineList;
590
591 inline bool visualCursorMovement() const
592 { return visualMovement || (block.docHandle() && block.docHandle()->defaultCursorMoveStyle == Qt::VisualMoveStyle); }
593
594 inline int preeditAreaPosition() const { return specialData ? specialData->preeditPosition : -1; }
595 inline QString preeditAreaText() const { return specialData ? specialData->preeditText : QString(); }
596 void setPreeditArea(int position, const QString &text);
597
598 inline bool hasFormats() const
599 { return block.docHandle() || (specialData && !specialData->formats.isEmpty()); }
600 inline QVector<QTextLayout::FormatRange> formats() const
601 { return specialData ? specialData->formats : QVector<QTextLayout::FormatRange>(); }
602 void setFormats(const QVector<QTextLayout::FormatRange> &formats);
603
604private:
605 static void init(QTextEngine *e);
606
607 struct SpecialData {
608 int preeditPosition;
609 QString preeditText;
610 QVector<QTextLayout::FormatRange> formats;
611 QVector<QTextCharFormat> resolvedFormats;
612 // only used when no docHandle is available
613 QScopedPointer<QTextFormatCollection> formatCollection;
614 };
615 SpecialData *specialData;
616
617 void indexFormats();
618 void resolveFormats() const;
619
620public:
621 bool atWordSeparator(int position) const;
622
623 QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0, int from = 0, int count = -1) const;
624
625 void shapeLine(const QScriptLine &line);
626 QFixed leadingSpaceWidth(const QScriptLine &line);
627
628 QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
629 int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
630 int previousLogicalPosition(int oldPos) const;
631 int nextLogicalPosition(int oldPos) const;
632 int lineNumberForTextPosition(int pos);
633 int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op);
634 std::vector<int> insertionPointsForLine(int lineNum);
635 void resetFontEngineCache();
636
637 void enableDelayDecorations(bool enable = true) { delayDecorations = enable; }
638
639 void addUnderline(QPainter *painter, const QLineF &line);
640 void addStrikeOut(QPainter *painter, const QLineF &line);
641 void addOverline(QPainter *painter, const QLineF &line);
642
643 void drawDecorations(QPainter *painter);
644 void clearDecorations();
645 void adjustUnderlines();
646
647private:
648 void addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList);
649 void adjustUnderlines(ItemDecorationList::iterator start,
650 ItemDecorationList::iterator end,
651 qreal underlinePos, qreal penWidth);
652 void drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList);
653 void setBoundary(int strPos) const;
654 void addRequiredBoundaries() const;
655 void shapeText(int item) const;
656#if QT_CONFIG(harfbuzz)
657 int shapeTextWithHarfbuzzNG(const QScriptItem &si,
658 const ushort *string,
659 int itemLength,
660 QFontEngine *fontEngine,
661 const QVector<uint> &itemBoundaries,
662 bool kerningEnabled,
663 bool hasLetterSpacing) const;
664#endif
665 int shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *string, int itemLength, QFontEngine *fontEngine, const QVector<uint> &itemBoundaries, bool kerningEnabled) const;
666
667 int endOfLine(int lineNum);
668 int beginningOfLine(int lineNum);
669 int getClusterLength(unsigned short *logClusters, const QCharAttributes *attributes, int from, int to, int glyph_pos, int *start);
670};
671
672class Q_GUI_EXPORT QStackTextEngine : public QTextEngine {
673public:
674 enum { MemSize = 256*40/sizeof(void *) };
675 QStackTextEngine(const QString &string, const QFont &f);
676 LayoutData _layoutData;
677 void *_memory[MemSize];
678};
679Q_DECLARE_TYPEINFO(QTextEngine::ItemDecoration, Q_MOVABLE_TYPE);
680
681struct QTextLineItemIterator
682{
683 QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(),
684 const QTextLayout::FormatRange *_selection = nullptr);
685
686 inline bool atEnd() const { return logicalItem >= nItems - 1; }
687 inline bool atBeginning() const { return logicalItem <= 0; }
688 QScriptItem &next();
689
690 bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const;
691 inline bool isOutsideSelection() const {
692 QFixed tmp1, tmp2;
693 return !getSelectionBounds(&tmp1, &tmp2);
694 }
695
696 QTextEngine *eng;
697
698 QFixed x;
699 const QScriptLine &line;
700 QScriptItem *si;
701
702 const int lineNum;
703 const int lineEnd;
704 const int firstItem;
705 const int lastItem;
706 const int nItems;
707 int logicalItem;
708 int item;
709 int itemLength;
710
711 int glyphsStart;
712 int glyphsEnd;
713 int itemStart;
714 int itemEnd;
715
716 QFixed itemWidth;
717
718 QVarLengthArray<int> visualOrder;
719
720 const QTextLayout::FormatRange *selection;
721};
722
723QT_END_NAMESPACE
724
725#endif // QTEXTENGINE_P_H
726

source code of qtbase/src/gui/text/qtextengine_p.h