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
38Q_LOGGING_CATEGORY(lcText, "qt.quick.text")
39
40using namespace Qt::StringLiterals;
41
42const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
43
44#if !defined(QQUICKTEXT_LARGETEXT_THRESHOLD)
45 #define QQUICKTEXT_LARGETEXT_THRESHOLD 10000
46#endif
47// if QString::size() > largeTextSizeThreshold, we render more often, but only visible lines
49
51 : fontInfo(font), lineWidth(0)
52 , color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
53 , lineCount(1), multilengthEos(-1)
54 , elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
55 , format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap)
56 , style(QQuickText::Normal)
57 , renderType(QQuickTextUtil::textRenderType<QQuickText>())
58 , updateType(UpdatePaintNode)
59 , maximumLineCountValid(false), updateOnComponentComplete(true), richText(false)
60 , styledText(false), widthExceeded(false), heightExceeded(false), internalWidthUpdate(false)
61 , requireImplicitSize(false), implicitWidthValid(false), implicitHeightValid(false)
62 , truncated(false), hAlignImplicit(true), rightToLeftText(false)
63 , layoutTextElided(false), textHasChanged(true), needToUpdateLayout(false), formatModifiesFontSize(false)
64 , polishSize(false)
65 , updateSizeRecursionGuard(false)
66{
68}
69
71 : padding(0)
72 , topPadding(0)
73 , leftPadding(0)
74 , rightPadding(0)
75 , bottomPadding(0)
76 , explicitTopPadding(false)
77 , explicitLeftPadding(false)
78 , explicitRightPadding(false)
79 , explicitBottomPadding(false)
80 , lineHeight(1.0)
81 , doc(nullptr)
82 , minimumPixelSize(12)
83 , minimumPointSize(12)
84 , maximumLineCount(INT_MAX)
85 , renderTypeQuality(QQuickText::DefaultRenderTypeQuality)
86 , lineHeightValid(false)
87 , lineHeightMode(QQuickText::ProportionalHeight)
88 , fontSizeMode(QQuickText::FixedSize)
89{
90}
91
93{
94 Q_Q(QQuickText);
95 q->setAcceptedMouseButtons(Qt::LeftButton);
97 q->setFlag(QQuickItem::ItemObservesViewport); // default until size is known
98}
99
101{
102 if (extra.isAllocated()) {
103 qDeleteAll(extra->imgTags);
104 extra->imgTags.clear();
105 }
106}
107
109{
110 if (!requireImplicitSize) {
111 // We don't calculate implicitWidth unless it is required.
112 // We need to force a size update now to ensure implicitWidth is calculated
113 QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
114 me->requireImplicitSize = true;
115 me->updateSize();
116 }
117 return implicitWidth;
118}
119
121{
122 if (!requireImplicitSize) {
123 QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
124 me->requireImplicitSize = true;
125 me->updateSize();
126 }
127 return implicitHeight;
128}
129
131{
132 Q_Q(const QQuickText);
133 return q->width() - q->leftPadding() - q->rightPadding();
134}
135
137{
138 Q_Q(const QQuickText);
139 return q->height() - q->topPadding() - q->bottomPadding();
140}
141
143{
144 Q_Q(QQuickText);
145 qreal oldPadding = q->topPadding();
146 if (!reset || extra.isAllocated()) {
147 extra.value().topPadding = value;
148 extra.value().explicitTopPadding = !reset;
149 }
150 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
151 updateSize();
152 emit q->topPaddingChanged();
153 }
154}
155
157{
158 Q_Q(QQuickText);
159 qreal oldPadding = q->leftPadding();
160 if (!reset || extra.isAllocated()) {
161 extra.value().leftPadding = value;
162 extra.value().explicitLeftPadding = !reset;
163 }
164 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
165 updateSize();
166 emit q->leftPaddingChanged();
167 }
168}
169
171{
172 Q_Q(QQuickText);
173 qreal oldPadding = q->rightPadding();
174 if (!reset || extra.isAllocated()) {
175 extra.value().rightPadding = value;
176 extra.value().explicitRightPadding = !reset;
177 }
178 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
179 updateSize();
180 emit q->rightPaddingChanged();
181 }
182}
183
185{
186 Q_Q(QQuickText);
187 qreal oldPadding = q->bottomPadding();
188 if (!reset || extra.isAllocated()) {
189 extra.value().bottomPadding = value;
190 extra.value().explicitBottomPadding = !reset;
191 }
192 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
193 updateSize();
194 emit q->bottomPaddingChanged();
195 }
196}
197
207void QQuickText::q_updateLayout()
208{
209 Q_D(QQuickText);
210 d->updateLayout();
211}
212
214{
215 Q_Q(QQuickText);
216 if (!q->isComponentComplete()) {
218 return;
219 }
221 layoutTextElided = false;
222
223 if (extra.isAllocated())
224 extra->visibleImgTags.clear();
225 needToUpdateLayout = false;
226
227 // Setup instance of QTextLayout for all cases other than richtext
228 if (!richText) {
229 if (textHasChanged) {
230 if (styledText && !text.isEmpty()) {
232 // needs temporary bool because formatModifiesFontSize is in a bit-field
233 bool fontSizeModified = false;
234 QList<QQuickStyledTextImgTag*> someImgTags = extra.isAllocated() ? extra->imgTags : QList<QQuickStyledTextImgTag*>();
235 QQuickStyledText::parse(text, layout, someImgTags, q->baseUrl(), qmlContext(q), !maximumLineCountValid, &fontSizeModified);
236 if (someImgTags.size() || extra.isAllocated())
237 extra.value().imgTags = someImgTags;
238 formatModifiesFontSize = fontSizeModified;
239 multilengthEos = -1;
240 } else {
241 QString tmp = text;
242 multilengthEos = tmp.indexOf(QLatin1Char('\x9c'));
243 if (multilengthEos != -1)
244 tmp = tmp.mid(0, multilengthEos);
245 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
246 layout.setText(tmp);
247 }
248 textHasChanged = false;
249 }
250 } else if (extra.isAllocated() && extra->lineHeightValid) {
251 ensureDoc();
254 QTextBlockFormat blockFormat;
256 for (QTextBlock it = extra->doc->begin(); it != extra->doc->end(); it = it.next()) {
258 cursor.mergeBlockFormat(blockFormat);
259 }
260 }
261
262 updateSize();
263
264 if (needToUpdateLayout) {
265 needToUpdateLayout = false;
266 textHasChanged = true;
267 updateLayout();
268 }
269
270 q->polish();
271}
272
278QVariant QQuickText::loadResource(int type, const QUrl &source)
279{
280 Q_D(QQuickText);
281 const QUrl url = d->extra->doc->baseUrl().resolved(source);
282 if (url.isLocalFile()) {
283 // qmlWarning if the file doesn't exist (because QTextDocument::loadResource() can't do that)
285 if (!fi.exists())
286 qmlWarning(this) << "Cannot open: " << url.toString();
287 // let QTextDocument::loadResource() handle local file loading
288 return {};
289 }
290 // see if we already started a load job
291 for (auto it = d->extra->pixmapsInProgress.cbegin(); it != d->extra->pixmapsInProgress.cend();) {
292 auto *job = *it;
293 if (job->url() == url) {
294 if (job->isError()) {
295 qmlWarning(this) << job->error();
296 delete *it;
297 it = d->extra->pixmapsInProgress.erase(it);
298 return QImage();
299 }
300 qCDebug(lcText) << "already downloading" << url;
301 // existing job: return a null variant if it's not done yet
302 return job->isReady() ? job->image() : QVariant();
303 }
304 ++it;
305 }
306 qCDebug(lcText) << "loading" << source << "resolved" << url
307 << "type" << static_cast<QTextDocument::ResourceType>(type);
310 // don't cache it in QQuickPixmapCache, because it's cached in QTextDocumentPrivate::cachedResources
311 QQuickPixmap *p = new QQuickPixmap(context->engine(), url, QQuickPixmap::Options{});
312 p->connectFinished(this, SLOT(resourceRequestFinished()));
313 d->extra->pixmapsInProgress.append(p);
314 // the new job is probably not done; return a null variant if the caller should poll again
315 return p->isReady() ? p->image() : QVariant();
316}
317
321void QQuickText::resourceRequestFinished()
322{
323 Q_D(QQuickText);
324 bool allDone = true;
325 for (auto it = d->extra->pixmapsInProgress.cbegin(); it != d->extra->pixmapsInProgress.cend();) {
326 auto *job = *it;
327 if (job->isError()) {
328 // get QTextDocument::loadResource() to call QQuickText::loadResource() again, to return the placeholder
329 qCDebug(lcText) << "failed to load" << job->url();
330 d->extra->doc->resource(QTextDocument::ImageResource, job->url());
331 } else if (job->isReady()) {
332 // get QTextDocument::loadResource() to call QQuickText::loadResource() again, and cache the result
333 auto res = d->extra->doc->resource(QTextDocument::ImageResource, job->url());
334 // If QTextDocument::resource() returned a valid variant, it's been cached too. Either way, the job is done.
335 qCDebug(lcText) << (res.isValid() ? "done downloading" : "failed to load") << job->url();
336 delete *it;
337 it = d->extra->pixmapsInProgress.erase(it);
338 } else {
339 allDone = false;
340 ++it;
341 }
342 }
343 if (allDone) {
344 Q_ASSERT(d->extra->pixmapsInProgress.isEmpty());
345 d->updateLayout();
346 }
347}
348
352void QQuickText::imageDownloadFinished()
353{
354 Q_D(QQuickText);
355 if (!d->extra.isAllocated())
356 return;
357
358 if (std::any_of(d->extra->imgTags.cbegin(), d->extra->imgTags.cend(),
359 [] (auto *image) { return image->pix && image->pix->isLoading(); })) {
360 // return if we still have any active download
361 return;
362 }
363
364 // when all the remote images have been downloaded,
365 // if one of the sizes was not specified at parsing time
366 // we use the implicit size from pixmapcache and re-layout.
367
368 bool needToUpdateLayout = false;
369 for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
370 if (!img->size.isValid()) {
371 img->size = img->pix->implicitSize();
372 needToUpdateLayout = true;
373 }
374 }
375
376 if (needToUpdateLayout) {
377 d->textHasChanged = true;
378 d->updateLayout();
379 } else {
381 update();
382 }
383}
384
386{
387 Q_Q(QQuickText);
388
389 qreal yoff = 0;
390
391 if (q->heightValid()) {
393 yoff = dy;
395 yoff = dy/2;
396 }
397
398 q->setBaselineOffset(baseline + yoff + q->topPadding());
399}
400
402{
403 Q_Q(QQuickText);
404 const QSizeF contentSize(q->contentWidth(), q->contentHeight());
405
406 if (contentSize != previousSize) {
407 emit q->contentSizeChanged();
408 if (contentSize.width() != previousSize.width())
409 emit q->contentWidthChanged(contentSize.width());
410 if (contentSize.height() != previousSize.height())
411 emit q->contentHeightChanged(contentSize.height());
412 }
413}
414
416{
417 Q_Q(QQuickText);
418
419 if (!q->isComponentComplete()) {
421 return;
422 }
423
424 if (!requireImplicitSize) {
427 // if the implicitWidth is used, then updateSize() has already been called (recursively)
429 return;
430 }
431
432 qreal hPadding = q->leftPadding() + q->rightPadding();
433 qreal vPadding = q->topPadding() + q->bottomPadding();
434
435 const QSizeF previousSize(q->contentWidth(), q->contentHeight());
436
438 // How much more expensive is it to just do a full layout on an empty string here?
439 // There may be subtle differences in the height and baseline calculations between
440 // QTextLayout and QFontMetrics and the number of variables that can affect the size
441 // and position of a line is increasing.
443 qreal fontHeight = qCeil(fm.height()); // QScriptLine and therefore QTextLine rounds up
444 if (!richText) { // line height, so we will as well.
446 ? lineHeight()
447 : fontHeight * lineHeight();
448 }
449 updateBaseline(fm.ascent(), q->height() - fontHeight - vPadding);
450 q->setImplicitSize(hPadding, fontHeight + qMax(lineHeightOffset(), 0) + vPadding);
451 layedOutTextRect = QRectF(0, 0, 0, fontHeight);
452 advance = QSizeF();
453 signalSizeChange(previousSize);
454 lineCount = 1;
455 emit q->lineCountChanged();
457 q->update();
458 return;
459 }
460
461 QSizeF size(0, 0);
462
463 //setup instance of QTextLayout for all cases other than richtext
464 if (!richText) {
465 qreal baseline = 0;
467
468 if (internalWidthUpdate) // probably the result of a binding loop, but by letting it
469 return; // get this far we'll get a warning to that effect if it is.
470
472 size = textRect.size();
473 updateBaseline(baseline, q->height() - size.height() - vPadding);
474 } else {
475 widthExceeded = true; // always relayout rich text on width changes..
476 heightExceeded = false; // rich text layout isn't affected by height changes.
477 ensureDoc();
478 extra->doc->setDefaultFont(font);
479 QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
480 if (rightToLeftText) {
481 if (horizontalAlignment == QQuickText::AlignLeft)
482 horizontalAlignment = QQuickText::AlignRight;
483 else if (horizontalAlignment == QQuickText::AlignRight)
484 horizontalAlignment = QQuickText::AlignLeft;
485 }
487 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
489 option.setUseDesignMetrics(renderType != QQuickText::NativeRendering);
490 extra->doc->setDefaultTextOption(option);
491 qreal naturalWidth = 0;
492 if (requireImplicitSize && q->widthValid()) {
493 extra->doc->setTextWidth(-1);
494 naturalWidth = extra->doc->idealWidth();
495 const bool wasInLayout = internalWidthUpdate;
496 internalWidthUpdate = true;
497 q->setImplicitWidth(naturalWidth + hPadding);
498 internalWidthUpdate = wasInLayout;
499 }
501 return;
502
503 extra->doc->setPageSize(QSizeF(q->width(), -1));
504 if (q->widthValid() && (wrapMode != QQuickText::NoWrap || extra->doc->idealWidth() < availableWidth()))
505 extra->doc->setTextWidth(availableWidth());
506 else
507 extra->doc->setTextWidth(extra->doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
508
509 QSizeF dsize = extra->doc->size();
510 layedOutTextRect = QRectF(QPointF(0,0), dsize);
511 size = QSizeF(extra->doc->idealWidth(),dsize.height());
512
513
515 QTextBlock firstBlock = extra->doc->firstBlock();
516 if (firstBlock.isValid() && firstBlock.layout() != nullptr && firstBlock.lineCount() > 0)
517 baseline = firstBlock.layout()->lineAt(0).ascent();
518
519 updateBaseline(baseline, q->height() - size.height() - vPadding);
520
521 //### need to confirm cost of always setting these for richText
522 internalWidthUpdate = true;
523 qreal oldWidth = q->width();
524 qreal iWidth = -1;
525 if (!q->widthValid())
526 iWidth = size.width();
527 if (iWidth > -1)
528 q->setImplicitSize(iWidth + hPadding, size.height() + qMax(lineHeightOffset(), 0) + vPadding);
529 internalWidthUpdate = false;
530
531 // If the implicit width update caused a recursive change of the width,
532 // we will have skipped integral parts of the layout due to the
533 // internalWidthUpdate recursion guard. To make sure everything is up
534 // to date, we need to run a second pass over the layout when updateSize()
535 // is done.
536 if (!qFuzzyCompare(q->width(), oldWidth) && !updateSizeRecursionGuard) {
538 updateSize();
540 } else {
541 if (iWidth == -1)
542 q->setImplicitHeight(size.height() + lineHeightOffset() + vPadding);
543
544 QTextBlock firstBlock = extra->doc->firstBlock();
545 while (firstBlock.layout()->lineCount() == 0)
546 firstBlock = firstBlock.next();
547
548 QTextBlock lastBlock = extra->doc->lastBlock();
549 while (lastBlock.layout()->lineCount() == 0)
550 lastBlock = lastBlock.previous();
551
552 if (firstBlock.lineCount() > 0 && lastBlock.lineCount() > 0) {
553 QTextLine firstLine = firstBlock.layout()->lineAt(0);
554 QTextLine lastLine = lastBlock.layout()->lineAt(lastBlock.layout()->lineCount() - 1);
555 advance = QSizeF(lastLine.horizontalAdvance(),
556 (lastLine.y() + lastBlock.layout()->position().y() + lastLine.ascent()) - (firstLine.y() + firstBlock.layout()->position().y() + firstLine.ascent()));
557 } else {
558 advance = QSizeF();
559 }
560 }
561 }
562
563 signalSizeChange(previousSize);
565 q->update();
566}
567
569 : QObject(), m_line(nullptr), m_height(0), m_lineOffset(0)
570{
571}
572
574{
575 m_line = line;
576}
577
579{
580 m_lineOffset = offset;
581}
582
584{
585 m_fullLayoutTextLength = length;
586}
587
589{
590 if (m_line)
591 return m_line->lineNumber() + m_lineOffset;
592 return 0;
593}
594
596{
597 if (m_line)
598 return m_line->naturalTextWidth();
599 return 0;
600}
601
603{
604 if (m_line && (m_line->textStart() + m_line->textLength()) == m_fullLayoutTextLength) {
605 // Ensure that isLast will change if the user reduced the width of the line
606 // so that the text no longer fits.
607 return m_line->width() >= m_line->naturalTextWidth();
608 }
609
610 return false;
611}
612
614{
615 if (m_line)
616 return m_line->width();
617 return 0;
618}
619
621{
622 if (m_line)
623 m_line->setLineWidth(width);
624}
625
627{
628 if (m_height)
629 return m_height;
630 if (m_line)
631 return m_line->height();
632 return 0;
633}
634
636{
637 if (m_line)
638 m_line->setPosition(QPointF(m_line->x(), m_line->y() - m_line->height() + height));
639 m_height = height;
640}
641
643{
644 if (m_line)
645 return m_line->x();
646 return 0;
647}
648
650{
651 if (m_line)
652 m_line->setPosition(QPointF(x, m_line->y()));
653}
654
656{
657 if (m_line)
658 return m_line->y();
659 return 0;
660}
661
663{
664 if (m_line)
665 m_line->setPosition(QPointF(m_line->x(), y));
666}
667
673
674void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, int fullLayoutTextLength, int lineOffset)
675{
676 Q_Q(QQuickText);
677
678 if (!textLine)
680 textLine->setFullLayoutTextLength(fullLayoutTextLength);
684 textLine->setLineOffset(lineOffset);
685
686 // use the text item's width by default if it has one and wrap is on or text must be aligned
687 if (q->widthValid() && (q->wrapMode() != QQuickText::NoWrap ||
688 q->effectiveHAlign() != QQuickText::AlignLeft))
690 else
691 textLine->setWidth(INT_MAX);
692 if (lineHeight() != 1.0)
694
695 emit q->lineLaidOut(textLine.get());
696
697 height += textLine->height();
698}
699
701 const int start, const int length, int offset, QVector<QTextLayout::FormatRange> *elidedFormats)
702{
703 const int end = start + length;
704 const QVector<QTextLayout::FormatRange> formats = layout.formats();
705 for (int i = 0; i < formats.size(); ++i) {
707 const int formatLength = qMin(format.start + format.length, end) - qMax(format.start, start);
708 if (formatLength > 0) {
709 format.start = qMax(offset, format.start - start + offset);
710 format.length = formatLength;
711 elidedFormats->append(format);
712 }
713 }
714}
715
716QString QQuickTextPrivate::elidedText(qreal lineWidth, const QTextLine &line, const QTextLine *nextLine) const
717{
718 if (nextLine) {
719 return layout.engine()->elidedText(
722 0,
723 line.textStart(),
724 line.textLength() + nextLine->textLength());
725 } else {
726 QString elideText = layout.text().mid(line.textStart(), line.textLength());
727 if (!styledText) {
728 // QFontMetrics won't help eliding styled text.
729 elideText[elideText.size() - 1] = elideChar;
730 // Appending the elide character may push the line over the maximum width
731 // in which case the elided text will need to be elided.
733 if (metrics.horizontalAdvance(elideChar) + line.naturalTextWidth() >= lineWidth)
734 elideText = metrics.elidedText(elideText, Qt::TextElideMode(elideMode), lineWidth);
735 }
736 return elideText;
737 }
738}
739
746
755{
756 Q_Q(QQuickText);
757
758 bool singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
759 bool multilineElide = elideMode == QQuickText::ElideRight
760 && q->widthValid()
761 && (q->heightValid() || maximumLineCountValid);
762
764 && ((singlelineElide && availableWidth() <= 0.)
765 || (multilineElide && q->heightValid() && availableHeight() <= 0.))) {
766 // we are elided and we have a zero width or height
767 widthExceeded = q->widthValid() && availableWidth() <= 0.;
768 heightExceeded = q->heightValid() && availableHeight() <= 0.;
769
770 if (!truncated) {
771 truncated = true;
772 emit q->truncatedChanged();
773 }
774 if (lineCount) {
775 lineCount = 0;
776 q->setFlag(QQuickItem::ItemObservesViewport, false);
777 emit q->lineCountChanged();
778 }
779
780 if (qFuzzyIsNull(q->width())) {
782 textHasChanged = true;
783 }
784
787 *baseline = fm.ascent();
788 return QRectF(0, 0, 0, height);
789 }
790
791 bool shouldUseDesignMetrics = renderType != QQuickText::NativeRendering;
792 if (extra.isAllocated())
793 extra->visibleImgTags.clear();
795 QTextOption textOption = layout.textOption();
796 if (textOption.alignment() != q->effectiveHAlign()
797 || textOption.wrapMode() != QTextOption::WrapMode(wrapMode)
798 || textOption.useDesignMetrics() != shouldUseDesignMetrics) {
799 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
801 textOption.setUseDesignMetrics(shouldUseDesignMetrics);
802 layout.setTextOption(textOption);
803 }
804 if (layout.font() != font)
806
807 lineWidth = (q->widthValid() || implicitWidthValid) && q->width() > 0
808 ? q->width()
809 : FLT_MAX;
810 qreal maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
811
812 const bool customLayout = isLineLaidOutConnected();
813 const bool wasTruncated = truncated;
814
815 bool canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
816
817 bool horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
818 bool verticalFit = fontSizeMode() & QQuickText::VerticalFit
819 && (q->heightValid() || (maximumLineCountValid && canWrap));
820
821 const bool pixelSize = font.pixelSize() != -1;
822 QString layoutText = layout.text();
823
824 const qreal minimumSize = pixelSize
825 ? static_cast<qreal>(minimumPixelSize())
827 qreal largeFont = pixelSize ? font.pixelSize() : font.pointSizeF();
829 ? qMin<qreal>(minimumSize, largeFont)
830 : largeFont;
831 qreal scaledFontSize = largeFont;
832 const qreal sizeFittingThreshold(0.01);
833
834 bool widthChanged = false;
835 widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit);
836 heightExceeded = availableHeight() <= 0 && (multilineElide || verticalFit);
837
838 QRectF br;
839
840 QFont scaledFont = font;
841
842 int visibleCount = 0;
843 bool elide;
844 qreal height = 0;
845 QString elideText;
846 bool once = true;
847 int elideStart = 0;
848 int elideEnd = 0;
849 bool noBreakLastLine = multilineElide && (wrapMode == QQuickText::Wrap || wrapMode == QQuickText::WordWrap);
850
851 int eos = multilengthEos;
852
853 // Repeated layouts with reduced font sizes or abbreviated strings may be required if the text
854 // doesn't fit within the item dimensions, or a binding to implicitWidth/Height changes
855 // the item dimensions.
856 for (;;) {
857 if (!once) {
858 if (pixelSize)
859 scaledFont.setPixelSize(scaledFontSize);
860 else
861 scaledFont.setPointSizeF(scaledFontSize);
862 if (layout.font() != scaledFont)
863 layout.setFont(scaledFont);
864 }
865
867
868 bool wrapped = false;
869 bool truncateHeight = false;
870 truncated = false;
871 elide = false;
872 int unwrappedLineCount = 1;
873 const int maxLineCount = maximumLineCount();
874 height = 0;
875 qreal naturalHeight = 0;
876 qreal previousHeight = 0;
877 br = QRectF();
878
879 QRectF unelidedRect;
881 for (visibleCount = 1; ; ++visibleCount) {
883
884 if (noBreakLastLine && visibleCount == maxLineCount)
886 if (customLayout) {
887 setupCustomLineGeometry(line, naturalHeight, layoutText.size());
888 } else {
889 setLineGeometry(line, lineWidth, naturalHeight);
890 }
891 if (noBreakLastLine && visibleCount == maxLineCount)
893
894 unelidedRect = br.united(line.naturalTextRect());
895
896 // Elide the previous line if the accumulated height of the text exceeds the height
897 // of the element.
898 if (multilineElide && naturalHeight > maxHeight && visibleCount > 1) {
899 elide = true;
900 heightExceeded = true;
901 if (eos != -1) // There's an abbreviated string available, skip the rest as it's
902 break; // all going to be discarded.
903
904 truncated = true;
905 truncateHeight = true;
906
907 visibleCount -= 1;
908
909 const QTextLine previousLine = layout.lineAt(visibleCount - 1);
910 elideText = layoutText.at(line.textStart() - 1) != QChar::LineSeparator
911 ? elidedText(line.width(), previousLine, &line)
912 : elidedText(line.width(), previousLine);
913 elideStart = previousLine.textStart();
914 // elideEnd isn't required for right eliding.
915
916 height = previousHeight;
917 break;
918 }
919
920 const bool isLastLine = line.textStart() + line.textLength() >= layoutText.size();
921 if (isLastLine) {
922 if (singlelineElide && visibleCount == 1 && line.naturalTextWidth() > line.width()) {
923 // Elide a single previousLine of text if its width exceeds the element width.
924 elide = true;
925 widthExceeded = true;
926 if (eos != -1) // There's an abbreviated string available.
927 break;
928
929 truncated = true;
930 elideText = layout.engine()->elidedText(
932 QFixed::fromReal(line.width()),
933 0,
934 line.textStart(),
935 line.textLength());
936 elideStart = line.textStart();
937 elideEnd = elideStart + line.textLength();
938 } else {
939 br = unelidedRect;
940 height = naturalHeight;
941 }
942 break;
943 } else {
944 const bool wrappedLine = layoutText.at(line.textStart() + line.textLength() - 1) != QChar::LineSeparator;
945 wrapped |= wrappedLine;
946
947 if (!wrappedLine)
948 ++unwrappedLineCount;
949
950 // Stop if the maximum number of lines has been reached
951 if (visibleCount == maxLineCount) {
952 truncated = true;
953 heightExceeded |= wrapped;
954
955 if (multilineElide) {
956 elide = true;
957 if (eos != -1) // There's an abbreviated string available
958 break;
959
960 const QTextLine nextLine = layout.createLine();
961 elideText = wrappedLine
962 ? elidedText(line.width(), line, &nextLine)
963 : elidedText(line.width(), line);
964 elideStart = line.textStart();
965 // elideEnd isn't required for right eliding.
966 } else {
967 br = unelidedRect;
968 height = naturalHeight;
969 }
970 break;
971 }
972 }
973 br = unelidedRect;
974 previousHeight = height;
975 height = naturalHeight;
976 }
977 widthExceeded |= wrapped;
978
979 // Save the implicit size of the text on the first layout only.
980 if (once) {
981 once = false;
982
983 // If implicit sizes are required layout any additional lines up to the maximum line
984 // count.
985 if ((requireImplicitSize) && line.isValid() && unwrappedLineCount < maxLineCount) {
986 // Layout the remainder of the wrapped lines up to maxLineCount to get the implicit
987 // height.
988 for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
990 if (!line.isValid())
991 break;
992 if (layoutText.at(line.textStart() - 1) == QChar::LineSeparator)
993 ++unwrappedLineCount;
994 setLineGeometry(line, lineWidth, naturalHeight);
995 }
996
997 // Create the remainder of the unwrapped lines up to maxLineCount to get the
998 // implicit width.
999 const int eol = line.isValid()
1000 ? line.textStart() + line.textLength()
1001 : layoutText.size();
1002 if (eol < layoutText.size() && layoutText.at(eol) != QChar::LineSeparator)
1004 for (; line.isValid() && unwrappedLineCount <= maxLineCount; ++unwrappedLineCount)
1006 }
1007 layout.endLayout();
1008
1009 const qreal naturalWidth = layout.maximumWidth();
1010
1011 bool wasInLayout = internalWidthUpdate;
1012 internalWidthUpdate = true;
1013 q->setImplicitSize(naturalWidth + q->leftPadding() + q->rightPadding(), naturalHeight + qMax(lineHeightOffset(), 0) + q->topPadding() + q->bottomPadding());
1014 internalWidthUpdate = wasInLayout;
1015
1016 // Update any variables that are dependent on the validity of the width or height.
1017 singlelineElide = elideMode != QQuickText::ElideNone && q->widthValid();
1018 multilineElide = elideMode == QQuickText::ElideRight
1019 && q->widthValid()
1020 && (q->heightValid() || maximumLineCountValid);
1021 canWrap = wrapMode != QQuickText::NoWrap && q->widthValid();
1022
1023 horizontalFit = fontSizeMode() & QQuickText::HorizontalFit && q->widthValid();
1024 verticalFit = fontSizeMode() & QQuickText::VerticalFit
1025 && (q->heightValid() || (maximumLineCountValid && canWrap));
1026
1027 const qreal oldWidth = lineWidth;
1028 const qreal oldHeight = maxHeight;
1029
1030 const qreal availWidth = availableWidth();
1031 const qreal availHeight = availableHeight();
1032
1033 lineWidth = q->widthValid() && q->width() > 0 ? availWidth : naturalWidth;
1034 maxHeight = q->heightValid() ? availHeight : FLT_MAX;
1035
1036 // If the width of the item has changed and it's possible the result of wrapping,
1037 // eliding, scaling has changed, or the text is not left aligned do another layout.
1038 if ((!qFuzzyCompare(lineWidth, oldWidth) || (widthExceeded && lineWidth > oldWidth))
1039 && (singlelineElide || multilineElide || canWrap || horizontalFit
1040 || q->effectiveHAlign() != QQuickText::AlignLeft)) {
1041 widthChanged = true;
1042 widthExceeded = lineWidth >= qMin(oldWidth, naturalWidth);
1043 heightExceeded = false;
1044 continue;
1045 }
1046
1047 // If the height of the item has changed and it's possible the result of eliding,
1048 // line count truncation or scaling has changed, do another layout.
1049 if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
1050 && (multilineElide || (canWrap && maximumLineCountValid))) {
1051 widthExceeded = false;
1052 heightExceeded = false;
1053 continue;
1054 }
1055
1056 // If the horizontal alignment is not left and the width was not valid we need to relayout
1057 // now that we know the maximum line width.
1058 if (!q->widthValid() && !implicitWidthValid && unwrappedLineCount > 1 && q->effectiveHAlign() != QQuickText::AlignLeft) {
1059 widthExceeded = false;
1060 heightExceeded = false;
1061 continue;
1062 }
1063 } else if (widthChanged) {
1064 widthChanged = false;
1065 if (line.isValid()) {
1066 for (int lineCount = layout.lineCount(); lineCount < maxLineCount; ++lineCount) {
1068 if (!line.isValid())
1069 break;
1070 setLineGeometry(line, lineWidth, naturalHeight);
1071 }
1072 }
1073 layout.endLayout();
1074
1075 bool wasInLayout = internalWidthUpdate;
1076 internalWidthUpdate = true;
1077 q->setImplicitHeight(naturalHeight + qMax(lineHeightOffset(), 0) + q->topPadding() + q->bottomPadding());
1078 internalWidthUpdate = wasInLayout;
1079
1080 multilineElide = elideMode == QQuickText::ElideRight
1081 && q->widthValid()
1082 && (q->heightValid() || maximumLineCountValid);
1083 verticalFit = fontSizeMode() & QQuickText::VerticalFit
1084 && (q->heightValid() || (maximumLineCountValid && canWrap));
1085
1086 const qreal oldHeight = maxHeight;
1087 maxHeight = q->heightValid() ? availableHeight() : FLT_MAX;
1088 // If the height of the item has changed and it's possible the result of eliding,
1089 // line count truncation or scaling has changed, do another layout.
1090 if ((maxHeight < qMin(oldHeight, naturalHeight) || (heightExceeded && maxHeight > oldHeight))
1091 && (multilineElide || (canWrap && maximumLineCountValid))) {
1092 widthExceeded = false;
1093 heightExceeded = false;
1094 continue;
1095 }
1096 } else {
1097 layout.endLayout();
1098 }
1099
1100 // If the next needs to be elided and there's an abbreviated string available
1101 // go back and do another layout with the abbreviated string.
1102 if (eos != -1 && elide) {
1103 int start = eos + 1;
1104 eos = text.indexOf(QLatin1Char('\x9c'), start);
1105 layoutText = text.mid(start, eos != -1 ? eos - start : -1);
1106 layoutText.replace(QLatin1Char('\n'), QChar::LineSeparator);
1107 layout.setText(layoutText);
1108 textHasChanged = true;
1109 continue;
1110 }
1111
1112 br.moveTop(0);
1113
1114 // Find the advance of the text layout
1115 if (layout.lineCount() > 0) {
1116 QTextLine firstLine = layout.lineAt(0);
1117 QTextLine lastLine = layout.lineAt(layout.lineCount() - 1);
1118 advance = QSizeF(lastLine.horizontalAdvance(),
1119 lastLine.y() - firstLine.y());
1120 } else {
1121 advance = QSizeF();
1122 }
1123
1124 if (!horizontalFit && !verticalFit)
1125 break;
1126
1127 // Can't find a better fit
1128 if (qFuzzyCompare(smallFont, largeFont))
1129 break;
1130
1131 // Try and find a font size that better fits the dimensions of the element.
1132 if (horizontalFit) {
1133 if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
1134 widthExceeded = true;
1135 largeFont = scaledFontSize;
1136
1137 scaledFontSize = (smallFont + largeFont) / 2;
1138
1139 continue;
1140 } else if (!verticalFit) {
1141 smallFont = scaledFontSize;
1142
1143 // Check to see if the current scaledFontSize is acceptable
1144 if ((largeFont - smallFont) < sizeFittingThreshold)
1145 break;
1146
1147 scaledFontSize = (smallFont + largeFont) / 2;
1148 }
1149 }
1150
1151 if (verticalFit) {
1152 if (truncateHeight || unelidedRect.height() > maxHeight) {
1153 heightExceeded = true;
1154 largeFont = scaledFontSize;
1155
1156 scaledFontSize = (smallFont + largeFont) / 2;
1157
1158 } else {
1159 smallFont = scaledFontSize;
1160
1161 // Check to see if the current scaledFontSize is acceptable
1162 if ((largeFont - smallFont) < sizeFittingThreshold)
1163 break;
1164
1165 scaledFontSize = (smallFont + largeFont) / 2;
1166 }
1167 }
1168 }
1169
1170 implicitWidthValid = true;
1171 implicitHeightValid = true;
1172
1173 QFontInfo scaledFontInfo(scaledFont);
1174 if (fontInfo.weight() != scaledFontInfo.weight()
1175 || fontInfo.pixelSize() != scaledFontInfo.pixelSize()
1176 || fontInfo.italic() != scaledFontInfo.italic()
1177 || !qFuzzyCompare(fontInfo.pointSizeF(), scaledFontInfo.pointSizeF())
1178 || fontInfo.family() != scaledFontInfo.family()
1179 || fontInfo.styleName() != scaledFontInfo.styleName()) {
1180 fontInfo = scaledFontInfo;
1181 emit q->fontInfoChanged();
1182 }
1183
1184 if (eos != multilengthEos)
1185 truncated = true;
1186
1188
1189 if (elide) {
1190 if (!elideLayout) {
1193 }
1195 if (engine && engine->hasFormats()) {
1196 QVector<QTextLayout::FormatRange> formats;
1197 switch (elideMode) {
1199 elideFormats(elideStart, elideText.size() - 1, 0, &formats);
1200 break;
1202 elideFormats(elideEnd - elideText.size() + 1, elideText.size() - 1, 1, &formats);
1203 break;
1205 const int index = elideText.indexOf(elideChar);
1206 if (index != -1) {
1207 elideFormats(elideStart, index, 0, &formats);
1209 elideEnd - elideText.size() + index + 1,
1210 elideText.size() - index - 1,
1211 index + 1,
1212 &formats);
1213 }
1214 break;
1215 }
1216 default:
1217 break;
1218 }
1220 }
1221
1224 elideLayout->setText(elideText);
1226
1227 QTextLine elidedLine = elideLayout->createLine();
1228 elidedLine.setPosition(QPointF(0, height));
1229 if (customLayout) {
1230 setupCustomLineGeometry(elidedLine, height, elideText.size(), visibleCount - 1);
1231 } else {
1232 setLineGeometry(elidedLine, lineWidth, height);
1233 }
1235
1236 br = br.united(elidedLine.naturalTextRect());
1237
1238 if (visibleCount == 1)
1240 } else {
1242 }
1243
1244 QTextLine firstLine = visibleCount == 1 && elideLayout
1245 ? elideLayout->lineAt(0)
1246 : layout.lineAt(0);
1247 if (firstLine.isValid())
1248 *baseline = firstLine.y() + firstLine.ascent();
1249
1250 if (!customLayout)
1251 br.setHeight(height);
1252
1253 //Update the number of visible lines
1254 if (lineCount != visibleCount) {
1255 lineCount = visibleCount;
1256 emit q->lineCountChanged();
1257 }
1258
1259 if (truncated != wasTruncated)
1260 emit q->truncatedChanged();
1261
1262 return br;
1263}
1264
1266{
1267 Q_Q(QQuickText);
1268 line.setLineWidth(lineWidth);
1269
1270 if (extra.isAllocated() && extra->imgTags.isEmpty()) {
1271 line.setPosition(QPointF(line.position().x(), height));
1273 return;
1274 }
1275
1276 qreal textTop = 0;
1277 qreal textHeight = line.height();
1278 qreal totalLineHeight = textHeight;
1279
1280 QList<QQuickStyledTextImgTag *> imagesInLine;
1281
1282 if (extra.isAllocated()) {
1283 for (QQuickStyledTextImgTag *image : std::as_const(extra->imgTags)) {
1284 if (image->position >= line.textStart() &&
1285 image->position < line.textStart() + line.textLength()) {
1286
1287 if (!image->pix) {
1288 const QQmlContext *context = qmlContext(q);
1289 const QUrl url = context->resolvedUrl(q->baseUrl()).resolved(image->url);
1290 image->pix.reset(new QQuickPixmap(context->engine(), url, QRect(), image->size * devicePixelRatio()));
1291
1292 if (image->pix->isLoading()) {
1293 image->pix->connectFinished(q, SLOT(imageDownloadFinished()));
1294 } else if (image->pix->isReady()) {
1295 if (!image->size.isValid()) {
1296 image->size = image->pix->implicitSize();
1297 // if the size of the image was not explicitly set, we need to
1298 // call updateLayout() once again.
1299 needToUpdateLayout = true;
1300 }
1301 } else if (image->pix->isError()) {
1302 qmlWarning(q) << image->pix->error();
1303 }
1304 }
1305
1306 qreal ih = qreal(image->size.height());
1307 if (image->align == QQuickStyledTextImgTag::Top)
1308 image->pos.setY(0);
1309 else if (image->align == QQuickStyledTextImgTag::Middle)
1310 image->pos.setY((textHeight / 2.0) - (ih / 2.0));
1311 else
1312 image->pos.setY(textHeight - ih);
1313 imagesInLine << image;
1314 textTop = qMax(textTop, qAbs(image->pos.y()));
1315 }
1316 }
1317 }
1318
1319 for (QQuickStyledTextImgTag *image : std::as_const(imagesInLine)) {
1320 totalLineHeight = qMax(totalLineHeight, textTop + image->pos.y() + image->size.height());
1321 const int leadX = line.cursorToX(image->position);
1322 const int trailX = line.cursorToX(image->position, QTextLine::Trailing);
1323 const bool rtl = trailX < leadX;
1324 image->pos.setX(leadX + (rtl ? (-image->offset - image->size.width()) : image->offset));
1325 image->pos.setY(image->pos.y() + height + textTop);
1326 extra->visibleImgTags << image;
1327 }
1328
1329 line.setPosition(QPointF(line.position().x(), height + textTop));
1330 height += (lineHeightMode() == QQuickText::FixedHeight) ? lineHeight() : totalLineHeight * lineHeight();
1331}
1332
1337{
1338 QFontMetricsF fm(font);
1339 qreal fontHeight = qCeil(fm.height()); // QScriptLine and therefore QTextLine rounds up
1340 return lineHeightMode() == QQuickText::FixedHeight ? fontHeight - lineHeight()
1341 : (1.0 - lineHeight()) * fontHeight;
1342}
1343
1348{
1349 if (!extra.isAllocated() || !extra->doc) {
1350 Q_Q(QQuickText);
1351 extra.value().doc = new QTextDocument(q);
1352 auto *doc = extra->doc;
1353 extra->imageHandler = new QQuickTextImageHandler(doc);
1354 doc->documentLayout()->registerHandler(QTextFormat::ImageObject, extra->imageHandler);
1355 doc->setPageSize(QSizeF(0, 0));
1356 doc->setDocumentMargin(0);
1357 const QQmlContext *context = qmlContext(q);
1358 doc->setBaseUrl(context ? context->resolvedUrl(q->baseUrl()) : q->baseUrl());
1359 }
1360}
1361
1363{
1364 ensureDoc();
1365#if QT_CONFIG(textmarkdownreader)
1366 if (markdownText)
1367 extra->doc->setMarkdown(text);
1368 else
1369#endif
1370#if QT_CONFIG(texthtmlparser)
1371 extra->doc->setHtml(text);
1372#else
1373 extra->doc->setPlainText(text);
1374#endif
1375 rightToLeftText = extra->doc->toPlainText().isRightToLeft();
1376}
1377
1379{
1380 return (window ? window->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
1381}
1382
1451{
1452 Q_D(QQuickText);
1453 d->init();
1454}
1455
1457: QQuickImplicitSizeItem(dd, parent)
1458{
1459 Q_D(QQuickText);
1460 d->init();
1461}
1462
1464{
1465 Q_D(QQuickText);
1466 if (d->extra.isAllocated()) {
1467 qDeleteAll(d->extra->pixmapsInProgress);
1468 d->extra->pixmapsInProgress.clear();
1469 }
1470}
1471
1743
1781
1789
1850
1857
1869
1873{
1874 Q_D(const QQuickText);
1875 return d->sourceFont;
1876}
1877
1879{
1880 Q_D(QQuickText);
1881 if (d->sourceFont == font)
1882 return;
1883
1884 d->sourceFont = font;
1885 QFont oldFont = d->font;
1886 d->font = font;
1887
1888 if (!antialiasing())
1889 d->font.setStyleStrategy(QFont::NoAntialias);
1890
1891 if (d->font.pointSizeF() != -1) {
1892 // 0.5pt resolution
1893 qreal size = qRound(d->font.pointSizeF()*2.0);
1894 d->font.setPointSizeF(size/2.0);
1895 }
1896
1897 if (oldFont != d->font) {
1898 // if the format changes the size of the text
1899 // with headings or <font> tag, we need to re-parse
1900 if (d->formatModifiesFontSize)
1901 d->textHasChanged = true;
1902 d->implicitWidthValid = false;
1903 d->implicitHeightValid = false;
1904 d->updateLayout();
1905 }
1906
1907 emit fontChanged(d->sourceFont);
1908}
1909
1911{
1912 Q_D(QQuickText);
1913 Q_UNUSED(value);
1914 switch (change) {
1916 if (!antialiasing())
1917 d->font.setStyleStrategy(QFont::NoAntialias);
1918 else
1919 d->font.setStyleStrategy(QFont::PreferAntialias);
1920 d->implicitWidthValid = false;
1921 d->implicitHeightValid = false;
1922 d->updateLayout();
1923 break;
1924
1926 {
1927 bool needUpdateLayout = false;
1928 if (d->renderType == NativeRendering) {
1929 // Native rendering optimizes for a given pixel grid, so its results must not be scaled.
1930 // Text layout code respects the current device pixel ratio automatically, we only need
1931 // to rerun layout after the ratio changed.
1932 // Changes of implicit size should be minimal; they are hard to avoid.
1933 d->implicitWidthValid = false;
1934 d->implicitHeightValid = false;
1935 needUpdateLayout = true;
1936 }
1937
1938 if (d->extra.isAllocated()) {
1939 // check if we have scalable inline images with explicit size set, which should be reloaded
1940 for (QQuickStyledTextImgTag *image : std::as_const(d->extra->visibleImgTags)) {
1941 if (image->size.isValid() && QQuickPixmap::isScalableImageFormat(image->url)) {
1942 image->pix.reset();
1943 needUpdateLayout = true;
1944 }
1945 }
1946 }
1947
1948 if (needUpdateLayout)
1949 d->updateLayout();
1950 }
1951 break;
1952
1953 default:
1954 break;
1955 }
1957}
1958
1971{
1972 Q_D(const QQuickText);
1973 return d->text;
1974}
1975
1977{
1978 Q_D(QQuickText);
1979 if (d->text == n)
1980 return;
1981
1982 d->markdownText = d->format == MarkdownText;
1983 d->richText = d->format == RichText || d->markdownText;
1984 d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n));
1985 d->text = n;
1986 if (isComponentComplete()) {
1987 if (d->richText) {
1988 d->updateDocumentText();
1989 } else {
1990 d->clearFormats();
1991 d->rightToLeftText = d->text.isRightToLeft();
1992 }
1993 d->determineHorizontalAlignment();
1994 }
1995 d->textHasChanged = true;
1996 d->implicitWidthValid = false;
1997 d->implicitHeightValid = false;
1998
1999 if (d->extra.isAllocated()) {
2000 qDeleteAll(d->extra->imgTags);
2001 d->extra->imgTags.clear();
2002 }
2004 d->updateLayout();
2005 setAcceptHoverEvents(d->richText || d->styledText);
2006 emit textChanged(d->text);
2007}
2008
2031{
2032 Q_D(const QQuickText);
2033 return QColor::fromRgba(d->color);
2034}
2035
2037{
2038 Q_D(QQuickText);
2039 QRgb rgb = color.rgba();
2040 if (d->color == rgb)
2041 return;
2042
2043 d->color = rgb;
2044 if (isComponentComplete()) {
2046 update();
2047 }
2049}
2050
2062{
2063 Q_D(const QQuickText);
2064 return QColor::fromRgba(d->linkColor);
2065}
2066
2068{
2069 Q_D(QQuickText);
2070 QRgb rgb = color.rgba();
2071 if (d->linkColor == rgb)
2072 return;
2073
2074 d->linkColor = rgb;
2075 if (isComponentComplete()) {
2077 update();
2078 }
2080}
2081
2106{
2107 Q_D(const QQuickText);
2108 return d->style;
2109}
2110
2112{
2113 Q_D(QQuickText);
2114 if (d->style == style)
2115 return;
2116
2117 d->style = style;
2118 if (isComponentComplete()) {
2120 update();
2121 }
2122 emit styleChanged(d->style);
2123}
2124
2141{
2142 Q_D(const QQuickText);
2143 return QColor::fromRgba(d->styleColor);
2144}
2145
2147{
2148 Q_D(QQuickText);
2149 QRgb rgb = color.rgba();
2150 if (d->styleColor == rgb)
2151 return;
2152
2153 d->styleColor = rgb;
2154 if (isComponentComplete()) {
2156 update();
2157 }
2159}
2160
2186{
2187 Q_D(const QQuickText);
2188 return d->hAlign;
2189}
2190
2192{
2193 Q_D(QQuickText);
2194 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
2195 d->hAlignImplicit = false;
2196 if (d->setHAlign(align, forceAlign) && isComponentComplete())
2197 d->updateLayout();
2198}
2199
2201{
2202 Q_D(QQuickText);
2203 d->hAlignImplicit = true;
2204 if (isComponentComplete() && d->determineHorizontalAlignment())
2205 d->updateLayout();
2206}
2207
2209{
2210 Q_D(const QQuickText);
2211 QQuickText::HAlignment effectiveAlignment = d->hAlign;
2212 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
2213 switch (d->hAlign) {
2215 effectiveAlignment = QQuickText::AlignRight;
2216 break;
2218 effectiveAlignment = QQuickText::AlignLeft;
2219 break;
2220 default:
2221 break;
2222 }
2223 }
2224 return effectiveAlignment;
2225}
2226
2228{
2229 Q_Q(QQuickText);
2230 if (hAlign != alignment || forceAlign) {
2231 QQuickText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
2232 hAlign = alignment;
2233
2234 emit q->horizontalAlignmentChanged(hAlign);
2235 if (oldEffectiveHAlign != q->effectiveHAlign())
2236 emit q->effectiveHorizontalAlignmentChanged();
2237 return true;
2238 }
2239 return false;
2240}
2241
2243{
2244 if (hAlignImplicit) {
2245#if QT_CONFIG(im)
2246 bool alignToRight = text.isEmpty() ? QGuiApplication::inputMethod()->inputDirection() == Qt::RightToLeft : rightToLeftText;
2247#else
2248 bool alignToRight = rightToLeftText;
2249#endif
2251 }
2252 return false;
2253}
2254
2256{
2257 Q_Q(QQuickText);
2258 if (q->isComponentComplete()) {
2260 updateLayout();
2261 emit q->effectiveHorizontalAlignmentChanged();
2262 }
2263 }
2264}
2265
2267{
2268 Q_D(const QQuickText);
2269 return d->vAlign;
2270}
2271
2273{
2274 Q_D(QQuickText);
2275 if (d->vAlign == align)
2276 return;
2277
2278 d->vAlign = align;
2279
2280 if (isComponentComplete())
2281 d->updateLayout();
2282
2284}
2285
2305{
2306 Q_D(const QQuickText);
2307 return d->wrapMode;
2308}
2309
2311{
2312 Q_D(QQuickText);
2313 if (mode == d->wrapMode)
2314 return;
2315
2316 d->wrapMode = mode;
2317 d->updateLayout();
2318
2320}
2321
2332{
2333 Q_D(const QQuickText);
2334 return d->lineCount;
2335}
2336
2348{
2349 Q_D(const QQuickText);
2350 return d->truncated;
2351}
2352
2365{
2366 Q_D(const QQuickText);
2367 return d->maximumLineCount();
2368}
2369
2371{
2372 Q_D(QQuickText);
2373
2374 d->maximumLineCountValid = lines==INT_MAX ? false : true;
2375 if (d->maximumLineCount() != lines) {
2376 d->extra.value().maximumLineCount = lines;
2377 d->implicitHeightValid = false;
2378 d->updateLayout();
2380 }
2381}
2382
2384{
2385 Q_D(QQuickText);
2386 setMaximumLineCount(INT_MAX);
2387 if (d->truncated != false) {
2388 d->truncated = false;
2390 }
2391}
2392
2456{
2457 Q_D(const QQuickText);
2458 return d->format;
2459}
2460
2462{
2463 Q_D(QQuickText);
2464 if (format == d->format)
2465 return;
2466 d->format = format;
2467 bool wasRich = d->richText;
2468 d->markdownText = format == MarkdownText;
2469 d->richText = format == RichText || d->markdownText;
2470 d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
2471
2472 if (isComponentComplete()) {
2473 if (!wasRich && d->richText) {
2474 d->updateDocumentText();
2475 } else {
2476 d->clearFormats();
2477 d->rightToLeftText = d->text.isRightToLeft();
2478 d->textHasChanged = true;
2479 }
2480 d->determineHorizontalAlignment();
2481 }
2482 d->updateLayout();
2483 setAcceptHoverEvents(d->richText || d->styledText);
2484 setAcceptedMouseButtons(d->richText || d->styledText ? Qt::LeftButton : Qt::NoButton);
2485
2486 emit textFormatChanged(d->format);
2487}
2488
2516{
2517 Q_D(const QQuickText);
2518 return d->elideMode;
2519}
2520
2522{
2523 Q_D(QQuickText);
2524 if (mode == d->elideMode)
2525 return;
2526
2527 d->elideMode = mode;
2528 d->updateLayout();
2529
2531}
2532
2557{
2558 Q_D(const QQuickText);
2559 if (!d->extra.isAllocated() || d->extra->baseUrl.isEmpty()) {
2560 if (QQmlContext *context = qmlContext(this))
2561 return context->baseUrl();
2562 else
2563 return QUrl();
2564 } else {
2565 return d->extra->baseUrl;
2566 }
2567}
2568
2570{
2571 Q_D(QQuickText);
2572 if (baseUrl() != url) {
2573 d->extra.value().baseUrl = url;
2574
2575 if (d->richText) {
2576 d->ensureDoc();
2577 d->extra->doc->setBaseUrl(url);
2578 }
2579 if (d->styledText) {
2580 d->textHasChanged = true;
2581 if (d->extra.isAllocated()) {
2582 qDeleteAll(d->extra->imgTags);
2583 d->extra->imgTags.clear();
2584 }
2585 d->updateLayout();
2586 }
2588 }
2589}
2590
2592{
2593 if (QQmlContext *context = qmlContext(this))
2594 setBaseUrl(context->baseUrl());
2595 else
2596 setBaseUrl(QUrl());
2597}
2598
2607{
2608 Q_D(const QQuickText);
2609
2610 QRectF rect = d->layedOutTextRect;
2611 rect.moveLeft(QQuickTextUtil::alignedX(rect.width(), width(), effectiveHAlign()));
2612 rect.moveTop(QQuickTextUtil::alignedY(rect.height() + d->lineHeightOffset(), height(), d->vAlign));
2613
2614 if (d->style != Normal)
2615 rect.adjust(-1, 0, 1, 2);
2616 // Could include font max left/right bearings to either side of rectangle.
2617
2618 return rect;
2619}
2620
2633{
2634 Q_D(const QQuickText);
2635
2637 if (d->style != Normal)
2638 rect.adjust(-1, 0, 1, 2);
2639 return rect;
2640}
2641
2643void QQuickText::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
2644{
2645 Q_D(QQuickText);
2646 if (d->text.isEmpty()) {
2647 QQuickItem::geometryChange(newGeometry, oldGeometry);
2648 return;
2649 }
2650
2651 bool widthChanged = newGeometry.width() != oldGeometry.width();
2652 bool heightChanged = newGeometry.height() != oldGeometry.height();
2653 bool wrapped = d->wrapMode != QQuickText::NoWrap;
2654 bool elide = d->elideMode != QQuickText::ElideNone;
2655 bool scaleFont = d->fontSizeMode() != QQuickText::FixedSize && (widthValid() || heightValid());
2656 bool verticalScale = (d->fontSizeMode() & QQuickText::VerticalFit) && heightValid();
2657
2658 bool widthMaximum = newGeometry.width() >= oldGeometry.width() && !d->widthExceeded;
2659 bool heightMaximum = newGeometry.height() >= oldGeometry.height() && !d->heightExceeded;
2660
2661 bool verticalPositionChanged = heightChanged && d->vAlign != AlignTop;
2662
2663 if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
2664 goto geomChangeDone;
2665
2666 if ((effectiveHAlign() != QQuickText::AlignLeft && widthChanged) || verticalPositionChanged) {
2667 // If the width has changed and we're not left aligned do an update so the text is
2668 // repositioned even if a full layout isn't required. And the same for vertical.
2670 update();
2671 }
2672
2673 if (!wrapped && !elide && !scaleFont && !verticalPositionChanged)
2674 goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
2675
2676 if (elide // eliding and dimensions were and remain invalid;
2677 && ((widthValid() && oldGeometry.width() <= 0 && newGeometry.width() <= 0)
2678 || (heightValid() && oldGeometry.height() <= 0 && newGeometry.height() <= 0))) {
2679 goto geomChangeDone;
2680 }
2681
2682 if (widthMaximum && heightMaximum && !d->isLineLaidOutConnected() && !verticalPositionChanged) // Size is sufficient and growing.
2683 goto geomChangeDone;
2684
2685 if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
2686 if (!verticalPositionChanged) {
2687 if (newGeometry.height() > oldGeometry.height()) {
2688 if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
2689 // Height is adequate and growing, and it wasn't 0 previously.
2690 goto geomChangeDone;
2691 }
2692 if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
2693 goto geomChangeDone;
2694 } else if (newGeometry.height() < oldGeometry.height()) {
2695 if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
2696 goto geomChangeDone;
2697
2698 if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
2699 && d->elideMode != QQuickText::ElideRight
2700 && !(d->maximumLineCountValid && d->widthExceeded)) {
2701 goto geomChangeDone;
2702 }
2703 }
2704 }
2705 } else if (!heightChanged && widthMaximum) {
2706 if (oldGeometry.width() > 0) {
2707 // no change to height, width is adequate and wasn't 0 before
2708 // (old width could also be negative if it was 0 and the margins
2709 // were set)
2710 goto geomChangeDone;
2711 }
2712 }
2713
2714 if (d->updateOnComponentComplete || d->textHasChanged) {
2715 // We need to re-elide
2716 d->updateLayout();
2717 } else {
2718 // We just need to re-layout
2719 d->updateSize();
2720 }
2721
2722geomChangeDone:
2723 QQuickItem::geometryChange(newGeometry, oldGeometry);
2724}
2725
2726void QQuickText::triggerPreprocess()
2727{
2728 Q_D(QQuickText);
2729 if (d->updateType == QQuickTextPrivate::UpdateNone)
2731 update();
2732}
2733
2735{
2736 Q_UNUSED(data);
2737 Q_D(QQuickText);
2738
2739 if (d->text.isEmpty()) {
2740 delete oldNode;
2741 return nullptr;
2742 }
2743
2744 if (d->updateType != QQuickTextPrivate::UpdatePaintNode && oldNode != nullptr) {
2745 // Update done in preprocess() in the nodes
2746 d->updateType = QQuickTextPrivate::UpdateNone;
2747 return oldNode;
2748 }
2749
2750 d->updateType = QQuickTextPrivate::UpdateNone;
2751
2752 const qreal dy = QQuickTextUtil::alignedY(d->layedOutTextRect.height() + d->lineHeightOffset(), d->availableHeight(), d->vAlign) + topPadding();
2753
2754 QSGInternalTextNode *node = nullptr;
2755 if (!oldNode)
2756 node = d->sceneGraphContext()->createInternalTextNode(d->sceneGraphRenderContext());
2757 else
2758 node = static_cast<QSGInternalTextNode *>(oldNode);
2759
2761
2762 node->setTextStyle(QSGTextNode::TextStyle(d->style));
2763 node->setRenderType(QSGTextNode::RenderType(d->renderType));
2764 node->setRenderTypeQuality(d->renderTypeQuality());
2765 node->clear();
2766 node->setMatrix(QMatrix4x4());
2767
2768 node->setColor(QColor::fromRgba(d->color));
2769 node->setStyleColor(QColor::fromRgba(d->styleColor));
2770 node->setLinkColor(QColor::fromRgba(d->linkColor));
2771
2772 if (d->richText) {
2773 node->setViewport(clipRect());
2774 const qreal dx = QQuickTextUtil::alignedX(d->layedOutTextRect.width(), d->availableWidth(), effectiveHAlign()) + leftPadding();
2775 d->ensureDoc();
2776 node->addTextDocument(QPointF(dx, dy), d->extra->doc);
2777 } else if (d->layedOutTextRect.width() > 0) {
2779 node->setViewport(clipRect());
2780 else
2781 node->setViewport(QRectF{});
2782 const qreal dx = QQuickTextUtil::alignedX(d->lineWidth, d->availableWidth(), effectiveHAlign()) + leftPadding();
2783 int unelidedLineCount = d->lineCount;
2784 if (d->elideLayout)
2785 unelidedLineCount -= 1;
2786 if (unelidedLineCount > 0)
2787 node->addTextLayout(QPointF(dx, dy), &d->layout, -1, -1,0, unelidedLineCount);
2788
2789 if (d->elideLayout)
2790 node->addTextLayout(QPointF(dx, dy), d->elideLayout.get());
2791
2792 if (d->extra.isAllocated()) {
2793 for (QQuickStyledTextImgTag *img : std::as_const(d->extra->visibleImgTags)) {
2794 if (img->pix && img->pix->isReady())
2795 node->addImage(QRectF(img->pos.x() + dx, img->pos.y() + dy, img->size.width(), img->size.height()), img->pix->image());
2796 }
2797 }
2798 }
2799
2800 // The font caches have now been initialized on the render thread, so they have to be
2801 // invalidated before we can use them from the main thread again.
2803
2804 return node;
2805}
2806
2808{
2809 Q_D(QQuickText);
2810 const bool clipNodeChanged =
2811 d->componentComplete && d->clipNode() && d->clipNode()->rect() != clipRect();
2812 if (clipNodeChanged)
2813 d->dirty(QQuickItemPrivate::Clip);
2814
2815 // If the fonts used for rendering are different from the ones used in the GUI thread,
2816 // it means we will get warnings and corrupted text. If this case is detected, we need
2817 // to update the text layout before creating the scenegraph nodes.
2818 if (!d->assignedFont.isEmpty() && QFontInfo(d->font).family() != d->assignedFont)
2819 d->polishSize = true;
2820
2821 if (d->polishSize) {
2822 d->updateSize();
2823 d->polishSize = false;
2824 }
2826}
2827
2835{
2836 Q_D(const QQuickText);
2837 return d->layedOutTextRect.width();
2838}
2839
2847{
2848 Q_D(const QQuickText);
2849 return d->layedOutTextRect.height() + qMax(d->lineHeightOffset(), 0);
2850}
2851
2862{
2863 Q_D(const QQuickText);
2864 return d->lineHeight();
2865}
2866
2868{
2869 Q_D(QQuickText);
2870
2871 if ((d->lineHeight() == lineHeight) || (lineHeight < 0.0))
2872 return;
2873
2874 d->extra.value().lineHeightValid = true;
2875 d->extra.value().lineHeight = lineHeight;
2876 d->implicitHeightValid = false;
2877 d->updateLayout();
2879}
2880
2892{
2893 Q_D(const QQuickText);
2894 return d->lineHeightMode();
2895}
2896
2898{
2899 Q_D(QQuickText);
2900 if (mode == d->lineHeightMode())
2901 return;
2902
2903 d->implicitHeightValid = false;
2904 d->extra.value().lineHeightValid = true;
2905 d->extra.value().lineHeightMode = mode;
2906 d->updateLayout();
2907
2909}
2910
2947{
2948 Q_D(const QQuickText);
2949 return d->fontSizeMode();
2950}
2951
2953{
2954 Q_D(QQuickText);
2955 if (d->fontSizeMode() == mode)
2956 return;
2957
2958 d->polishSize = true;
2959 polish();
2960
2961 d->extra.value().fontSizeMode = mode;
2963}
2964
2976{
2977 Q_D(const QQuickText);
2978 return d->minimumPixelSize();
2979}
2980
2982{
2983 Q_D(QQuickText);
2984 if (d->minimumPixelSize() == size)
2985 return;
2986
2987 if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid())) {
2988 d->polishSize = true;
2989 polish();
2990 }
2991 d->extra.value().minimumPixelSize = size;
2993}
2994
3006{
3007 Q_D(const QQuickText);
3008 return d->minimumPointSize();
3009}
3010
3012{
3013 Q_D(QQuickText);
3014 if (d->minimumPointSize() == size)
3015 return;
3016
3017 if (d->fontSizeMode() != FixedSize && (widthValid() || heightValid())) {
3018 d->polishSize = true;
3019 polish();
3020 }
3021 d->extra.value().minimumPointSize = size;
3023}
3024
3029{
3030 Q_D(const QQuickText);
3031 if (d->richText && d->extra.isAllocated())
3032 return d->extra->pixmapsInProgress.size();
3033 return 0;
3034}
3035
3038{
3039 Q_D(QQuickText);
3040 if (d->updateOnComponentComplete) {
3041 if (d->richText) {
3042 d->updateDocumentText();
3043 } else {
3044 d->rightToLeftText = d->text.isRightToLeft();
3045 }
3046 d->determineHorizontalAlignment();
3047 }
3049 if (d->updateOnComponentComplete)
3050 d->updateLayout();
3051}
3052
3054{
3055 for (int i = 0; i < layout->lineCount(); ++i) {
3057 if (line.naturalTextRect().contains(mousePos)) {
3058 int charPos = line.xToCursor(mousePos.x(), QTextLine::CursorOnCharacter);
3059 const auto formats = layout->formats();
3060 for (const QTextLayout::FormatRange &formatRange : formats) {
3061 if (formatRange.format.isAnchor()
3062 && charPos >= formatRange.start
3063 && charPos < formatRange.start + formatRange.length) {
3064 return formatRange.format.anchorHref();
3065 }
3066 }
3067 break;
3068 }
3069 }
3070 return QString();
3071}
3072
3074{
3075 Q_Q(const QQuickText);
3076 QPointF translatedMousePos = mousePos;
3077 translatedMousePos.rx() -= q->leftPadding();
3078 translatedMousePos.ry() -= q->topPadding() + QQuickTextUtil::alignedY(layedOutTextRect.height() + lineHeightOffset(), availableHeight(), vAlign);
3079 if (styledText) {
3080 QString link = anchorAt(&layout, translatedMousePos);
3081 if (link.isEmpty() && elideLayout)
3082 link = anchorAt(elideLayout.get(), translatedMousePos);
3083 return link;
3084 } else if (richText && extra.isAllocated() && extra->doc) {
3085 translatedMousePos.rx() -= QQuickTextUtil::alignedX(layedOutTextRect.width(), availableWidth(), q->effectiveHAlign());
3086 return extra->doc->documentLayout()->anchorAt(translatedMousePos);
3087 }
3088 return QString();
3089}
3090
3092{
3093 Q_Q(QQuickText);
3094 IS_SIGNAL_CONNECTED(q, QQuickText, linkActivated, (const QString &));
3095}
3096
3099{
3100 Q_D(QQuickText);
3101
3102 QString link;
3103 if (d->isLinkActivatedConnected())
3104 link = d->anchorAt(event->position());
3105
3106 if (link.isEmpty()) {
3107 event->setAccepted(false);
3108 } else {
3109 d->extra.value().activeLink = link;
3110 }
3111
3112 // ### may malfunction if two of the same links are clicked & dragged onto each other)
3113
3114 if (!event->isAccepted())
3116}
3117
3118
3121{
3122 Q_D(QQuickText);
3123
3124 // ### confirm the link, and send a signal out
3125
3126 QString link;
3127 if (d->isLinkActivatedConnected())
3128 link = d->anchorAt(event->position());
3129
3130 if (!link.isEmpty() && d->extra.isAllocated() && d->extra->activeLink == link)
3131 emit linkActivated(d->extra->activeLink);
3132 else
3133 event->setAccepted(false);
3134
3135 if (!event->isAccepted())
3137}
3138
3140{
3141 Q_Q(QQuickText);
3142 IS_SIGNAL_CONNECTED(q, QQuickText, linkHovered, (const QString &));
3143}
3144
3145static void getLinks_helper(const QTextLayout *layout, QVector<QQuickTextPrivate::LinkDesc> *links)
3146{
3147 for (const QTextLayout::FormatRange &formatRange : layout->formats()) {
3148 if (formatRange.format.isAnchor()) {
3149 const int start = formatRange.start;
3150 const int len = formatRange.length;
3151 QTextLine line = layout->lineForTextPosition(start);
3152 QRectF r;
3153 r.setTop(line.y());
3154 r.setLeft(line.cursorToX(start, QTextLine::Leading));
3155 r.setHeight(line.height());
3156 r.setRight(line.cursorToX(start + len, QTextLine::Trailing));
3157 // ### anchorNames() is empty?! Not sure why this doesn't work
3158 // QString anchorName = formatRange.format.anchorNames().value(0); //### pick the first?
3159 // Therefore, we resort to QString::mid()
3160 QString anchorName = layout->text().mid(start, len);
3161 const QString anchorHref = formatRange.format.anchorHref();
3162 if (anchorName.isEmpty())
3163 anchorName = anchorHref;
3164 links->append( { anchorName, anchorHref, start, start + len, r.toRect()} );
3165 }
3166 }
3167}
3168
3169QVector<QQuickTextPrivate::LinkDesc> QQuickTextPrivate::getLinks() const
3170{
3171 QVector<QQuickTextPrivate::LinkDesc> links;
3173 return links;
3174}
3175
3176
3200{
3201 Q_D(const QQuickText);
3202 if (const_cast<QQuickTextPrivate *>(d)->isLinkHoveredConnected()) {
3203 if (d->extra.isAllocated())
3204 return d->extra->hoveredLink;
3205 } else {
3206#if QT_CONFIG(cursor)
3207 if (QQuickWindow *wnd = window()) {
3208 QPointF pos = QCursor::pos(wnd->screen()) - wnd->position() - mapToScene(QPointF(0, 0));
3209 return d->anchorAt(pos);
3210 }
3211#endif // cursor
3212 }
3213 return QString();
3214}
3215
3217{
3218 Q_Q(QQuickText);
3219 qCDebug(lcHoverTrace) << q;
3220 QString link;
3221 if (isLinkHoveredConnected()) {
3222 if (event->type() != QEvent::HoverLeave)
3223 link = anchorAt(event->position());
3224
3225 if ((!extra.isAllocated() && !link.isEmpty()) || (extra.isAllocated() && extra->hoveredLink != link)) {
3226 extra.value().hoveredLink = link;
3227 emit q->linkHovered(extra->hoveredLink);
3228 }
3229 }
3230 event->ignore();
3231}
3232
3234{
3235 Q_D(QQuickText);
3236 d->processHoverEvent(event);
3237}
3238
3240{
3241 Q_D(QQuickText);
3242 d->processHoverEvent(event);
3243}
3244
3246{
3247 Q_D(QQuickText);
3248 d->processHoverEvent(event);
3249}
3250
3252{
3253 Q_D(QQuickText);
3254 d->textHasChanged = true;
3255 QMetaObject::invokeMethod(this,[&]{q_updateLayout();});
3256}
3257
3259{
3260 // If there's a lot of text, we may need QQuickText::updatePaintNode() to call
3261 // QSGInternalTextNode::addTextLayout() again to populate a different range of lines
3265 }
3267}
3268
3292{
3293 Q_D(const QQuickText);
3294 return d->renderTypeQuality();
3295}
3296
3297void QQuickText::setRenderTypeQuality(int renderTypeQuality)
3298{
3299 Q_D(QQuickText);
3300 if (renderTypeQuality == d->renderTypeQuality())
3301 return;
3302 d->extra.value().renderTypeQuality = renderTypeQuality;
3303
3304 if (isComponentComplete()) {
3306 update();
3307 }
3308
3309 emit renderTypeQualityChanged();
3310}
3311
3338{
3339 Q_D(const QQuickText);
3340 return d->renderType;
3341}
3342
3344{
3345 Q_D(QQuickText);
3346 if (d->renderType == renderType)
3347 return;
3348
3349 d->renderType = renderType;
3351
3352 if (isComponentComplete())
3353 d->updateLayout();
3354}
3355
3356#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
3357#if QT_DEPRECATED_SINCE(5, 15)
3364void QQuickText::doLayout()
3365{
3366 forceLayout();
3367}
3368
3369#endif
3370#endif
3377void QQuickText::forceLayout()
3378{
3379 Q_D(QQuickText);
3380 d->updateSize();
3381}
3382
3392QString QQuickText::linkAt(qreal x, qreal y) const
3393{
3394 Q_D(const QQuickText);
3395 return d->anchorAt(QPointF(x, y));
3396}
3397
3405{
3406 Q_D(QQuickText);
3407
3408 if (d->richText && d->extra.isAllocated() && d->extra->doc != nullptr) {
3409 QTextBlock block;
3410 for (block = d->extra->doc->firstBlock(); block.isValid(); block = block.next()) {
3411 if (block.layout() != nullptr && block.layout()->engine() != nullptr)
3412 block.layout()->engine()->resetFontEngineCache();
3413 }
3414 } else {
3415 if (d->layout.engine() != nullptr)
3416 d->layout.engine()->resetFontEngineCache();
3417 }
3418}
3419
3432{
3433 Q_D(const QQuickText);
3434 return d->padding();
3435}
3436
3438{
3439 Q_D(QQuickText);
3440 if (qFuzzyCompare(d->padding(), padding))
3441 return;
3442
3443 d->extra.value().padding = padding;
3444 d->updateSize();
3445 emit paddingChanged();
3446 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
3447 emit topPaddingChanged();
3448 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
3449 emit leftPaddingChanged();
3450 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
3451 emit rightPaddingChanged();
3452 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
3453 emit bottomPaddingChanged();
3454}
3455
3457{
3458 setPadding(0);
3459}
3460
3462{
3463 Q_D(const QQuickText);
3464 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
3465 return d->extra->topPadding;
3466 return d->padding();
3467}
3468
3470{
3471 Q_D(QQuickText);
3472 d->setTopPadding(padding);
3473}
3474
3476{
3477 Q_D(QQuickText);
3478 d->setTopPadding(0, true);
3479}
3480
3482{
3483 Q_D(const QQuickText);
3484 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
3485 return d->extra->leftPadding;
3486 return d->padding();
3487}
3488
3490{
3491 Q_D(QQuickText);
3492 d->setLeftPadding(padding);
3493}
3494
3496{
3497 Q_D(QQuickText);
3498 d->setLeftPadding(0, true);
3499}
3500
3502{
3503 Q_D(const QQuickText);
3504 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
3505 return d->extra->rightPadding;
3506 return d->padding();
3507}
3508
3510{
3511 Q_D(QQuickText);
3512 d->setRightPadding(padding);
3513}
3514
3516{
3517 Q_D(QQuickText);
3518 d->setRightPadding(0, true);
3519}
3520
3522{
3523 Q_D(const QQuickText);
3524 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
3525 return d->extra->bottomPadding;
3526 return d->padding();
3527}
3528
3530{
3531 Q_D(QQuickText);
3532 d->setBottomPadding(padding);
3533}
3534
3536{
3537 Q_D(QQuickText);
3538 d->setBottomPadding(0, true);
3539}
3540
3597{
3598 Q_D(const QQuickText);
3599
3600 QJSEngine *engine = qjsEngine(this);
3601 if (!engine) {
3602 qmlWarning(this) << "fontInfo: item has no JS engine";
3603 return QJSValue();
3604 }
3605
3607 value.setProperty(QStringLiteral("family"), d->fontInfo.family());
3608 value.setProperty(QStringLiteral("styleName"), d->fontInfo.styleName());
3609 value.setProperty(QStringLiteral("bold"), d->fontInfo.bold());
3610 value.setProperty(QStringLiteral("weight"), d->fontInfo.weight());
3611 value.setProperty(QStringLiteral("italic"), d->fontInfo.italic());
3612 value.setProperty(QStringLiteral("pointSize"), d->fontInfo.pointSizeF());
3613 value.setProperty(QStringLiteral("pixelSize"), d->fontInfo.pixelSize());
3614 return value;
3615}
3616
3630{
3631 Q_D(const QQuickText);
3632 return d->advance;
3633}
3634
3636
3637#include "moc_qquicktext_p.cpp"
\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:3131
int pixelSize() const
Returns the pixel size of the matched window system font.
Definition qfont.cpp:3143
QString family() const
Returns the family name of the matched window system font.
Definition qfont.cpp:3092
bool italic() const
Returns the italic value of the matched window system font.
Definition qfont.cpp:3155
QString styleName() const
Definition qfont.cpp:3107
int weight() const
Returns the weight of the matched window system font.
Definition qfont.cpp:3201
\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.
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:1162
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:142
iterator erase(const_iterator i)
Definition qset.h:145
const_iterator cbegin() const noexcept
Definition qset.h:138
\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:4517
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
QString mid(qsizetype position, qsizetype n=-1) const &
Definition qstring.cpp:5300
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
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...
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
static void * context
#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 Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
int qCeil(T v)
Definition qmath.h:36
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
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:75
#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...
\inmodule QtQuick
Definition qquickitem.h:159