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