mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Use QImage instead of QPixmap for theme preview.
Working with QPixmap from non-main thread is not defined.
This commit is contained in:
parent
e89350d4b7
commit
0ef3e19bc2
6 changed files with 113 additions and 77 deletions
|
@ -1710,14 +1710,16 @@ void MediaView::initThemePreview() {
|
||||||
|
|
||||||
Window::Theme::CurrentData current;
|
Window::Theme::CurrentData current;
|
||||||
current.backgroundId = Window::Theme::Background()->id();
|
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();
|
current.backgroundTiled = Window::Theme::Background()->tile();
|
||||||
|
|
||||||
const auto path = _doc->location().name();
|
const auto path = _doc->location().name();
|
||||||
const auto id = _themePreviewId = rand_value<uint64>();
|
const auto id = _themePreviewId = rand_value<uint64>();
|
||||||
const auto weak = make_weak(this);
|
const auto weak = make_weak(this);
|
||||||
crl::async([=] {
|
crl::async([=, data = std::move(current)]() mutable {
|
||||||
auto preview = Window::Theme::GeneratePreview(path, current);
|
auto preview = Window::Theme::GeneratePreview(
|
||||||
|
path,
|
||||||
|
std::move(data));
|
||||||
crl::on_main(weak, [=, result = std::move(preview)]() mutable {
|
crl::on_main(weak, [=, result = std::move(preview)]() mutable {
|
||||||
if (id != _themePreviewId) {
|
if (id != _themePreviewId) {
|
||||||
return;
|
return;
|
||||||
|
@ -2261,12 +2263,19 @@ void MediaView::paintThemePreview(Painter &p, QRect clip) {
|
||||||
auto fill = _themePreviewRect.intersected(clip);
|
auto fill = _themePreviewRect.intersected(clip);
|
||||||
if (!fill.isEmpty()) {
|
if (!fill.isEmpty()) {
|
||||||
if (_themePreview) {
|
if (_themePreview) {
|
||||||
p.drawPixmapLeft(_themePreviewRect.x(), _themePreviewRect.y(), width(), _themePreview->preview);
|
p.drawImage(
|
||||||
|
myrtlrect(_themePreviewRect).topLeft(),
|
||||||
|
_themePreview->preview);
|
||||||
} else {
|
} else {
|
||||||
p.fillRect(fill, st::themePreviewBg);
|
p.fillRect(fill, st::themePreviewBg);
|
||||||
p.setFont(st::themePreviewLoadingFont);
|
p.setFont(st::themePreviewLoadingFont);
|
||||||
p.setPen(st::themePreviewLoadingFg);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,13 @@ const QPixmap &circleMask(int width, int height) {
|
||||||
|
|
||||||
} // namespace
|
} // 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) {
|
QImage prepareBlur(QImage img) {
|
||||||
auto ratio = img.devicePixelRatio();
|
auto ratio = img.devicePixelRatio();
|
||||||
auto fmt = img.format();
|
auto fmt = img.format();
|
||||||
|
|
|
@ -22,6 +22,62 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
|
|
||||||
#include "base/flags.h"
|
#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 FileLoader;
|
||||||
class mtpFileLoader;
|
class mtpFileLoader;
|
||||||
|
|
||||||
|
@ -35,13 +91,6 @@ enum LoadToCacheSetting {
|
||||||
LoadToCacheAsWell,
|
LoadToCacheAsWell,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ImageRoundRadius {
|
|
||||||
None,
|
|
||||||
Large,
|
|
||||||
Small,
|
|
||||||
Ellipse,
|
|
||||||
};
|
|
||||||
|
|
||||||
inline uint32 packInt(int32 a) {
|
inline uint32 packInt(int32 a) {
|
||||||
return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(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);
|
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 DelayedStorageImage;
|
||||||
|
|
||||||
class HistoryItem;
|
class HistoryItem;
|
||||||
|
|
|
@ -57,7 +57,7 @@ struct Preview {
|
||||||
QString path;
|
QString path;
|
||||||
Instance instance;
|
Instance instance;
|
||||||
QByteArray content;
|
QByteArray content;
|
||||||
QPixmap preview;
|
QImage preview;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Apply(const QString &filepath);
|
bool Apply(const QString &filepath);
|
||||||
|
|
|
@ -94,9 +94,9 @@ QString fillLetters(const QString &name) {
|
||||||
|
|
||||||
class Generator {
|
class Generator {
|
||||||
public:
|
public:
|
||||||
Generator(const Instance &theme, const CurrentData ¤t);
|
Generator(const Instance &theme, CurrentData &¤t);
|
||||||
|
|
||||||
QPixmap generate();
|
QImage generate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class Status {
|
enum class Status {
|
||||||
|
@ -173,7 +173,7 @@ private:
|
||||||
|
|
||||||
const Instance &_theme;
|
const Instance &_theme;
|
||||||
const style::palette &_palette;
|
const style::palette &_palette;
|
||||||
const CurrentData &_current;
|
CurrentData _current;
|
||||||
Painter *_p = nullptr;
|
Painter *_p = nullptr;
|
||||||
|
|
||||||
QRect _rect;
|
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());
|
_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 ¤t)
|
Generator::Generator(const Instance &theme, CurrentData &¤t)
|
||||||
: _theme(theme)
|
: _theme(theme)
|
||||||
, _palette(_theme.palette)
|
, _palette(_theme.palette)
|
||||||
, _current(current) {
|
, _current(std::move(current)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap Generator::generate() {
|
QImage Generator::generate() {
|
||||||
prepare();
|
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.setDevicePixelRatio(cRetinaFactor());
|
||||||
result.fill(st::themePreviewBg->c);
|
result.fill(st::themePreviewBg->c);
|
||||||
|
|
||||||
|
@ -379,7 +381,7 @@ QPixmap Generator::generate() {
|
||||||
}
|
}
|
||||||
Platform::PreviewWindowFramePaint(result, _palette, _body, _rect.width());
|
Platform::PreviewWindowFramePaint(result, _palette, _body, _rect.width());
|
||||||
|
|
||||||
return App::pixmapFromImageInPlace(std::move(result));
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Generator::paintHistoryList() {
|
void Generator::paintHistoryList() {
|
||||||
|
@ -408,11 +410,12 @@ void Generator::paintHistoryBackground() {
|
||||||
background.load(qsl(":/gui/art/bg.jpg"));
|
background.load(qsl(":/gui/art/bg.jpg"));
|
||||||
tiled = false;
|
tiled = false;
|
||||||
} else {
|
} else {
|
||||||
background = _current.backgroundImage.toImage();
|
background = std::move(_current.backgroundImage);
|
||||||
tiled = _current.backgroundTiled;
|
tiled = _current.backgroundTiled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
background = std::move(background).convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
background = std::move(background).convertToFormat(
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
background.setDevicePixelRatio(cRetinaFactor());
|
background.setDevicePixelRatio(cRetinaFactor());
|
||||||
_p->setClipRect(_history);
|
_p->setClipRect(_history);
|
||||||
if (tiled) {
|
if (tiled) {
|
||||||
|
@ -420,7 +423,10 @@ void Generator::paintHistoryBackground() {
|
||||||
auto height = background.height();
|
auto height = background.height();
|
||||||
auto repeatTimesX = qCeil(_history.width() * cIntRetinaFactor() / float64(width));
|
auto repeatTimesX = qCeil(_history.width() * cIntRetinaFactor() / float64(width));
|
||||||
auto repeatTimesY = qCeil((_history.height() - fromy) * cIntRetinaFactor() / float64(height));
|
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());
|
imageForTiled.setDevicePixelRatio(background.devicePixelRatio());
|
||||||
auto imageForTiledBytes = imageForTiled.bits();
|
auto imageForTiledBytes = imageForTiled.bits();
|
||||||
auto bytesInLine = width * sizeof(uint32);
|
auto bytesInLine = width * sizeof(uint32);
|
||||||
|
@ -432,7 +438,8 @@ void Generator::paintHistoryBackground() {
|
||||||
imageForTiledBytes += bytesInLine;
|
imageForTiledBytes += bytesInLine;
|
||||||
}
|
}
|
||||||
imageBytes += background.bytesPerLine();
|
imageBytes += background.bytesPerLine();
|
||||||
imageForTiledBytes += imageForTiled.bytesPerLine() - (repeatTimesX * bytesInLine);
|
imageForTiledBytes += imageForTiled.bytesPerLine()
|
||||||
|
- (repeatTimesX * bytesInLine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_p->drawImage(_history.x(), _history.y() + fromy, imageForTiled);
|
_p->drawImage(_history.x(), _history.y() + fromy, imageForTiled);
|
||||||
|
@ -891,13 +898,18 @@ void Generator::restoreTextPalette() {
|
||||||
|
|
||||||
} // namespace
|
} // 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>();
|
auto result = std::make_unique<Preview>();
|
||||||
result->path = filepath;
|
result->path = filepath;
|
||||||
if (!LoadFromFile(filepath, &result->instance, &result->content)) {
|
if (!LoadFromFile(filepath, &result->instance, &result->content)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
result->preview = Generator(result->instance, data).generate();
|
result->preview = Generator(
|
||||||
|
result->instance,
|
||||||
|
std::move(data)
|
||||||
|
).generate();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,20 @@ namespace Theme {
|
||||||
|
|
||||||
struct CurrentData {
|
struct CurrentData {
|
||||||
int32 backgroundId = 0;
|
int32 backgroundId = 0;
|
||||||
QPixmap backgroundImage;
|
QImage backgroundImage;
|
||||||
bool backgroundTiled = false;
|
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();
|
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 Theme
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
Loading…
Add table
Reference in a new issue