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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtbase/src/gui/text/qtextimagehandler.cpp