Move background caching to Window::SessionController.

This commit is contained in:
John Preston 2021-08-13 18:39:50 +03:00
parent 1bc5277d51
commit 2667bb3568
5 changed files with 168 additions and 161 deletions

View file

@ -7,14 +7,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/ */
#include "mainwidget.h" #include "mainwidget.h"
#include <rpl/combine.h>
#include <rpl/merge.h>
#include <rpl/flatten_latest.h>
#include "api/api_updates.h" #include "api/api_updates.h"
#include "data/data_photo.h" #include "data/data_photo.h"
#include "data/data_document.h" #include "data/data_document.h"
#include "data/data_document_media.h" #include "data/data_document_media.h"
#include "data/data_document_resolver.h" #include "data/data_document_resolver.h"
#include "data/data_wall_paper.h"
#include "data/data_web_page.h" #include "data/data_web_page.h"
#include "data/data_game.h" #include "data/data_game.h"
#include "data/data_peer_values.h" #include "data/data_peer_values.h"
@ -122,9 +120,6 @@ namespace {
// Send channel views each second. // Send channel views each second.
constexpr auto kSendViewsTimeout = crl::time(1000); constexpr auto kSendViewsTimeout = crl::time(1000);
// Cache background scaled image after 3s.
constexpr auto kCacheBackgroundTimeout = 3000;
} // namespace } // namespace
enum StackItemType { enum StackItemType {
@ -239,7 +234,6 @@ MainWidget::MainWidget(
, _dialogs(this, _controller) , _dialogs(this, _controller)
, _history(this, _controller) , _history(this, _controller)
, _playerPlaylist(this, _controller) , _playerPlaylist(this, _controller)
, _cacheBackgroundTimer([=] { cacheBackground(); })
, _viewsIncrementTimer([=] { viewsIncrement(); }) , _viewsIncrementTimer([=] { viewsIncrement(); })
, _changelogs(Core::Changelogs::Create(&controller->session())) { , _changelogs(Core::Changelogs::Create(&controller->session())) {
setupConnectingWidget(); setupConnectingWidget();
@ -345,15 +339,6 @@ MainWidget::MainWidget(
QCoreApplication::instance()->installEventFilter(this); QCoreApplication::instance()->installEventFilter(this);
using Update = Window::Theme::BackgroundUpdate;
Window::Theme::Background()->updates(
) | rpl::start_with_next([=](const Update &update) {
if (update.type == Update::Type::New
|| update.type == Update::Type::Changed) {
clearCachedBackground();
}
}, lifetime());
subscribe(Media::Player::instance()->playerWidgetOver(), [this](bool over) { subscribe(Media::Player::instance()->playerWidgetOver(), [this](bool over) {
if (over) { if (over) {
if (_playerPlaylist->isHidden()) { if (_playerPlaylist->isHidden()) {
@ -780,76 +765,6 @@ bool MainWidget::selectingPeer() const {
return _hider ? true : false; return _hider ? true : false;
} }
void MainWidget::cacheBackground() {
const auto background = Window::Theme::Background();
if (background->colorForFill()) {
return;
}
const auto gradient = background->gradientForFill();
const auto patternOpacity = background->paper().patternOpacity();
const auto &bg = background->pixmap();
if (background->tile() || bg.isNull()) {
auto result = gradient.isNull()
? QImage(
_willCacheFor.size() * cIntRetinaFactor(),
QImage::Format_ARGB32_Premultiplied)
: gradient.scaled(
_willCacheFor.size() * cIntRetinaFactor(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
result.setDevicePixelRatio(cRetinaFactor());
if (!bg.isNull()) {
QPainter p(&result);
if (!gradient.isNull()) {
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
p.setOpacity(patternOpacity);
}
const auto &tiled = background->pixmapForTiled();
auto w = tiled.width() / cRetinaFactor();
auto h = tiled.height() / cRetinaFactor();
auto sx = 0;
auto sy = 0;
auto cx = qCeil(_willCacheFor.width() / w);
auto cy = qCeil(_willCacheFor.height() / h);
for (int i = sx; i < cx; ++i) {
for (int j = sy; j < cy; ++j) {
p.drawPixmap(QPointF(i * w, j * h), tiled);
}
}
}
_cachedX = 0;
_cachedY = 0;
_cachedBackground = Ui::PixmapFromImage(std::move(result));
} else {
QRect to, from;
Window::Theme::ComputeBackgroundRects(_willCacheFor, bg.size(), to, from);
auto image = bg.toImage().copy(from).scaled(
to.width() * cIntRetinaFactor(),
to.height() * cIntRetinaFactor(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
auto result = gradient.isNull()
? std::move(image)
: gradient.scaled(
image.size(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
result.setDevicePixelRatio(cRetinaFactor());
if (!gradient.isNull()) {
QPainter p(&result);
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
p.setOpacity(patternOpacity);
p.drawImage(QRect(QPoint(), to.size()), image);
}
image = QImage();
_cachedX = to.x();
_cachedY = to.y();
_cachedBackground = Ui::PixmapFromImage(std::move(result));
_cachedBackground.setDevicePixelRatio(cRetinaFactor());
}
_cachedFor = _willCacheFor;
}
crl::time MainWidget::highlightStartTime(not_null<const HistoryItem*> item) const { crl::time MainWidget::highlightStartTime(not_null<const HistoryItem*> item) const {
return _history->highlightStartTime(item); return _history->highlightStartTime(item);
} }
@ -1179,25 +1094,6 @@ void MainWidget::dialogsCancelled() {
_history->activate(); _history->activate();
} }
void MainWidget::clearCachedBackground() {
_cachedBackground = QPixmap();
_cacheBackgroundTimer.cancel();
update();
}
QPixmap MainWidget::cachedBackground(const QRect &forRect, int &x, int &y) {
if (!_cachedBackground.isNull() && forRect == _cachedFor) {
x = _cachedX;
y = _cachedY;
return _cachedBackground;
}
if (_willCacheFor != forRect || !_cacheBackgroundTimer.isActive()) {
_willCacheFor = forRect;
_cacheBackgroundTimer.callOnce(kCacheBackgroundTimeout);
}
return QPixmap();
}
void MainWidget::setChatBackground( void MainWidget::setChatBackground(
const Data::WallPaper &background, const Data::WallPaper &background,
QImage &&image) { QImage &&image) {

View file

@ -185,8 +185,6 @@ public:
void searchMessages(const QString &query, Dialogs::Key inChat); void searchMessages(const QString &query, Dialogs::Key inChat);
QPixmap cachedBackground(const QRect &forRect, int &x, int &y);
void setChatBackground( void setChatBackground(
const Data::WallPaper &background, const Data::WallPaper &background,
QImage &&image = QImage()); QImage &&image = QImage());
@ -299,9 +297,6 @@ private:
void showAll(); void showAll();
void clearHider(not_null<Window::HistoryHider*> instance); void clearHider(not_null<Window::HistoryHider*> instance);
void cacheBackground();
void clearCachedBackground();
[[nodiscard]] auto floatPlayerDelegate() [[nodiscard]] auto floatPlayerDelegate()
-> not_null<Media::Player::FloatDelegate*>; -> not_null<Media::Player::FloatDelegate*>;
not_null<Ui::RpWidget*> floatPlayerWidget() override; not_null<Ui::RpWidget*> floatPlayerWidget() override;
@ -389,12 +384,6 @@ private:
int _exportTopBarHeight = 0; int _exportTopBarHeight = 0;
int _contentScrollAddToY = 0; int _contentScrollAddToY = 0;
QPixmap _cachedBackground;
QRect _cachedFor, _willCacheFor;
int _cachedX = 0;
int _cachedY = 0;
base::Timer _cacheBackgroundTimer;
PhotoData *_deletingPhoto = nullptr; PhotoData *_deletingPhoto = nullptr;
base::flat_map<not_null<PeerData*>, base::flat_set<MsgId>> _viewsIncremented; base::flat_map<not_null<PeerData*>, base::flat_set<MsgId>> _viewsIncremented;

View file

@ -97,51 +97,50 @@ void SectionWidget::PaintBackground(
return; return;
} }
auto fromy = controller->content()->backgroundFromY(); auto fromy = controller->content()->backgroundFromY();
auto x = 0, y = 0; auto cached = controller->cachedBackground(fill);
auto cached = controller->content()->cachedBackground(fill, x, y); if (!cached.pixmap.isNull()) {
if (cached.isNull()) { p.drawPixmap(cached.x, fromy + cached.y, cached.pixmap);
const auto gradient = background->gradientForFill(); return;
const auto patternOpacity = background->paper().patternOpacity(); }
const auto &bg = background->pixmap(); const auto gradient = background->gradientForFill();
if (background->tile() || bg.isNull()) { const auto patternOpacity = background->paper().patternOpacity();
if (!gradient.isNull()) { const auto &bg = background->pixmap();
auto hq = PainterHighQualityEnabler(p); if (!bg.isNull() && !background->tile()) {
p.drawImage(fill, gradient); auto hq = PainterHighQualityEnabler(p);
p.setCompositionMode(QPainter::CompositionMode_SoftLight); QRect to, from;
p.setOpacity(patternOpacity); Window::Theme::ComputeBackgroundRects(fill, bg.size(), to, from);
} if (!gradient.isNull()) {
if (!bg.isNull()) { p.drawImage(to, gradient);
auto &tiled = background->pixmapForTiled(); p.setCompositionMode(QPainter::CompositionMode_SoftLight);
auto left = clip.left(); p.setOpacity(patternOpacity);
auto top = clip.top(); }
auto right = clip.left() + clip.width(); to.moveTop(to.top() + fromy);
auto bottom = clip.top() + clip.height(); p.drawPixmap(to, bg, from);
auto w = tiled.width() / cRetinaFactor(); return;
auto h = tiled.height() / cRetinaFactor(); }
auto sx = qFloor(left / w); if (!gradient.isNull()) {
auto sy = qFloor((top - fromy) / h); auto hq = PainterHighQualityEnabler(p);
auto cx = qCeil(right / w); p.drawImage(fill, gradient);
auto cy = qCeil((bottom - fromy) / h); p.setCompositionMode(QPainter::CompositionMode_SoftLight);
for (auto i = sx; i < cx; ++i) { p.setOpacity(patternOpacity);
for (auto j = sy; j < cy; ++j) { }
p.drawPixmap(QPointF(i * w, fromy + j * h), tiled); if (!bg.isNull()) {
} auto &tiled = background->pixmapForTiled();
} auto left = clip.left();
} auto top = clip.top();
} else { auto right = clip.left() + clip.width();
auto hq = PainterHighQualityEnabler(p); auto bottom = clip.top() + clip.height();
QRect to, from; auto w = tiled.width() / cRetinaFactor();
Window::Theme::ComputeBackgroundRects(fill, bg.size(), to, from); auto h = tiled.height() / cRetinaFactor();
if (!gradient.isNull()) { auto sx = qFloor(left / w);
p.drawImage(to, gradient); auto sy = qFloor((top - fromy) / h);
p.setCompositionMode(QPainter::CompositionMode_SoftLight); auto cx = qCeil(right / w);
p.setOpacity(patternOpacity); auto cy = qCeil((bottom - fromy) / h);
} for (auto i = sx; i < cx; ++i) {
to.moveTop(to.top() + fromy); for (auto j = sy; j < cy; ++j) {
p.drawPixmap(to, bg, from); p.drawPixmap(QPointF(i * w, fromy + j * h), tiled);
}
} }
} else {
p.drawPixmap(x, fromy + y, cached);
} }
} }

View file

@ -59,6 +59,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "support/support_helper.h" #include "support/support_helper.h"
#include "storage/file_upload.h" #include "storage/file_upload.h"
#include "facades.h" #include "facades.h"
#include "window/themes/window_theme.h"
#include "styles/style_window.h" #include "styles/style_window.h"
#include "styles/style_dialogs.h" #include "styles/style_dialogs.h"
#include "styles/style_layers.h" // st::boxLabel #include "styles/style_layers.h" // st::boxLabel
@ -68,6 +69,9 @@ namespace {
constexpr auto kMaxChatEntryHistorySize = 50; constexpr auto kMaxChatEntryHistorySize = 50;
// Cache background scaled image after 3s.
constexpr auto kCacheBackgroundTimeout = 3000;
} // namespace } // namespace
void ActivateWindow(not_null<SessionController*> controller) { void ActivateWindow(not_null<SessionController*> controller) {
@ -463,7 +467,8 @@ SessionController::SessionController(
std::make_unique<ChatHelpers::TabbedSelector>( std::make_unique<ChatHelpers::TabbedSelector>(
_window->widget(), _window->widget(),
this)) this))
, _invitePeekTimer([=] { checkInvitePeek(); }) { , _invitePeekTimer([=] { checkInvitePeek(); })
, _cacheBackgroundTimer([=] { cacheBackground(); }) {
init(); init();
if (Media::Player::instance()->pauseGifByRoundVideo()) { if (Media::Player::instance()->pauseGifByRoundVideo()) {
@ -506,6 +511,15 @@ SessionController::SessionController(
})); }));
}, _lifetime); }, _lifetime);
using Update = Window::Theme::BackgroundUpdate;
Window::Theme::Background()->updates(
) | rpl::start_with_next([=](const Update &update) {
if (update.type == Update::Type::New
|| update.type == Update::Type::Changed) {
clearCachedBackground();
}
}, lifetime());
session->addWindow(this); session->addWindow(this);
} }
@ -1303,6 +1317,99 @@ void SessionController::openDocument(
session().data().message(contextId)); session().data().message(contextId));
} }
CachedBackground SessionController::cachedBackground(QRect area) {
if (!_cachedBackground.pixmap.isNull()
&& area == _cachedBackground.area) {
return _cachedBackground;
}
if (_willCacheForArea != area || !_cacheBackgroundTimer.isActive()) {
_willCacheForArea = area;
_cacheBackgroundTimer.callOnce(kCacheBackgroundTimeout);
}
return {};
}
void SessionController::cacheBackground() {
const auto background = Window::Theme::Background();
if (background->colorForFill()) {
return;
}
const auto gradient = background->gradientForFill();
const auto patternOpacity = background->paper().patternOpacity();
const auto &bg = background->pixmap();
if (background->tile() || bg.isNull()) {
auto result = gradient.isNull()
? QImage(
_willCacheForArea.size() * cIntRetinaFactor(),
QImage::Format_ARGB32_Premultiplied)
: gradient.scaled(
_willCacheForArea.size() * cIntRetinaFactor(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
result.setDevicePixelRatio(cRetinaFactor());
if (!bg.isNull()) {
QPainter p(&result);
if (!gradient.isNull()) {
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
p.setOpacity(patternOpacity);
}
const auto &tiled = background->pixmapForTiled();
auto w = tiled.width() / cRetinaFactor();
auto h = tiled.height() / cRetinaFactor();
auto sx = 0;
auto sy = 0;
auto cx = qCeil(_willCacheForArea.width() / w);
auto cy = qCeil(_willCacheForArea.height() / h);
for (int i = sx; i < cx; ++i) {
for (int j = sy; j < cy; ++j) {
p.drawPixmap(QPointF(i * w, j * h), tiled);
}
}
}
_cachedBackground = CachedBackground{
.pixmap = Ui::PixmapFromImage(std::move(result)),
.area = _willCacheForArea,
};
} else {
QRect to, from;
Window::Theme::ComputeBackgroundRects(
_willCacheForArea,
bg.size(),
to,
from);
auto image = bg.toImage().copy(from).scaled(
to.width() * cIntRetinaFactor(),
to.height() * cIntRetinaFactor(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
auto result = gradient.isNull()
? std::move(image)
: gradient.scaled(
image.size(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
result.setDevicePixelRatio(cRetinaFactor());
if (!gradient.isNull()) {
QPainter p(&result);
p.setCompositionMode(QPainter::CompositionMode_SoftLight);
p.setOpacity(patternOpacity);
p.drawImage(QRect(QPoint(), to.size()), image);
}
image = QImage();
_cachedBackground = {
.pixmap = Ui::PixmapFromImage(std::move(result)),
.area = _willCacheForArea,
.x = to.x(),
.y = to.y(),
};
}
}
void SessionController::clearCachedBackground() {
_cachedBackground = {};
_cacheBackgroundTimer.cancel();
}
SessionController::~SessionController() { SessionController::~SessionController() {
resetFakeUnreadWhileOpened(); resetFakeUnreadWhileOpened();
} }

View file

@ -56,6 +56,13 @@ class SectionMemento;
class Controller; class Controller;
class FiltersMenu; class FiltersMenu;
struct CachedBackground {
QPixmap pixmap;
QRect area;
int x = 0;
int y = 0;
};
enum class GifPauseReason { enum class GifPauseReason {
Any = 0, Any = 0,
InlineResults = (1 << 0), InlineResults = (1 << 0),
@ -393,6 +400,8 @@ public:
void toggleFiltersMenu(bool enabled); void toggleFiltersMenu(bool enabled);
[[nodiscard]] rpl::producer<> filtersMenuChanged() const; [[nodiscard]] rpl::producer<> filtersMenuChanged() const;
[[nodiscard]] CachedBackground cachedBackground(QRect area);
rpl::lifetime &lifetime() { rpl::lifetime &lifetime() {
return _lifetime; return _lifetime;
} }
@ -422,6 +431,9 @@ private:
void checkInvitePeek(); void checkInvitePeek();
void cacheBackground();
void clearCachedBackground();
const not_null<Controller*> _window; const not_null<Controller*> _window;
std::unique_ptr<Passport::FormController> _passportForm; std::unique_ptr<Passport::FormController> _passportForm;
@ -449,6 +461,10 @@ private:
rpl::event_stream<> _filtersMenuChanged; rpl::event_stream<> _filtersMenuChanged;
CachedBackground _cachedBackground;
QRect _willCacheForArea;
base::Timer _cacheBackgroundTimer;
rpl::lifetime _lifetime; rpl::lifetime _lifetime;
}; };