File indexing completed on 2024-05-19 05:38:06

0001 /*
0002     SPDX-FileCopyrightText: 2018 Julian Wolff <wolff@julianwolff.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include <cmath>
0008 
0009 #include <QApplication>
0010 #include <QPainter>
0011 #include <QPalette>
0012 
0013 #include <KWindowSystem>
0014 
0015 #include "kxftconfig.h"
0016 #include "previewimageprovider.h"
0017 #include "previewrenderengine.h"
0018 
0019 /**
0020  * @brief Combines a list of images vertically into one image
0021  *
0022  * Combines a list of images vertically with the given spacing
0023  * between adjacent rows of images.
0024  * The width of the combined image is the width of the longest
0025  * image in the list, and the height is the sum of the heights
0026  * of all images in the list.
0027  * The device pixel ratio of the combined image is the same
0028  * as that of the first image in the list.
0029  *
0030  * @param images the list of images to be combined
0031  * @param bgnd the background color of the combined image
0032  * @param _spacing the spacing between adjacent rows of images
0033  * @return the combined image
0034  */
0035 QImage combineImages(const QList<QImage> &images, const QColor &bgnd, int _spacing = 0)
0036 {
0037     if (images.empty()) {
0038         return QImage();
0039     }
0040 
0041     int width = 0;
0042     int height = 0;
0043     const double devicePixelRatio = images.at(0).devicePixelRatio();
0044     const int spacing = std::lround(_spacing * devicePixelRatio);
0045     for (const auto &image : images) {
0046         if (width < image.width()) {
0047             width = image.width();
0048         }
0049         height += image.height();
0050     }
0051     height += spacing * images.count();
0052 
0053     // To correctly align the image pixels on a high dpi display,
0054     // the image dimensions need to be a multiple of devicePixelRatio
0055     QImage combinedImage(width * devicePixelRatio, height * devicePixelRatio, images.at(0).format());
0056     combinedImage.setDevicePixelRatio(devicePixelRatio);
0057     combinedImage.fill(bgnd);
0058 
0059     int offset = spacing; // Top margin
0060     QPainter p(&combinedImage);
0061     for (const auto &image : images) {
0062         p.drawImage(0, offset, image);
0063         offset += image.height() + spacing;
0064     }
0065 
0066     return combinedImage;
0067 }
0068 
0069 PreviewImageProvider::PreviewImageProvider(const QFont &font)
0070     : QQuickImageProvider(QQuickImageProvider::Image)
0071     , m_font(font)
0072 {
0073 }
0074 
0075 QImage PreviewImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
0076 {
0077     Q_UNUSED(requestedSize)
0078     if (!KWindowSystem::isPlatformX11()) {
0079         return QImage();
0080     }
0081 
0082     int subPixelIndex = 0;
0083     int hintingIndex = 0;
0084 
0085     const auto idpart = QStringView(id).split(QLatin1Char('.'))[0];
0086     const auto sections = idpart.split(QLatin1Char('_'));
0087 
0088     if (sections.size() >= 2) {
0089         subPixelIndex = sections[0].toInt() + KXftConfig::SubPixel::None;
0090         hintingIndex = sections[1].toInt() + KXftConfig::Hint::None;
0091     } else {
0092         return QImage();
0093     }
0094 
0095     KXftConfig xft;
0096 
0097     KXftConfig::AntiAliasing::State oldAntialiasing = xft.getAntiAliasing();
0098     double oldStart = 0;
0099     double oldEnd = 0;
0100     xft.getExcludeRange(oldStart, oldEnd);
0101     KXftConfig::SubPixel::Type oldSubPixelType = KXftConfig::SubPixel::NotSet;
0102     xft.getSubPixelType(oldSubPixelType);
0103     KXftConfig::Hint::Style oldHintStyle = KXftConfig::Hint::NotSet;
0104     xft.getHintStyle(oldHintStyle);
0105 
0106     xft.setAntiAliasing(KXftConfig::AntiAliasing::Enabled);
0107     xft.setExcludeRange(0, 0);
0108 
0109     KXftConfig::SubPixel::Type subPixelType = (KXftConfig::SubPixel::Type)subPixelIndex;
0110     xft.setSubPixelType(subPixelType);
0111 
0112     KXftConfig::Hint::Style hintStyle = (KXftConfig::Hint::Style)hintingIndex;
0113     xft.setHintStyle(hintStyle);
0114 
0115     xft.apply();
0116 
0117     QColor text(QApplication::palette().color(QPalette::Text));
0118     QColor bgnd(QApplication::palette().color(QPalette::Window));
0119 
0120     PreviewRenderEngine eng(true);
0121     QList<QImage> lines;
0122 
0123     lines << eng.drawAutoSize(m_font, text, bgnd, eng.getDefaultPreviewString());
0124 
0125     QImage img = combineImages(lines, bgnd, lines[0].height() * .25);
0126 
0127     xft.setAntiAliasing(oldAntialiasing);
0128     xft.setExcludeRange(oldStart, oldEnd);
0129     xft.setSubPixelType(oldSubPixelType);
0130     xft.setHintStyle(oldHintStyle);
0131 
0132     xft.apply();
0133 
0134     *size = img.size();
0135 
0136     return img;
0137 }