Use QImage instead of QPixmap for theme preview.

Working with QPixmap from non-main thread is not defined.
This commit is contained in:
John Preston 2018-01-02 22:10:49 +03:00
parent e89350d4b7
commit 0ef3e19bc2
6 changed files with 113 additions and 77 deletions

View File

@ -1710,14 +1710,16 @@ void MediaView::initThemePreview() {
Window::Theme::CurrentData current;
current.backgroundId = Window::Theme::Background()->id();
current.backgroundImage = Window::Theme::Background()->pixmap();
current.backgroundImage = Window::Theme::Background()->pixmap().toImage();
current.backgroundTiled = Window::Theme::Background()->tile();
const auto path = _doc->location().name();
const auto id = _themePreviewId = rand_value<uint64>();
const auto weak = make_weak(this);
crl::async([=] {
auto preview = Window::Theme::GeneratePreview(path, current);
crl::async([=, data = std::move(current)]() mutable {
auto preview = Window::Theme::GeneratePreview(
path,
std::move(data));
crl::on_main(weak, [=, result = std::move(preview)]() mutable {
if (id != _themePreviewId) {
return;
@ -2261,12 +2263,19 @@ void MediaView::paintThemePreview(Painter &p, QRect clip) {
auto fill = _themePreviewRect.intersected(clip);
if (!fill.isEmpty()) {
if (_themePreview) {
p.drawPixmapLeft(_themePreviewRect.x(), _themePreviewRect.y(), width(), _themePreview->preview);
p.drawImage(
myrtlrect(_themePreviewRect).topLeft(),
_themePreview->preview);
} else {
p.fillRect(fill, st::themePreviewBg);
p.setFont(st::themePreviewLoadingFont);
p.setPen(st::themePreviewLoadingFg);
p.drawText(_themePreviewRect, lang(_themePreviewId ? lng_theme_preview_generating : lng_theme_preview_invalid), QTextOption(style::al_center));
p.drawText(
_themePreviewRect,
lang(_themePreviewId
? lng_theme_preview_generating
: lng_theme_preview_invalid),
QTextOption(style::al_center));
}
}

View File

@ -59,6 +59,13 @@ const QPixmap &circleMask(int width, int height) {
} // namespace
QPixmap PixmapFast(QImage &&image) {
Expects(image.format() == QImage::Format_ARGB32_Premultiplied
|| image.format() == QImage::Format_RGB32);
return QPixmap::fromImage(std::move(image), Qt::NoFormatConversion);
}
QImage prepareBlur(QImage img) {
auto ratio = img.devicePixelRatio();
auto fmt = img.format();

View File

@ -22,6 +22,62 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "base/flags.h"
enum class ImageRoundRadius {
None,
Large,
Small,
Ellipse,
};
namespace Images {
QPixmap PixmapFast(QImage &&image);
QImage prepareBlur(QImage image);
void prepareRound(
QImage &image,
ImageRoundRadius radius,
RectParts corners = RectPart::AllCorners,
QRect target = QRect());
void prepareRound(
QImage &image,
QImage *cornerMasks,
RectParts corners = RectPart::AllCorners,
QRect target = QRect());
void prepareCircle(QImage &image);
QImage prepareColored(style::color add, QImage image);
QImage prepareOpaque(QImage image);
enum class Option {
None = 0,
Smooth = (1 << 0),
Blurred = (1 << 1),
Circled = (1 << 2),
RoundedLarge = (1 << 3),
RoundedSmall = (1 << 4),
RoundedTopLeft = (1 << 5),
RoundedTopRight = (1 << 6),
RoundedBottomLeft = (1 << 7),
RoundedBottomRight = (1 << 8),
RoundedAll = (None
| RoundedTopLeft
| RoundedTopRight
| RoundedBottomLeft
| RoundedBottomRight),
Colored = (1 << 9),
TransparentBackground = (1 << 10),
};
using Options = base::flags<Option>;
inline constexpr auto is_flag_type(Option) { return true; };
QImage prepare(QImage img, int w, int h, Options options, int outerw, int outerh, const style::color *colored = nullptr);
inline QPixmap pixmap(QImage img, int w, int h, Options options, int outerw, int outerh, const style::color *colored = nullptr) {
return QPixmap::fromImage(prepare(img, w, h, options, outerw, outerh, colored), Qt::ColorOnly);
}
} // namespace Images
class FileLoader;
class mtpFileLoader;
@ -35,13 +91,6 @@ enum LoadToCacheSetting {
LoadToCacheAsWell,
};
enum class ImageRoundRadius {
None,
Large,
Small,
Ellipse,
};
inline uint32 packInt(int32 a) {
return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(a);
}
@ -192,53 +241,6 @@ inline bool operator!=(const WebFileImageLocation &a, const WebFileImageLocation
return !(a == b);
}
namespace Images {
QImage prepareBlur(QImage image);
void prepareRound(
QImage &image,
ImageRoundRadius radius,
RectParts corners = RectPart::AllCorners,
QRect target = QRect());
void prepareRound(
QImage &image,
QImage *cornerMasks,
RectParts corners = RectPart::AllCorners,
QRect target = QRect());
void prepareCircle(QImage &image);
QImage prepareColored(style::color add, QImage image);
QImage prepareOpaque(QImage image);
enum class Option {
None = 0,
Smooth = (1 << 0),
Blurred = (1 << 1),
Circled = (1 << 2),
RoundedLarge = (1 << 3),
RoundedSmall = (1 << 4),
RoundedTopLeft = (1 << 5),
RoundedTopRight = (1 << 6),
RoundedBottomLeft = (1 << 7),
RoundedBottomRight = (1 << 8),
RoundedAll = (None
| RoundedTopLeft
| RoundedTopRight
| RoundedBottomLeft
| RoundedBottomRight),
Colored = (1 << 9),
TransparentBackground = (1 << 10),
};
using Options = base::flags<Option>;
inline constexpr auto is_flag_type(Option) { return true; };
QImage prepare(QImage img, int w, int h, Options options, int outerw, int outerh, const style::color *colored = nullptr);
inline QPixmap pixmap(QImage img, int w, int h, Options options, int outerw, int outerh, const style::color *colored = nullptr) {
return QPixmap::fromImage(prepare(img, w, h, options, outerw, outerh, colored), Qt::ColorOnly);
}
} // namespace Images
class DelayedStorageImage;
class HistoryItem;

View File

@ -57,7 +57,7 @@ struct Preview {
QString path;
Instance instance;
QByteArray content;
QPixmap preview;
QImage preview;
};
bool Apply(const QString &filepath);

View File

@ -94,9 +94,9 @@ QString fillLetters(const QString &name) {
class Generator {
public:
Generator(const Instance &theme, const CurrentData &current);
Generator(const Instance &theme, CurrentData &&current);
QPixmap generate();
QImage generate();
private:
enum class Status {
@ -173,7 +173,7 @@ private:
const Instance &_theme;
const style::palette &_palette;
const CurrentData &_current;
CurrentData _current;
Painter *_p = nullptr;
QRect _rect;
@ -350,16 +350,18 @@ void Generator::generateData() {
_bubbles.back().replyText.setText(st::messageTextStyle, "Mark Twain said that " + QString() + QChar(9757) + QChar(55356) + QChar(57339), Ui::DialogTextOptions());
}
Generator::Generator(const Instance &theme, const CurrentData &current)
Generator::Generator(const Instance &theme, CurrentData &&current)
: _theme(theme)
, _palette(_theme.palette)
, _current(current) {
, _current(std::move(current)) {
}
QPixmap Generator::generate() {
QImage Generator::generate() {
prepare();
auto result = QImage(_rect.size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
auto result = QImage(
_rect.size() * cIntRetinaFactor(),
QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(cRetinaFactor());
result.fill(st::themePreviewBg->c);
@ -379,7 +381,7 @@ QPixmap Generator::generate() {
}
Platform::PreviewWindowFramePaint(result, _palette, _body, _rect.width());
return App::pixmapFromImageInPlace(std::move(result));
return result;
}
void Generator::paintHistoryList() {
@ -408,11 +410,12 @@ void Generator::paintHistoryBackground() {
background.load(qsl(":/gui/art/bg.jpg"));
tiled = false;
} else {
background = _current.backgroundImage.toImage();
background = std::move(_current.backgroundImage);
tiled = _current.backgroundTiled;
}
}
background = std::move(background).convertToFormat(QImage::Format_ARGB32_Premultiplied);
background = std::move(background).convertToFormat(
QImage::Format_ARGB32_Premultiplied);
background.setDevicePixelRatio(cRetinaFactor());
_p->setClipRect(_history);
if (tiled) {
@ -420,7 +423,10 @@ void Generator::paintHistoryBackground() {
auto height = background.height();
auto repeatTimesX = qCeil(_history.width() * cIntRetinaFactor() / float64(width));
auto repeatTimesY = qCeil((_history.height() - fromy) * cIntRetinaFactor() / float64(height));
auto imageForTiled = QImage(width * repeatTimesX, height * repeatTimesY, QImage::Format_ARGB32_Premultiplied);
auto imageForTiled = QImage(
width * repeatTimesX,
height * repeatTimesY,
QImage::Format_ARGB32_Premultiplied);
imageForTiled.setDevicePixelRatio(background.devicePixelRatio());
auto imageForTiledBytes = imageForTiled.bits();
auto bytesInLine = width * sizeof(uint32);
@ -432,7 +438,8 @@ void Generator::paintHistoryBackground() {
imageForTiledBytes += bytesInLine;
}
imageBytes += background.bytesPerLine();
imageForTiledBytes += imageForTiled.bytesPerLine() - (repeatTimesX * bytesInLine);
imageForTiledBytes += imageForTiled.bytesPerLine()
- (repeatTimesX * bytesInLine);
}
}
_p->drawImage(_history.x(), _history.y() + fromy, imageForTiled);
@ -891,13 +898,18 @@ void Generator::restoreTextPalette() {
} // namespace
std::unique_ptr<Preview> GeneratePreview(const QString &filepath, const CurrentData &data) {
std::unique_ptr<Preview> GeneratePreview(
const QString &filepath,
CurrentData &&data) {
auto result = std::make_unique<Preview>();
result->path = filepath;
if (!LoadFromFile(filepath, &result->instance, &result->content)) {
return nullptr;
}
result->preview = Generator(result->instance, data).generate();
result->preview = Generator(
result->instance,
std::move(data)
).generate();
return result;
}

View File

@ -27,14 +27,20 @@ namespace Theme {
struct CurrentData {
int32 backgroundId = 0;
QPixmap backgroundImage;
QImage backgroundImage;
bool backgroundTiled = false;
};
std::unique_ptr<Preview> GeneratePreview(const QString &filepath, const CurrentData &data);
std::unique_ptr<Preview> GeneratePreview(
const QString &filepath,
CurrentData &&data);
int DefaultPreviewTitleHeight();
void DefaultPreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRect body, int outerWidth);
void DefaultPreviewWindowFramePaint(
QImage &preview,
const style::palette &palette,
QRect body,
int outerWidth);
} // namespace Theme
} // namespace Window