7#include <private/qtextengine_p.h>
8#include <private/qfontengine_p.h>
9#include <qabstracttextdocumentlayout.h>
13QT_IMPL_METATYPE_EXTERN(QStaticText)
15QStaticTextUserData::~QStaticTextUserData()
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
106
107
108
109
110
111
112
113
114
115
116
117
120
121
122QStaticText::QStaticText()
123 : data(
new QStaticTextPrivate)
128
129
130QStaticText::QStaticText(
const QString &text)
131 : data(
new QStaticTextPrivate)
138
139
140QStaticText::QStaticText(
const QStaticText &other)
146
147
148QStaticText::~QStaticText()
150 Q_ASSERT(!data || data->ref.loadRelaxed() >= 1);
154
155
156void QStaticText::detach()
158 if (data->ref.loadRelaxed() != 1)
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178void QStaticText::prepare(
const QTransform &matrix,
const QFont &font)
180 data->matrix = matrix;
187
188
189QStaticText &QStaticText::operator=(
const QStaticText &other)
196
197
198
199
202
203
204
205bool QStaticText::operator==(
const QStaticText &other)
const
207 return (data == other.data
208 || (data->text == other.data->text
209 && data->font == other.data->font
210 && data->textWidth == other.data->textWidth));
214
215
216
217bool QStaticText::operator!=(
const QStaticText &other)
const
219 return !(*
this == other);
223
224
225
226
227
228
229void QStaticText::setText(
const QString &text)
237
238
239
240
241
242
243
244
245
246
247void QStaticText::setTextFormat(Qt::TextFormat textFormat)
250 data->textFormat = textFormat;
255
256
257
258
259Qt::TextFormat QStaticText::textFormat()
const
261 return Qt::TextFormat(data->textFormat);
265
266
267
268
269QString QStaticText::text()
const
275
276
277
278
279
280
281
282
283
284
285
286void QStaticText::setPerformanceHint(PerformanceHint performanceHint)
288 if ((performanceHint == ModerateCaching && !data->useBackendOptimizations)
289 || (performanceHint == AggressiveCaching && data->useBackendOptimizations)) {
293 data->useBackendOptimizations = (performanceHint == AggressiveCaching);
298
299
300
301
302QStaticText::PerformanceHint QStaticText::performanceHint()
const
304 return data->useBackendOptimizations ? AggressiveCaching : ModerateCaching;
308
309
310
311
312void QStaticText::setTextOption(
const QTextOption &textOption)
315 data->textOption = textOption;
320
321
322QTextOption QStaticText::textOption()
const
324 return data->textOption;
328
329
330
331
332
333
334
335
336
337
338
339
340void QStaticText::setTextWidth(qreal textWidth)
343 data->textWidth = textWidth;
348
349
350
351
352qreal QStaticText::textWidth()
const
354 return data->textWidth;
358
359
360
361
362QSizeF QStaticText::size()
const
364 if (data->needsRelayout)
366 return data->actualSize;
369QStaticTextPrivate::QStaticTextPrivate()
370 : textWidth(-1.0), items(
nullptr), itemCount(0), glyphPool(
nullptr), positionPool(
nullptr),
371 needsRelayout(
true), useBackendOptimizations(
false), textFormat(Qt::AutoText),
372 untransformedCoordinates(
false)
376QStaticTextPrivate::QStaticTextPrivate(
const QStaticTextPrivate &other)
377 : text(other.text), font(other.font), textWidth(other.textWidth), matrix(other.matrix),
378 items(
nullptr), itemCount(0), glyphPool(
nullptr), positionPool(
nullptr), textOption(other.textOption),
379 needsRelayout(
true), useBackendOptimizations(other.useBackendOptimizations),
380 textFormat(other.textFormat), untransformedCoordinates(other.untransformedCoordinates)
384QStaticTextPrivate::~QStaticTextPrivate()
388 delete[] positionPool;
391QStaticTextPrivate *QStaticTextPrivate::get(
const QStaticText *q)
393 return q->data.data();
398 class DrawTextItemRecorder:
public QPaintEngine
401 DrawTextItemRecorder(
bool untransformedCoordinates,
bool useBackendOptimizations)
402 : m_dirtyPen(
false), m_useBackendOptimizations(useBackendOptimizations),
403 m_untransformedCoordinates(untransformedCoordinates), m_currentColor(0, 0, 0, 0)
407 virtual void updateState(
const QPaintEngineState &newState) override
409 if (newState.state() & QPaintEngine::DirtyPen
410 && newState.pen().color() != m_currentColor) {
412 m_currentColor = newState.pen().color();
416 virtual void drawTextItem(
const QPointF &position,
const QTextItem &textItem) override
418 const QTextItemInt &ti =
static_cast<
const QTextItemInt &>(textItem);
420 QStaticTextItem currentItem;
421 currentItem.setFontEngine(ti.fontEngine);
422 currentItem.font = ti.font();
423 currentItem.glyphOffset = m_glyphs.size();
424 currentItem.positionOffset = m_glyphs.size();
425 currentItem.useBackendOptimizations = m_useBackendOptimizations;
427 currentItem.color = m_currentColor;
429 QTransform matrix = m_untransformedCoordinates ? QTransform() : state->transform();
430 matrix.translate(position.x(), position.y());
432 QVarLengthArray<glyph_t> glyphs;
433 QVarLengthArray<QFixedPoint> positions;
434 ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
436 int size = glyphs.size();
437 Q_ASSERT(size == positions.size());
438 currentItem.numGlyphs = size;
440 m_glyphs.resize(m_glyphs.size() + size);
441 m_positions.resize(m_glyphs.size());
443 glyph_t *glyphsDestination = m_glyphs.data() + currentItem.glyphOffset;
444 memcpy(glyphsDestination, glyphs.constData(),
sizeof(glyph_t) * currentItem.numGlyphs);
446 QFixedPoint *positionsDestination = m_positions.data() + currentItem.positionOffset;
447 memcpy(positionsDestination, positions.constData(),
sizeof(QFixedPoint) * currentItem.numGlyphs);
449 m_items.append(currentItem);
452 virtual void drawPolygon(
const QPointF *,
int , PolygonDrawMode ) override
457 virtual bool begin(QPaintDevice *) override {
return true; }
458 virtual bool end() override {
return true; }
459 virtual void drawPixmap(
const QRectF &,
const QPixmap &,
const QRectF &) override {}
460 virtual Type type()
const override
465 QList<QStaticTextItem> items()
const
470 QList<QFixedPoint> positions()
const
475 QList<glyph_t> glyphs()
const
481 QList<QStaticTextItem> m_items;
482 QList<QFixedPoint> m_positions;
483 QList<glyph_t> m_glyphs;
486 bool m_useBackendOptimizations;
487 bool m_untransformedCoordinates;
488 QColor m_currentColor;
491 class DrawTextItemDevice:
public QPaintDevice
494 DrawTextItemDevice(
bool untransformedCoordinates,
bool useBackendOptimizations)
496 m_paintEngine =
new DrawTextItemRecorder(untransformedCoordinates,
497 useBackendOptimizations);
500 ~DrawTextItemDevice()
502 delete m_paintEngine;
505 int metric(PaintDeviceMetric m)
const override
516 case PdmPhysicalDpiX:
517 val = qt_defaultDpiX();
520 case PdmPhysicalDpiY:
521 val = qt_defaultDpiY();
529 case PdmDevicePixelRatio:
532 case PdmDevicePixelRatioScaled:
533 val = devicePixelRatioFScale();
537 qWarning(
"DrawTextItemDevice::metric: Invalid metric command");
542 virtual QPaintEngine *paintEngine()
const override
544 return m_paintEngine;
547 QList<glyph_t> glyphs()
const
549 return m_paintEngine->glyphs();
552 QList<QFixedPoint> positions()
const
554 return m_paintEngine->positions();
557 QList<QStaticTextItem> items()
const
559 return m_paintEngine->items();
563 DrawTextItemRecorder *m_paintEngine;
567void QStaticTextPrivate::paintText(
const QPointF &topLeftPosition, QPainter *p,
const QColor &pen)
569 bool preferRichText = textFormat == Qt::RichText
570 || (textFormat == Qt::AutoText && Qt::mightBeRichText(text));
572 if (!preferRichText) {
573 QTextLayout textLayout;
574 textLayout.setText(text);
575 textLayout.setFont(font);
576 textLayout.setTextOption(textOption);
577 textLayout.setCacheEnabled(
true);
580 textLayout.beginLayout();
582 QTextLine line = textLayout.createLine();
585 line.setLeadingIncluded(
true);
587 if (textWidth >= 0.0)
588 line.setLineWidth(textWidth);
590 line.setLineWidth(QFIXED_MAX);
591 line.setPosition(QPointF(0.0, height));
592 height += line.height();
593 if (line.leading() < 0)
594 height += qCeil(line.leading());
596 textLayout.endLayout();
598 actualSize = textLayout.boundingRect().size();
600 textLayout.draw(p, topLeftPosition);
602 QTextDocument document;
603#ifndef QT_NO_CSSPARSER
604 document.setDefaultStyleSheet(QString::fromLatin1(
"body { color: rgba(%1, %2, %3, %4%) }")
605 .arg(QString::number(pen.red()))
606 .arg(QString::number(pen.green()))
607 .arg(QString::number(pen.blue()))
608 .arg(QString::number(pen.alpha())));
610 document.setDefaultFont(font);
611 document.setDocumentMargin(0.0);
612#ifndef QT_NO_TEXTHTMLPARSER
613 document.setHtml(text);
615 document.setPlainText(text);
617 if (textWidth >= 0.0)
618 document.setTextWidth(textWidth);
620 document.adjustSize();
621 document.setDefaultTextOption(textOption);
624 p->translate(topLeftPosition);
625 QAbstractTextDocumentLayout::PaintContext ctx;
626 ctx.palette.setColor(QPalette::Text, pen);
627 document.documentLayout()->draw(p, ctx);
630 actualSize = document.size();
634void QStaticTextPrivate::init()
638 delete[] positionPool;
640 position = QPointF(0, 0);
642 DrawTextItemDevice device(untransformedCoordinates, useBackendOptimizations);
644 QPainter painter(&device);
645 painter.setFont(font);
646 painter.setTransform(matrix);
648 paintText(QPointF(0, 0), &painter, QColor(0, 0, 0, 0));
651 QList<QStaticTextItem> deviceItems = device.items();
652 QList<QFixedPoint> positions = device.positions();
653 QList<glyph_t> glyphs = device.glyphs();
655 itemCount = deviceItems.size();
656 items =
new QStaticTextItem[itemCount];
658 glyphPool =
new glyph_t[glyphs.size()];
659 memcpy(glyphPool, glyphs.constData(), glyphs.size() *
sizeof(glyph_t));
661 positionPool =
new QFixedPoint[positions.size()];
662 memcpy(positionPool, positions.constData(), positions.size() *
sizeof(QFixedPoint));
664 for (
int i=0; i<itemCount; ++i) {
665 items[i] = deviceItems.at(i);
667 items[i].glyphs = glyphPool + items[i].glyphOffset;
668 items[i].glyphPositions = positionPool + items[i].positionOffset;
671 needsRelayout =
false;