diff --git a/Telegram/SourceFiles/boxes/background_box.cpp b/Telegram/SourceFiles/boxes/background_box.cpp index a0cc65620..360e79d60 100644 --- a/Telegram/SourceFiles/boxes/background_box.cpp +++ b/Telegram/SourceFiles/boxes/background_box.cpp @@ -326,8 +326,18 @@ void BackgroundBox::Inner::validatePaperThumbnail( paper.dataMedia = document->createMediaView(); paper.dataMedia->thumbnailWanted(paper.data.fileOrigin()); } - } - if (!paper.dataMedia || !paper.dataMedia->thumbnail()) { + if (!paper.dataMedia->thumbnail()) { + return; + } + } else if (!paper.data.backgroundColors().empty()) { + paper.thumbnail = Ui::PixmapFromImage( + Data::GenerateWallPaper( + st::backgroundSize * cIntRetinaFactor(), + paper.data.backgroundColors(), + paper.data.gradientRotation())); + paper.thumbnail.setDevicePixelRatio(cRetinaFactor()); + return; + } else { return; } } diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index d4f836e2b..a6136f4fc 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -419,12 +419,24 @@ BackgroundPreviewBox::BackgroundPreviewBox( if (_media) { _media->thumbnailWanted(_paper.fileOrigin()); } + generateBackground(); _controller->session().downloaderTaskFinished( ) | rpl::start_with_next([=] { update(); }, lifetime()); } +void BackgroundPreviewBox::generateBackground() { + if (_paper.backgroundColors().empty()) { + return; + } + _generated = Ui::PixmapFromImage(Data::GenerateWallPaper( + QSize(st::boxWideWidth, st::boxWideWidth) * cIntRetinaFactor(), + _paper.backgroundColors(), + _paper.gradientRotation())); + _generated.setDevicePixelRatio(cRetinaFactor()); +} + not_null BackgroundPreviewBox::delegate() { return static_cast(this); } @@ -525,21 +537,23 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) { Painter p(this); const auto ms = crl::now(); - const auto color = _paper.backgroundColor(); - if (color) { - p.fillRect(e->rect(), *color); + if (_scaled.isNull()) { + setScaledFromThumb(); } - if (!color || _paper.isPattern()) { - if (!_scaled.isNull() || setScaledFromThumb()) { - paintImage(p); - paintRadial(p); - } else if (!color) { - p.fillRect(e->rect(), st::boxBg); - return; - } else { - // Progress of pattern loading. - paintRadial(p); - } + if (!_generated.isNull() + && (_scaled.isNull() + || (_fadeOutThumbnail.isNull() && _fadeIn.animating()))) { + p.drawPixmap(0, 0, _generated); + } + if (!_scaled.isNull()) { + paintImage(p); + paintRadial(p); + } else if (_generated.isNull()) { + p.fillRect(e->rect(), st::boxBg); + return; + } else { + // Progress of pattern loading. + paintRadial(p); } paintTexts(p, ms); } @@ -655,7 +669,10 @@ void BackgroundPreviewBox::radialAnimationCallback(crl::time now) { checkLoadedDocument(); } -bool BackgroundPreviewBox::setScaledFromThumb() { +void BackgroundPreviewBox::setScaledFromThumb() { + if (!_scaled.isNull()) { + return; + } const auto localThumbnail = _paper.localThumbnail(); const auto thumbnail = localThumbnail ? localThumbnail @@ -663,9 +680,9 @@ bool BackgroundPreviewBox::setScaledFromThumb() { ? _media->thumbnail() : nullptr; if (!thumbnail) { - return false; + return; } else if (_paper.isPattern() && _paper.document() != nullptr) { - return false; + return; } auto scaled = PrepareScaledFromFull( thumbnail->original(), @@ -679,7 +696,6 @@ bool BackgroundPreviewBox::setScaledFromThumb() { Data::PrepareBlurredBackground(thumbnail->original()), Images::Option(0)); setScaledFromImage(std::move(scaled), std::move(blurred)); - return true; } void BackgroundPreviewBox::setScaledFromImage( diff --git a/Telegram/SourceFiles/boxes/background_preview_box.h b/Telegram/SourceFiles/boxes/background_preview_box.h index e0345afae..59d00a306 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.h +++ b/Telegram/SourceFiles/boxes/background_preview_box.h @@ -56,8 +56,9 @@ private: void radialAnimationCallback(crl::time now); QRect radialRect() const; + void generateBackground(); void checkLoadedDocument(); - bool setScaledFromThumb(); + void setScaledFromThumb(); void setScaledFromImage(QImage &&image, QImage &&blurred); void updateServiceBg(const std::vector &bg); std::vector patternBackgroundColors() const; @@ -76,7 +77,7 @@ private: Data::WallPaper _paper; std::shared_ptr _media; QImage _full; - QPixmap _scaled, _blurred, _fadeOutThumbnail; + QPixmap _generated, _scaled, _blurred, _fadeOutThumbnail; Ui::Animations::Simple _fadeIn; Ui::RadialAnimation _radial; base::binary_guard _generating; diff --git a/Telegram/SourceFiles/data/data_wall_paper.cpp b/Telegram/SourceFiles/data/data_wall_paper.cpp index a71931e4f..ade068261 100644 --- a/Telegram/SourceFiles/data/data_wall_paper.cpp +++ b/Telegram/SourceFiles/data/data_wall_paper.cpp @@ -755,26 +755,31 @@ bool IsCloudWallPaper(const WallPaper &paper) { p.fillRect(0, 0, width, height, QBrush(std::move(gradient))); p.end(); - return image; + return Images::DitherImage(std::move(image)); } -QImage PreparePatternImage( +QImage GenerateWallPaper( QSize size, - Fn drawPattern, const std::vector &bg, - int rotation, - float64 opacity) { + int gradientRotation, + float64 patternOpacity, + Fn drawPattern) { auto result = QImage(size, QImage::Format_ARGB32_Premultiplied); if (bg.size() < 2) { result.fill(bg.empty() ? DefaultBackgroundColor() : bg.front()); } else { - result = FillDitheredGradient(std::move(result), bg, rotation); + result = FillDitheredGradient( + std::move(result), + bg, + gradientRotation); + } + if (drawPattern) { + auto p = QPainter(&result); + p.setCompositionMode(QPainter::CompositionMode_SoftLight); + p.setOpacity(patternOpacity); + drawPattern(p); + p.end(); } - auto p = QPainter(&result); - p.setCompositionMode(QPainter::CompositionMode_SoftLight); - p.setOpacity(opacity); - drawPattern(p); - p.end(); return result; } @@ -782,11 +787,16 @@ QImage PreparePatternImage( QImage PreparePatternImage( QImage pattern, const std::vector &bg, - int rotation, - float64 opacity) { - auto result = PreparePatternImage(pattern.size(), [&](QPainter &p) { - p.drawImage(QRect(QPoint(), pattern.size()), pattern); - }, bg, rotation, opacity); + int gradientRotation, + float64 patternOpacity) { + auto result = GenerateWallPaper( + pattern.size(), + bg, + gradientRotation, + patternOpacity, + [&](QPainter &p) { + p.drawImage(QRect(QPoint(), pattern.size()), pattern); + }); pattern = QImage(); return result; diff --git a/Telegram/SourceFiles/data/data_wall_paper.h b/Telegram/SourceFiles/data/data_wall_paper.h index e4ff66e78..ab514d870 100644 --- a/Telegram/SourceFiles/data/data_wall_paper.h +++ b/Telegram/SourceFiles/data/data_wall_paper.h @@ -122,17 +122,17 @@ private: [[nodiscard]] bool IsDefaultWallPaper(const WallPaper &paper); [[nodiscard]] bool IsCloudWallPaper(const WallPaper &paper); -[[nodiscard]] QImage PreparePatternImage( +[[nodiscard]] QImage GenerateWallPaper( QSize size, - Fn drawPattern, const std::vector &bg, - int rotation, - float64 opacity); + int gradientRotation, + float64 patternOpacity = 1., + Fn drawPattern = nullptr); [[nodiscard]] QImage PreparePatternImage( QImage pattern, const std::vector &bg, - int rotation, - float64 opacity); + int gradientRotation, + float64 patternOpacity); [[nodiscard]] QImage PrepareBlurredBackground(QImage image); [[nodiscard]] QImage GenerateDitheredGradient( const std::vector &colors, diff --git a/Telegram/SourceFiles/window/themes/window_theme.cpp b/Telegram/SourceFiles/window/themes/window_theme.cpp index d2bb49973..10babdca8 100644 --- a/Telegram/SourceFiles/window/themes/window_theme.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme.cpp @@ -436,77 +436,6 @@ bool InitializeFromSaved(Saved &&saved) { return true; } -[[nodiscard]] QImage DitherImage(QImage image) { - Expects(image.bytesPerLine() == image.width() * 4); - - const auto width = image.width(); - const auto height = image.height(); - - if (width < 16 || height < 16) { - return image; - } - - const auto area = width * height; - const auto shifts = std::make_unique(area); - memset_rand(shifts.get(), area); - - // shiftx = int(shift & 0x0F) - 8; shifty = int(shift >> 4) - 8; - // Clamp shifts close to edges. - for (auto y = 0; y != 8; ++y) { - const auto min = 8 - y; - const auto shifted = (min << 4); - auto shift = shifts.get() + y * width; - for (const auto till = shift + width; shift != till; ++shift) { - if ((*shift >> 4) < min) { - *shift = shifted | (*shift & 0x0F); - } - } - } - for (auto y = height - 7; y != height; ++y) { - const auto max = 8 + (height - y - 1); - const auto shifted = (max << 4); - auto shift = shifts.get() + y * width; - for (const auto till = shift + width; shift != till; ++shift) { - if ((*shift >> 4) > max) { - *shift = shifted | (*shift & 0x0F); - } - } - } - for (auto shift = shifts.get(), ytill = shift + area - ; shift != ytill - ; shift += width - 8) { - for (const auto till = shift + 8; shift != till; ++shift) { - const auto min = (till - shift); - if ((*shift & 0x0F) < min) { - *shift = (*shift & 0xF0) | min; - } - } - } - for (auto shift = shifts.get(), ytill = shift + area; shift != ytill;) { - shift += width - 7; - for (const auto till = shift + 7; shift != till; ++shift) { - const auto max = 8 + (till - shift - 1); - if ((*shift & 0x0F) > max) { - *shift = (*shift & 0xF0) | max; - } - } - } - - auto result = image; - result.detach(); - - const auto src = reinterpret_cast(image.constBits()); - const auto dst = reinterpret_cast(result.bits()); - for (auto index = 0; index != area; ++index) { - const auto shift = shifts[index]; - const auto shiftx = int(shift & 0x0F) - 8; - const auto shifty = int(shift >> 4) - 8; - dst[index] = src[index + (shifty * width) + shiftx]; - } - - return result; -} - [[nodiscard]] QImage PostprocessBackgroundImage( QImage image, const Data::WallPaper &paper) { @@ -517,7 +446,7 @@ bool InitializeFromSaved(Saved &&saved) { image.setDevicePixelRatio(cRetinaFactor()); if (Data::IsDefaultWallPaper(paper) || Data::details::IsTestingDefaultWallPaper(paper)) { - return DitherImage(std::move(image)); + return Images::DitherImage(std::move(image)); } return image; } diff --git a/Telegram/SourceFiles/window/window_main_menu.cpp b/Telegram/SourceFiles/window/window_main_menu.cpp index a755be623..e2a8b031e 100644 --- a/Telegram/SourceFiles/window/window_main_menu.cpp +++ b/Telegram/SourceFiles/window/window_main_menu.cpp @@ -993,13 +993,13 @@ void MainMenu::refreshBackground() { QRect to, from; Window::Theme::ComputeBackgroundRects(fill, pixmap.size(), to, from); - auto backgroundImage = paper.isPattern() - ? Data::PreparePatternImage( + auto backgroundImage = !paper.backgroundColors().empty() + ? Data::GenerateWallPaper( fill.size() * cIntRetinaFactor(), - [&](QPainter &p) { p.drawPixmap(to, pixmap, from); }, paper.backgroundColors(), paper.gradientRotation(), - paper.patternOpacity()) + paper.patternOpacity(), + [&](QPainter &p) { p.drawPixmap(to, pixmap, from); }) : QImage( fill.size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 40f0e3c6d..3d5fcdb7d 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 40f0e3c6d43a02c20a5cb189ead8559c97bbbd9b +Subproject commit 3d5fcdb7ddab336ee2fadc3ceeced420e2c1f504