Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qquicktextnodeengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtCore/qpoint.h>
7#include <QtGui/qabstracttextdocumentlayout.h>
8#include <QtGui/qrawfont.h>
9#include <QtGui/qtextdocument.h>
10#include <QtGui/qtextlayout.h>
11#include <QtGui/qtextobject.h>
12#include <QtGui/qtexttable.h>
13#include <QtGui/qtextlist.h>
14
15#include <private/qquicktext_p.h>
16#include <private/qtextdocumentlayout_p.h>
17#include <private/qtextimagehandler_p.h>
18#include <private/qrawfont_p.h>
19#include <private/qglyphrun_p.h>
20#include <private/qquickitem_p.h>
21
23
25
27 : fontEngine(QRawFontPrivate::get(node->glyphRun.rawFont())->fontEngine)
28 , clipNode(node->clipNode)
29 , color(node->color.rgba())
30 , selectionState(node->selectionState)
31{
32}
33
35 SelectionState selState,
36 const QRectF &brect,
37 const Decorations &decs,
38 const QColor &c,
39 const QColor &bc, const QColor &dc,
40 const QPointF &pos, qreal a)
41 : glyphRun(g)
42 , boundingRect(brect)
43 , selectionState(selState)
44 , clipNode(nullptr)
45 , decorations(decs)
46 , color(c)
47 , backgroundColor(bc)
48 , decorationColor(dc)
49 , position(pos)
50 , ascent(a)
51 , leftChildIndex(-1)
52 , rightChildIndex(-1)
53{
55 ranges.append(qMakePair(d->textRangeStart, d->textRangeEnd));
56}
57
58
59void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const QGlyphRun &glyphRun, SelectionState selectionState,
60 Decorations decorations, const QColor &textColor,
61 const QColor &backgroundColor, const QColor &decorationColor, const QPointF &position)
62{
63 QRectF searchRect = glyphRun.boundingRect();
64 searchRect.translate(position);
65
66 if (qFuzzyIsNull(searchRect.width()) || qFuzzyIsNull(searchRect.height()))
67 return;
68
69 decorations |= (glyphRun.underline() ? Decoration::Underline : Decoration::NoDecoration);
70 decorations |= (glyphRun.overline() ? Decoration::Overline : Decoration::NoDecoration);
71 decorations |= (glyphRun.strikeOut() ? Decoration::StrikeOut : Decoration::NoDecoration);
72 decorations |= (backgroundColor.isValid() ? Decoration::Background : Decoration::NoDecoration);
73
74 qreal ascent = glyphRun.rawFont().ascent();
75 insert(binaryTree, BinaryTreeNode(glyphRun,
76 selectionState,
77 searchRect,
78 decorations,
79 textColor,
80 backgroundColor,
81 decorationColor,
83 ascent));
84}
85
86void QQuickTextNodeEngine::BinaryTreeNode::insert(QVarLengthArray<BinaryTreeNode, 16> *binaryTree, const BinaryTreeNode &binaryTreeNode)
87{
88 int newIndex = binaryTree->size();
89 binaryTree->append(binaryTreeNode);
90 if (newIndex == 0)
91 return;
92
93 int searchIndex = 0;
94 forever {
95 BinaryTreeNode *node = binaryTree->data() + searchIndex;
96 if (binaryTreeNode.boundingRect.left() < node->boundingRect.left()) {
97 if (node->leftChildIndex < 0) {
98 node->leftChildIndex = newIndex;
99 break;
100 } else {
101 searchIndex = node->leftChildIndex;
102 }
103 } else {
104 if (node->rightChildIndex < 0) {
105 node->rightChildIndex = newIndex;
106 break;
107 } else {
108 searchIndex = node->rightChildIndex;
109 }
110 }
111 }
112}
113
114void QQuickTextNodeEngine::BinaryTreeNode::inOrder(const QVarLengthArray<BinaryTreeNode, 16> &binaryTree,
115 QVarLengthArray<int> *sortedIndexes, int currentIndex)
116{
117 Q_ASSERT(currentIndex < binaryTree.size());
118
119 const BinaryTreeNode *node = binaryTree.data() + currentIndex;
120 if (node->leftChildIndex >= 0)
121 inOrder(binaryTree, sortedIndexes, node->leftChildIndex);
122
123 sortedIndexes->append(currentIndex);
124
125 if (node->rightChildIndex >= 0)
126 inOrder(binaryTree, sortedIndexes, node->rightChildIndex);
127}
128
129
131 const QTextCharFormat &charFormat,
132 const QColor &textColor,
133 const QVarLengthArray<QTextLayout::FormatRange> &colorChanges,
134 int textPos, int fragmentEnd,
135 int selectionStart, int selectionEnd)
136{
137 if (charFormat.foreground().style() != Qt::NoBrush)
138 setTextColor(charFormat.foreground().color());
139 else
140 setTextColor(textColor);
141
142 while (textPos < fragmentEnd) {
143 int blockRelativePosition = textPos - block.position();
144 QTextLine line = block.layout()->lineForTextPosition(blockRelativePosition);
145 if (!currentLine().isValid()
146 || line.lineNumber() != currentLine().lineNumber()) {
148 }
149
150 Q_ASSERT(line.textLength() > 0);
151 int lineEnd = line.textStart() + block.position() + line.textLength();
152
153 int len = qMin(lineEnd - textPos, fragmentEnd - textPos);
154 Q_ASSERT(len > 0);
155
156 int currentStepEnd = textPos + len;
157
158 addGlyphsForRanges(colorChanges,
159 textPos - block.position(),
160 currentStepEnd - block.position(),
161 selectionStart - block.position(),
162 selectionEnd - block.position());
163
164 textPos = currentStepEnd;
165 }
166 return textPos;
167}
168
169void QQuickTextNodeEngine::addTextDecorations(const QVarLengthArray<TextDecoration> &textDecorations,
170 qreal offset, qreal thickness)
171{
172 for (int i=0; i<textDecorations.size(); ++i) {
173 TextDecoration textDecoration = textDecorations.at(i);
174
175 {
176 QRectF &rect = textDecoration.rect;
177 rect.setY(qRound(rect.y() + m_currentLine.ascent() + offset));
178 rect.setHeight(thickness);
179 }
180
181 m_lines.append(textDecoration);
182 }
183}
184
185void QQuickTextNodeEngine::processCurrentLine()
186{
187 // No glyphs, do nothing
188 if (m_currentLineTree.isEmpty())
189 return;
190
191 // 1. Go through current line and get correct decoration position for each node based on
192 // neighbouring decorations. Add decoration to global list
193 // 2. Create clip nodes for all selected text. Try to merge as many as possible within
194 // the line.
195 // 3. Add QRects to a list of selection rects.
196 // 4. Add all nodes to a global processed list
197 QVarLengthArray<int> sortedIndexes; // Indexes in tree sorted by x position
198 BinaryTreeNode::inOrder(m_currentLineTree, &sortedIndexes);
199
200 Q_ASSERT(sortedIndexes.size() == m_currentLineTree.size());
201
202 SelectionState currentSelectionState = Unselected;
203 QRectF currentRect;
204
205 Decorations currentDecorations = Decoration::NoDecoration;
206 qreal underlineOffset = 0.0;
207 qreal underlineThickness = 0.0;
208
209 qreal overlineOffset = 0.0;
210 qreal overlineThickness = 0.0;
211
212 qreal strikeOutOffset = 0.0;
213 qreal strikeOutThickness = 0.0;
214
215 QRectF decorationRect = currentRect;
216
217 QColor lastColor;
218 QColor lastBackgroundColor;
219 QColor lastDecorationColor;
220
221 QVarLengthArray<TextDecoration> pendingUnderlines;
222 QVarLengthArray<TextDecoration> pendingOverlines;
223 QVarLengthArray<TextDecoration> pendingStrikeOuts;
224 if (!sortedIndexes.isEmpty()) {
225 QQuickDefaultClipNode *currentClipNode = m_hasSelection ? new QQuickDefaultClipNode(QRectF()) : nullptr;
226 bool currentClipNodeUsed = false;
227 for (int i=0; i<=sortedIndexes.size(); ++i) {
228 BinaryTreeNode *node = nullptr;
229 if (i < sortedIndexes.size()) {
230 int sortedIndex = sortedIndexes.at(i);
231 Q_ASSERT(sortedIndex < m_currentLineTree.size());
232
233 node = m_currentLineTree.data() + sortedIndex;
234 if (i == 0)
235 currentSelectionState = node->selectionState;
236 }
237
238 // Update decorations
239 if (currentDecorations != Decoration::NoDecoration) {
240 decorationRect.setY(m_position.y() + m_currentLine.y());
241 decorationRect.setHeight(m_currentLine.height());
242
243 if (node != nullptr)
244 decorationRect.setRight(node->boundingRect.left());
245
246 TextDecoration textDecoration(currentSelectionState, decorationRect, lastColor);
247 if (lastDecorationColor.isValid() &&
248 (currentDecorations.testFlag(Decoration::Underline) ||
249 currentDecorations.testFlag(Decoration::Overline) ||
250 currentDecorations.testFlag(Decoration::StrikeOut)))
251 textDecoration.color = lastDecorationColor;
252
253 if (currentDecorations & Decoration::Underline)
254 pendingUnderlines.append(textDecoration);
255
256 if (currentDecorations & Decoration::Overline)
257 pendingOverlines.append(textDecoration);
258
259 if (currentDecorations & Decoration::StrikeOut)
260 pendingStrikeOuts.append(textDecoration);
261
262 if (currentDecorations & Decoration::Background)
263 m_backgrounds.append(qMakePair(decorationRect, lastBackgroundColor));
264 }
265
266 // If we've reached an unselected node from a selected node, we add the
267 // selection rect to the graph, and we add decoration every time the
268 // selection state changes, because that means the text color changes
269 if (node == nullptr || node->selectionState != currentSelectionState) {
270 currentRect.setY(m_position.y() + m_currentLine.y());
271 currentRect.setHeight(m_currentLine.height());
272
273 if (currentSelectionState == Selected)
274 m_selectionRects.append(currentRect);
275
276 if (currentClipNode != nullptr) {
277 if (!currentClipNodeUsed) {
278 delete currentClipNode;
279 } else {
280 currentClipNode->setIsRectangular(true);
281 currentClipNode->setRect(currentRect);
282 currentClipNode->update();
283 }
284 }
285
286 if (node != nullptr && m_hasSelection)
287 currentClipNode = new QQuickDefaultClipNode(QRectF());
288 else
289 currentClipNode = nullptr;
290 currentClipNodeUsed = false;
291
292 if (node != nullptr) {
293 currentSelectionState = node->selectionState;
294 currentRect = node->boundingRect;
295
296 // Make sure currentRect is valid, otherwise the unite won't work
297 if (currentRect.isNull())
298 currentRect.setSize(QSizeF(1, 1));
299 }
300 } else {
301 if (currentRect.isNull())
302 currentRect = node->boundingRect;
303 else
304 currentRect = currentRect.united(node->boundingRect);
305 }
306
307 if (node != nullptr) {
308 if (node->selectionState == Selected) {
309 node->clipNode = currentClipNode;
310 currentClipNodeUsed = true;
311 }
312
313 decorationRect = node->boundingRect;
314
315 // If previous item(s) had underline and current does not, then we add the
316 // pending lines to the lists and likewise for overlines and strikeouts
317 if (!pendingUnderlines.isEmpty()
318 && !(node->decorations & Decoration::Underline)) {
319 addTextDecorations(pendingUnderlines, underlineOffset, underlineThickness);
320
321 pendingUnderlines.clear();
322
323 underlineOffset = 0.0;
324 underlineThickness = 0.0;
325 }
326
327 // ### Add pending when overlineOffset/thickness changes to minimize number of
328 // nodes
329 if (!pendingOverlines.isEmpty()) {
330 addTextDecorations(pendingOverlines, overlineOffset, overlineThickness);
331
332 pendingOverlines.clear();
333
334 overlineOffset = 0.0;
335 overlineThickness = 0.0;
336 }
337
338 // ### Add pending when overlineOffset/thickness changes to minimize number of
339 // nodes
340 if (!pendingStrikeOuts.isEmpty()) {
341 addTextDecorations(pendingStrikeOuts, strikeOutOffset, strikeOutThickness);
342
343 pendingStrikeOuts.clear();
344
345 strikeOutOffset = 0.0;
346 strikeOutThickness = 0.0;
347 }
348
349 // Merge current values with previous. Prefer greatest thickness
350 QRawFont rawFont = node->glyphRun.rawFont();
351 if (node->decorations & Decoration::Underline) {
352 if (rawFont.lineThickness() > underlineThickness) {
353 underlineThickness = rawFont.lineThickness();
354 underlineOffset = rawFont.underlinePosition();
355 }
356 }
357
358 if (node->decorations & Decoration::Overline) {
359 overlineOffset = -rawFont.ascent();
360 overlineThickness = rawFont.lineThickness();
361 }
362
363 if (node->decorations & Decoration::StrikeOut) {
364 strikeOutThickness = rawFont.lineThickness();
365 strikeOutOffset = rawFont.ascent() / -3.0;
366 }
367
368 currentDecorations = node->decorations;
369 lastColor = node->color;
370 lastBackgroundColor = node->backgroundColor;
371 lastDecorationColor = node->decorationColor;
372 m_processedNodes.append(*node);
373 }
374 }
375
376 if (!pendingUnderlines.isEmpty())
377 addTextDecorations(pendingUnderlines, underlineOffset, underlineThickness);
378
379 if (!pendingOverlines.isEmpty())
380 addTextDecorations(pendingOverlines, overlineOffset, overlineThickness);
381
382 if (!pendingStrikeOuts.isEmpty())
383 addTextDecorations(pendingStrikeOuts, strikeOutOffset, strikeOutThickness);
384 }
385
386 m_currentLineTree.clear();
387 m_currentLine = QTextLine();
388 m_hasSelection = false;
389}
390
392 SelectionState selectionState,
393 QTextFrameFormat::Position layoutPosition)
394{
395 QRectF searchRect = rect;
396 if (layoutPosition == QTextFrameFormat::InFlow) {
397 if (m_currentLineTree.isEmpty()) {
398 qreal y = m_currentLine.ascent() - ascent;
399 if (m_currentTextDirection == Qt::RightToLeft)
400 searchRect.moveTopRight(m_position + m_currentLine.rect().topRight() + QPointF(0, y));
401 else
402 searchRect.moveTopLeft(m_position + m_currentLine.position() + QPointF(0, y));
403 } else {
404 const BinaryTreeNode *lastNode = m_currentLineTree.data() + m_currentLineTree.size() - 1;
405 if (lastNode->glyphRun.isRightToLeft()) {
406 QPointF lastPos = lastNode->boundingRect.topLeft();
407 searchRect.moveTopRight(lastPos - QPointF(0, ascent - lastNode->ascent));
408 } else {
409 QPointF lastPos = lastNode->boundingRect.topRight();
410 searchRect.moveTopLeft(lastPos - QPointF(0, ascent - lastNode->ascent));
411 }
412 }
413 }
414
415 BinaryTreeNode::insert(&m_currentLineTree, searchRect, image, ascent, selectionState);
416 m_hasContents = true;
417}
418
420 SelectionState selectionState,
421 QTextDocument *textDocument, int pos,
422 QTextFrameFormat::Position layoutPosition)
423{
424 QTextObjectInterface *handler = textDocument->documentLayout()->handlerForObject(format.objectType());
425 if (handler != nullptr) {
427 QSizeF size = handler->intrinsicSize(textDocument, pos, format);
428
429 if (format.objectType() == QTextFormat::ImageObject) {
430 QTextImageFormat imageFormat = format.toImageFormat();
431 QTextImageHandler *imageHandler = static_cast<QTextImageHandler *>(handler);
432 image = imageHandler->image(textDocument, imageFormat);
433 }
434
435 if (image.isNull()) {
438 {
440 handler->drawObject(&painter, image.rect(), textDocument, pos, format);
441 }
442 }
443
444 // Use https://developer.mozilla.org/de/docs/Web/CSS/vertical-align as a reference
445 // The top/bottom positions are supposed to be higher/lower than the text and reference
446 // the line height, not the text height (using QFontMetrics)
447 qreal ascent;
448 QTextLine line = block.layout()->lineForTextPosition(pos - block.position());
449 switch (format.verticalAlignment())
450 {
452 ascent = line.ascent();
453 break;
455 // Middlepoint of line (height - descent) + Half object height
456 ascent = (line.ascent() + line.descent()) / 2 - line.descent() + size.height() / 2;
457 break;
459 ascent = size.height() - line.descent();
460 break;
462 default:
463 ascent = size.height();
464 }
465
466 addImage(QRectF(position, size), image, ascent, selectionState, layoutPosition);
467 }
468}
469
471{
472 BinaryTreeNode::insert(&m_currentLineTree,
473 glyphRun,
476 m_textColor,
477 m_backgroundColor,
478 m_decorationColor,
479 m_position);
480}
481
483{
484 int currentSize = m_currentLineTree.size();
485 BinaryTreeNode::insert(&m_currentLineTree,
486 glyphRun,
487 Selected,
489 m_textColor,
490 m_backgroundColor,
491 m_decorationColor,
492 m_position);
493 m_hasSelection = m_hasSelection || m_currentLineTree.size() > currentSize;
494}
495
496void QQuickTextNodeEngine::addGlyphsForRanges(const QVarLengthArray<QTextLayout::FormatRange> &ranges,
497 int start, int end,
498 int selectionStart, int selectionEnd)
499{
500 int currentPosition = start;
501 int remainingLength = end - start;
502 for (int j=0; j<ranges.size(); ++j) {
503 const QTextLayout::FormatRange &range = ranges.at(j);
504 if (range.start + range.length > currentPosition
505 && range.start < currentPosition + remainingLength) {
506
507 if (range.start > currentPosition) {
508 addGlyphsInRange(currentPosition, range.start - currentPosition,
509 QColor(), QColor(), QColor(), selectionStart, selectionEnd);
510 }
511 int rangeEnd = qMin(range.start + range.length, currentPosition + remainingLength);
512 QColor rangeColor;
513 if (range.format.hasProperty(QTextFormat::ForegroundBrush))
514 rangeColor = range.format.foreground().color();
515 else if (range.format.isAnchor())
516 rangeColor = m_anchorColor;
517 QColor rangeBackgroundColor = range.format.hasProperty(QTextFormat::BackgroundBrush)
518 ? range.format.background().color()
519 : QColor();
520
521 QColor rangeDecorationColor = range.format.hasProperty(QTextFormat::TextUnderlineColor)
522 ? range.format.underlineColor()
523 : QColor();
524
525 addGlyphsInRange(range.start, rangeEnd - range.start,
526 rangeColor, rangeBackgroundColor, rangeDecorationColor,
527 selectionStart, selectionEnd);
528
529 currentPosition = range.start + range.length;
530 remainingLength = end - currentPosition;
531
532 } else if (range.start > currentPosition + remainingLength || remainingLength <= 0) {
533 break;
534 }
535 }
536
537 if (remainingLength > 0) {
538 addGlyphsInRange(currentPosition, remainingLength, QColor(), QColor(), QColor(),
539 selectionStart, selectionEnd);
540 }
541
542}
543
544void QQuickTextNodeEngine::addGlyphsInRange(int rangeStart, int rangeLength,
545 const QColor &color, const QColor &backgroundColor, const QColor &decorationColor,
546 int selectionStart, int selectionEnd)
547{
548 QColor oldColor;
549 if (color.isValid()) {
550 oldColor = m_textColor;
551 m_textColor = color;
552 }
553
554 QColor oldBackgroundColor = m_backgroundColor;
555 if (backgroundColor.isValid()) {
556 oldBackgroundColor = m_backgroundColor;
557 m_backgroundColor = backgroundColor;
558 }
559
560 QColor oldDecorationColor = m_decorationColor;
561 if (decorationColor.isValid()) {
562 oldDecorationColor = m_decorationColor;
563 m_decorationColor = decorationColor;
564 }
565
566 bool hasSelection = selectionEnd >= 0
567 && selectionStart <= selectionEnd;
568
569 QTextLine &line = m_currentLine;
570 int rangeEnd = rangeStart + rangeLength;
571 if (!hasSelection || (selectionStart > rangeEnd || selectionEnd < rangeStart)) {
572 QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart, rangeLength);
573 for (int j=0; j<glyphRuns.size(); ++j) {
574 const QGlyphRun &glyphRun = glyphRuns.at(j);
575 addUnselectedGlyphs(glyphRun);
576 }
577 } else {
578 if (rangeStart < selectionStart) {
579 int length = qMin(selectionStart - rangeStart, rangeLength);
580 QList<QGlyphRun> glyphRuns = line.glyphRuns(rangeStart, length);
581 for (int j=0; j<glyphRuns.size(); ++j) {
582 const QGlyphRun &glyphRun = glyphRuns.at(j);
583 addUnselectedGlyphs(glyphRun);
584 }
585 }
586
587 if (rangeEnd > selectionStart) {
588 int start = qMax(selectionStart, rangeStart);
589 int length = qMin(selectionEnd - start + 1, rangeEnd - start);
590 QList<QGlyphRun> glyphRuns = line.glyphRuns(start, length);
591
592 for (int j=0; j<glyphRuns.size(); ++j) {
593 const QGlyphRun &glyphRun = glyphRuns.at(j);
594 addSelectedGlyphs(glyphRun);
595 }
596 }
597
598 if (selectionEnd >= rangeStart && selectionEnd < rangeEnd) {
599 int start = selectionEnd + 1;
600 int length = rangeEnd - selectionEnd - 1;
601 QList<QGlyphRun> glyphRuns = line.glyphRuns(start, length);
602 for (int j=0; j<glyphRuns.size(); ++j) {
603 const QGlyphRun &glyphRun = glyphRuns.at(j);
604 addUnselectedGlyphs(glyphRun);
605 }
606 }
607 }
608
609 if (decorationColor.isValid())
610 m_decorationColor = oldDecorationColor;
611
612 if (backgroundColor.isValid())
613 m_backgroundColor = oldBackgroundColor;
614
615 if (oldColor.isValid())
616 m_textColor = oldColor;
617}
618
621 const QBrush &borderBrush)
622{
623 const QColor &color = borderBrush.color();
624
625 // Currently we don't support other styles than solid
626 Q_UNUSED(borderStyle);
627
628 m_backgrounds.append(qMakePair(QRectF(rect.left(), rect.top(), border, rect.height() + border), color));
629 m_backgrounds.append(qMakePair(QRectF(rect.left() + border, rect.top(), rect.width(), border), color));
630 m_backgrounds.append(qMakePair(QRectF(rect.right(), rect.top() + border, border, rect.height() - border), color));
631 m_backgrounds.append(qMakePair(QRectF(rect.left() + border, rect.bottom(), rect.width(), border), color));
632}
633
635{
636 QTextDocumentLayout *documentLayout = qobject_cast<QTextDocumentLayout *>(document->documentLayout());
637 if (Q_UNLIKELY(!documentLayout))
638 return;
639
640 QTextFrameFormat frameFormat = frame->format().toFrameFormat();
641 QTextTable *table = qobject_cast<QTextTable *>(frame);
642
643 QRectF boundingRect = table == nullptr
644 ? documentLayout->frameBoundingRect(frame)
645 : documentLayout->tableBoundingRect(table);
646
647 QBrush bg = frame->frameFormat().background();
648 if (bg.style() != Qt::NoBrush)
649 m_backgrounds.append(qMakePair(boundingRect, bg.color()));
650
651 if (!frameFormat.hasProperty(QTextFormat::FrameBorder))
652 return;
653
654 qreal borderWidth = frameFormat.border();
655 if (qFuzzyIsNull(borderWidth))
656 return;
657
658 QBrush borderBrush = frameFormat.borderBrush();
659 QTextFrameFormat::BorderStyle borderStyle = frameFormat.borderStyle();
660 if (borderStyle == QTextFrameFormat::BorderStyle_None)
661 return;
662
663 const auto collapsed = table->format().borderCollapse();
664
665 if (!collapsed) {
666 addBorder(boundingRect.adjusted(frameFormat.leftMargin(), frameFormat.topMargin(),
667 -frameFormat.rightMargin() - borderWidth,
668 -frameFormat.bottomMargin() - borderWidth),
669 borderWidth, borderStyle, borderBrush);
670 }
671 if (table != nullptr) {
672 int rows = table->rows();
673 int columns = table->columns();
674
675 for (int row=0; row<rows; ++row) {
676 for (int column=0; column<columns; ++column) {
677 QTextTableCell cell = table->cellAt(row, column);
678
679 QRectF cellRect = documentLayout->tableCellBoundingRect(table, cell);
680 addBorder(cellRect.adjusted(-borderWidth, -borderWidth, collapsed ? -borderWidth : 0, collapsed ? -borderWidth : 0), borderWidth,
681 borderStyle, borderBrush);
682 }
683 }
684 }
685}
686
688{
689 return qHashMulti(seed, key.fontEngine, key.clipNode, key.color, key.selectionState);
690}
691
692void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularNodes,
693 QList<BinaryTreeNode *> *imageNodes)
694{
695 QHash<BinaryTreeNodeKey, QList<BinaryTreeNode *> > map;
696
697 for (int i = 0; i < m_processedNodes.size(); ++i) {
698 BinaryTreeNode *node = m_processedNodes.data() + i;
699
700 if (node->image.isNull()) {
701 if (node->glyphRun.isEmpty())
702 continue;
703
705
706 QList<BinaryTreeNode *> &nodes = map[key];
707 if (nodes.isEmpty())
708 regularNodes->append(node);
709
710 nodes.append(node);
711 } else {
712 imageNodes->append(node);
713 }
714 }
715
716 for (int i = 0; i < regularNodes->size(); ++i) {
717 BinaryTreeNode *primaryNode = regularNodes->at(i);
718 BinaryTreeNodeKey key(primaryNode);
719
720 const QList<BinaryTreeNode *> &nodes = map.value(key);
721 Q_ASSERT(nodes.first() == primaryNode);
722
723 int count = 0;
724 for (int j = 0; j < nodes.size(); ++j)
725 count += nodes.at(j)->glyphRun.glyphIndexes().size();
726
727 if (count != primaryNode->glyphRun.glyphIndexes().size()) {
728 QGlyphRun &glyphRun = primaryNode->glyphRun;
729 QVector<quint32> glyphIndexes = glyphRun.glyphIndexes();
730 glyphIndexes.reserve(count);
731
732 QVector<QPointF> glyphPositions = glyphRun.positions();
733 glyphPositions.reserve(count);
734
735 QRectF glyphBoundingRect = glyphRun.boundingRect();
736
737 for (int j = 1; j < nodes.size(); ++j) {
738 BinaryTreeNode *otherNode = nodes.at(j);
739 glyphIndexes += otherNode->glyphRun.glyphIndexes();
740 primaryNode->ranges += otherNode->ranges;
741 glyphBoundingRect = glyphBoundingRect.united(otherNode->boundingRect);
742
743 QVector<QPointF> otherPositions = otherNode->glyphRun.positions();
744 for (int k = 0; k < otherPositions.size(); ++k)
745 glyphPositions += otherPositions.at(k) + (otherNode->position - primaryNode->position);
746 }
747
748 Q_ASSERT(glyphPositions.size() == count);
749 Q_ASSERT(glyphIndexes.size() == count);
750
751 glyphRun.setGlyphIndexes(glyphIndexes);
752 glyphRun.setPositions(glyphPositions);
753 glyphRun.setBoundingRect(glyphBoundingRect);
754 }
755 }
756}
757
760 const QColor &styleColor)
761{
762 if (m_currentLine.isValid())
763 processCurrentLine();
764
765 QList<BinaryTreeNode *> nodes;
766 QList<BinaryTreeNode *> imageNodes;
767 mergeProcessedNodes(&nodes, &imageNodes);
768
769 for (int i = 0; i < m_backgrounds.size(); ++i) {
770 const QRectF &rect = m_backgrounds.at(i).first;
771 const QColor &color = m_backgrounds.at(i).second;
772 if (color.alpha() != 0)
773 parentNode->addRectangleNode(rect, color);
774 }
775
776 // Add all text with unselected color first
777 for (int i = 0; i < nodes.size(); ++i) {
778 const BinaryTreeNode *node = nodes.at(i);
779 parentNode->addGlyphs(node->position, node->glyphRun, node->color, style, styleColor, nullptr);
780 }
781
782 for (int i = 0; i < imageNodes.size(); ++i) {
783 const BinaryTreeNode *node = imageNodes.at(i);
784 if (node->selectionState == Unselected)
785 parentNode->addImage(node->boundingRect, node->image);
786 }
787
788 // Then, prepend all selection rectangles to the tree
789 for (int i = 0; i < m_selectionRects.size(); ++i) {
790 const QRectF &rect = m_selectionRects.at(i);
791 if (m_selectionColor.alpha() != 0)
792 parentNode->addRectangleNode(rect, m_selectionColor);
793 }
794
795 // Add decorations for each node to the tree.
796 for (int i = 0; i < m_lines.size(); ++i) {
797 const TextDecoration &textDecoration = m_lines.at(i);
798
799 QColor color = textDecoration.selectionState == Selected
800 ? m_selectedTextColor
801 : textDecoration.color;
802
803 parentNode->addDecorationNode(textDecoration.rect, color);
804 }
805
806 // Finally add the selected text on top of everything
807 for (int i = 0; i < nodes.size(); ++i) {
808 const BinaryTreeNode *node = nodes.at(i);
809 QQuickDefaultClipNode *clipNode = node->clipNode;
810 if (clipNode != nullptr && clipNode->parent() == nullptr)
811 parentNode->appendChildNode(clipNode);
812
813 if (node->selectionState == Selected) {
814 QColor color = m_selectedTextColor;
815 int previousNodeIndex = i - 1;
816 int nextNodeIndex = i + 1;
817 const BinaryTreeNode *previousNode = previousNodeIndex < 0 ? 0 : nodes.at(previousNodeIndex);
818 while (previousNode != nullptr && qFuzzyCompare(previousNode->boundingRect.left(), node->boundingRect.left()))
819 previousNode = --previousNodeIndex < 0 ? 0 : nodes.at(previousNodeIndex);
820
821 const BinaryTreeNode *nextNode = nextNodeIndex == nodes.size() ? 0 : nodes.at(nextNodeIndex);
822
823 if (previousNode != nullptr && previousNode->selectionState == Unselected)
824 parentNode->addGlyphs(previousNode->position, previousNode->glyphRun, color, style, styleColor, clipNode);
825
826 if (nextNode != nullptr && nextNode->selectionState == Unselected)
827 parentNode->addGlyphs(nextNode->position, nextNode->glyphRun, color, style, styleColor, clipNode);
828
829 // If the previous or next node completely overlaps this one, then we have already drawn the glyphs of
830 // this node
831 bool drawCurrent = false;
832 if (previousNode != nullptr || nextNode != nullptr) {
833 for (int i = 0; i < node->ranges.size(); ++i) {
834 const QPair<int, int> &range = node->ranges.at(i);
835
836 int rangeLength = range.second - range.first + 1;
837 if (previousNode != nullptr) {
838 for (int j = 0; j < previousNode->ranges.size(); ++j) {
839 const QPair<int, int> &otherRange = previousNode->ranges.at(j);
840
841 if (range.first < otherRange.second && range.second > otherRange.first) {
842 int start = qMax(range.first, otherRange.first);
843 int end = qMin(range.second, otherRange.second);
844 rangeLength -= end - start + 1;
845 if (rangeLength == 0)
846 break;
847 }
848 }
849 }
850
851 if (nextNode != nullptr && rangeLength > 0) {
852 for (int j = 0; j < nextNode->ranges.size(); ++j) {
853 const QPair<int, int> &otherRange = nextNode->ranges.at(j);
854
855 if (range.first < otherRange.second && range.second > otherRange.first) {
856 int start = qMax(range.first, otherRange.first);
857 int end = qMin(range.second, otherRange.second);
858 rangeLength -= end - start + 1;
859 if (rangeLength == 0)
860 break;
861 }
862 }
863 }
864
865 if (rangeLength > 0) {
866 drawCurrent = true;
867 break;
868 }
869 }
870 } else {
871 drawCurrent = true;
872 }
873
874 if (drawCurrent)
875 parentNode->addGlyphs(node->position, node->glyphRun, color, style, styleColor, clipNode);
876 }
877 }
878
879 for (int i = 0; i < imageNodes.size(); ++i) {
880 const BinaryTreeNode *node = imageNodes.at(i);
881 if (node->selectionState == Selected) {
882 parentNode->addImage(node->boundingRect, node->image);
883 if (node->selectionState == Selected) {
884 QColor color = m_selectionColor;
885 color.setAlpha(128);
886 parentNode->addRectangleNode(node->boundingRect, color);
887 }
888 }
889 }
890}
891
892void QQuickTextNodeEngine::mergeFormats(QTextLayout *textLayout, QVarLengthArray<QTextLayout::FormatRange> *mergedFormats)
893{
894 Q_ASSERT(mergedFormats != nullptr);
895 if (textLayout == nullptr)
896 return;
897
898 QVector<QTextLayout::FormatRange> additionalFormats = textLayout->formats();
899 for (int i=0; i<additionalFormats.size(); ++i) {
900 QTextLayout::FormatRange additionalFormat = additionalFormats.at(i);
901 if (additionalFormat.format.hasProperty(QTextFormat::ForegroundBrush)
902 || additionalFormat.format.hasProperty(QTextFormat::BackgroundBrush)
903 || additionalFormat.format.isAnchor()) {
904 // Merge overlapping formats
905 if (!mergedFormats->isEmpty()) {
906 QTextLayout::FormatRange *lastFormat = mergedFormats->data() + mergedFormats->size() - 1;
907
908 if (additionalFormat.start < lastFormat->start + lastFormat->length) {
909 QTextLayout::FormatRange *mergedRange = nullptr;
910
911 int length = additionalFormat.length;
912 if (additionalFormat.start > lastFormat->start) {
913 lastFormat->length = additionalFormat.start - lastFormat->start;
914 length -= lastFormat->length;
915
916 mergedFormats->append(QTextLayout::FormatRange());
917 mergedRange = mergedFormats->data() + mergedFormats->size() - 1;
918 lastFormat = mergedFormats->data() + mergedFormats->size() - 2;
919 } else {
920 mergedRange = lastFormat;
921 }
922
923 mergedRange->format = lastFormat->format;
924 mergedRange->format.merge(additionalFormat.format);
925 mergedRange->start = additionalFormat.start;
926
927 int end = qMin(additionalFormat.start + additionalFormat.length,
928 lastFormat->start + lastFormat->length);
929
930 mergedRange->length = end - mergedRange->start;
931 length -= mergedRange->length;
932
933 additionalFormat.start = end;
934 additionalFormat.length = length;
935 }
936 }
937
938 if (additionalFormat.length > 0)
939 mergedFormats->append(additionalFormat);
940 }
941 }
942
943}
944
955 const QColor &textColor, const QColor &anchorColor, int selectionStart, int selectionEnd, const QRectF &viewport)
956{
957 Q_ASSERT(textDocument);
958#if QT_CONFIG(im)
959 int preeditLength = block.isValid() ? block.layout()->preeditAreaText().size() : 0;
960 int preeditPosition = block.isValid() ? block.layout()->preeditAreaPosition() : -1;
961#endif
962
964
965 QVarLengthArray<QTextLayout::FormatRange> colorChanges;
966 mergeFormats(block.layout(), &colorChanges);
967
968 const QTextCharFormat charFormat = block.charFormat();
969 const QRectF blockBoundingRect = textDocument->documentLayout()->blockBoundingRect(block).translated(position);
970 if (viewport.isValid()) {
971 if (!blockBoundingRect.intersects(viewport))
972 return;
973 qCDebug(lcSgText) << "adding block with length" << block.length() << ':' << blockBoundingRect << "in viewport" << viewport;
974 }
975
976 if (charFormat.background().style() != Qt::NoBrush)
977 m_backgrounds.append(qMakePair(blockBoundingRect, charFormat.background().color()));
978
979 if (QTextList *textList = block.textList()) {
980 QPointF pos = blockBoundingRect.topLeft();
981 QTextLayout *layout = block.layout();
982 if (layout->lineCount() > 0) {
983 QTextLine firstLine = layout->lineAt(0);
984 Q_ASSERT(firstLine.isValid());
985
986 setCurrentLine(firstLine);
987
988 QRectF textRect = firstLine.naturalTextRect();
989 pos += textRect.topLeft();
990 if (block.textDirection() == Qt::RightToLeft)
991 pos.rx() += textRect.width();
992
993 QFont font(charFormat.font());
995 QTextListFormat listFormat = textList->format();
996
997 QString listItemBullet;
998 switch (listFormat.style()) {
1000 listItemBullet = QChar(0x25E6); // White bullet
1001 break;
1003 listItemBullet = QChar(0x25AA); // Black small square
1004 break;
1010 listItemBullet = textList->itemText(block);
1011 break;
1012 default:
1013 listItemBullet = QChar(0x2022); // Black bullet
1014 break;
1015 };
1016
1017 switch (block.blockFormat().marker()) {
1019 listItemBullet = QChar(0x2612); // Checked checkbox
1020 break;
1022 listItemBullet = QChar(0x2610); // Unchecked checkbox
1023 break;
1025 break;
1026 }
1027
1028 QSizeF size(fontMetrics.horizontalAdvance(listItemBullet), fontMetrics.height());
1029 qreal xoff = fontMetrics.horizontalAdvance(QLatin1Char(' '));
1030 if (block.textDirection() == Qt::LeftToRight)
1031 xoff = -xoff - size.width();
1032 setPosition(pos + QPointF(xoff, 0));
1033
1035 layout.setFont(font);
1036 layout.setText(listItemBullet); // Bullet
1037 layout.beginLayout();
1038 QTextLine line = layout.createLine();
1039 line.setPosition(QPointF(0, 0));
1040 layout.endLayout();
1041
1042 // set the color for the bullets, instead of using the previous QTextBlock's color.
1043 if (charFormat.foreground().style() == Qt::NoBrush)
1044 setTextColor(textColor);
1045 else
1046 setTextColor(charFormat.foreground().color());
1047
1048 QList<QGlyphRun> glyphRuns = layout.glyphRuns();
1049 for (int i=0; i<glyphRuns.size(); ++i)
1050 addUnselectedGlyphs(glyphRuns.at(i));
1051 }
1052 }
1053
1054 int textPos = block.position();
1055 QTextBlock::iterator blockIterator = block.begin();
1056
1057 while (!blockIterator.atEnd()) {
1058 QTextFragment fragment = blockIterator.fragment();
1059 QString text = fragment.text();
1060 if (text.isEmpty())
1061 continue;
1062
1063 QTextCharFormat charFormat = fragment.charFormat();
1064 QFont font(charFormat.font());
1066
1067 int fontHeight = fontMetrics.descent() + fontMetrics.ascent();
1068 int valign = charFormat.verticalAlignment();
1070 setPosition(QPointF(blockBoundingRect.x(), blockBoundingRect.y() - fontHeight / 2));
1071 else if (valign == QTextCharFormat::AlignSubScript)
1072 setPosition(QPointF(blockBoundingRect.x(), blockBoundingRect.y() + fontHeight / 6));
1073 else
1074 setPosition(blockBoundingRect.topLeft());
1075
1076 if (text.contains(QChar::ObjectReplacementCharacter) && charFormat.objectType() != QTextFormat::NoObject) {
1077 QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat));
1078 if (!frame || frame->frameFormat().position() == QTextFrameFormat::InFlow) {
1079 int blockRelativePosition = textPos - block.position();
1080 QTextLine line = block.layout()->lineForTextPosition(blockRelativePosition);
1081 if (!currentLine().isValid()
1082 || line.lineNumber() != currentLine().lineNumber()) {
1084 }
1085
1087 (selectionStart < textPos + text.size()
1088 && selectionEnd >= textPos)
1091
1092 addTextObject(block, QPointF(), charFormat, selectionState, textDocument, textPos);
1093 }
1094 textPos += text.size();
1095 } else {
1096 if (charFormat.foreground().style() != Qt::NoBrush)
1097 setTextColor(charFormat.foreground().color());
1098 else if (charFormat.isAnchor())
1099 setTextColor(anchorColor);
1100 else
1101 setTextColor(textColor);
1102
1103 int fragmentEnd = textPos + fragment.length();
1104#if QT_CONFIG(im)
1105 if (preeditPosition >= 0
1106 && (preeditPosition + block.position()) >= textPos
1107 && (preeditPosition + block.position()) <= fragmentEnd) {
1108 fragmentEnd += preeditLength;
1109 }
1110#endif
1111 if (charFormat.background().style() != Qt::NoBrush || charFormat.hasProperty(QTextFormat::TextUnderlineColor)) {
1112 QTextLayout::FormatRange additionalFormat;
1113 additionalFormat.start = textPos - block.position();
1114 additionalFormat.length = fragmentEnd - textPos;
1115 additionalFormat.format = charFormat;
1116 colorChanges << additionalFormat;
1117 }
1118
1119 textPos = addText(block, charFormat, textColor, colorChanges, textPos, fragmentEnd,
1120 selectionStart, selectionEnd);
1121 }
1122
1123 ++blockIterator;
1124 }
1125
1126#if QT_CONFIG(im)
1127 if (preeditLength >= 0 && textPos <= block.position() + preeditPosition) {
1128 setPosition(blockBoundingRect.topLeft());
1129 textPos = block.position() + preeditPosition;
1130 QTextLine line = block.layout()->lineForTextPosition(preeditPosition);
1131 if (!currentLine().isValid()
1132 || line.lineNumber() != currentLine().lineNumber()) {
1134 }
1135 textPos = addText(block, block.charFormat(), textColor, colorChanges,
1136 textPos, textPos + preeditLength,
1137 selectionStart, selectionEnd);
1138 }
1139#endif
1140
1141 // Add block decorations (so far only horizontal rules)
1143 auto ruleLength = qvariant_cast<QTextLength>(block.blockFormat().property(QTextFormat::BlockTrailingHorizontalRulerWidth));
1144 QRectF ruleRect(0, 0, ruleLength.value(blockBoundingRect.width()), 1);
1145 ruleRect.moveCenter(blockBoundingRect.center());
1147 ? qvariant_cast<QBrush>(block.blockFormat().property(QTextFormat::BackgroundBrush)).color()
1148 : m_textColor;
1149 m_lines.append(TextDecoration(QQuickTextNodeEngine::Unselected, ruleRect, ruleColor));
1150 }
1151
1152 setCurrentLine(QTextLine()); // Reset current line because the text layout changed
1153 m_hasContents = true;
1154}
1155
1156
1158
virtual QRectF blockBoundingRect(const QTextBlock &block) const =0
Returns the bounding rectangle of block.
QTextObjectInterface * handlerForObject(int objectType) const
Returns a handler for objects of the given objectType.
\inmodule QtGui
Definition qbrush.h:30
const QColor & color() const
Returns the brush color.
Definition qbrush.h:121
Qt::BrushStyle style() const
Returns the brush style.
Definition qbrush.h:120
\inmodule QtCore
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
int alpha() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1466
void setAlpha(int alpha)
Sets the alpha of this color to alpha.
Definition qcolor.cpp:1481
bool isValid() const noexcept
Returns true if the color is valid; otherwise returns false.
Definition qcolor.h:285
\reentrant \inmodule QtGui
\reentrant
Definition qfont.h:22
static QGlyphRunPrivate * get(const QGlyphRun &glyphRun)
Definition qglyphrun_p.h:78
The QGlyphRun class provides direct access to the internal glyphs in a font.
Definition qglyphrun.h:20
bool overline() const
Returns true if this QGlyphRun should be painted with an overline decoration.
bool strikeOut() const
Returns true if this QGlyphRun should be painted with a strike out decoration.
void setPositions(const QList< QPointF > &positions)
Sets the positions of the edge of the baseline for each glyph in this set of glyph indexes to positio...
QList< quint32 > glyphIndexes() const
Returns the glyph indexes for this QGlyphRun object.
void setBoundingRect(const QRectF &boundingRect)
Sets the bounding rect of the glyphs in this QGlyphRun to be boundingRect.
QRawFont rawFont() const
Returns the font selected for this QGlyphRun object.
void setGlyphIndexes(const QList< quint32 > &glyphIndexes)
Set the glyph indexes for this QGlyphRun object to glyphIndexes.
bool isEmpty() const
Returns true if the QGlyphRun does not contain any glyphs.
QRectF boundingRect() const
Returns the smallest rectangle that contains all glyphs in this QGlyphRun.
QList< QPointF > positions() const
Returns the position of the edge of the baseline for each glyph in this set of glyph indexes.
bool underline() const
Returns true if this QGlyphRun should be painted with an underline decoration.
\inmodule QtGui
Definition qimage.h:37
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition qimage.cpp:1222
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void append(parameter_type t)
Definition qlist.h:458
T value(const Key &key, const T &defaultValue=T()) const
Definition qmap.h:357
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
void addSelectedGlyphs(const QGlyphRun &glyphRun)
void addUnselectedGlyphs(const QGlyphRun &glyphRun)
void addTextObject(const QTextBlock &block, const QPointF &position, const QTextCharFormat &format, SelectionState selectionState, QTextDocument *textDocument, int pos, QTextFrameFormat::Position layoutPosition=QTextFrameFormat::InFlow)
void mergeProcessedNodes(QList< BinaryTreeNode * > *regularNodes, QList< BinaryTreeNode * > *imageNodes)
void addTextBlock(QTextDocument *, const QTextBlock &, const QPointF &position, const QColor &textColor, const QColor &anchorColor, int selectionStart, int selectionEnd, const QRectF &viewport=QRectF())
void addGlyphsInRange(int rangeStart, int rangeEnd, const QColor &color, const QColor &backgroundColor, const QColor &underlineColor, int selectionStart, int selectionEnd)
void setTextColor(const QColor &textColor)
void setCurrentLine(const QTextLine &currentLine)
int addText(const QTextBlock &block, const QTextCharFormat &charFormat, const QColor &textColor, const QVarLengthArray< QTextLayout::FormatRange > &colorChanges, int textPos, int fragmentEnd, int selectionStart, int selectionEnd)
void addImage(const QRectF &rect, const QImage &image, qreal ascent, SelectionState selectionState, QTextFrameFormat::Position layoutPosition)
void addBorder(const QRectF &rect, qreal border, QTextFrameFormat::BorderStyle borderStyle, const QBrush &borderBrush)
void addFrameDecorations(QTextDocument *document, QTextFrame *frame)
void setCurrentTextDirection(Qt::LayoutDirection textDirection)
void addGlyphsForRanges(const QVarLengthArray< QTextLayout::FormatRange > &ranges, int start, int end, int selectionStart, int selectionEnd)
void addToSceneGraph(QSGInternalTextNode *parent, QQuickText::TextStyle style=QQuickText::Normal, const QColor &styleColor=QColor())
The QRawFont class provides access to a single physical instance of a font.
Definition qrawfont.h:24
qreal ascent() const
Returns the ascent of this QRawFont in pixel units.
Definition qrawfont.cpp:314
qreal underlinePosition() const
Returns the position from baseline for drawing underlines below the text rendered with this font.
Definition qrawfont.cpp:433
qreal lineThickness() const
Returns the thickness for drawing lines (underline, overline, etc.) along with text drawn in this fon...
Definition qrawfont.cpp:424
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:672
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr qreal x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:669
constexpr void setY(qreal pos) noexcept
Sets the top edge of the rectangle to the given finite y coordinate.
Definition qrect.h:509
constexpr QRectF adjusted(qreal x1, qreal y1, qreal x2, qreal y2) const noexcept
Returns a new rectangle with dx1, dy1, dx2 and dy2 added respectively to the existing coordinates of ...
Definition qrect.h:813
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:497
bool intersects(const QRectF &r) const noexcept
Returns true if this rectangle intersects with the given rectangle (i.e.
Definition qrect.cpp:2271
constexpr QPointF topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:511
constexpr QPointF center() const noexcept
Returns the center point of the rectangle.
Definition qrect.h:699
constexpr void translate(qreal dx, qreal dy) noexcept
Moves the rectangle dx along the x-axis and dy along the y-axis, relative to the current position.
Definition qrect.h:738
constexpr QPointF topRight() const noexcept
Returns the position of the rectangle's top-right corner.
Definition qrect.h:513
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
void addImage(const QRectF &rect, const QImage &image)
virtual void addDecorationNode(const QRectF &rect, const QColor &color)
QSGGlyphNode * addGlyphs(const QPointF &position, const QGlyphRun &glyphs, const QColor &color, QQuickText::TextStyle style=QQuickText::Normal, const QColor &styleColor=QColor(), QSGNode *parentNode=0)
void addRectangleNode(const QRectF &rect, const QColor &color)
void appendChildNode(QSGNode *node)
Appends node to this node's list of children.
Definition qsgnode.cpp:398
QSGNode * parent() const
Returns the parent node of this node.
Definition qsgnode.h:93
\inmodule QtCore
Definition qsize.h:208
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
bool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.h:1369
MarkerType marker() const
\reentrant
iterator begin() const
Returns a text block iterator pointing to the beginning of the text block.
int length() const
Returns the length of the block in characters.
QTextBlockFormat blockFormat() const
Returns the QTextBlockFormat that describes block-specific properties.
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QTextLayout * layout() const
Returns the QTextLayout that is used to lay out and display the block's contents.
int position() const
Returns the index of the block's first character within the document.
Qt::LayoutDirection textDirection() const
QTextCharFormat charFormat() const
Returns the QTextCharFormat that describes the block's character format.
QTextList * textList() const
If the block represents a list item, returns the list that the item belongs to; otherwise returns \nu...
bool isAnchor() const
Returns true if the text is formatted as an anchor; otherwise returns false.
VerticalAlignment verticalAlignment() const
Returns the vertical alignment used for characters with this format.
QFont font() const
Returns the font for this character format.
QRectF tableCellBoundingRect(QTextTable *table, const QTextTableCell &cell) const
virtual QRectF frameBoundingRect(QTextFrame *frame) const override
Returns the bounding rectangle of frame.
QRectF tableBoundingRect(QTextTable *table) const
\reentrant \inmodule QtGui
QAbstractTextDocumentLayout * documentLayout() const
Returns the document layout for this document.
QTextObject * objectForFormat(const QTextFormat &) const
Returns the text object associated with the format f.
QBrush background() const
Returns the brush used to paint the document's background.
@ BlockTrailingHorizontalRulerWidth
QTextImageFormat toImageFormat() const
Returns this format as an image format.
bool hasProperty(int propertyId) const
Returns true if the text format has a property with the given propertyId; otherwise returns false.
int objectType() const
Returns the text format's object type.
QVariant property(int propertyId) const
Returns the property specified by the given propertyId.
QBrush foreground() const
Returns the brush used to render foreground details, such as text, frame outlines,...
\reentrant
QString text() const
Returns the text fragment's as plain text.
QTextCharFormat charFormat() const
Returns the text fragment's character format.
int length() const
Returns the number of characters in the text fragment.
QBrush borderBrush() const
qreal leftMargin() const
qreal border() const
Returns the width of the border in pixels.
BorderStyle borderStyle() const
qreal bottomMargin() const
Position
This enum describes how a frame is located relative to the surrounding text.
qreal rightMargin() const
qreal topMargin() const
\reentrant
Definition qtextobject.h:81
QImage image(QTextDocument *doc, const QTextImageFormat &imageFormat)
\reentrant
Definition qtextlayout.h:70
QTextLine lineForTextPosition(int pos) const
Returns the line that contains the cursor position specified by pos.
QList< FormatRange > formats() const
int preeditAreaPosition() const
Returns the position of the area in the text layout that will be processed before editing occurs.
QString preeditAreaText() const
Returns the text that is inserted in the layout before editing occurs.
\reentrant
QRectF rect() const
Returns the line's bounding rectangle.
qreal height() const
Returns the line's height.
qreal y() const
Returns the line's y position.
bool isValid() const
Returns true if this text line is valid; otherwise returns false.
qreal ascent() const
Returns the line's ascent.
QPointF position() const
Returns the line's position relative to the text layout's position.
Style style() const
Returns the list format's style.
\reentrant
Definition qtextlist.h:18
The QTextObjectInterface class allows drawing of custom text objects in \l{QTextDocument}s.
virtual void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format)=0
Draws this text object using the specified painter.
virtual QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format)=0
The intrinsicSize() function returns the size of the text object represented by format in the given d...
\reentrant
Definition qtexttable.h:19
\reentrant
Definition qtexttable.h:63
QMap< QString, QString > map
[6]
QString text
cache insert(employee->id(), employee)
rect
[4]
fontMetrics
QRect textRect
@ TextDecoration
Combined button and popup list for selecting options.
@ LeftToRight
@ RightToLeft
@ transparent
Definition qnamespace.h:47
@ NoBrush
Definition image.cpp:4
#define Q_UNLIKELY(x)
static QDBusError::ErrorType get(const char *name)
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define forever
Definition qforeach.h:78
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMulti(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
static bool hasSelection()
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
n void setPosition(void) \n\
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLenum GLsizei GLsizei GLsizei GLint border
GLsizei range
GLuint color
[2]
GLuint start
GLenum GLuint GLintptr offset
GLboolean GLboolean g
GLint GLsizei GLsizei GLenum format
GLint y
GLenum GLenum GLsizei void GLsizei void * column
const GLubyte * c
GLenum GLenum GLsizei void * row
GLenum GLsizei len
GLenum GLenum GLsizei void * table
static const QRectF boundingRect(const QPointF *points, int pointCount)
QT_BEGIN_NAMESPACE constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
Definition qpair.h:19
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:187
QObject::connect nullptr
QVBoxLayout * layout
view viewport() -> scroll(dx, dy, deviceRect)
QPainter painter(this)
[7]
QFrame frame
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
static void insert(QVarLengthArray< BinaryTreeNode, 16 > *binaryTree, const QRectF &rect, const QImage &image, qreal ascent, SelectionState selectionState)
static void inOrder(const QVarLengthArray< BinaryTreeNode, 16 > &binaryTree, QVarLengthArray< int > *sortedIndexes, int currentIndex=0)