Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtextimagehandler.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
6
7#include <qguiapplication.h>
8#include <qtextformat.h>
9#include <qpainter.h>
10#include <qdebug.h>
11#include <qfile.h>
12#include <qicon.h>
13#include <private/qtextengine_p.h>
14#include <qpalette.h>
15#include <qthread.h>
16#include <limits>
17
19
20using namespace Qt::StringLiterals;
21
22static inline QUrl findAtNxFileOrResource(const QString &baseFileName,
23 qreal targetDevicePixelRatio,
24 qreal *sourceDevicePixelRatio,
25 QString *name)
26{
27 // qt_findAtNxFile expects a file name that can be tested with QFile::exists.
28 // so if the format.name() is a file:/ or qrc:/ URL, then we need to strip away the schema.
29 QString localFile;
30 const QUrl url(baseFileName);
31 bool hasFileScheme = false;
32 bool isResource = false;
33 if (url.isLocalFile()) {
34 localFile = url.toLocalFile();
35 hasFileScheme = true;
36 } else if (baseFileName.startsWith("qrc:/"_L1)) {
37 // QFile::exists() can only handle ":/file.txt"
38 localFile = baseFileName.sliced(3);
39 isResource = true;
40 } else {
41 localFile = baseFileName;
42 isResource = baseFileName.startsWith(":/"_L1);
43 }
44 *name = qt_findAtNxFile(localFile, targetDevicePixelRatio, sourceDevicePixelRatio);
45
46 if (hasFileScheme)
47 return QUrl::fromLocalFile(*name);
48 if (isResource)
49 return QUrl("qrc"_L1 + *name);
50 return QUrl(*name);
51}
52
53template<typename T>
54static T getAs(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio = 1.0)
55{
56 qreal sourcePixelRatio = 1.0;
57 QString name;
58 const QUrl url = findAtNxFileOrResource(format.name(), devicePixelRatio, &sourcePixelRatio, &name);
59 const QVariant data = doc->resource(QTextDocument::ImageResource, url);
60
61 T result;
62 if (data.userType() == QMetaType::QPixmap || data.userType() == QMetaType::QImage)
63 result = data.value<T>();
64 else if (data.metaType() == QMetaType::fromType<QByteArray>())
65 result.loadFromData(data.toByteArray());
66
67 if (result.isNull()) {
68 if (name.isEmpty() || !result.load(name))
69 return T(":/qt-project.org/styles/commonstyle/images/file-16.png"_L1);
70 doc->addResource(QTextDocument::ImageResource, url, result);
71 }
72
73 if (sourcePixelRatio != 1.0)
74 result.setDevicePixelRatio(sourcePixelRatio);
75 return result;
76}
77
78template<typename T>
79static QSize getSize(QTextDocument *doc, const QTextImageFormat &format)
80{
81 const bool hasWidth = format.hasProperty(QTextFormat::ImageWidth);
82 int width = qRound(format.width());
83 const bool hasHeight = format.hasProperty(QTextFormat::ImageHeight);
84 const int height = qRound(format.height());
85
86 const bool hasMaxWidth = format.hasProperty(QTextFormat::ImageMaxWidth);
87 const auto maxWidth = format.maximumWidth();
88
89 int effectiveMaxWidth = std::numeric_limits<int>::max();
90 if (hasMaxWidth) {
91 if (maxWidth.type() == QTextLength::PercentageLength)
92 effectiveMaxWidth = (doc->pageSize().width() - 2 * doc->documentMargin()) * maxWidth.value(100) / 100;
93 else
94 effectiveMaxWidth = maxWidth.rawValue();
95
96 width = qMin(effectiveMaxWidth, width);
97 }
98
99 T source;
100 QSize size(width, height);
101 if (!hasWidth || !hasHeight) {
102 source = getAs<T>(doc, format);
103 QSizeF sourceSize = source.deviceIndependentSize();
104
105 if (sourceSize.width() > effectiveMaxWidth) {
106 // image is bigger than effectiveMaxWidth, scale it down
107 sourceSize.setHeight(effectiveMaxWidth * (sourceSize.height() / qreal(sourceSize.width())));
108 sourceSize.setWidth(effectiveMaxWidth);
109 }
110
111 if (!hasWidth) {
112 if (!hasHeight)
113 size.setWidth(sourceSize.width());
114 else
115 size.setWidth(qMin(effectiveMaxWidth, qRound(height * (sourceSize.width() / qreal(sourceSize.height())))));
116 }
117 if (!hasHeight) {
118 if (!hasWidth)
119 size.setHeight(sourceSize.height());
120 else
121 size.setHeight(qRound(width * (sourceSize.height() / qreal(sourceSize.width()))));
122 }
123 }
124
125 qreal scale = 1.0;
126 QPaintDevice *pdev = doc->documentLayout()->paintDevice();
127 if (pdev) {
128 if (source.isNull())
129 source = getAs<T>(doc, format);
130 if (!source.isNull())
131 scale = qreal(pdev->logicalDpiY()) / qreal(qt_defaultDpi());
132 }
133 size *= scale;
134 return size;
135}
136
137QTextImageHandler::QTextImageHandler(QObject *parent)
138 : QObject(parent)
139{
140}
141
142QSizeF QTextImageHandler::intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format)
143{
144 Q_UNUSED(posInDocument);
145 const QTextImageFormat imageFormat = format.toImageFormat();
146
147 if (QCoreApplication::instance()->thread() != QThread::currentThread())
148 return getSize<QImage>(doc, imageFormat);
149 return getSize<QPixmap>(doc, imageFormat);
150}
151
152QImage QTextImageHandler::image(QTextDocument *doc, const QTextImageFormat &imageFormat)
153{
154 Q_ASSERT(doc != nullptr);
155
156 return getAs<QImage>(doc, imageFormat);
157}
158
159void QTextImageHandler::drawObject(QPainter *p, const QRectF &rect, QTextDocument *doc, int posInDocument, const QTextFormat &format)
160{
161 Q_UNUSED(posInDocument);
162 const QTextImageFormat imageFormat = format.toImageFormat();
163
164 if (QCoreApplication::instance()->thread() != QThread::currentThread()) {
165 const QImage image = getAs<QImage>(doc, imageFormat, p->device()->devicePixelRatio());
166 p->drawImage(rect, image, image.rect());
167 } else {
168 const QPixmap pixmap = getAs<QPixmap>(doc, imageFormat, p->device()->devicePixelRatio());
169 p->drawPixmap(rect, pixmap, pixmap.rect());
170 }
171}
172
173QT_END_NAMESPACE
174
175#include "moc_qtextimagehandler_p.cpp"
static QSize getSize(QTextDocument *doc, const QTextImageFormat &format)
static QUrl findAtNxFileOrResource(const QString &baseFileName, qreal targetDevicePixelRatio, qreal *sourceDevicePixelRatio, QString *name)
static T getAs(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio=1.0)