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
qquicktext.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
4#include "qquicktext_p.h"
5#include "qquicktext_p_p.h"
6
7#include <private/qqmldebugserviceinterfaces_p.h>
8#include <private/qqmldebugconnector_p.h>
9
10#include <QtQuick/private/qsgcontext_p.h>
11#include <private/qqmlglobal_p.h>
12#include <private/qsgadaptationlayer_p.h>
14#include "qquicktextutil_p.h"
15
16#include <QtQuick/private/qsgtexture_p.h>
17
18#include <QtQml/qqmlinfo.h>
19#include <QtGui/qevent.h>
20#include <QtGui/qabstracttextdocumentlayout.h>
21#include <QtGui/qpainter.h>
22#include <QtGui/qtextdocument.h>
23#include <QtGui/qtextobject.h>
24#include <QtGui/qtextcursor.h>
25#include <QtGui/qguiapplication.h>
26#include <QtGui/qinputmethod.h>
27
28#include <private/qtextengine_p.h>
29#include <private/qquickstyledtext_p.h>
30#include <QtQuick/private/qquickpixmap_p.h>
31
32#include <qmath.h>
33#include <limits.h>
34
36
37Q_STATIC_LOGGING_CATEGORY(lcText, "qt.quick.text")
38
39using namespace Qt::StringLiterals;
40
41const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
42
43#if !defined(QQUICKTEXT_LARGETEXT_THRESHOLD)
44 #define QQUICKTEXT_LARGETEXT_THRESHOLD 10000
45#endif
46// if QString::size() > largeTextSizeThreshold, we render more often, but only visible lines
48
50 : fontInfo(font), lineWidth(0)
51 , color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
52 , lineCount(1), multilengthEos(-1)
53 , elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
54 , format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap)
55 , style(QQuickText::Normal)
56 , renderType(QQuickTextUtil::textRenderType<QQuickText>())
57 , updateType(UpdatePaintNode)
58 , maximumLineCountValid(false), updateOnComponentComplete(true), richText(false)
59 , styledText(false), widthExceeded(false), heightExceeded(false), internalWidthUpdate(false)
60 , requireImplicitSize(false), implicitWidthValid(false), implicitHeightValid(false)
61 , truncated(false), hAlignImplicit(true), rightToLeftText(false)
62 , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
63 , polishSize(false)
64 , updateSizeRecursionGuard(false)
65{
67}
68
70 : padding(0)
71 , topPadding(0)
72 , leftPadding(0)
73 , rightPadding(0)
74 , bottomPadding(0)
75 , explicitTopPadding(false)
76 , explicitLeftPadding(false)
77 , explicitRightPadding(false)
78 , explicitBottomPadding(false)
79 , lineHeight(1.0)
80 , doc(nullptr)
81 , minimumPixelSize(12)
82 , minimumPointSize(12)
83 , maximumLineCount(INT_MAX)
84 , renderTypeQuality(QQuickText::DefaultRenderTypeQuality)
85 , lineHeightValid(false)
86 , lineHeightMode(QQuickText::ProportionalHeight)
87 , fontSizeMode(QQuickText::FixedSize)
88{
89}
90
92{
93 Q_Q(QQuickText);
94 q->setAcceptedMouseButtons(Qt::LeftButton);
96 q->setFlag(QQuickItem::ItemObservesViewport); // default until size is known
97}
98
106
108{
109 if (!requireImplicitSize) {
110 // We don't calculate implicitWidth unless it is required.
111 // We need to force a size update now to ensure implicitWidth is calculated
112 QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
113 me->requireImplicitSize = true;
114 me->updateSize();
115 }
116 return implicitWidth;
117}
118
120{
121 if (!requireImplicitSize) {
122 QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
123 me->requireImplicitSize = true;
124 me->updateSize();
125 }
126 return implicitHeight;
127}
128
130{
131 Q_Q(const QQuickText);
132 return q->width() - q->leftPadding() - q->rightPadding();
133}
134
136{
137 Q_Q(const QQuickText);
138 return q->height() - q->topPadding() - q->bottomPadding();
139}
140
142{
143 Q_Q(QQuickText);
144 qreal oldPadding = q->topPadding();
145 if (!reset || extra.isAllocated()) {
148 }
149 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
150 updateSize();
151 emit q->topPaddingChanged();
152 }
153}
154
156{
157 Q_Q(QQuickText);
158 qreal oldPadding = q->leftPadding();
159 if (!reset || extra.isAllocated()) {
162 }
163 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
164 updateSize();
165 emit q->leftPaddingChanged();
166 }
167}
168
170{
171 Q_Q(QQuickText);
172 qreal oldPadding = q->rightPadding();
173 if (!reset || extra.isAllocated()) {
176 }
177 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
178 updateSize();
179 emit q->rightPaddingChanged();
180 }
181}
182
184{
185 Q_Q(QQuickText);
186 qreal oldPadding = q->bottomPadding();
187 if (!reset || extra.isAllocated()) {
190 }
191 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
192 updateSize();
193 emit q->bottomPaddingChanged();
194 }
195}
196
206void QQuickText::q_updateLayout()
207{
208 Q_D(QQuickText);
209 d->updateLayout();
210}
211
213{
214 Q_Q(QQuickText);
215 if (!q->isComponentComplete()) {
217 return;
218 }
220 layoutTextElided = false;
221
222 if (extra.isAllocated())
224 needToUpdateLayout = false;
225
226 // Setup instance of QTextLayout for all cases other than richtext
227 if (!richText) {
228 if (textHasChanged) {
229 if (styledText && !text.isEmpty()) {
231 // needs temporary bool because formatModifiesFontSize is in a bit-field
232 bool fontSizeModified = false;
233 QList<QQuickStyledTextImgTag*> someImgTags = extra.isAllocated() ? extra->imgTags : QList<QQuickStyledTextImgTag*>();
234 QQuickStyledText::parse(text, layout, someImgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid, &fontSizeModified);
235 if (someImgTags.size() || extra.isAllocated())
236 extra.value().imgTags = someImgTags;
237 formatModifiesFontSize = fontSizeModified;
238 multilengthEos = -1;
239 } else {
240 QString tmp = text;
241 multilengthEos = tmp.indexOf(QLatin1Char('\x9c'));
242 if (multilengthEos != -1)
243 tmp = tmp.mid(0, multilengthEos);
244 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
245 layout.setText(tmp);
246 }
247 textHasChanged = false;
248 }
249 } else if (extra.isAllocated() && extra->lineHeightValid) {
250 ensureDoc();
253 QTextBlockFormat blockFormat;
255 for (QTextBlock it = extra->doc->begin(); it != extra->doc->end(); it = it.next()) {
257 cursor.mergeBlockFormat(blockFormat);
258 }
259 }
260
261 updateSize();
262
263 if (needToUpdateLayout) {
264 needToUpdateLayout = false;
265 textHasChanged = true;
266 updateLayout();
267 }
268
269 q->polish();
270}
271
277QVariant QQuickText::loadResource(int type, const QUrl &source)
278{
279 Q_D(QQuickText);
280 const QUrl url = d->extra->doc->baseUrl().resolved(source);
281 if (url.isLocalFile()) {
282 // qmlWarning if the file doesn't exist (because QTextDocument::loadResource() can't do that)
284 if (!fi.exists())
285 qmlWarning(this) << "Cannot open: " << url.toString();
286 // let QTextDocument::loadResource() handle local file loading
287 return {};
288 }
289 // see if we already started a load job
290 for (auto it = d->extra->pixmapsInProgress.cbegin(); it != d->extra->pixmapsInProgress.cend();) {
291 auto *job = *it;
292 if (job->url() == url) {
293 if (job->isError()) {
294 qmlWarning(this) << job->error();
295 delete *it;
296 it = d->extra->pixmapsInProgress.erase(it);
297 return QImage();
298 }
299 qCDebug(lcText) << "already downloading" << url;
300 // existing job: return a null variant if it's not done yet
301 return job->isReady() ? job->image() : QVariant();
302 }
303 ++it;
304 }
305 qCDebug(lcText) << "loading" << source << "resolved" << url
306 << "type" << static_cast<QTextDocument::ResourceType>(type);
308 Q_ASSERT(context);
309 // don't cache it in QQuickPixmapCache, because it's cached in QTextDocumentPrivate::cachedResources
310 QQuickPixmap *p = new QQuickPixmap(context->engine(), url, QQuickPixmap::Options{});
311 p->connectFinished(this, SLOT(resourceRequestFinished()));
312 d->extra->pixmapsInProgress.append(p);
313 // the new job is probably not done; return a null variant if the caller should poll again
314 return p->isReady() ? p->image() : QVariant();
315}
316
320void QQuickText::resourceRequestFinished()
321{
322 Q_D(QQuickText);
323 bool allDone = true;
324 for (auto it = d->extra->pixmapsInProgress.cbegin(); it != d->extra->pixmapsInProgress.cend();) {
325 auto *job = *it;
326 if (job->isError()) {
327 // get QTextDocument::loadResource() to call QQuickText::loadResource() again, to return the placeholder
328 qCDebug(lcText) << "failed to load" << job->url();
329 d->extra->doc->resource(QTextDocument::ImageResource, job->url());
330 } else if (job->isReady()) {
331 // get QTextDocument::loadResource() to call QQuickText::loadResource() again, and cache the result
332 auto res = d->extra->doc->resource(QTextDocument::ImageResource, job->url());
333 // If QTextDocument::resource() returned a valid variant, it's been cached too. Either way, the job is done.
334 qCDebug(lcText) << (res.isValid() ? "done downloading" : "failed to load") << job->url();
335 delete *it;
336 it = d->extra->pixmapsInProgress.erase(it);
337 } else {
338 allDone = false;
339 ++it;
340 }
341 }
342 if (allDone) {
343 Q_ASSERT(d->extra->pixmapsInProgress.isEmpty());
344 d->updateLayout();
345 }
346}
347
351void QQuickText::imageDownloadFinished()
352{
353 Q_D(QQuickText);
354 if (!d->extra.isAllocated())
355 return;
356
357 if (std::any_of(d->extra->imgTags.cbegin(), d->extra->imgTags.cend(),
358 [] (auto *image) { return image->pix && image->pix->isLoading(); })) {
359 // return if we still have any active download
360 return;
361 }
362
363 // when all the remote images have been downloaded,
364 // if one of the sizes was not specified at parsing time
365 // we use the implicit size from pixmapcache and re-layout.
366
367 bool needToUpdateLayout = false;
368 for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
369 if (!img->size.isValid()) {
370 img->size = img->pix->implicitSize();
371 needToUpdateLayout = true;
372 }
373 }
374
375 if (needToUpdateLayout) {
376 d->textHasChanged = true;
377 d->updateLayout();
378 } else {
380 update();
381 }
382}
383
385{
386 Q_Q(QQuickText);
387
388 qreal yoff = 0;
389
390 if (q->heightValid()) {
392 yoff = dy;
394 yoff = dy/2;
395 }
396
397 q->setBaselineOffset(baseline + yoff + q->topPadding());
398}
399
401{
402 Q_Q(QQuickText);
403 const QSizeF contentSize(q->contentWidth(), q->contentHeight());
404
405 if (contentSize != previousSize) {
406 emit q->contentSizeChanged();
407 if (contentSize.width() != previousSize.width())
408 emit q->contentWidthChanged(contentSize.width());
409 if (contentSize.height() != previousSize.height())
410 emit q->contentHeightChanged(contentSize.height());
411 }
412}
413
415{
416 Q_Q(QQuickText);
417
418 if (!q->isComponentComplete()) {
420 return;
421 }
422
423 if (!requireImplicitSize) {
426 // if the implicitWidth is used, then updateSize() has already been called (recursively)
428 return;
429 }
430
431 qreal hPadding = q->leftPadding() + q->rightPadding();
432 qreal vPadding = q->topPadding() + q->bottomPadding();
433
434 const QSizeF previousSize(q->contentWidth(), q->contentHeight());
435
437 // How much more expensive is it to just do a full layout on an empty string here?
438 // There may be subtle differences in the height and baseline calculations between
439 // QTextLayout and QFontMetrics and the number of variables that can affect the size
440 // and position of a line is increasing.
442 qreal fontHeight = qCeil(fm.height()); // QScriptLine and therefore QTextLine rounds up
443 if (!richText) { // line height, so we will as well.
445 ? lineHeight()
446 : fontHeight * lineHeight();
447 }
448 updateBaseline(fm.ascent(), q->height() - fontHeight - vPadding);
449 q->setImplicitSize(hPadding, fontHeight + qMax(lineHeightOffset(), 0) + vPadding);
450 layedOutTextRect = QRectF(0, 0, 0, fontHeight);
451 advance = QSizeF();
452 signalSizeChange(previousSize);
453 lineCount = 1;
454 emit q->lineCountChanged();
456 q->update();
457 return;
458 }
459
460 QSizeF size(0, 0);
461
462 //setup instance of QTextLayout for all cases other than richtext
463 if (!richText) {
464 qreal baseline = 0;
466
467 if (internalWidthUpdate) // probably the result of a binding loop, but by letting it
468 return; // get this far we'll get a warning to that effect if it is.
469
471 size = textRect.size();
472 updateBaseline(baseline, q->height() - size.height() - vPadding);
473 } else {
474 widthExceeded = true; // always relayout rich text on width changes..
475 heightExceeded = false; // rich text layout isn't affected by height changes.
476 ensureDoc();
478 QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
479 if (rightToLeftText) {
480 if (horizontalAlignment == QQuickText::AlignLeft)
481 horizontalAlignment = QQuickText::AlignRight;
482 else if (horizontalAlignment == QQuickText::AlignRight)
483 horizontalAlignment = QQuickText::AlignLeft;
484 }
486 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
488 option.setUseDesignMetrics(renderType != QQuickText::NativeRendering);
490 qreal naturalWidth = 0;
491 if (requireImplicitSize && q->widthValid()) {
492 extra->doc->setTextWidth(-1);
493 naturalWidth = extra->doc->idealWidth();
494 const bool wasInLayout = internalWidthUpdate;
495 internalWidthUpdate = true;
496 q->setImplicitWidth(naturalWidth + hPadding);
497 internalWidthUpdate = wasInLayout;
498 }
500 return;
501
502 extra->doc->setPageSize(QSizeF(q->width(), -1));
503 if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < availableWidth()))
505 else
506 extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
507
508 QSizeF dsize = extra->doc->size();
509 layedOutTextRect = QRectF(QPointF(0,0), dsize);
510 size = QSizeF(extra->doc->idealWidth(),dsize.height());
511
512
514 QTextBlock firstBlock = extra->doc->firstBlock();
515 if (firstBlock.isValid() && firstBlock.layout() != nullptr && firstBlock.lineCount() > 0)
516 baseline = firstBlock.layout()->lineAt(0).ascent();
517
518 updateBaseline(baseline, q->height() - size.height() - vPadding);
519
520 //### need to confirm cost of always setting these for richText
521 internalWidthUpdate = true;
522 qreal oldWidth = q->width();
523 qreal iWidth = -1;
524 if (!q->widthValid())
525 iWidth = size.width();
526 if (iWidth > -1)
527 q->setImplicitSize(iWidth + hPadding, size.height() + qMax(lineHeightOffset(), 0) + vPadding);
528 internalWidthUpdate = false;
529
530 // If the implicit width update caused a recursive change of the width,
531 // we will have skipped integral parts of the layout due to the
532 // internalWidthUpdate recursion guard. To make sure everything is up
533 // to date, we need to run a second pass over the layout when updateSize()
534 // is done.
535 if (!qFuzzyCompare(q->width(), oldWidth) && !updateSizeRecursionGuard) {
537 updateSize();
539 } else {
540 if (iWidth == -1)
541 q->setImplicitHeight(size.height() + lineHeightOffset() + vPadding);
542
543 QTextBlock firstBlock = extra->doc->firstBlock();
544 while (firstBlock.layout()->lineCount() == 0)
545 firstBlock = firstBlock.next();
546
547 QTextBlock lastBlock = extra->doc->lastBlock();
548 while (lastBlock.layout()->lineCount() == 0)
549 lastBlock = lastBlock.previous();
550
551 if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
552 QTextLine firstLine = firstBlock.layout()->lineAt(0);
553 QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
554 advance = QSizeF(lastLine.horizontalAdvance(),
555 (lastLine.y() + lastBlock.layout()->position().y() + lastLine.ascent()) - (firstLine.y() + firstBlock.layout()->position().y() + firstLine.ascent()));
556 } else {
557 advance = QSizeF();
558 }
559 }
560 }
561
562 signalSizeChange(previousSize);
564 q->update();
565}
566
568 : QObject(), m_line(nullptr), m_height(0), m_lineOffset(0)
569{
570}
571
573{
574 m_line = line;
575}
576
578{
579 m_lineOffset = offset;
580}
581
583{
584 m_fullLayoutTextLength = length;
585}
586
588{
589 if (m_line)
590 return m_line->lineNumber() + m_lineOffset;
591 return 0;
592}
593
595{
596 if (m_line)
597 return m_line->naturalTextWidth();
598 return 0;
599}
600
602{
603 if (m_line && (m_line->textStart() + m_line->textLength()) == m_fullLayoutTextLength) {
604 // Ensure that isLast will change if the user reduced the width of the line
605 // so that the text no longer fits.
606 return m_line->width() >= m_line->naturalTextWidth();
607 }
608
609 return false;
610}
611
613{
614 if (m_line)
615 return m_line->width();
616 return 0;
617}
618
620{
621 if (m_line)
622 m_line->setLineWidth(width);
623}
624
626{
627 if (m_height)
628 return m_height;
629 if (m_line)
630 return m_line->height();
631 return 0;
632}
633
635{
636 if (m_line)
637 m_line->setPosition(QPointF(m_line->x(), m_line->y() - m_line->height() + height));
638 m_height = height;
639}
640
642{
643 if (m_line)
644 return m_line->x();
645 return 0;
646}
647
649{
650 if (m_line)
651 m_line->setPosition(QPointF(x, m_line->y()));
652}
653
655{
656 if (m_line)
657 return m_line->y();
658 return 0;
659}
660
662{
663 if (m_line)
664 m_line->setPosition(QPointF(m_line->x(), y));
665}
666
672
673void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, int fullLayoutTextLength, int lineOffset)
674{
675 Q_Q(QQuickText);
676
677 if (!textLine)
679 textLine->setFullLayoutTextLength(fullLayoutTextLength);
683 textLine->setLineOffset(lineOffset);
684
685 // use the text item's width by default if it has one and wrap is on or text must be aligned
686 if (q->widthValid() && (q->wrapMode() != QQuickText::NoWrap ||
687 q->effectiveHAlign() != QQuickText::AlignLeft))
689 else
690 textLine->setWidth(INT_MAX);
691 if (lineHeight() != 1.0)
693
694 emit q->lineLaidOut(textLine.get());
695
696 height += textLine->height();
697}
698
700 const int start, const int length, int offset, QVector<QTextLayout::FormatRange> *elidedFormats)
701{
702 const int end = start + length;
703 const QVector<QTextLayout::FormatRange> formats = layout.formats();
704 for (int i = 0; i < formats.size(); ++i) {
706 const int formatLength = qMin(format.start + format.length, end) - qMax(format.start, start);
707 if (formatLength > 0) {
708 format.start = qMax(offset, format.start - start + offset);
709 format.length = formatLength;
710 elidedFormats->append(format);
711 }
712 }
713}
714
715QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, const QTextLine *nextLine) const
716{
717 if (nextLine) {
718 return layout.engine()->elidedText(
721 0,
722 line.textStart(),
723 line.textLength() + nextLine->textLength());
724 } else {
725 QString elideText = layout.text().mid(line.textStart(), line.textLength());
726 if (!styledText) {
727 // QFontMetrics won't help eliding styled text.
728 elideText[elideText.size() - 1] = elideChar;
729 // Appending the elide character may push the line over the maximum width
730 // in which case the elided text will need to be elided.
732 if (metrics.horizontalAdvance(elideChar) + line.naturalTextWidth() >= lineWidth)
733 elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
734 }
735 return elideText;
736 }
737}
738
745
754{
755 Q_Q(QQuickText);
756
757 bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
758 bool multilineElide = elideMode == QQuickText::ElideRight
759 && q->widthValid()
760 && (q->heightValid() || maximumLineCountValid);
761
763 && ((singlelineElide && availableWidth() <= 0.)
764 || (multilineElide && q->heightValid() && availableHeight() <= 0.))) {
765 // we are elided and we have a zero width or height
766 widthExceeded = q->widthValid() && availableWidth() <= 0.;
767 heightExceeded = q->heightValid() && availableHeight() <= 0.;
768
769 if (!truncated) {
770 truncated = true;
771 emit q->truncatedChanged();
772 }
773 if (lineCount) {
774 lineCount = 0;
775 q->setFlag(QQuickItem::ItemObservesViewport, false);
776 emit q->lineCountChanged();
777 }
778
779 if (qFuzzyIsNull(q->width())) {
781 textHasChanged = true;
782 }
783
786 *baseline = fm.ascent();
787 return QRectF(0, 0, 0, height);
788 }
789
790 bool shouldUseDesignMetrics = renderType != QQuickText::NativeRendering;
791 if (extra.isAllocated())
794 QTextOption textOption = layout.textOption();
795 if (textOption.alignment() != q->effectiveHAlign()
796 || textOption.wrapMode() != QTextOption::WrapMode(wrapMode)
797 || textOption.useDesignMetrics() != shouldUseDesignMetrics) {
798 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
800 textOption.setUseDesignMetrics(shouldUseDesignMetrics);
801 layout.setTextOption(textOption);
802 }
803 if (layout.font() != font)
805
806 lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0
807 ? q->width()
808 : FLT_MAX;
809 qreal maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
810
811 const bool customLayout = isLineLaidOutConnected();
812 const bool wasTruncated = truncated;
813
814 bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
815
816 bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
817 bool verticalFit = fontSizeMode() & QQuickText::VerticalFit
818 && (q->heightValid() || (maximumLineCountValid && canWrap));
819
820 const bool pixelSize = font.pixelSize() != -1;
821 QString layoutText = layout.text();
822
823 const qreal minimumSize = pixelSize
824 ? static_cast<qreal>(minimumPixelSize())
826 qreal largeFont = pixelSize ? font.pixelSize() : font.pointSizeF();
828 ? qMin<qreal>(minimumSize, largeFont)
829 : largeFont;
830 qreal scaledFontSize = largeFont;
831 const qreal sizeFittingThreshold(0.01);
832
833 bool widthChanged = false;
834 widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit);
835 heightExceeded = availableHeight() <= 0 && (multilineElide || verticalFit);
836
837 QRectF br;
838
839 QFont scaledFont = font;
840
841 int visibleCount = 0;
842 bool elide;
843 qreal height = 0;
844 QString elideText;
845 bool once = true;
846 int elideStart = 0;
847 int elideEnd = 0;
848 bool noBreakLastLine = multilineElide && (wrapMode == QQuickText::Wrap || wrapMode == QQuickText::WordWrap);
849
850 int eos = multilengthEos;
851
852 // Repeated layouts with reduced font sizes or abbreviated strings may be required if the text
853 // doesn't fit within the item dimensions, or a binding to implicitWidth/Height changes
854 // the item dimensions.
855 for (;;) {
856 if (!once) {
857 if (pixelSize)
858 scaledFont.setPixelSize(scaledFontSize);
859 else
860 scaledFont.setPointSizeF(scaledFontSize);
861 if (layout.font() != scaledFont)
862 layout.setFont(scaledFont);
863 }
864
866
867 bool wrapped = false;
868 bool truncateHeight = false;
869 truncated = false;
870 elide = false;
871 int unwrappedLineCount = 1;
872 const int maxLineCount = maximumLineCount();
873 height = 0;
874 qreal naturalHeight = 0;
875 qreal previousHeight = 0;
876 br = QRectF();
877
878 QRectF unelidedRect;
880 for (visibleCount = 1; ; ++visibleCount) {
882
883 if (noBreakLastLine && visibleCount == maxLineCount)
885 if (customLayout) {
886 setupCustomLineGeometry(line, naturalHeight, layoutText.size());
887 } else {
888 setLineGeometry(line, lineWidth, naturalHeight);
889 }
890 if (noBreakLastLine && visibleCount == maxLineCount)
892
893 unelidedRect = br.united(line.naturalTextRect());
894
895 // Elide the previous line if the accumulated height of the text exceeds the height
896 // of the element.
897 if (multilineElide && naturalHeight > maxHeight && visibleCount > 1) {
898 elide = true;
899 heightExceeded = true;
900 if (eos != -1) // There's an abbreviated string available, skip the rest as it's
901 break; // all going to be discarded.
902
903 truncated = true;
904 truncateHeight = true;
905
906 visibleCount -= 1;
907
908 const QTextLine previousLine = layout.lineAt(visibleCount - 1);
909 elideText = layoutText.at(line.textStart() - 1) != QChar::LineSeparator
910 ? elidedText(line.width(), previousLine, &line)
911 : elidedText(line.width(), previousLine);
912 elideStart = previousLine.textStart();
913 // elideEnd isn't required for right eliding.
914
915 height = previousHeight;
916 break;
917 }
918
919 const bool isLastLine = line.textStart() + line.textLength() >= layoutText.size();
920 if (isLastLine) {
921 if (singlelineElide && visibleCount == 1 && line.naturalTextWidth() > line.width()) {
922 // Elide a single previousLine of text if its width exceeds the element width.
923 elide = true;
924 widthExceeded = true;
925 if (eos != -1) // There's an abbreviated string available.
926 break;
927
928 truncated = true;
929 elideText = layout.engine()->elidedText(
931 QFixed::fromReal(line.width()),
932 0,
933 line.textStart(),
934 line.textLength());
935 elideStart = line.textStart();
936 elideEnd = elideStart + line.textLength();
937 } else {
938 br = unelidedRect;
939 height = naturalHeight;
940 }
941 break;
942 } else {
943 const bool wrappedLine = layoutText.at(line.textStart() + line.textLength() - 1) != QChar::LineSeparator;
944 wrapped |= wrappedLine;
945
946 if (!wrappedLine)
947 ++unwrappedLineCount;
948
949 // Stop if the maximum number of lines has been reached
950 if (visibleCount == maxLineCount) {
951 truncated = true;
952 heightExceeded |= wrapped;
953
954 if (multilineElide) {
955 elide = true;
956 if (eos != -1) // There's an abbreviated string available
957 break;
958
959 const QTextLine nextLine = layout.createLine();
960 elideText = wrappedLine
961 ? elidedText(line.width(), line, &nextLine)
962 : elidedText(line.width(), line);
963 elideStart = line.textStart();
964 // elideEnd isn't required for right eliding.
965 } else {
966 br = unelidedRect;
967 height = naturalHeight;
968 }
969 break;
970 }
971 }
972 br = unelidedRect;
973 previousHeight = height;
974 height = naturalHeight;
975 }
976 widthExceeded |= wrapped;
977
978 // Save the implicit size of the text on the first layout only.
979 if (once) {
980 once = false;
981
982 // If implicit sizes are required layout any additional lines up to the maximum line
983 // count.
984 if ((requireImplicitSize) && line.isValid() && unwrappedLineCount < maxLineCount) {
985 // Layout the remainder of the wrapped lines up to maxLineCount to get the implicit
986 // height.
987 for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
989 if (!line.isValid())
990 break;
991 if (layoutText.at(line.textStart() - 1) == QChar::LineSeparator)
992 ++unwrappedLineCount;
993 setLineGeometry(line, lineWidth, naturalHeight);
994 }
995
996 // Create the remainder of the unwrapped lines up to maxLineCount to get the
997 // implicit width.
998 const int eol = line.isValid()
999 ? line.textStart() + line.textLength()
1000 : layoutText.size();
1001 if (eol < layoutText.size() && layoutText.at(eol) != QChar::LineSeparator)
1003 for (; line.isValid() && unwrappedLineCount <= maxLineCount; ++unwrappedLineCount)
1005 }
1006 layout.endLayout();
1007
1008 const qreal naturalWidth = layout.maximumWidth();
1009
1010 bool wasInLayout = internalWidthUpdate;
1011 internalWidthUpdate = true;
1012 q->setImplicitSize(naturalWidth + q->leftPadding() + q->rightPadding(), naturalHeight + qMax(lineHeightOffset(), 0) + q->topPadding() + q->bottomPadding());
1013 internalWidthUpdate = wasInLayout;
1014
1015 // Update any variables that are dependent on the validity of the width or height.
1016 singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
1017 multilineElide = elideMode == QQuickText::ElideRight
1018 && q->widthValid()
1019 && (q->heightValid() || maximumLineCountValid);
1020 canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
1021
1022 horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
1023 verticalFit = fontSizeMode() & QQuickText::VerticalFit
1024 && (q->heightValid() || (maximumLineCountValid && canWrap));
1025
1026 const qreal oldWidth = lineWidth;
1027 const qreal oldHeight = maxHeight;
1028
1029 const qreal availWidth = availableWidth();
1030 const qreal availHeight = availableHeight();
1031
1032 lineWidth = q->widthValid() && q->width() > 0 ? availWidth : naturalWidth;
1033 maxHeight = q->heightValid() ? availHeight : FLT_MAX;
1034
1035 // If the width of the item has changed and it's possible the result of wrapping,
1036 // eliding, scaling has changed, or the text is not left aligned do another layout.
1037 if ((!qFuzzyCompare(lineWidth, oldWidth) || (widthExceeded && lineWidth > oldWidth))
1038 && (singlelineElide || multilineElide || canWrap || horizontalFit
1039 || q->effectiveHAlign() != QQuickText::AlignLeft)) {
1040 widthChanged = true;
1041 widthExceeded = lineWidth >= qMin(oldWidth, naturalWidth);
1042 heightExceeded = false;
1043 continue;
1044 }
1045
1046 // If the height of the item has changed and it's possible the result of eliding,
1047 // line count truncation or scaling has changed, do another layout.
1048 if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
1049 && (multilineElide || (canWrap && maximumLineCountValid))) {
1050 widthExceeded = false;
1051 heightExceeded = false;
1052 continue;
1053 }
1054
1055 // If the horizontal alignment is not left and the width was not valid we need to relayout
1056 // now that we know the maximum line width.
1057 if (!q->widthValid() && !implicitWidthValid && unwrappedLineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft) {
1058 widthExceeded = false;
1059 heightExceeded = false;
1060 continue;
1061 }
1062 } else if (widthChanged) {
1063 widthChanged = false;
1064 if (line.isValid()) {
1065 for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
1067 if (!line.isValid())
1068 break;
1069 setLineGeometry(line, lineWidth, naturalHeight);
1070 }
1071 }
1072 layout.endLayout();
1073
1074 bool wasInLayout = internalWidthUpdate;
1075 internalWidthUpdate = true;
1076 q->setImplicitHeight(naturalHeight + qMax(lineHeightOffset(), 0) + q->topPadding() + q->bottomPadding());
1077 internalWidthUpdate = wasInLayout;
1078
1079 multilineElide = elideMode == QQuickText::ElideRight
1080 && q->widthValid()
1081 && (q->heightValid() || maximumLineCountValid);
1082 verticalFit = fontSizeMode() & QQuickText::VerticalFit
1083 && (q->heightValid() || (maximumLineCountValid && canWrap));
1084
1085 const qreal oldHeight = maxHeight;
1086 maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
1087 // If the height of the item has changed and it's possible the result of eliding,
1088 // line count truncation or scaling has changed, do another layout.
1089 if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
1090 && (multilineElide || (canWrap && maximumLineCountValid))) {
1091 widthExceeded = false;
1092 heightExceeded = false;
1093 continue;
1094 }
1095 } else {
1096 layout.endLayout();
1097 }
1098
1099 // If the next needs to be elided and there's an abbreviated string available
1100 // go back and do another layout with the abbreviated string.
1101 if (eos != -1 && elide) {
1102 int start = eos + 1;
1103 eos = text.indexOf(QLatin1Char('\x9c'), start);
1104 layoutText = text.mid(start, eos != -1 ? eos - start : -1);
1105 layoutText.replace(QLatin1Char('\n'), QChar::LineSeparator);
1106 layout.setText(layoutText);
1107 textHasChanged = true;
1108 continue;
1109 }
1110
1111 br.moveTop(0);
1112
1113 // Find the advance of the text layout
1114 if (layout.lineCount() > 0) {
1115 QTextLine firstLine = layout.lineAt(0);
1116 QTextLine lastLine = layout.lineAt(layout.lineCount() - 1);
1117 advance = QSizeF(lastLine.horizontalAdvance(),
1118 lastLine.y() - firstLine.y());
1119 } else {
1120 advance = QSizeF();
1121 }
1122
1123 if (!horizontalFit && !verticalFit)
1124 break;
1125
1126 // Can't find a better fit
1127 if (qFuzzyCompare(smallFont, largeFont))
1128 break;
1129
1130 // Try and find a font size that better fits the dimensions of the element.
1131 if (horizontalFit) {
1132 if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
1133 widthExceeded = true;
1134 largeFont = scaledFontSize;
1135
1136 scaledFontSize = (smallFont + largeFont) / 2;
1137
1138 continue;
1139 } else if (!verticalFit) {
1140 smallFont = scaledFontSize;
1141
1142 // Check to see if the current scaledFontSize is acceptable
1143 if ((largeFont - smallFont) < sizeFittingThreshold)
1144 break;
1145
1146 scaledFontSize = (smallFont + largeFont) / 2;
1147 }
1148 }
1149
1150 if (verticalFit) {
1151 if (truncateHeight || unelidedRect.height() > maxHeight) {
1152 heightExceeded = true;
1153 largeFont = scaledFontSize;
1154
1155 scaledFontSize = (smallFont + largeFont) / 2;
1156
1157 } else {
1158 smallFont = scaledFontSize;
1159
1160 // Check to see if the current scaledFontSize is acceptable
1161 if ((largeFont - smallFont) < sizeFittingThreshold)
1162 break;
1163
1164 scaledFontSize = (smallFont + largeFont) / 2;
1165 }
1166 }
1167 }
1168
1169 implicitWidthValid = true;
1170 implicitHeightValid = true;
1171
1172 QFontInfo scaledFontInfo(scaledFont);
1173 if (fontInfo.weight() != scaledFontInfo.weight()
1174 || fontInfo.pixelSize() != scaledFontInfo.pixelSize()
1175 || fontInfo.italic() != scaledFontInfo.italic()
1176 || !qFuzzyCompare(fontInfo.pointSizeF(), scaledFontInfo.pointSizeF())
1177 || fontInfo.family() != scaledFontInfo.family()
1178 || fontInfo.styleName() != scaledFontInfo.styleName()) {
1179 fontInfo = scaledFontInfo;
1180 emit q->fontInfoChanged();
1181 }
1182
1183 if (eos != multilengthEos)
1184 truncated = true;
1185
1187
1188 if (elide) {
1189 if (!elideLayout) {
1192 }
1194 if (engine && engine->hasFormats()) {
1195 QVector<QTextLayout::FormatRange> formats;
1196 switch (elideMode) {
1198 elideFormats(elideStart, elideText.size() - 1, 0, &formats);
1199 break;
1201 elideFormats(elideEnd - elideText.size() + 1, elideText.size() - 1, 1, &formats);
1202 break;
1204 const int index = elideText.indexOf(elideChar);
1205 if (index != -1) {
1206 elideFormats(elideStart, index, 0, &formats);
1208 elideEnd - elideText.size() + index + 1,
1209 elideText.size() - index - 1,
1210 index + 1,
1211 &formats);
1212 }
1213 break;
1214 }
1215 default:
1216 break;
1217 }
1219 }
1220
1223 elideLayout->setText(elideText);
1225
1226 QTextLine elidedLine = elideLayout->createLine();
1227 elidedLine.setPosition(QPointF(0, height));
1228 if (customLayout) {
1229 setupCustomLineGeometry(elidedLine, height, elideText.size(), visibleCount - 1);
1230 } else {
1231 setLineGeometry(elidedLine, lineWidth, height);
1232 }
1234
1235 br = br.united(elidedLine.naturalTextRect());
1236
1237 if (visibleCount == 1)
1239 } else {
1241 }
1242
1243 QTextLine firstLine = visibleCount == 1 && elideLayout
1244 ? elideLayout->lineAt(0)
1245 : layout.lineAt(0);
1246 if (firstLine.isValid())
1247 *baseline = firstLine.y() + firstLine.ascent();
1248
1249 if (!customLayout)
1250 br.setHeight(height);
1251
1252 //Update the number of visible lines
1253 if (lineCount != visibleCount) {
1254 lineCount = visibleCount;
1255 emit q->lineCountChanged();
1256 }
1257
1258 if (truncated != wasTruncated)
1259 emit q->truncatedChanged();
1260
1261 return br;
1262}
1263
1265{
1266 Q_Q(QQuickText);
1267 line.setLineWidth(lineWidth);
1268
1269 if (extra.isAllocated() && extra->imgTags.isEmpty()) {
1270 line.setPosition(QPointF(line.position().x(), height));
1272 return;
1273 }
1274
1275 qreal textTop = 0;
1276 qreal textHeight = line.height();
1277 qreal totalLineHeight = textHeight;
1278
1279 QList<QQuickStyledTextImgTag *> imagesInLine;
1280
1281 if (extra.isAllocated()) {
1282 for (QQuickStyledTextImgTag *image : std::as_const(extra->imgTags)) {
1283 if (image->position >= line.textStart() &&
1284 image->position < line.textStart() + line.textLength()) {
1285
1286 if (!image->pix) {
1287 const QQmlContext *context = qmlContext(q);
1288 const QUrl url = context->resolvedUrl(q->baseUrl()).resolved(image->url);
1289 image->pix.reset(new QQuickPixmap(context->engine(), url, QRect(), image->size * devicePixelRatio()));
1290
1291 if (image->pix->isLoading()) {
1292 image->pix->connectFinished(q, SLOT(imageDownloadFinished()));
1293 } else if (image->pix->isReady()) {
1294 if (!image->size.isValid()) {
1295 image->size = image->pix->implicitSize();
1296 // if the size of the image was not explicitly set, we need to
1297 // call updateLayout() once again.
1298 needToUpdateLayout = true;
1299 }
1300 } else if (image->pix->isError()) {
1301 qmlWarning(q) << image->pix->error();
1302 }
1303 }
1304
1305 qreal ih = qreal(image->size.height());
1306 if (image->align == QQuickStyledTextImgTag::Top)
1307 image->pos.setY(0);
1308 else if (image->align == QQuickStyledTextImgTag::Middle)
1309 image->pos.setY((textHeight / 2.0) - (ih / 2.0));
1310 else
1311 image->pos.setY(textHeight - ih);
1312 imagesInLine << image;
1313 textTop = qMax(textTop, qAbs(image->pos.y()));
1314 }
1315 }
1316 }
1317
1318 for (QQuickStyledTextImgTag *image : std::as_const(imagesInLine)) {
1319 totalLineHeight = qMax(totalLineHeight, textTop + image->pos.y() + image->size.height());
1320 const int leadX = line.cursorToX(image->position);
1321 const int trailX = line.cursorToX(image->position, QTextLine::Trailing);
1322 const bool rtl = trailX < leadX;
1323 image->pos.setX(leadX + (rtl ? (-image->offset - image->size.width()) : image->offset));
1324 image->pos.setY(image->pos.y() + height + textTop);
1326 }
1327
1328 line.setPosition(QPointF(line.position().x(), height + textTop));
1329 height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : totalLineHeight * lineHeight();
1330}
1331
1336{
1337 QFontMetricsF fm(font);
1338 qreal fontHeight = qCeil(fm.height()); // QScriptLine and therefore QTextLine rounds up
1339 return lineHeightMode() == QQuickText::FixedHeight ? fontHeight - lineHeight()
1340 : (1.0 - lineHeight()) * fontHeight;
1341}
1342
1347{
1348 if (!extra.isAllocated() || !extra->doc) {
1349 Q_Q(QQuickText);
1350 extra.value().doc = new QTextDocument(q);
1351 auto *doc = extra->doc;
1353 doc->documentLayout()->registerHandler(QTextFormat::ImageObject, extra->imageHandler);
1354 doc->setPageSize(QSizeF(0, 0));
1355 doc->setDocumentMargin(0);
1356 const QQmlContext *context = qmlContext(q);
1357 doc->setBaseUrl(context ? context->resolvedUrl(q->baseUrl()) : q->baseUrl());
1358 }
1359}
1360
1362{
1363 ensureDoc();
1364#if QT_CONFIG(textmarkdownreader)
1365 if (markdownText)
1366 extra->doc->setMarkdown(text);
1367 else
1368#endif
1369#if QT_CONFIG(texthtmlparser)
1370 extra->doc->setHtml(text);
1371#else
1373#endif
1375}
1376
1378{
1379 return (window ? window->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
1380}
1381
1450{
1451 Q_D(QQuickText);
1452 d->init();
1453}
1454
1456: QQuickImplicitSizeItem(dd, parent)
1457{
1458 Q_D(QQuickText);
1459 d->init();
1460}
1461
1463{
1464 Q_D(QQuickText);
1465 if (d->extra.isAllocated()) {
1466 qDeleteAll(d->extra->pixmapsInProgress);
1467 d->extra->pixmapsInProgress.clear();
1468 }
1469}
1470
1742
1780
1788
1849
1856
1868
1875
1894
1898{
1899 Q_D(const QQuickText);
1900 return d->sourceFont;
1901}
1902
1904{
1905 Q_D(QQuickText);
1906 if (d->sourceFont == font)
1907 return;
1908
1909 d->sourceFont = font;
1910 QFont oldFont = d->font;
1911 d->font = font;
1912
1913 if (!antialiasing())
1914 d->font.setStyleStrategy(QFont::NoAntialias);
1915
1916 if (d->font.pointSizeF() != -1) {
1917 // 0.5pt resolution
1918 qreal size = qRound(d->font.pointSizeF()*2.0);
1919 d->font.setPointSizeF(size/2.0);
1920 }
1921
1922 if (oldFont != d->font) {
1923 // if the format changes the size of the text
1924 // with headings or <font> tag, we need to re-parse
1925 if (d->formatModifiesFontSize)
1926 d->textHasChanged = true;
1927 d->implicitWidthValid = false;
1928 d->implicitHeightValid = false;
1929 d->updateLayout();
1930 }
1931
1932 emit fontChanged(d->sourceFont);
1933}
1934
1936{
1937 Q_D(QQuickText);
1938 Q_UNUSED(value);
1939 switch (change) {
1941 if (!antialiasing())
1942 d->font.setStyleStrategy(QFont::NoAntialias);
1943 else
1944 d->font.setStyleStrategy(QFont::PreferAntialias);
1945 d->implicitWidthValid = false;
1946 d->implicitHeightValid = false;
1947 d->updateLayout();
1948 break;
1949
1951 {
1952 bool needUpdateLayout = false;
1953 if (d->renderType == NativeRendering) {
1954 // Native rendering optimizes for a given pixel grid, so its results must not be scaled.
1955 // Text layout code respects the current device pixel ratio automatically, we only need
1956 // to rerun layout after the ratio changed.
1957 // Changes of implicit size should be minimal; they are hard to avoid.
1958 d->implicitWidthValid = false;
1959 d->implicitHeightValid = false;
1960 needUpdateLayout = true;
1961 }
1962
1963 if (d->extra.isAllocated()) {
1964 // check if we have scalable inline images with explicit size set, which should be reloaded
1965 for (QQuickStyledTextImgTag *image : std::as_const(d->extra->visibleImgTags)) {
1966 if (image->size.isValid() && QQuickPixmap::isScalableImageFormat(image->url)) {
1967 image->pix.reset();
1968 needUpdateLayout = true;
1969 }
1970 }
1971 }
1972
1973 if (needUpdateLayout)
1974 d->updateLayout();
1975 }
1976 break;
1977
1978 default:
1979 break;
1980 }
1982}
1983
1996{
1997 Q_D(const QQuickText);
1998 return d->text;
1999}
2000
2002{
2003 Q_D(QQuickText);
2004 if (d->text == n)
2005 return;
2006
2007 d->markdownText = d->format == MarkdownText;
2008 d->richText = d->format == RichText || d->markdownText;
2009 d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n));
2010 d->text = n;
2011 if (isComponentComplete()) {
2012 if (d->richText) {
2013 d->updateDocumentText();
2014 } else {
2015 d->clearFormats();
2016 d->rightToLeftText = d->text.isRightToLeft();
2017 }
2018 d->determineHorizontalAlignment();
2019 }
2020 d->textHasChanged = true;
2021 d->implicitWidthValid = false;
2022 d->implicitHeightValid = false;
2023
2024 if (d->extra.isAllocated()) {
2025 qDeleteAll(d->extra->imgTags);
2026 d->extra->imgTags.clear();
2027 }
2029 d->updateLayout();
2030 setAcceptHoverEvents(d->richText || d->styledText);
2031 emit textChanged(d->text);
2032}
2033
2056{
2057 Q_D(const QQuickText);
2058 return QColor::fromRgba(d->color);
2059}
2060
2062{
2063 Q_D(QQuickText);
2064 QRgb rgb = color.rgba();
2065 if (d->color == rgb)
2066 return;
2067
2068 d->color = rgb;
2069 if (isComponentComplete()) {
2071 update();
2072 }
2074}
2075
2087{
2088 Q_D(const QQuickText);
2089 return QColor::fromRgba(d->linkColor);
2090}
2091
2093{
2094 Q_D(QQuickText);
2095 QRgb rgb = color.rgba();
2096 if (d->linkColor == rgb)
2097 return;
2098
2099 d->linkColor = rgb;
2100 if (isComponentComplete()) {
2102 update();
2103 }
2105}
2106
2131{
2132 Q_D(const QQuickText);
2133 return d->style;
2134}
2135
2137{
2138 Q_D(QQuickText);
2139 if (d->style == style)
2140 return;
2141
2142 d->style = style;
2143 if (isComponentComplete()) {
2145 update();
2146 }
2147 emit styleChanged(d->style);
2148}
2149
2166{
2167 Q_D(const QQuickText);
2168 return QColor::fromRgba(d->styleColor);
2169}
2170
2172{
2173 Q_D(QQuickText);
2174 QRgb rgb = color.rgba();
2175 if (d->styleColor == rgb)
2176 return;
2177
2178 d->styleColor = rgb;
2179 if (isComponentComplete()) {
2181 update();
2182 }
2184}
2185
2211{
2212 Q_D(const QQuickText);
2213 return d->hAlign;
2214}
2215
2217{
2218 Q_D(QQuickText);
2219 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
2220 d->hAlignImplicit = false;
2221 if (d->setHAlign(align, forceAlign) && isComponentComplete())
2222 d->updateLayout();
2223}
2224
2226{
2227 Q_D(QQuickText);
2228 d->hAlignImplicit = true;
2229 if (isComponentComplete() && d->determineHorizontalAlignment())
2230 d->updateLayout();
2231}
2232
2234{
2235 Q_D(const QQuickText);
2236 QQuickText::HAlignment effectiveAlignment = d->hAlign;
2237 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
2238 switch (d->hAlign) {
2240 effectiveAlignment = QQuickText::AlignRight;
2241 break;
2243 effectiveAlignment = QQuickText::AlignLeft;
2244 break;
2245 default:
2246 break;
2247 }
2248 }
2249 return effectiveAlignment;
2250}
2251
2253{
2254 Q_Q(QQuickText);
2255 if (hAlign != alignment || forceAlign) {
2256 QQuickText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
2257 hAlign = alignment;
2258
2259 emit q->horizontalAlignmentChanged(hAlign);
2260 if (oldEffectiveHAlign != q->effectiveHAlign())
2261 emit q->effectiveHorizontalAlignmentChanged();
2262 return true;
2263 }
2264 return false;
2265}
2266
2268{
2269 if (hAlignImplicit) {
2270#if QT_CONFIG(im)
2271 bool alignToRight = text.isEmpty() ? QGuiApplication::inputMethod()->inputDirection() == Qt::RightToLeft : rightToLeftText;
2272#else
2273 bool alignToRight = rightToLeftText;
2274#endif
2276 }
2277 return false;
2278}
2279
2281{
2282 Q_Q(QQuickText);
2283 if (q->isComponentComplete()) {
2285 updateLayout();
2286 emit q->effectiveHorizontalAlignmentChanged();
2287 }
2288 }
2289}
2290
2292{
2293 Q_D(const QQuickText);
2294 return d->vAlign;
2295}
2296
2298{
2299 Q_D(QQuickText);
2300 if (d->vAlign == align)
2301 return;
2302
2303 d->vAlign = align;
2304
2305 if (isComponentComplete())
2306 d->updateLayout();
2307
2309}
2310
2330{
2331 Q_D(const QQuickText);
2332 return d->wrapMode;
2333}
2334
2336{
2337 Q_D(QQuickText);
2338 if (mode == d->wrapMode)
2339 return;
2340
2341 d->wrapMode = mode;
2342 d->updateLayout();
2343
2345}
2346
2357{
2358 Q_D(const QQuickText);
2359 return d->lineCount;
2360}
2361
2373{
2374 Q_D(const QQuickText);
2375 return d->truncated;
2376}
2377
2390{
2391 Q_D(const QQuickText);
2392 return d->maximumLineCount();
2393}
2394
2396{
2397 Q_D(QQuickText);
2398
2399 d->maximumLineCountValid = lines==INT_MAX ? false : true;
2400 if (d->maximumLineCount() != lines) {
2401 d->extra.value().maximumLineCount = lines;
2402 d->implicitHeightValid = false;
2403 d->updateLayout();
2405 }
2406}
2407
2409{
2410 Q_D(QQuickText);
2411 setMaximumLineCount(INT_MAX);
2412 if (d->truncated != false) {
2413 d->truncated = false;
2415 }
2416}
2417
2481{
2482 Q_D(const QQuickText);
2483 return d->format;
2484}
2485
2487{
2488 Q_D(QQuickText);
2489 if (format == d->format)
2490 return;
2491 d->format = format;
2492 bool wasRich = d->richText;
2493 d->markdownText = format == MarkdownText;
2494 d->richText = format == RichText || d->markdownText;
2495 d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
2496
2497 if (isComponentComplete()) {
2498 if (!wasRich && d->richText) {
2499 d->updateDocumentText();
2500 } else {
2501 d->clearFormats();
2502 d->rightToLeftText = d->text.isRightToLeft();
2503 d->textHasChanged = true;
2504 }
2505 d->determineHorizontalAlignment();
2506 }
2507 d->updateLayout();
2508 setAcceptHoverEvents(d->richText || d->styledText);
2509 setAcceptedMouseButtons(d->richText || d->styledText ? Qt::LeftButton : Qt::NoButton);
2510
2511 emit textFormatChanged(d->format);
2512}
2513
2541{
2542 Q_D(const QQuickText);
2543 return d->elideMode;
2544}
2545
2547{
2548 Q_D(QQuickText);
2549 if (mode == d->elideMode)
2550 return;
2551
2552 d->elideMode = mode;
2553 d->updateLayout();
2554
2556}
2557
2582{
2583 Q_D(const QQuickText);
2584 if (!d->extra.isAllocated() || d->extra->baseUrl.isEmpty()) {
2585 if (QQmlContext *context = qmlContext(this))
2586 return context->baseUrl();
2587 else
2588 return QUrl();
2589 } else {
2590 return d->extra->baseUrl;
2591 }
2592}
2593
2595{
2596 Q_D(QQuickText);
2597 if (baseUrl() != url) {
2598 d->extra.value().baseUrl = url;
2599
2600 if (d->richText) {
2601 d->ensureDoc();
2602 d->extra->doc->setBaseUrl(url);
2603 }
2604 if (d->styledText) {
2605 d->textHasChanged = true;
2606 if (d->extra.isAllocated()) {
2607 qDeleteAll(d->extra->imgTags);
2608 d->extra->imgTags.clear();
2609 }
2610 d->updateLayout();
2611 }
2613 }
2614}
2615
2617{
2618 if (QQmlContext *context = qmlContext(this))
2619 setBaseUrl(context->baseUrl());
2620 else
2621 setBaseUrl(QUrl());
2622}
2623
2632{
2633 Q_D(const QQuickText);
2634
2635 QRectF rect = d->layedOutTextRect;
2636 rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), effectiveHAlign()));
2637 rect.moveTop(QQuickTextUtil::alignedY(rect.height() + d->lineHeightOffset(), height(), d->vAlign));
2638
2639 if (d->style != Normal)
2640 rect.adjust(-1, 0, 1, 2);
2641 // Could include font max left/right bearings to either side of rectangle.
2642
2643 return rect;
2644}
2645
2658{
2659 Q_D(const QQuickText);
2660
2662 if (d->style != Normal)
2663 rect.adjust(-1, 0, 1, 2);
2664 return rect;
2665}
2666
2668void QQuickText::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
2669{
2670 Q_D(QQuickText);
2671 if (d->text.isEmpty()) {
2672 QQuickItem::geometryChange(newGeometry, oldGeometry);
2673 return;
2674 }
2675
2676 bool widthChanged = newGeometry.width() != oldGeometry.width();
2677 bool heightChanged = newGeometry.height() != oldGeometry.height();
2678 bool wrapped = d->wrapMode != QQuickText::NoWrap;
2679 bool elide = d->elideMode != QQuickText::ElideNone;
2680 bool scaleFont = d->fontSizeMode() != QQuickText::FixedSize && (widthValid() || heightValid());
2681 bool verticalScale = (d->fontSizeMode() & QQuickText::VerticalFit) && heightValid();
2682
2683 bool widthMaximum = newGeometry.width() >= oldGeometry.width() && !d->widthExceeded;
2684 bool heightMaximum = newGeometry.height() >= oldGeometry.height() && !d->heightExceeded;
2685
2686 bool verticalPositionChanged = heightChanged && d->vAlign != AlignTop;
2687
2688 if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
2689 goto geomChangeDone;
2690
2691 if ((effectiveHAlign() != QQuickText::AlignLeft && widthChanged) || verticalPositionChanged) {
2692 // If the width has changed and we're not left aligned do an update so the text is
2693 // repositioned even if a full layout isn't required. And the same for vertical.
2695 update();
2696 }
2697
2698 if (!wrapped && !elide && !scaleFont && !verticalPositionChanged)
2699 goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
2700
2701 if (elide // eliding and dimensions were and remain invalid;
2702 && ((widthValid() && oldGeometry.width() <= 0 && newGeometry.width() <= 0)
2703 || (heightValid() && oldGeometry.height() <= 0 && newGeometry.height() <= 0))) {
2704 goto geomChangeDone;
2705 }
2706
2707 if (widthMaximum && heightMaximum && !d->isLineLaidOutConnected() && !verticalPositionChanged) // Size is sufficient and growing.
2708 goto geomChangeDone;
2709
2710 if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
2711 if (!verticalPositionChanged) {
2712 if (newGeometry.height() > oldGeometry.height()) {
2713 if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
2714 // Height is adequate and growing, and it wasn't 0 previously.
2715 goto geomChangeDone;
2716 }
2717 if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
2718 goto geomChangeDone;
2719 } else if (newGeometry.height() < oldGeometry.height()) {
2720 if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
2721 goto geomChangeDone;
2722
2723 if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
2724 && d->elideMode != QQuickText::ElideRight
2725 && !(d->maximumLineCountValid && d->widthExceeded)) {
2726 goto geomChangeDone;
2727 }
2728 }
2729 }
2730 } else if (!heightChanged && widthMaximum) {
2731 if (oldGeometry.width() > 0) {
2732 // no change to height, width is adequate and wasn't 0 before
2733 // (old width could also be negative if it was 0 and the margins
2734 // were set)
2735 goto geomChangeDone;
2736 }
2737 }
2738
2739 if (d->updateOnComponentComplete || d->textHasChanged) {
2740 // We need to re-elide
2741 d->updateLayout();
2742 } else {
2743 // We just need to re-layout
2744 d->updateSize();
2745 }
2746
2747geomChangeDone:
2748 QQuickItem::geometryChange(newGeometry, oldGeometry);
2749}
2750
2751void QQuickText::triggerPreprocess()
2752{
2753 Q_D(QQuickText);
2754 if (d->updateType == QQuickTextPrivate::UpdateNone)
2756 update();
2757}
2758
2760{
2761 Q_UNUSED(data);
2762 Q_D(QQuickText);
2763
2764 if (d->text.isEmpty()) {
2765 delete oldNode;
2766 return nullptr;
2767 }
2768
2769 if (d->updateType != QQuickTextPrivate::UpdatePaintNode && oldNode != nullptr) {
2770 // Update done in preprocess() in the nodes
2771 d->updateType = QQuickTextPrivate::UpdateNone;
2772 return oldNode;
2773 }
2774
2775 d->updateType = QQuickTextPrivate::UpdateNone;
2776
2777 const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), d->availableHeight(), d->vAlign) + topPadding();
2778
2779 QSGInternalTextNode *node = nullptr;
2780 if (!oldNode)
2781 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
2782 else
2783 node = static_cast<QSGInternalTextNode *>(oldNode);
2784
2786
2787 node->setTextStyle(QSGTextNode::TextStyle(d->style));
2788 node->setRenderType(QSGTextNode::RenderType(d->renderType));
2789 node->setRenderTypeQuality(d->renderTypeQuality());
2790 node->clear();
2791 node->setMatrix(QMatrix4x4());
2792
2793 node->setColor(QColor::fromRgba(d->color));
2794 node->setStyleColor(QColor::fromRgba(d->styleColor));
2795 node->setLinkColor(QColor::fromRgba(d->linkColor));
2796
2797 if (d->richText) {
2798 node->setViewport(clipRect());
2799 const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), d->availableWidth(), effectiveHAlign()) + leftPadding();
2800 d->ensureDoc();
2801 node->addTextDocument(QPointF(dx, dy), d->extra->doc);
2802 } else if (d->layedOutTextRect.width() > 0) {
2804 node->setViewport(clipRect());
2805 else
2806 node->setViewport(QRectF{});
2807 const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, d->availableWidth(), effectiveHAlign()) + leftPadding();
2808 int unelidedLineCount = d->lineCount;
2809 if (d->elideLayout)
2810 unelidedLineCount -= 1;
2811 if (unelidedLineCount > 0)
2812 node->addTextLayout(QPointF(dx, dy), &d->layout, -1, -1,0, unelidedLineCount);
2813
2814 if (d->elideLayout)
2815 node->addTextLayout(QPointF(dx, dy), d->elideLayout.get());
2816
2817 if (d->extra.isAllocated()) {
2818 for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
2819 if (img->pix && img->pix->isReady())
2820 node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, img->size.width(), img->size.height()), img->pix->image());
2821 }
2822 }
2823 }
2824
2825 // The font caches have now been initialized on the render thread, so they have to be
2826 // invalidated before we can use them from the main thread again.
2828
2829 return node;
2830}
2831
2833{
2834 Q_D(QQuickText);
2835 const bool clipNodeChanged =
2836 d->componentComplete && d->clipNode() && d->clipNode()->rect() != clipRect();
2837 if (clipNodeChanged)
2838 d->dirty(QQuickItemPrivate::Clip);
2839
2840 // If the fonts used for rendering are different from the ones used in the GUI thread,
2841 // it means we will get warnings and corrupted text. If this case is detected, we need
2842 // to update the text layout before creating the scenegraph nodes.
2843 if (!d->assignedFont.isEmpty() && QFontInfo(d->font).family() != d->assignedFont)
2844 d->polishSize = true;
2845
2846 if (d->polishSize) {
2847 d->updateSize();
2848 d->polishSize = false;
2849 }
2851}
2852
2860{
2861 Q_D(const QQuickText);
2862 return d->layedOutTextRect.width();
2863}
2864
2872{
2873 Q_D(const QQuickText);
2874 return d->layedOutTextRect.height() + qMax(d->lineHeightOffset(), 0);
2875}
2876
2887{
2888 Q_D(const QQuickText);
2889 return d->lineHeight();
2890}
2891
2893{
2894 Q_D(QQuickText);
2895
2896 if ((d->lineHeight() == lineHeight) || (lineHeight < 0.0))
2897 return;
2898
2899 d->extra.value().lineHeightValid = true;
2900 d->extra.value().lineHeight = lineHeight;
2901 d->implicitHeightValid = false;
2902 d->updateLayout();
2904}
2905
2917{
2918 Q_D(const QQuickText);
2919 return d->lineHeightMode();
2920}
2921
2923{
2924 Q_D(QQuickText);
2925 if (mode == d->lineHeightMode())
2926 return;
2927
2928 d->implicitHeightValid = false;
2929 d->extra.value().lineHeightValid = true;
2930 d->extra.value().lineHeightMode = mode;
2931 d->updateLayout();
2932
2934}
2935
2972{
2973 Q_D(const QQuickText);
2974 return d->fontSizeMode();
2975}
2976
2978{
2979 Q_D(QQuickText);
2980 if (d->fontSizeMode() == mode)
2981 return;
2982
2983 d->polishSize = true;
2984 polish();
2985
2986 d->extra.value().fontSizeMode = mode;
2988}
2989
3001{
3002 Q_D(const QQuickText);
3003 return d->minimumPixelSize();
3004}
3005
3007{
3008 Q_D(QQuickText);
3009 if (d->minimumPixelSize() == size)
3010 return;
3011
3012 if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid())) {
3013 d->polishSize = true;
3014 polish();
3015 }
3016 d->extra.value().minimumPixelSize = size;
3018}
3019
3031{
3032 Q_D(const QQuickText);
3033 return d->minimumPointSize();
3034}
3035
3037{
3038 Q_D(QQuickText);
3039 if (d->minimumPointSize() == size)
3040 return;
3041
3042 if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid())) {
3043 d->polishSize = true;
3044 polish();
3045 }
3046 d->extra.value().minimumPointSize = size;
3048}
3049
3054{
3055 Q_D(const QQuickText);
3056 if (d->richText && d->extra.isAllocated())
3057 return d->extra->pixmapsInProgress.size();
3058 return 0;
3059}
3060
3063{
3064 Q_D(QQuickText);
3065 if (d->updateOnComponentComplete) {
3066 if (d->richText) {
3067 d->updateDocumentText();
3068 } else {
3069 d->rightToLeftText = d->text.isRightToLeft();
3070 }
3071 d->determineHorizontalAlignment();
3072 }
3074 if (d->updateOnComponentComplete)
3075 d->updateLayout();
3076}
3077
3079{
3080 for (int i = 0; i < layout->lineCount(); ++i) {
3082 if (line.naturalTextRect().contains(mousePos)) {
3083 int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter);
3084 const auto formats = layout->formats();
3085 for (const QTextLayout::FormatRange &formatRange : formats) {
3086 if (formatRange.format.isAnchor()
3087 && charPos >= formatRange.start
3088 && charPos < formatRange.start + formatRange.length) {
3089 return formatRange.format.anchorHref();
3090 }
3091 }
3092 break;
3093 }
3094 }
3095 return QString();
3096}
3097
3099{
3100 Q_Q(const QQuickText);
3101 QPointF translatedMousePos = mousePos;
3102 translatedMousePos.rx() -= q->leftPadding();
3103 translatedMousePos.ry() -= q->topPadding() + QQuickTextUtil::alignedY(layedOutTextRect.height() + lineHeightOffset(), availableHeight(), vAlign);
3104 if (styledText) {
3105 QString link = anchorAt(&layout, translatedMousePos);
3106 if (link.isEmpty() && elideLayout)
3107 link = anchorAt(elideLayout.get(), translatedMousePos);
3108 return link;
3109 } else if (richText && extra.isAllocated() && extra->doc) {
3110 translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), availableWidth(), q->effectiveHAlign());
3111 return extra->doc->documentLayout()->anchorAt(translatedMousePos);
3112 }
3113 return QString();
3114}
3115
3117{
3118 Q_Q(QQuickText);
3119 IS_SIGNAL_CONNECTED(q, QQuickText, linkActivated, (const QString &));
3120}
3121
3124{
3125 Q_D(QQuickText);
3126
3127 QString link;
3128 if (d->isLinkActivatedConnected())
3129 link = d->anchorAt(event->position());
3130
3131 if (link.isEmpty()) {
3132 event->setAccepted(false);
3133 } else {
3134 d->extra.value().activeLink = link;
3135 }
3136
3137 // ### may malfunction if two of the same links are clicked & dragged onto each other)
3138
3139 if (!event->isAccepted())
3141}
3142
3143
3146{
3147 Q_D(QQuickText);
3148
3149 // ### confirm the link, and send a signal out
3150
3151 QString link;
3152 if (d->isLinkActivatedConnected())
3153 link = d->anchorAt(event->position());
3154
3155 if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link)
3156 emit linkActivated(d->extra->activeLink);
3157 else
3158 event->setAccepted(false);
3159
3160 if (!event->isAccepted())
3162}
3163
3165{
3166 Q_Q(QQuickText);
3167 IS_SIGNAL_CONNECTED(q, QQuickText, linkHovered, (const QString &));
3168}
3169
3170static void getLinks_helper(const QTextLayout *layout, QVector<QQuickTextPrivate::LinkDesc> *links)
3171{
3172 for (const QTextLayout::FormatRange &formatRange : layout->formats()) {
3173 if (formatRange.format.isAnchor()) {
3174 const int start = formatRange.start;
3175 const int len = formatRange.length;
3176 QTextLine line = layout->lineForTextPosition(start);
3177 QRectF r;
3178 r.setTop(line.y());
3179 r.setLeft(line.cursorToX(start, QTextLine::Leading));
3180 r.setHeight(line.height());
3181 r.setRight(line.cursorToX(start + len, QTextLine::Trailing));
3182 // ### anchorNames() is empty?! Not sure why this doesn't work
3183 // QString anchorName = formatRange.format.anchorNames().value(0); //### pick the first?
3184 // Therefore, we resort to QString::mid()
3185 QString anchorName = layout->text().mid(start, len);
3186 const QString anchorHref = formatRange.format.anchorHref();
3187 if (anchorName.isEmpty())
3188 anchorName = anchorHref;
3189 links->append( { anchorName, anchorHref, start, start + len, r.toRect()} );
3190 }
3191 }
3192}
3193
3194QVector<QQuickTextPrivate::LinkDesc> QQuickTextPrivate::getLinks() const
3195{
3196 QVector<QQuickTextPrivate::LinkDesc> links;
3198 return links;
3199}
3200
3201
3225{
3226 Q_D(const QQuickText);
3227 if (const_cast<QQuickTextPrivate *>(d)->isLinkHoveredConnected()) {
3228 if (d->extra.isAllocated())
3229 return d->extra->hoveredLink;
3230 } else {
3231#if QT_CONFIG(cursor)
3232 if (QQuickWindow *wnd = window()) {
3233 QPointF pos = QCursor::pos(wnd->screen()) - wnd->position() - mapToScene(QPointF(0, 0));
3234 return d->anchorAt(pos);
3235 }
3236#endif // cursor
3237 }
3238 return QString();
3239}
3240
3242{
3243 Q_Q(QQuickText);
3244 qCDebug(lcHoverTrace) << q;
3245 QString link;
3246 if (isLinkHoveredConnected()) {
3247 if (event->type() != QEvent::HoverLeave)
3248 link = anchorAt(event->position());
3249
3250 if ((!extra.isAllocated() && !link.isEmpty()) || (extra.isAllocated() && extra->hoveredLink != link)) {
3251 extra.value().hoveredLink = link;
3252 emit q->linkHovered(extra->hoveredLink);
3253 }
3254 }
3255 event->ignore();
3256}
3257
3259{
3260 Q_D(QQuickText);
3261 d->processHoverEvent(event);
3262}
3263
3265{
3266 Q_D(QQuickText);
3267 d->processHoverEvent(event);
3268}
3269
3271{
3272 Q_D(QQuickText);
3273 d->processHoverEvent(event);
3274}
3275
3277{
3278 Q_D(QQuickText);
3279 d->textHasChanged = true;
3280 QMetaObject::invokeMethod(this,[&]{q_updateLayout();});
3281}
3282
3284{
3285 // If there's a lot of text, we may need QQuickText::updatePaintNode() to call
3286 // QSGInternalTextNode::addTextLayout() again to populate a different range of lines
3290 }
3292}
3293
3317{
3318 Q_D(const QQuickText);
3319 return d->renderTypeQuality();
3320}
3321
3322void QQuickText::setRenderTypeQuality(int renderTypeQuality)
3323{
3324 Q_D(QQuickText);
3325 if (renderTypeQuality == d->renderTypeQuality())
3326 return;
3327 d->extra.value().renderTypeQuality = renderTypeQuality;
3328
3329 if (isComponentComplete()) {
3331 update();
3332 }
3333
3334 emit renderTypeQualityChanged();
3335}
3336
3363{
3364 Q_D(const QQuickText);
3365 return d->renderType;
3366}
3367
3369{
3370 Q_D(QQuickText);
3371 if (d->renderType == renderType)
3372 return;
3373
3374 d->renderType = renderType;
3376
3377 if (isComponentComplete())
3378 d->updateLayout();
3379}
3380
3381#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
3382#if QT_DEPRECATED_SINCE(5, 15)
3389void QQuickText::doLayout()
3390{
3391 forceLayout();
3392}
3393
3394#endif
3395#endif
3402void QQuickText::forceLayout()
3403{
3404 Q_D(QQuickText);
3405 d->updateSize();
3406}
3407
3417QString QQuickText::linkAt(qreal x, qreal y) const
3418{
3419 Q_D(const QQuickText);
3420 return d->anchorAt(QPointF(x, y));
3421}
3422
3430{
3431 Q_D(QQuickText);
3432
3433 if (d->richText && d->extra.isAllocated() && d->extra->doc != nullptr) {
3434 QTextBlock block;
3435 for (block = d->extra->doc->firstBlock(); block.isValid(); block = block.next()) {
3436 if (block.layout() != nullptr && block.layout()->engine() != nullptr)
3437 block.layout()->engine()->resetFontEngineCache();
3438 }
3439 } else {
3440 if (d->layout.engine() != nullptr)
3441 d->layout.engine()->resetFontEngineCache();
3442 }
3443}
3444
3457{
3458 Q_D(const QQuickText);
3459 return d->padding();
3460}
3461
3463{
3464 Q_D(QQuickText);
3465 if (qFuzzyCompare(d->padding(), padding))
3466 return;
3467
3468 d->extra.value().padding = padding;
3469 d->updateSize();
3470 emit paddingChanged();
3471 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
3472 emit topPaddingChanged();
3473 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
3474 emit leftPaddingChanged();
3475 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
3476 emit rightPaddingChanged();
3477 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
3478 emit bottomPaddingChanged();
3479}
3480
3482{
3483 setPadding(0);
3484}
3485
3487{
3488 Q_D(const QQuickText);
3489 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
3490 return d->extra->topPadding;
3491 return d->padding();
3492}
3493
3495{
3496 Q_D(QQuickText);
3497 d->setTopPadding(padding);
3498}
3499
3501{
3502 Q_D(QQuickText);
3503 d->setTopPadding(0, true);
3504}
3505
3507{
3508 Q_D(const QQuickText);
3509 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
3510 return d->extra->leftPadding;
3511 return d->padding();
3512}
3513
3515{
3516 Q_D(QQuickText);
3517 d->setLeftPadding(padding);
3518}
3519
3521{
3522 Q_D(QQuickText);
3523 d->setLeftPadding(0, true);
3524}
3525
3527{
3528 Q_D(const QQuickText);
3529 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
3530 return d->extra->rightPadding;
3531 return d->padding();
3532}
3533
3535{
3536 Q_D(QQuickText);
3537 d->setRightPadding(padding);
3538}
3539
3541{
3542 Q_D(QQuickText);
3543 d->setRightPadding(0, true);
3544}
3545
3547{
3548 Q_D(const QQuickText);
3549 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
3550 return d->extra->bottomPadding;
3551 return d->padding();
3552}
3553
3555{
3556 Q_D(QQuickText);
3557 d->setBottomPadding(padding);
3558}
3559
3561{
3562 Q_D(QQuickText);
3563 d->setBottomPadding(0, true);
3564}
3565
3622{
3623 Q_D(const QQuickText);
3624
3625 QJSEngine *engine = qjsEngine(this);
3626 if (!engine) {
3627 qmlWarning(this) << "fontInfo: item has no JS engine";
3628 return QJSValue();
3629 }
3630
3632 value.setProperty(QStringLiteral("family"), d->fontInfo.family());
3633 value.setProperty(QStringLiteral("styleName"), d->fontInfo.styleName());
3634 value.setProperty(QStringLiteral("bold"), d->fontInfo.bold());
3635 value.setProperty(QStringLiteral("weight"), d->fontInfo.weight());
3636 value.setProperty(QStringLiteral("italic"), d->fontInfo.italic());
3637 value.setProperty(QStringLiteral("pointSize"), d->fontInfo.pointSizeF());
3638 value.setProperty(QStringLiteral("pixelSize"), d->fontInfo.pixelSize());
3639 return value;
3640}
3641
3655{
3656 Q_D(const QQuickText);
3657 return d->advance;
3658}
3659
3661
3662#include "moc_qquicktext_p.cpp"
QString anchorAt(const QPointF &pos) const
Returns the reference of the anchor the given position, or an empty string if no anchor exists at tha...
\inmodule QtCore
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
static QColor fromRgba(QRgb rgba) noexcept
Static convenience function that returns a QColor constructed from the given QRgb value rgba.
Definition qcolor.cpp:2385
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
Definition qcursor.cpp:188
@ HoverLeave
Definition qcoreevent.h:176
\reentrant
Definition qfontinfo.h:16
qreal pointSizeF() const
Returns the point size of the matched window system font.
Definition qfont.cpp:3148
int pixelSize() const
Returns the pixel size of the matched window system font.
Definition qfont.cpp:3160
QString family() const
Returns the family name of the matched window system font.
Definition qfont.cpp:3109
bool italic() const
Returns the italic value of the matched window system font.
Definition qfont.cpp:3172
QString styleName() const
Definition qfont.cpp:3124
int weight() const
Returns the weight of the matched window system font.
Definition qfont.cpp:3218
\reentrant \inmodule QtGui
qreal ascent() const
Returns the ascent of the font.
\reentrant
Definition qfont.h:22
int pixelSize() const
Returns the pixel size of the font if it was set with setPixelSize().
Definition qfont.cpp:1074
qreal pointSizeF() const
Returns the point size of the font.
Definition qfont.cpp:1034
@ NoAntialias
Definition qfont.h:47
@ PreferAntialias
Definition qfont.h:46
static QInputMethod * inputMethod()
returns the input method.
\inmodule QtGui
Definition qevent.h:246
\inmodule QtGui
Definition qimage.h:37
The QJSEngine class provides an environment for evaluating JavaScript code.
Definition qjsengine.h:26
QJSValue newObject()
Creates a JavaScript object of class Object.
The QJSValue class acts as a container for Qt/JavaScript data types.
Definition qjsvalue.h:31
void setProperty(const QString &name, const QJSValue &value)
Sets the value of this QJSValue's property with the given name to the given value.
bool isAllocated() const
bool isEmpty() const noexcept
Definition qlist.h:402
void clear()
Definition qlist.h:435
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
\inmodule QtGui
Definition qevent.h:196
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:343
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
Definition qpoint.h:348
constexpr qreal & rx() noexcept
Returns a reference to the x coordinate of this point.
Definition qpoint.h:363
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to \l{QFile}.
Definition qqmlfile.cpp:742
virtual bool transformChanged(QQuickItem *transformedItem)
virtual void implicitHeightChanged()
void dirty(DirtyType)
QQuickWindow * window
quint32 implicitAntialiasing
virtual void implicitWidthChanged()
QQuickAnchorLine baseline() const
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
QPointF mapToScene(const QPointF &point) const
Maps the given point in this item's coordinate system to the equivalent point within the scene's coor...
virtual void mouseReleaseEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse release events for an item.
void heightChanged()
Flags flags() const
Returns the item flags for this item.
void setFlag(Flag flag, bool enabled=true)
Enables the specified flag for this item if enabled is true; if enabled is false, the flag is disable...
virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
void widthChanged()
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
void setAcceptHoverEvents(bool enabled)
If enabled is true, this sets the item to accept hover events; otherwise, hover events are not accept...
void setAcceptedMouseButtons(Qt::MouseButtons buttons)
Sets the mouse buttons accepted by this item to buttons.
QSizeF size() const
QQuickWindow * window() const
Returns the window in which this item is rendered.
virtual void mousePressEvent(QMouseEvent *event)
This event handler can be reimplemented in a subclass to receive mouse press events for an item.
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
bool heightValid() const
Returns whether the height property has been set explicitly.
bool antialiasing
\qmlproperty bool QtQuick::Item::antialiasing
Definition qquickitem.h:113
bool smooth
\qmlproperty bool QtQuick::Item::smooth
Definition qquickitem.h:112
bool widthValid() const
Returns whether the width property has been set explicitly.
virtual QRectF clipRect() const
Returns the rectangular area within this item that is currently visible in \l viewportItem(),...
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
@ ItemAntialiasingHasChanged
Definition qquickitem.h:153
@ ItemDevicePixelRatioHasChanged
Definition qquickitem.h:154
@ ItemObservesViewport
Definition qquickitem.h:138
void update()
Schedules a call to updatePaintNode() for this item.
void polish()
Schedules a polish event for this item.
static bool isScalableImageFormat(const QUrl &url)
static void parse(const QString &string, QTextLayout &layout, QList< QQuickStyledTextImgTag * > &imgTags, const QUrl &baseUrl, QQmlContext *context, bool preloadImages, bool *fontSizeModified)
void setWidth(qreal width)
void setFullLayoutTextLength(int length)
void setY(qreal y)
void setLine(QTextLine *line)
FINALbool isLast
void setLineOffset(int offset)
void setHeight(qreal height)
void setX(qreal x)
QQuickText::LineHeightMode lineHeightMode() const
qreal getImplicitHeight() const override
QVector< LinkDesc > getLinks() const
int minimumPixelSize() const
qreal padding() const
QLazilyAllocated< ExtraData > extra
qreal availableHeight() const
void setRightPadding(qreal value, bool reset=false)
void elideFormats(int start, int length, int offset, QVector< QTextLayout::FormatRange > *elidedFormats)
bool isLinkActivatedConnected()
bool transformChanged(QQuickItem *transformedItem) override
int minimumPointSize() const
void processHoverEvent(QHoverEvent *event)
QScopedPointer< QTextLayout > elideLayout
int maximumLineCount() const
void ensureDoc()
Ensures the QQuickTextPrivate::doc variable is set to a valid text document.
QScopedPointer< QQuickTextLine > textLine
QQuickText::RenderType renderType
qreal getImplicitWidth() const override
QQuickText::TextElideMode elideMode
QQuickText::WrapMode wrapMode
void setBottomPadding(qreal value, bool reset=false)
bool setHAlign(QQuickText::HAlignment, bool forceAlign=false)
qreal availableWidth() const
int lineHeightOffset() const
Returns the y offset when aligning text with a non-1.0 lineHeight.
void setTopPadding(qreal value, bool reset=false)
void mirrorChange() override
bool determineHorizontalAlignment()
QQuickText::VAlignment vAlign
static const int largeTextSizeThreshold
bool isLineLaidOutConnected()
QString elidedText(qreal lineWidth, const QTextLine &line, const QTextLine *nextLine=nullptr) const
qreal devicePixelRatio() const
void setLeftPadding(qreal value, bool reset=false)
bool isLinkHoveredConnected()
QQuickText::FontSizeMode fontSizeMode() const
void updateBaseline(qreal baseline, qreal dy)
static const QChar elideChar
void signalSizeChange(const QSizeF &previousSize)
void setLineGeometry(QTextLine &line, qreal lineWidth, qreal &height)
void setupCustomLineGeometry(QTextLine &line, qreal &height, int fullLayoutTextLength, int lineOffset=0)
qreal lineHeight() const
QStringList links() const
QQuickText::HAlignment hAlign
static QString anchorAt(const QTextLayout *layout, const QPointF &mousePos)
QRectF setupTextLayout(qreal *const baseline)
Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText.
static qreal alignedX(qreal textWidth, qreal itemWidth, int alignment)
static qreal alignedY(qreal textHeight, qreal itemHeight, int alignment)
void resetPadding()
QQuickText(QQuickItem *parent=nullptr)
\qmltype Text \instantiates QQuickText \inqmlmodule QtQuick\inherits Item
void verticalAlignmentChanged(QQuickText::VAlignment alignment)
void minimumPointSizeChanged()
void resetTopPadding()
void setBaseUrl(const QUrl &url)
void setRenderType(RenderType renderType)
void invalidate() override
void updatePolish() override
This function should perform any layout as required for this item.
QRectF boundingRect() const override
Returns the extents of the text after layout.
void setPadding(qreal padding)
int resourcesLoading() const
Returns the number of resources (images) that are being loaded asynchronously.
int minimumPixelSize
TextStyle style
void minimumPixelSizeChanged()
void setText(const QString &)
void setStyle(TextStyle style)
void setFont(const QFont &font)
void wrapModeChanged()
HAlignment effectiveHAlign() const
void textChanged(const QString &text)
void elideModeChanged(QQuickText::TextElideMode mode)
void setLeftPadding(qreal padding)
QRectF clipRect() const override
Returns a rectangular area slightly larger than what is currently visible in \l viewportItem(); other...
qreal topPadding
void setMinimumPixelSize(int size)
FontSizeMode fontSizeMode
qreal lineHeight
void setMaximumLineCount(int lines)
void lineHeightModeChanged(LineHeightMode mode)
TextFormat textFormat
void renderTypeChanged()
QColor linkColor
void mouseReleaseEvent(QMouseEvent *event) override
HAlignment hAlign() const
\qmlproperty enumeration QtQuick::Text::horizontalAlignment \qmlproperty enumeration QtQuick::Text::v...
void resetBaseUrl()
void fontSizeModeChanged()
void fontChanged(const QFont &font)
void setElideMode(TextElideMode)
WrapMode wrapMode
VAlignment vAlign() const
void setLineHeightMode(LineHeightMode)
void setLinkColor(const QColor &color)
void componentComplete() override
qreal padding
void setLineHeight(qreal lineHeight)
void setVAlign(VAlignment align)
void truncatedChanged()
void hoverLeaveEvent(QHoverEvent *event) override
This event handler can be reimplemented in a subclass to receive hover-leave events for an item.
void setHAlign(HAlignment align)
qreal rightPadding
int renderTypeQuality
void mousePressEvent(QMouseEvent *event) override
void setFontSizeMode(FontSizeMode mode)
void styleChanged(QQuickText::TextStyle style)
void styleColorChanged()
qreal leftPadding
void setTopPadding(qreal padding)
void baseUrlChanged()
TextElideMode elide
QSizeF advance
void linkColorChanged()
void textFormatChanged(QQuickText::TextFormat textFormat)
void setTextFormat(TextFormat format)
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override
void resetRightPadding()
TextElideMode elideMode() const
\qmlproperty enumeration QtQuick::Text::elide
void linkActivated(const QString &link)
int minimumPointSize
QSGNode * updatePaintNode(QSGNode *, UpdatePaintNodeData *) override
Called on the render thread when it is time to sync the state of the item with the scene graph.
qreal bottomPadding
QJSValue fontInfo
qreal contentHeight
void maximumLineCountChanged()
void setColor(const QColor &c)
void lineHeightChanged(qreal lineHeight)
void hoverMoveEvent(QHoverEvent *event) override
This event handler can be reimplemented in a subclass to receive hover-move events for an item.
void setRightPadding(qreal padding)
LineHeightMode lineHeightMode
QString hoveredLink
void setWrapMode(WrapMode w)
void invalidateFontCaches()
QString text
void resetHAlign()
void setBottomPadding(qreal padding)
QColor styleColor
void setMinimumPointSize(int size)
void setRenderTypeQuality(int renderTypeQuality)
void itemChange(ItemChange change, const ItemChangeData &value) override
Called when change occurs for this item.
QColor color
void setStyleColor(const QColor &c)
int maximumLineCount
void resetMaximumLineCount()
void resetLeftPadding()
void colorChanged()
RenderType renderType
qreal contentWidth
~QQuickText() override
void hoverEnterEvent(QHoverEvent *event) override
This event handler can be reimplemented in a subclass to receive hover-enter events for an item.
void resetBottomPadding()
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:732
constexpr qreal width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:729
constexpr void setTop(qreal pos) noexcept
Sets the top edge of the rectangle to the given finite y coordinate.
Definition qrect.h:681
constexpr void setHeight(qreal h) noexcept
Sets the height of the rectangle to the given finite height.
Definition qrect.h:821
constexpr void moveTop(qreal pos) noexcept
Moves the rectangle vertically, leaving the rectangle's top line at the given finite y coordinate.
Definition qrect.h:705
QRectF united(const QRectF &other) const noexcept
Definition qrect.h:852
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
void addImage(const QRectF &rect, const QImage &image)
void setTextStyle(TextStyle textStyle) override
Sets the style of the rendered text to textStyle.
void clear() override
Clears the contents of the node, deleting nodes and other data that represents the layouts and docume...
void setLinkColor(QColor linkColor) override
Sets the color of or hyperlinks to linkColor in the text.
void setFiltering(QSGTexture::Filtering filtering) override
Sets the sampling mode used when scaling images that are part of the displayed text to filtering.
void setRenderType(RenderType renderType) override
Sets the type of glyph node in use to renderType.
void setRenderTypeQuality(int renderTypeQuality) override
If the \l renderType() in use supports it, set the quality to use when rendering the text.
void setStyleColor(QColor styleColor) override
Sets the style color to use when rendering the text to styleColor.
void setColor(QColor color) override
Sets the main color to use when rendering the text to color.
void setViewport(const QRectF &viewport) override
Sets the bounding rect of the viewport where the text is displayed to viewport.
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
Definition qsgnode.h:37
void addTextLayout(QPointF position, QTextLayout *layout, int selectionStart=-1, int selectionCount=-1, int lineStart=0, int lineCount=-1)
Adds the contents of layout to the text node at position.
Definition qsgtextnode.h:67
void addTextDocument(QPointF position, QTextDocument *document, int selectionStart=-1, int selectionCount=-1)
Adds the contents of document to the text node at position.
Definition qsgtextnode.h:77
RenderType
This enum type describes type of glyph node used for rendering the text.
Definition qsgtextnode.h:29
TextStyle
This enum type describes styles that can be applied to text rendering.
Definition qsgtextnode.h:20
void setMatrix(const QMatrix4x4 &matrix)
Sets this transform node's matrix to matrix.
Definition qsgnode.cpp:1160
T * get() const noexcept
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
const_iterator cend() const noexcept
Definition qset.h:143
iterator erase(const_iterator i)
Definition qset.h:146
const_iterator cbegin() const noexcept
Definition qset.h:139
\inmodule QtCore
Definition qsize.h:208
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:332
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:335
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4522
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3829
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5307
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
bool isRightToLeft() const
Returns true if the string is read right to left.
Definition qstring.cpp:9319
void setLineHeight(qreal height, int heightType)
\reentrant
int lineCount() const
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QTextBlock next() const
Returns the text block in the document after this block, or an empty text block if this is the last o...
QTextLayout * layout() const
Returns the QTextLayout that is used to lay out and display the block's contents.
QTextBlock previous() const
Returns the text block in the document before this block, or an empty text block if this is the first...
\reentrant \inmodule QtGui
Definition qtextcursor.h:30
\reentrant \inmodule QtGui
ResourceType
This enum describes the types of resources that can be loaded by QTextDocument's loadResource() funct...
void setHtml(const QString &html)
Replaces the entire contents of the document with the given HTML-formatted text in the html string.
qreal idealWidth() const
void setDefaultTextOption(const QTextOption &option)
QAbstractTextDocumentLayout * documentLayout() const
Returns the document layout for this document.
QSizeF size
the actual size of the document. This is equivalent to documentLayout()->documentSize();
QTextBlock begin() const
Returns the document's first text block.
void setDefaultFont(const QFont &font)
Sets the default font to use in the document layout.
void setPageSize(const QSizeF &size)
QString toPlainText() const
Returns the plain text contained in the document.
QTextBlock end() const
This function returns a block to test for the end of the document while iterating over it.
QTextBlock firstBlock() const
void setPlainText(const QString &text)
Replaces the entire contents of the document with the given plain text.
QTextBlock lastBlock() const
void setTextWidth(qreal width)
QTextOption option
void resetFontEngineCache()
QString elidedText(Qt::TextElideMode mode, QFixed width, int flags=0, int from=0, int count=-1) const
\reentrant
Definition qtextlayout.h:70
const QTextOption & textOption() const
Returns the current text option used to control the layout process.
void setFont(const QFont &f)
Sets the layout's font to the given font.
QTextLine createLine()
Returns a new text line to be laid out if there is text to be inserted into the layout; otherwise ret...
void beginLayout()
Begins the layout process.
QTextEngine * engine() const
void setCacheEnabled(bool enable)
Enables caching of the complete layout information if enable is true; otherwise disables layout cachi...
void setFormats(const QList< FormatRange > &overrides)
void setText(const QString &string)
Sets the layout's text to the given string.
QList< FormatRange > formats() const
QString text() const
Returns the layout's text.
void clearFormats()
int lineCount() const
Returns the number of lines in this text layout.
qreal maximumWidth() const
The maximum width the layout could expand to; this is essentially the width of the entire text.
QTextLine lineAt(int i) const
Returns the {i}-th line of text in this text layout.
void setTextOption(const QTextOption &option)
Sets the text option structure that controls the layout process to the given option.
QFont font() const
Returns the current font that is used for the layout, or a default font if none is set.
void endLayout()
Ends the layout process.
void clearLayout()
QPointF position() const
\reentrant
int textStart() const
Returns the start of the line from the beginning of the string passed to the QTextLayout.
qreal height() const
Returns the line's height.
qreal naturalTextWidth() const
Returns the width of the line that is occupied by text.
qreal y() const
Returns the line's y position.
qreal width() const
Returns the line's width as specified by the layout() function.
void setPosition(const QPointF &pos)
Moves the line to position pos.
@ CursorOnCharacter
void setLineWidth(qreal width)
Lays out the line with the given width.
qreal ascent() const
Returns the line's ascent.
int lineNumber() const
Returns the position of the line in the text engine.
qreal x() const
Returns the line's x position.
int textLength() const
Returns the length of the text in the line.
\reentrant
Definition qtextoption.h:18
WrapMode wrapMode() const
Returns the text wrap mode defined by the option.
Definition qtextoption.h:68
Qt::Alignment alignment() const
Returns the text alignment defined by the option.
Definition qtextoption.h:55
void setWrapMode(WrapMode wrap)
Sets the option's text wrap mode to the given mode.
Definition qtextoption.h:67
void setUseDesignMetrics(bool b)
If enable is true then the layout will use design metrics; otherwise it will use the metrics of the p...
Definition qtextoption.h:91
void setAlignment(Qt::Alignment alignment)
Sets the option's text alignment to the specified alignment.
bool useDesignMetrics() const
Returns true if the layout uses design rather than device metrics; otherwise returns false.
Definition qtextoption.h:92
WrapMode
This enum describes how text is wrapped in a document.
Definition qtextoption.h:60
\inmodule QtCore
Definition qurl.h:94
bool isLocalFile() const
Definition qurl.cpp:3445
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition qurl.cpp:2725
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2831
\inmodule QtCore
Definition qvariant.h:65
QCursor cursor
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
rect
[4]
uint alignment
QRect textRect
EGLint EGLint * formats
Combined button and popup list for selecting options.
Definition qcompare.h:63
@ LeftButton
Definition qnamespace.h:58
@ NoButton
Definition qnamespace.h:57
@ RightToLeft
Q_GUI_EXPORT bool mightBeRichText(QAnyStringView)
Returns true if the string text is likely to be rich text; otherwise returns false.
TextElideMode
Definition qnamespace.h:188
Definition image.cpp:4
#define rgb(r, g, b)
Definition qcolor.cpp:124
#define qApp
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
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
Q_QML_EXPORT QJSEngine * qjsEngine(const QObject *)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
int qCeil(T v)
Definition qmath.h:36
QT_BEGIN_NAMESPACE constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:19
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:21
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
#define SLOT(a)
Definition qobjectdefs.h:52
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLint GLsizei width
GLuint color
[2]
GLenum type
GLbitfield flags
GLuint start
GLenum GLuint GLintptr offset
GLfloat n
GLint GLsizei GLsizei GLenum format
GLint y
GLsizei GLsizei GLchar * source
struct _cl_event * event
GLboolean reset
GLuint res
GLint void * img
Definition qopenglext.h:233
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
GLuint GLenum option
GLenum GLsizei len
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:72
#define IS_SIGNAL_CONNECTED(Sender, SenderType, Name, Arguments)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define QQUICKTEXT_LARGETEXT_THRESHOLD
static void getLinks_helper(const QTextLayout *layout, QVector< QQuickTextPrivate::LinkDesc > *links)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
#define QStringLiteral(str)
#define emit
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:187
bool testFlag(MaskType mask, FlagType flag)
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
QVBoxLayout * layout
QJSEngine engine
[0]
static constexpr QFixed fromReal(qreal r)
Definition qfixed_p.h:35
\inmodule QtCore \reentrant
Definition qchar.h:18
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...
QList< QQuickStyledTextImgTag * > imgTags
QList< QQuickStyledTextImgTag * > visibleImgTags
QQuickTextImageHandler * imageHandler
\inmodule QtQuick
Definition qquickitem.h:159