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 79 QT_BEGIN_NAMESPACE 80 81 class QFontPrivate; 82 class QFontEngine; 83 84 class QString; 85 class QPainter; 86 87 class QAbstractTextDocumentLayout; 88 89 typedef 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 96 struct Q_GUI_EXPORT glyph_metrics_t 97 { glyph_metrics_tglyph_metrics_t98 inline glyph_metrics_t() 99 : x(100000), y(100000) {} glyph_metrics_tglyph_metrics_t100 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; isValidglyph_metrics_t116 inline bool isValid() const {return x != 100000 && y != 100000;} 117 leftBearingglyph_metrics_t118 inline QFixed leftBearing() const 119 { 120 if (!isValid()) 121 return QFixed(); 122 123 return x; 124 } 125 rightBearingglyph_metrics_t126 inline QFixed rightBearing() const 127 { 128 if (!isValid()) 129 return QFixed(); 130 131 return xoff - x - width; 132 } 133 }; 134 Q_DECLARE_TYPEINFO(glyph_metrics_t, Q_PRIMITIVE_TYPE); 135 136 struct 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 }; 166 Q_DECLARE_TYPEINFO(QScriptAnalysis, Q_PRIMITIVE_TYPE); 167 168 struct QGlyphJustification 169 { QGlyphJustificationQGlyphJustification170 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 }; 184 Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE); 185 186 struct QGlyphAttributes { 187 uchar clusterStart : 1; 188 uchar dontPrint : 1; 189 uchar justification : 4; 190 uchar reserved : 2; 191 }; 192 Q_STATIC_ASSERT(sizeof(QGlyphAttributes) == 1); 193 Q_DECLARE_TYPEINFO(QGlyphAttributes, Q_PRIMITIVE_TYPE); 194 195 struct 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 QGlyphLayoutQGlyphLayout211 inline QGlyphLayout() : numGlyphs(0) {} 212 QGlyphLayoutQGlyphLayout213 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 effectiveAdvanceQGlyphLayout241 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 dataQGlyphLayout260 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: QVarLengthGlyphLayoutArray(int totalGlyphs)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 resize(int totalGlyphs)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 288 template <int N> struct QGlyphLayoutArray : public QGlyphLayout 289 { 290 public: QGlyphLayoutArrayQGlyphLayoutArray291 QGlyphLayoutArray() 292 : QGlyphLayout(reinterpret_cast<char *>(buffer), N) 293 { 294 memset(buffer, 0, sizeof(buffer)); 295 } 296 297 private: 298 void *buffer[(N * SpaceNeeded) / sizeof(void *) + 1]; 299 }; 300 301 struct QScriptItem; 302 /// Internal QTextItem 303 class QTextItemInt : public QTextItem 304 { 305 public: 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 333 struct QScriptItem 334 { QScriptItemQScriptItem335 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; heightQScriptItem348 Q_DECL_CONSTEXPR QFixed height() const noexcept { return ascent + descent; } 349 private: 350 friend class QVector<QScriptItem>; QScriptItemQScriptItem351 QScriptItem() {} // for QVector, don't use 352 }; 353 Q_DECLARE_TYPEINFO(QScriptItem, Q_PRIMITIVE_TYPE); 354 355 typedef QVector<QScriptItem> QScriptItemArray; 356 357 struct Q_AUTOTEST_EXPORT QScriptLine 358 { 359 // created and filled in QTextLine::layout_helper QScriptLineQScriptLine360 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; heightQScriptLine379 QFixed height() const { return ascent + descent 380 + (leadingIncluded? qMax(QFixed(),leading) : QFixed()); } baseQScriptLine381 QFixed base() const { return ascent; } 382 void setDefaultHeight(QTextEngine *eng); 383 void operator+=(const QScriptLine &other); 384 }; 385 Q_DECLARE_TYPEINFO(QScriptLine, Q_PRIMITIVE_TYPE); 386 387 388 inline 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 397 typedef QVector<QScriptLine> QScriptLineArray; 398 399 class QFontPrivate; 400 class QTextFormatCollection; 401 402 class Q_GUI_EXPORT QTextEngine { 403 public: 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 { ItemDecorationItemDecoration429 ItemDecoration() {} // for QVector, don't use ItemDecorationItemDecoration430 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 length(int item)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 } length(const QScriptItem * si)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; font()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 */ logClusters(const QScriptItem * si)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 */ availableGlyphs(const QScriptItem * si)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 */ shapedGlyphs(const QScriptItem * si)514 inline QGlyphLayout shapedGlyphs(const QScriptItem *si) const { 515 return layoutData->glyphLayout.mid(si->glyph_data_offset, si->num_glyphs); 516 } 517 ensureSpace(int nGlyphs)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; formatCollection()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; docLayout()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 544 private: 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; resetFontEngineCache552 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 562 public: 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 visualCursorMovement()591 inline bool visualCursorMovement() const 592 { return visualMovement || (block.docHandle() && block.docHandle()->defaultCursorMoveStyle == Qt::VisualMoveStyle); } 593 preeditAreaPosition()594 inline int preeditAreaPosition() const { return specialData ? specialData->preeditPosition : -1; } preeditAreaText()595 inline QString preeditAreaText() const { return specialData ? specialData->preeditText : QString(); } 596 void setPreeditArea(int position, const QString &text); 597 hasFormats()598 inline bool hasFormats() const 599 { return block.docHandle() || (specialData && !specialData->formats.isEmpty()); } formats()600 inline QVector<QTextLayout::FormatRange> formats() const 601 { return specialData ? specialData->formats : QVector<QTextLayout::FormatRange>(); } 602 void setFormats(const QVector<QTextLayout::FormatRange> &formats); 603 604 private: 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 620 public: 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 647 private: 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 672 class Q_GUI_EXPORT QStackTextEngine : public QTextEngine { 673 public: 674 enum { MemSize = 256*40/sizeof(void *) }; 675 QStackTextEngine(const QString &string, const QFont &f); 676 LayoutData _layoutData; 677 void *_memory[MemSize]; 678 }; 679 Q_DECLARE_TYPEINFO(QTextEngine::ItemDecoration, Q_MOVABLE_TYPE); 680 681 struct QTextLineItemIterator 682 { 683 QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(), 684 const QTextLayout::FormatRange *_selection = nullptr); 685 atEndQTextLineItemIterator686 inline bool atEnd() const { return logicalItem >= nItems - 1; } atBeginningQTextLineItemIterator687 inline bool atBeginning() const { return logicalItem <= 0; } 688 QScriptItem &next(); 689 690 bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const; isOutsideSelectionQTextLineItemIterator691 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 723 QT_END_NAMESPACE 724 725 #endif // QTEXTENGINE_P_H 726