From f66c9c3f1cb287bd8d66df7e29a071cbcd769f47 Mon Sep 17 00:00:00 2001 From: Volodymyr Zolotopupov Date: Mon, 13 Apr 2026 12:54:21 +0300 Subject: [PATCH] POC: Wayland fractional scale support --- .gitmodules | 4 +- Telegram/SourceFiles/api/api_chat_invite.cpp | 2 +- Telegram/SourceFiles/boxes/background_box.cpp | 2 +- .../boxes/background_preview_box.cpp | 7 +- .../boxes/filters/edit_filter_links.cpp | 6 +- .../SourceFiles/boxes/gift_premium_box.cpp | 11 +- Telegram/SourceFiles/boxes/peer_list_box.cpp | 7 +- .../boxes/peers/add_participants_box.cpp | 2 +- .../boxes/peers/edit_peer_color_box.cpp | 4 +- .../boxes/peers/edit_peer_invite_links.cpp | 2 +- .../boxes/peers/peer_short_info_box.cpp | 14 +- .../boxes/peers/prepare_short_info_box.cpp | 3 +- .../boxes/peers/replace_boost_box.cpp | 37 ++- .../SourceFiles/boxes/peers/tag_info_box.cpp | 2 +- .../SourceFiles/boxes/premium_preview_box.cpp | 4 +- Telegram/SourceFiles/boxes/send_files_box.cpp | 3 +- Telegram/SourceFiles/boxes/star_gift_box.cpp | 12 +- .../SourceFiles/boxes/star_gift_cover_box.cpp | 21 +- .../boxes/star_gift_craft_animation.cpp | 18 +- .../SourceFiles/boxes/sticker_set_box.cpp | 25 +- Telegram/SourceFiles/boxes/stickers_box.cpp | 2 +- .../calls/calls_emoji_fingerprint.cpp | 13 +- Telegram/SourceFiles/calls/calls_userpic.cpp | 16 +- .../SourceFiles/calls/calls_video_bubble.cpp | 8 +- .../calls/calls_video_incoming.cpp | 4 +- .../calls/group/calls_group_members.cpp | 4 +- .../calls/group/calls_group_members_row.cpp | 6 +- .../calls/group/calls_group_messages_ui.cpp | 33 ++- .../group/calls_group_viewport_opengl.cpp | 28 +-- .../chat_helpers/emoji_list_widget.cpp | 11 +- .../chat_helpers/emoji_suggestions_widget.cpp | 2 +- .../chat_helpers/field_autocomplete.cpp | 13 +- .../chat_helpers/message_field.cpp | 5 +- .../stickers_emoji_image_loader.cpp | 13 +- .../chat_helpers/stickers_list_footer.cpp | 32 ++- .../chat_helpers/stickers_list_footer.h | 1 + .../chat_helpers/stickers_list_widget.cpp | 21 +- .../SourceFiles/chat_helpers/tabbed_panel.cpp | 8 +- .../chat_helpers/tabbed_selector.cpp | 72 +++--- Telegram/SourceFiles/core/sandbox.cpp | 5 +- .../SourceFiles/data/data_forum_topic.cpp | 4 +- .../data/data_message_reactions.cpp | 26 ++- .../data/stickers/data_custom_emoji.cpp | 18 +- .../dialogs/dialogs_inner_widget.cpp | 15 +- Telegram/SourceFiles/dialogs/dialogs_row.cpp | 14 +- .../dialogs/dialogs_search_tags.cpp | 14 +- .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 22 +- .../dialogs/ui/dialogs_stories_list.cpp | 10 +- .../dialogs/ui/top_peers_strip.cpp | 8 +- .../editor/editor_layer_widget.cpp | 7 +- .../history_view_compose_controls.cpp | 5 +- .../history_view_voice_record_bar.cpp | 2 +- .../view/history_view_emoji_interactions.cpp | 5 +- .../view/history_view_group_call_bar.cpp | 10 +- .../view/history_view_paid_reaction_toast.cpp | 10 +- .../history/view/history_view_reply.cpp | 10 +- .../view/history_view_sticker_toast.cpp | 10 +- .../view/media/history_view_custom_emoji.cpp | 2 +- .../view/media/history_view_document.cpp | 4 +- .../history/view/media/history_view_gif.cpp | 18 +- .../view/media/history_view_large_emoji.cpp | 2 +- .../view/media/history_view_location.cpp | 4 +- .../history/view/media/history_view_media.cpp | 4 +- .../view/media/history_view_media_common.cpp | 6 +- .../view/media/history_view_media_generic.cpp | 6 +- .../view/media/history_view_media_grouped.cpp | 2 +- .../history/view/media/history_view_photo.cpp | 65 ++++-- .../history/view/media/history_view_poll.cpp | 4 +- .../media/history_view_similar_channels.cpp | 15 +- .../view/media/history_view_sticker.cpp | 8 +- .../media/history_view_sticker_player.cpp | 13 +- .../media/history_view_theme_document.cpp | 8 +- .../media/history_view_userpic_suggestion.cpp | 7 +- .../view/reactions/history_view_reactions.cpp | 35 ++- .../view/reactions/history_view_reactions.h | 3 + .../history_view_reactions_button.cpp | 24 +- .../reactions/history_view_reactions_button.h | 1 + .../reactions/history_view_reactions_list.cpp | 10 +- .../history_view_reactions_selector.cpp | 23 +- .../history_view_reactions_strip.cpp | 15 +- .../reactions/history_view_reactions_tabs.cpp | 5 +- .../starref/info_bot_starref_join_widget.cpp | 7 +- .../boosts/create_giveaway_box.cpp | 2 +- .../boosts/giveaway/boost_badge.cpp | 5 +- .../boosts/giveaway/giveaway_type_row.cpp | 2 +- .../channel_statistics/earn/earn_icons.cpp | 6 +- .../peer_gifts/info_peer_gifts_common.cpp | 19 +- .../info/profile/info_profile_badge.cpp | 4 +- .../info/profile/info_profile_cover.cpp | 6 +- .../info_profile_members_controllers.cpp | 7 +- .../info/profile/info_profile_top_bar.cpp | 4 +- .../info_userpic_emoji_builder_preview.cpp | 2 +- .../info_userpic_emoji_builder_widget.cpp | 2 +- .../inline_bot_layout_internal.cpp | 12 +- .../inline_bots/inline_bot_layout_item.cpp | 7 +- .../inline_bots/inline_results_widget.cpp | 4 +- Telegram/SourceFiles/intro/intro_step.cpp | 10 +- Telegram/SourceFiles/mainwindow.cpp | 33 ++- .../media/clip/media_clip_reader.cpp | 31 +-- .../media/clip/media_clip_reader.h | 2 +- .../media/player/media_player_button.cpp | 10 +- .../media/player/media_player_float.cpp | 10 +- .../media/stories/media_stories_sibling.cpp | 2 +- .../streaming/media_streaming_utility.cpp | 3 +- .../media/view/media_view_overlay_opengl.cpp | 38 +-- .../media/view/media_view_overlay_opengl.h | 2 +- .../SourceFiles/overview/overview_layout.cpp | 36 +-- .../payments/ui/payments_reaction_box.cpp | 2 +- .../settings/business/settings_chat_links.cpp | 5 +- .../settings/sections/settings_chat.cpp | 5 +- .../settings/sections/settings_main.cpp | 3 +- .../sections/settings_notifications.cpp | 5 +- .../settings/settings_credits_graphics.cpp | 2 +- .../widgets/point_details_widget.cpp | 6 +- .../SourceFiles/ui/boxes/about_cocoon_box.cpp | 2 +- .../SourceFiles/ui/boxes/choose_font_box.cpp | 7 +- .../SourceFiles/ui/boxes/emoji_stake_box.cpp | 2 +- Telegram/SourceFiles/ui/boxes/peer_qr_box.cpp | 15 +- .../SourceFiles/ui/cached_round_corners.cpp | 105 +++++---- .../SourceFiles/ui/cached_round_corners.h | 1 + .../attach_abstract_single_media_preview.cpp | 7 +- .../ui/chat/attach/attach_album_thumbnail.cpp | 15 +- Telegram/SourceFiles/ui/chat/chat_style.cpp | 37 +-- Telegram/SourceFiles/ui/chat/chat_theme.cpp | 12 +- .../SourceFiles/ui/chat/chats_filter_tag.cpp | 8 +- .../ui/chat/choose_theme_controller.cpp | 12 +- Telegram/SourceFiles/ui/chat/message_bar.cpp | 6 +- .../ui/controls/chat_service_checkbox.cpp | 5 +- .../ui/controls/filter_link_header.cpp | 2 +- .../ui/controls/labeled_emoji_tabs.cpp | 4 +- .../ui/controls/location_picker.cpp | 4 +- .../ui/controls/round_video_recorder.cpp | 6 +- .../SourceFiles/ui/controls/tabbed_search.cpp | 64 ++++-- .../SourceFiles/ui/controls/tabbed_search.h | 1 + .../ui/controls/userpic_button.cpp | 8 +- .../controls/who_reacted_context_action.cpp | 5 +- .../SourceFiles/ui/dynamic_thumbnails.cpp | 26 ++- .../ui/effects/credits_graphics.cpp | 4 +- .../ui/effects/premium_graphics.cpp | 10 +- .../ui/effects/premium_stars_colored.cpp | 2 +- .../SourceFiles/ui/effects/round_checkbox.cpp | 45 ++-- Telegram/SourceFiles/ui/empty_userpic.cpp | 10 +- Telegram/SourceFiles/ui/filter_icon_panel.cpp | 4 +- Telegram/SourceFiles/ui/image/image.cpp | 21 +- .../ui/top_background_gradient.cpp | 4 +- .../SourceFiles/ui/unread_badge_paint.cpp | 23 +- .../SourceFiles/ui/widgets/color_editor.cpp | 16 +- .../ui/widgets/gradient_round_button.cpp | 5 +- .../ui/widgets/middle_click_autoscroll.cpp | 2 +- .../SourceFiles/ui/widgets/multi_select.cpp | 5 +- .../SourceFiles/window/section_widget.cpp | 1 - .../window/themes/window_theme_editor_box.cpp | 5 +- .../window/themes/window_theme_preview.cpp | 14 +- .../themes/window_themes_cloud_list.cpp | 8 +- .../window/window_media_preview.cpp | 18 +- .../SourceFiles/window/window_media_preview.h | 1 + Telegram/build/audit_dpr.py | 217 ++++++++++++++++++ Telegram/lib_lottie | 2 +- Telegram/lib_ui | 2 +- 159 files changed, 1268 insertions(+), 756 deletions(-) create mode 100644 Telegram/build/audit_dpr.py diff --git a/.gitmodules b/.gitmodules index 2d65da99351772..e69c52f7ee35e1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -24,10 +24,10 @@ url = https://github.com/desktop-app/codegen.git [submodule "Telegram/lib_ui"] path = Telegram/lib_ui - url = https://github.com/desktop-app/lib_ui.git + url = git@github.com:zvova7890/lib_ui.git [submodule "Telegram/lib_lottie"] path = Telegram/lib_lottie - url = https://github.com/desktop-app/lib_lottie.git + url = git@github.com:zvova7890/lib_lottie.git [submodule "Telegram/lib_tl"] path = Telegram/lib_tl url = https://github.com/desktop-app/lib_tl.git diff --git a/Telegram/SourceFiles/api/api_chat_invite.cpp b/Telegram/SourceFiles/api/api_chat_invite.cpp index f1a3f81d1c67ae..fc4d0c3a9c402f 100644 --- a/Telegram/SourceFiles/api/api_chat_invite.cpp +++ b/Telegram/SourceFiles/api/api_chat_invite.cpp @@ -154,7 +154,7 @@ void ConfirmSubscriptionBox( creditsIconSize, 1.5); state->frame = QImage( - Size(photoSize * style::DevicePixelRatio()), + Size(style::DevicePixels(photoSize)), QImage::Format_ARGB32_Premultiplied); state->frame.setDevicePixelRatio(style::DevicePixelRatio()); const auto options = Images::Option::RoundCircle; diff --git a/Telegram/SourceFiles/boxes/background_box.cpp b/Telegram/SourceFiles/boxes/background_box.cpp index 40cb7c2f858d3e..aa3f41ca6ea1dc 100644 --- a/Telegram/SourceFiles/boxes/background_box.cpp +++ b/Telegram/SourceFiles/boxes/background_box.cpp @@ -657,7 +657,7 @@ void BackgroundBox::Inner::validatePaperThumbnail( } else if (!paper.data.backgroundColors().empty()) { paper.thumbnail = Ui::PixmapFromImage( Ui::GenerateBackgroundImage( - st::backgroundSize * style::DevicePixelRatio(), + style::DevicePixels(st::backgroundSize), paper.data.backgroundColors(), paper.data.gradientRotation())); paper.thumbnail.setDevicePixelRatio(style::DevicePixelRatio()); diff --git a/Telegram/SourceFiles/boxes/background_preview_box.cpp b/Telegram/SourceFiles/boxes/background_preview_box.cpp index dd07ffd5e702a1..5faddf74104f2f 100644 --- a/Telegram/SourceFiles/boxes/background_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/background_preview_box.cpp @@ -121,8 +121,9 @@ constexpr auto kMaxWallPaperSlugLength = 255; const auto takeHeight = (width > height) ? size : (height * size / width); - const auto ratio = style::DevicePixelRatio(); - return Images::Prepare(image, QSize(takeWidth, takeHeight) * ratio, { + return Images::Prepare(image, QSize( + style::DevicePixels(takeWidth), + style::DevicePixels(takeHeight)), { .options = Images::Option::TransparentBackground | blur, .outer = { size, size }, }); @@ -725,7 +726,7 @@ void BackgroundPreviewBox::applyForPeer() { } else if (_forBothOverlay) { return; } - const auto size = this->size() * style::DevicePixelRatio(); + const auto size = style::DevicePixels(this->size()); const auto bg = Images::DitherImage( Images::BlurLargeImage( Ui::GrabWidgetToImage(this).scaled( diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp index f15b69c94ec66c..8ac29fb00b05b7 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp @@ -359,7 +359,9 @@ PaintRoundImageCallback ChatRow::generatePaintUserpicCallback( int outerWidth, int size) mutable { const auto wide = size + style::ConvertScale(3); - const auto full = QSize(wide, wide) * style::DevicePixelRatio(); + const auto full = QSize( + style::DevicePixels(wide), + style::DevicePixels(wide)); auto repaint = false; if (_disabledFrame.size() != full) { repaint = true; @@ -967,7 +969,7 @@ void LinksController::rowPaintIcon( auto &icon = _icons[int(color)]; if (icon.isNull()) { icon = QImage( - QSize(inner, inner) * style::DevicePixelRatio(), + style::DevicePixels(QSize(inner, inner)), QImage::Format_ARGB32_Premultiplied); icon.fill(Qt::transparent); icon.setDevicePixelRatio(style::DevicePixelRatio()); diff --git a/Telegram/SourceFiles/boxes/gift_premium_box.cpp b/Telegram/SourceFiles/boxes/gift_premium_box.cpp index 88d437ae1cd2da..d079c56d4339cb 100644 --- a/Telegram/SourceFiles/boxes/gift_premium_box.cpp +++ b/Telegram/SourceFiles/boxes/gift_premium_box.cpp @@ -416,13 +416,12 @@ using SpinnerState = Data::GiftUpgradeSpinner::State; return; } } - const auto ratio = style::DevicePixelRatio(); const auto h = raw->height(); - if (state->fading.height() != h * ratio) { - state->fading = QImage( - QSize(1, h) * ratio, + const auto pixelHeight = style::DevicePixels(h); + if (state->fading.height() != pixelHeight) { + state->fading = QImage(style::DevicePixels(QSize(1, h)), QImage::Format_ARGB32_Premultiplied); - state->fading.setDevicePixelRatio(ratio); + state->fading.setDevicePixelRatio(style::DevicePixelRatio()); state->fading.fill(Qt::transparent); auto q = QPainter(&state->fading); auto brush = QLinearGradient(0, 0, 0, margin.top()); @@ -439,7 +438,7 @@ using SpinnerState = Data::GiftUpgradeSpinner::State; auto &now = state->rows[state->nowIndex]; const auto validate = [&](Row &row) { const auto size = row.widget->size(); - if (row.frame.size() != size * ratio) { + if (row.frame.size() != style::DevicePixels(size)) { row.frame = Ui::GrabWidgetToImage(row.widget.get()); } }; diff --git a/Telegram/SourceFiles/boxes/peer_list_box.cpp b/Telegram/SourceFiles/boxes/peer_list_box.cpp index c3f6d40560073c..5dc6a91f7448ce 100644 --- a/Telegram/SourceFiles/boxes/peer_list_box.cpp +++ b/Telegram/SourceFiles/boxes/peer_list_box.cpp @@ -67,11 +67,12 @@ PaintRoundImageCallback ForceRoundUserpicCallback(not_null peer) { auto userpic = Ui::PeerUserpicView(); auto cache = std::make_shared(); return [=](Painter &p, int x, int y, int outerWidth, int size) mutable { - const auto ratio = style::DevicePixelRatio(); - const auto cacheSize = QSize(size, size) * ratio; + const auto cacheSize = QSize( + style::DevicePixels(size), + style::DevicePixels(size)); if (cache->size() != cacheSize) { *cache = QImage(cacheSize, QImage::Format_ARGB32_Premultiplied); - cache->setDevicePixelRatio(ratio); + cache->setDevicePixelRatio(style::DevicePixelRatio()); } auto q = Painter(cache.get()); peer->paintUserpicLeft(q, userpic, 0, 0, outerWidth, size); diff --git a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp index d87ebcb4870bbe..0a82b63131642e 100644 --- a/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/add_participants_box.cpp @@ -337,7 +337,7 @@ PaintRoundImageCallback ForbiddenRow::generatePaintUserpicCallback( int outerWidth, int size) mutable { const auto wide = size + style::ConvertScale(3); - const auto full = QSize(wide, wide) * style::DevicePixelRatio(); + const auto full = style::DevicePixels(QSize(wide, wide)); auto repaint = false; if (_disabledFrame.size() != full) { repaint = true; diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp index 5f813d2b796d25..928779bf1fd8bb 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_color_box.cpp @@ -2827,9 +2827,9 @@ void CheckBoostLevel( ButtonWithEmoji ButtonStyleWithRightEmoji( not_null parent, const QString &noneString, - const style::SettingsButton &parentSt) { + const style::SettingsButton &parentSt) { const auto ratio = style::DevicePixelRatio(); - const auto emojiWidth = Data::FrameSizeFromTag({}) / ratio; + const auto emojiWidth = qRound(Data::FrameSizeFromTag({}) / ratio); const auto noneWidth = st::normalFont->width(noneString); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp index eacaa448ca8095..d82b107fd861cf 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_links.cpp @@ -708,7 +708,7 @@ void LinksController::rowPaintIcon( auto &icon = _icons[int(color)]; if (icon.isNull()) { icon = QImage( - QSize(inner, inner) * style::DevicePixelRatio(), + style::DevicePixels(QSize(inner, inner)), QImage::Format_ARGB32_Premultiplied); icon.fill(Qt::transparent); icon.setDevicePixelRatio(style::DevicePixelRatio()); diff --git a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp index 36b756325780b7..a5a355c0b20945 100644 --- a/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/peer_short_info_box.cpp @@ -151,8 +151,7 @@ PeerShortInfoCover::PeerShortInfoCover( refreshLabelsGeometry(); - _roundedTopImage = QImage( - QSize(_st.size, _st.radius) * style::DevicePixelRatio(), + _roundedTopImage = QImage(style::DevicePixels(QSize(_st.size, _st.radius)), QImage::Format_ARGB32_Premultiplied); _roundedTopImage.setDevicePixelRatio(style::DevicePixelRatio()); _roundedTopImage.fill(Qt::transparent); @@ -196,7 +195,7 @@ void PeerShortInfoCover::paint(QPainter &p) { RectPart::TopLeft | RectPart::TopRight); } else if (_userpicImage.isNull()) { auto image = QImage( - _widget->size() * style::DevicePixelRatio(), + style::DevicePixels(_widget->size()), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::black); _userpicImage = Images::Round( @@ -602,9 +601,10 @@ void PeerShortInfoCover::refreshBarImages() { _largeWidth = _smallWidth + 1; const auto makeBar = [&](int size) { const auto radius = _st.line / 2.; - auto result = QImage( - QSize(size, _st.line) * style::DevicePixelRatio(), - QImage::Format_ARGB32_Premultiplied); + const auto resultSize = QSize( + style::DevicePixels(size), + style::DevicePixels(_st.line)); + auto result = QImage(resultSize, QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(style::DevicePixelRatio()); result.fill(Qt::transparent); auto p = QPainter(&result); @@ -733,7 +733,7 @@ void PeerShortInfoBox::prepare() { }, _topRoundBackground->lifetime()); _roundedTop = QImage( - _topRoundBackground->size() * style::DevicePixelRatio(), + style::DevicePixels(_topRoundBackground->size()), QImage::Format_ARGB32_Premultiplied); _roundedTop.setDevicePixelRatio(style::DevicePixelRatio()); refreshRoundedTopImage(getDelegate()->style().bg->c); diff --git a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp index 91a05d3f0a15b9..54952190ddafa4 100644 --- a/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/prepare_short_info_box.cpp @@ -57,12 +57,11 @@ void GenerateImage( bool blurred = false) { using namespace Images; const auto size = state->size; - const auto ratio = style::DevicePixelRatio(); const auto options = blurred ? Option::Blur : Option(); state->current.photo = Images::Round( Images::Prepare( std::move(image), - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), { .options = options, .outer = { size, size } }), state->roundMask, RectPart::TopLeft | RectPart::TopRight); diff --git a/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp b/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp index 8ef319377c56e4..f6a6b91d6cd2cb 100644 --- a/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/replace_boost_box.cpp @@ -668,12 +668,12 @@ object_ptr CreateUserpicsTransfer( return !state->buttons.empty(); }) | rpl::on_next([=] { const auto outerw = overlay->width(); - const auto ratio = style::DevicePixelRatio(); - if (state->layer.size() != QSize(outerw, full) * ratio) { + const auto layerSize = style::DevicePixels(QSize(outerw, full)); + if (state->layer.size() != layerSize) { state->layer = QImage( - QSize(outerw, full) * ratio, + layerSize, QImage::Format_ARGB32_Premultiplied); - state->layer.setDevicePixelRatio(ratio); + state->layer.setDevicePixelRatio(style::DevicePixelRatio()); } state->layer.fill(Qt::transparent); @@ -821,12 +821,12 @@ object_ptr CreateUserpicsWithMoreBadge( return !state->buttons.empty(); }) | rpl::on_next([=, &st] { const auto outerw = overlay->width(); - const auto ratio = style::DevicePixelRatio(); - if (state->layer.size() != QSize(outerw, full) * ratio) { + const auto layerSize = style::DevicePixels(QSize(outerw, full)); + if (state->layer.size() != layerSize) { state->layer = QImage( - QSize(outerw, full) * ratio, + layerSize, QImage::Format_ARGB32_Premultiplied); - state->layer.setDevicePixelRatio(ratio); + state->layer.setDevicePixelRatio(style::DevicePixelRatio()); } state->layer.fill(Qt::transparent); @@ -922,13 +922,12 @@ class UniqueGiftBackground final : public Ui::DynamicImage { [[maybe_unused]] const auto preload = _patternEmoji->ready(); } const auto inner = QRect(0, 0, size, size); - const auto ratio = style::DevicePixelRatio(); - if (_backgroundCache.size() != inner.size() * ratio) { + if (_backgroundCache.size() != style::DevicePixels(inner.size())) { _backgroundCache = QImage( - inner.size() * ratio, + style::DevicePixels(inner.size()), QImage::Format_ARGB32_Premultiplied); _backgroundCache.fill(Qt::transparent); - _backgroundCache.setDevicePixelRatio(ratio); + _backgroundCache.setDevicePixelRatio(style::DevicePixelRatio()); const auto radius = st::giftBoxGiftRadius; auto p = QPainter(&_backgroundCache); @@ -1005,9 +1004,10 @@ class UniqueGiftBackground final : public Ui::DynamicImage { const auto ideal = st::boostReplaceUserpic.photoSize; const auto scale = size / float64(ideal); const auto ratio = style::DevicePixelRatio(); - if (state->layer.size() != QSize(ideal, ideal) * ratio) { + const auto layerSize = style::DevicePixels(QSize(ideal, ideal)); + if (state->layer.size() != layerSize) { state->layer = QImage( - QSize(ideal, ideal) * ratio, + layerSize, QImage::Format_ARGB32_Premultiplied); state->layer.setDevicePixelRatio(ratio); } @@ -1074,12 +1074,12 @@ object_ptr CreateGiftTransfer( overlay->paintRequest( ) | rpl::on_next([=] { const auto outerw = overlay->width(); - const auto ratio = style::DevicePixelRatio(); - if (state->layer.size() != QSize(outerw, full) * ratio) { + const auto layerSize = style::DevicePixels(QSize(outerw, full)); + if (state->layer.size() != layerSize) { state->layer = QImage( - QSize(outerw, full) * ratio, + layerSize, QImage::Format_ARGB32_Premultiplied); - state->layer.setDevicePixelRatio(ratio); + state->layer.setDevicePixelRatio(style::DevicePixelRatio()); } state->layer.fill(Qt::transparent); @@ -1108,4 +1108,3 @@ object_ptr CreateGiftTransfer( }, overlay->lifetime()); return result; } - diff --git a/Telegram/SourceFiles/boxes/peers/tag_info_box.cpp b/Telegram/SourceFiles/boxes/peers/tag_info_box.cpp index ee125790189616..6d44e32cf7360e 100644 --- a/Telegram/SourceFiles/boxes/peers/tag_info_box.cpp +++ b/Telegram/SourceFiles/boxes/peers/tag_info_box.cpp @@ -98,7 +98,7 @@ constexpr auto kTextLinesAlpha = 0.1; const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(imgWidth, imgHeight) * ratio, + style::DevicePixels(QSize(imgWidth, imgHeight)), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/boxes/premium_preview_box.cpp b/Telegram/SourceFiles/boxes/premium_preview_box.cpp index ff78f6b3733008..3acbfbb060bd3c 100644 --- a/Telegram/SourceFiles/boxes/premium_preview_box.cpp +++ b/Telegram/SourceFiles/boxes/premium_preview_box.cpp @@ -692,7 +692,7 @@ struct VideoPreviewDocument { | Option::RoundSkipTopRight); state->blurred = Images::Prepare( image->original(), - QSize(width, height) * style::DevicePixelRatio(), + style::DevicePixels(QSize(width, height)), { .options = (Option::Blur | Option::RoundLarge | corners) }); } } @@ -752,7 +752,7 @@ struct VideoPreviewDocument { check(); const auto ready = state->instance.player().ready() && !state->instance.player().videoSize().isEmpty(); - const auto size = QSize(width, height) * style::DevicePixelRatio(); + const auto size = style::DevicePixels(QSize(width, height)); using namespace Images; auto rounding = CornersMaskRef( diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index b098618f90c660..65412b3705e0eb 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -1073,7 +1073,8 @@ QImage SendFilesBox::preparePriceTagBg(QSize size) const { bg.fill(Qt::black); } - auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied); + auto result = QImage(style::DevicePixels(size), + QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); result.fill(Qt::black); auto p = QPainter(&result); diff --git a/Telegram/SourceFiles/boxes/star_gift_box.cpp b/Telegram/SourceFiles/boxes/star_gift_box.cpp index 6b404b99e1cffc..817f71a892d237 100644 --- a/Telegram/SourceFiles/boxes/star_gift_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_box.cpp @@ -652,10 +652,9 @@ void ShowSentToast( const auto bytes = document->createMediaView()->bytes(); const auto filepath = document->filepath(); - const auto ratio = style::DevicePixelRatio(); const auto player = preview->lifetime().make_state( Lottie::ReadContent(bytes, filepath), - Lottie::FrameRequest{ QSize(size, size) * ratio }, + Lottie::FrameRequest{ style::DevicePixels(QSize(size, size)) }, Lottie::Quality::Default); preview->paintRequest( @@ -665,7 +664,11 @@ void ShowSentToast( } const auto image = player->frame(); QPainter(preview).drawImage( - QRect(QPoint(), image.size() / ratio), + QRect( + QPoint(), + QSize( + style::LogicalPixels(image.width()), + style::LogicalPixels(image.height()))), image); if (player->frameIndex() + 1 != player->framesCount()) { player->markFrameShown(); @@ -2488,8 +2491,7 @@ void AddWearGiftCover( const auto width = cover->width(); const auto pointsHeight = st::uniqueGiftSubtitleTop; - const auto ratio = style::DevicePixelRatio(); - if (state->gradient.size() != cover->size() * ratio) { + if (state->gradient.size() != style::DevicePixels(cover->size())) { state->gradient = Ui::CreateTopBgGradient( cover->size(), state->gift); diff --git a/Telegram/SourceFiles/boxes/star_gift_cover_box.cpp b/Telegram/SourceFiles/boxes/star_gift_cover_box.cpp index 5c734212864176..9cf836314e3045 100644 --- a/Telegram/SourceFiles/boxes/star_gift_cover_box.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_cover_box.cpp @@ -869,11 +869,10 @@ UniqueGiftCoverWidget::~UniqueGiftCoverWidget() = default; QImage UniqueGiftCoverWidget::prepareBackdrop( BackdropView &backdrop, const PaintContext &context) { - const auto ratio = style::DevicePixelRatio(); const auto gradientSize = QSize( context.width, std::max(height(), _state->heightFinal)); - if (backdrop.gradient.size() != gradientSize * ratio) { + if (backdrop.gradient.size() != style::DevicePixels(gradientSize)) { backdrop.gradient = CreateTopBgGradient( gradientSize, backdrop.colors); @@ -949,11 +948,11 @@ QRect UniqueGiftCoverWidget::prepareCraftFrame( QImage &canvas, const CraftContext &context) { const auto full = this->size(); - const auto ratio = style::DevicePixelRatio(); - if (canvas.size() != full * ratio) { - canvas = QImage(full * ratio, QImage::Format_ARGB32_Premultiplied); - canvas.setDevicePixelRatio(ratio); + const auto fullPixels = QSize(style::DevicePixels(full)); + if (canvas.size() != fullPixels) { + canvas = QImage(fullPixels, QImage::Format_ARGB32_Premultiplied); + canvas.setDevicePixelRatio(style::DevicePixelRatio()); } LOG(("FULL: %1x%2").arg(full.width()).arg(full.height())); @@ -1020,7 +1019,9 @@ QRect UniqueGiftCoverWidget::prepareCraftFrame( .patternAreaHeight = pointsHeight, }, bgProgress); - return QRect(QPoint(), size * ratio); + return QRect( + QPoint(), + style::DevicePixels(size)); } bool UniqueGiftCoverWidget::paintGift( @@ -1196,15 +1197,15 @@ void UniqueGiftCoverWidget::paintSpinnerAnimation( { 0., QColor(255, 255, 255, 255) }, { 1., QColor(255, 255, 255, 0) }, }); - const auto ratio = int(faded.devicePixelRatio()); - const auto imgHeight = faded.height() / ratio; + const auto ratio = faded.devicePixelRatio(); + const auto imgHeight = qRound(faded.height() / ratio); q.fillRect(from, 0, fade, imgHeight, brush); q.end(); p.drawImage( QRect(0, 0, till, imgHeight), faded, - QRect(0, 0, till * ratio, faded.height())); + QRect(0, 0, style::DevicePixels(till, ratio), faded.height())); } } diff --git a/Telegram/SourceFiles/boxes/star_gift_craft_animation.cpp b/Telegram/SourceFiles/boxes/star_gift_craft_animation.cpp index e901ec135cc97c..7a990f4313818f 100644 --- a/Telegram/SourceFiles/boxes/star_gift_craft_animation.cpp +++ b/Telegram/SourceFiles/boxes/star_gift_craft_animation.cpp @@ -163,9 +163,9 @@ const auto kGiftAnimations = std::array{{ { [[nodiscard]] QImage CreateBgGradient( QSize size, const Data::UniqueGiftBackdrop &backdrop) { - const auto ratio = style::DevicePixelRatio(); - auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(ratio); + auto result = QImage(style::DevicePixels(size), + QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(style::DevicePixelRatio()); auto p = QPainter(&result); auto hq = PainterHighQualityEnabler(p); @@ -1230,10 +1230,9 @@ void CraftState::paint( float64 slideProgress) { const auto width = size.width(); const auto getBackdrop = [&](BackdropView &backdrop) { - const auto ratio = style::DevicePixelRatio(); const auto gradientSize = size; auto &gradient = backdrop.gradient; - if (gradient.size() != gradientSize * ratio) { + if (gradient.size() != style::DevicePixels(gradientSize)) { gradient = CreateBgGradient(gradientSize, backdrop.colors); } return gradient; @@ -1333,7 +1332,9 @@ void CraftState::updateForGiftCount(int count, Fn repaint) { CraftState::EmptySide CraftState::prepareEmptySide(int index) const { const auto size = forgeRect.size(); const auto ratio = style::DevicePixelRatio(); - auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied); + auto result = QImage( + style::DevicePixels(size), + QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); const auto bg = anim::color(forgeBg1, forgeBg2, index / 5.); @@ -1672,11 +1673,10 @@ void StartCraftAnimation( shared->paint(p, craftingSize, craftingHeight, slideProgress); } else { if (shared->craftBg.isNull()) { - const auto ratio = style::DevicePixelRatio(); shared->craftBg = QImage( - craftingSize * ratio, + style::DevicePixels(craftingSize), QImage::Format_ARGB32_Premultiplied); - shared->craftBg.setDevicePixelRatio(ratio); + shared->craftBg.setDevicePixelRatio(style::DevicePixelRatio()); shared->craftBg.fill(Qt::transparent); auto q = QPainter(&shared->craftBg); diff --git a/Telegram/SourceFiles/boxes/sticker_set_box.cpp b/Telegram/SourceFiles/boxes/sticker_set_box.cpp index 15eb12186e5433..5b9172fb94372b 100644 --- a/Telegram/SourceFiles/boxes/sticker_set_box.cpp +++ b/Telegram/SourceFiles/boxes/sticker_set_box.cpp @@ -93,8 +93,7 @@ using TLStickerSet = MTPmessages_StickerSet; auto sg = int64(); auto sb = int64(); auto sa = int64(); - const auto factor = style::DevicePixelRatio(); - const auto size = lockIcon.size() * factor; + const auto size = style::DevicePixels(lockIcon.size()); const auto width = std::min(frame.width(), size.width()); const auto height = std::min(frame.height(), size.height()); const auto radius = st::roundRadiusSmall; @@ -159,7 +158,7 @@ void ValidatePremiumLockBg( const auto factor = style::DevicePixelRatio(); const auto size = lockIcon.size(); image = QImage( - size * factor, + style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(factor); auto p = QPainter(&image); @@ -179,7 +178,7 @@ void ValidatePremiumStarFg(const style::icon &lockIcon, QImage &image) { const auto factor = style::DevicePixelRatio(); const auto size = lockIcon.size(); image = QImage( - size * factor, + style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(factor); image.fill(Qt::transparent); @@ -242,14 +241,13 @@ void StickerPremiumMark::paint( int outerWidth) { validateLock(frame, backCache); const auto &bg = frame.isNull() ? _lockGray : backCache; - const auto factor = style::DevicePixelRatio(); const auto radius = st::roundRadiusSmall; const auto shiftx = (_part == RectPart::Center) - ? (singleSize.width() - (bg.width() / factor)) / 2 - : (singleSize.width() - (bg.width() / factor) - radius); + ? (singleSize.width() - style::LogicalPixels(bg.width())) / 2 + : (singleSize.width() - style::LogicalPixels(bg.width()) - radius); const auto shifty = (_part == RectPart::Center) - ? (singleSize.height() - (bg.height() / factor)) / 2 - : (singleSize.height() - (bg.height() / factor) - radius); + ? (singleSize.height() - style::LogicalPixels(bg.height())) / 2 + : (singleSize.height() - style::LogicalPixels(bg.height()) - radius); const auto point = position + QPoint(shiftx, shifty); p.drawImage(point, bg); if (_premium && _part != RectPart::Center) { @@ -1809,8 +1807,8 @@ uint64 StickerSetBox::Inner::setId() const { QSize StickerSetBox::Inner::boundingBoxSize() const { if (isEmojiSet()) { using namespace Data; - const auto size = FrameSizeFromTag(CustomEmojiSizeTag::Large) - / style::DevicePixelRatio(); + const auto size = qRound(FrameSizeFromTag(CustomEmojiSizeTag::Large) + / style::DevicePixelRatio()); return { size, size }; } return QSize( @@ -1871,7 +1869,7 @@ void StickerSetBox::Inner::setupLottie(int index) { getLottiePlayer(), element.documentMedia.get(), ChatHelpers::StickerLottieSize::StickerSet, - boundingBoxSize() * style::DevicePixelRatio()); + style::DevicePixels(boundingBoxSize())); } void StickerSetBox::Inner::setupWebm(int index) { @@ -2075,8 +2073,9 @@ void StickerSetBox::Inner::paintSticker( }); } else if (element.lottie && element.lottie->ready()) { lottieFrame = element.lottie->frame(); + const auto factor = lottieFrame.devicePixelRatio(); p.drawImage( - QRect(ppos, lottieFrame.size() / style::DevicePixelRatio()), + QRect(ppos, lottieFrame.size() / factor), lottieFrame); _lottiePlayer->unpause(element.lottie); diff --git a/Telegram/SourceFiles/boxes/stickers_box.cpp b/Telegram/SourceFiles/boxes/stickers_box.cpp index ed4a7d02c74ef9..f9d66917fa4e28 100644 --- a/Telegram/SourceFiles/boxes/stickers_box.cpp +++ b/Telegram/SourceFiles/boxes/stickers_box.cpp @@ -1574,7 +1574,7 @@ void StickersBox::Inner::validateLottieAnimation(not_null row) { row->thumbnailMedia.get(), row->stickerMedia.get(), ChatHelpers::StickerLottieSize::SetsListThumbnail, - QSize(_st.photoSize, _st.photoSize) * style::DevicePixelRatio()); + style::DevicePixels(QSize(_st.photoSize, _st.photoSize))); if (!player) { return; } diff --git a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp index 041837048128ef..c5160cf407be4e 100644 --- a/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp +++ b/Telegram/SourceFiles/calls/calls_emoji_fingerprint.cpp @@ -247,7 +247,7 @@ base::unique_qptr CreateFingerprintAndSignalBars( // Paint. const auto background = raw->lifetime().make_state( - fullSize * style::DevicePixelRatio(), + style::DevicePixels(fullSize), QImage::Format_ARGB32_Premultiplied); background->setDevicePixelRatio(style::DevicePixelRatio()); rpl::merge( @@ -639,11 +639,10 @@ void SetupFingerprintTooltip(not_null widget) { } QImage MakeVerticalShadow(int height) { - const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(1, height) * ratio, + style::DevicePixels(QSize(1, height)), QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(ratio); + result.setDevicePixelRatio(style::DevicePixelRatio()); auto p = QPainter(&result); auto g = QLinearGradient(0, 0, 0, height); auto color = st::groupCallMembersBg->c; @@ -698,7 +697,7 @@ void SetupFingerprintBadgeWidget( if (label->textMaxWidth() > available) { label->setText(tr::lng_confcall_e2e_badge_small(tr::now)); } - const auto use = std::min(available, label->textMaxWidth()); + const auto use = std::min(qRound(available), label->textMaxWidth()); label->resizeToWidth(use); const auto ontheleft = kEmojiInFingerprint / 2; @@ -788,7 +787,7 @@ void PaintFingerprintEntry( return; } const auto ratio = style::DevicePixelRatio(); - const auto size = esize / ratio; + const auto size = qRound(esize / ratio); const auto add = 4; const auto height = size + 2 * add; const auto validateCache = [&](int index, EmojiPtr e) { @@ -800,7 +799,7 @@ void PaintFingerprintEntry( if (emoji.ptr != e) { emoji.ptr = e; emoji.image = QImage( - QSize(size, height) * ratio, + style::DevicePixels(QSize(size, height)), QImage::Format_ARGB32_Premultiplied); emoji.image.setDevicePixelRatio(ratio); emoji.image.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/calls/calls_userpic.cpp b/Telegram/SourceFiles/calls/calls_userpic.cpp index e1f55025dfb67b..95a2375394f263 100644 --- a/Telegram/SourceFiles/calls/calls_userpic.cpp +++ b/Telegram/SourceFiles/calls/calls_userpic.cpp @@ -170,7 +170,6 @@ void Userpic::refreshPhoto() { void Userpic::createCache(Image *image) { const auto size = this->size(); - const auto real = size * style::DevicePixelRatio(); //_useTransparency // ? (Images::Option::RoundLarge // | Images::Option::RoundSkipBottomLeft @@ -179,12 +178,17 @@ void Userpic::createCache(Image *image) { if (image) { auto width = image->width(); auto height = image->height(); + const auto side = style::DevicePixels(size); if (width > height) { - width = qMax((width * real) / height, 1); - height = real; + width = qMax( + int(base::SafeRound((double(width) * side) / height)), + 1); + height = side; } else { - height = qMax((height * real) / width, 1); - width = real; + height = qMax( + int(base::SafeRound((double(height) * side) / width)), + 1); + width = side; } _userPhoto = image->pixNoCache( { width, height }, @@ -195,7 +199,7 @@ void Userpic::createCache(Image *image) { _userPhoto.setDevicePixelRatio(style::DevicePixelRatio()); } else { auto filled = QImage( - QSize(real, real), + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); filled.setDevicePixelRatio(style::DevicePixelRatio()); filled.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/calls/calls_video_bubble.cpp b/Telegram/SourceFiles/calls/calls_video_bubble.cpp index 733aad28146b59..d607071467718a 100644 --- a/Telegram/SourceFiles/calls/calls_video_bubble.cpp +++ b/Telegram/SourceFiles/calls/calls_video_bubble.cpp @@ -126,14 +126,13 @@ void VideoBubble::paint() { const auto padding = st::boxRoundShadow.extend; const auto inner = _content.rect().marginsRemoved(padding); Ui::Shadow::paint(p, inner, _content.width(), st::boxRoundShadow); - const auto factor = style::DevicePixelRatio(); const auto left = _mirrored - ? (_frame.width() - (inner.width() * factor)) + ? (_frame.width() - style::DevicePixels(inner.width())) : 0; p.drawImage( inner, _frame, - QRect(QPoint(left, 0), inner.size() * factor)); + QRect(QPoint(left, 0), style::DevicePixels(inner.size()))); } _track->markFrameShown(); } @@ -145,8 +144,7 @@ void VideoBubble::prepareFrame() { return; } const auto padding = st::boxRoundShadow.extend; - const auto size = (_content.rect() - padding).size() - * style::DevicePixelRatio(); + const auto size = style::DevicePixels((_content.rect() - padding).size()); // Should we check 'original' and 'size' aspect ratios?.. const auto request = Webrtc::FrameRequest{ diff --git a/Telegram/SourceFiles/calls/calls_video_incoming.cpp b/Telegram/SourceFiles/calls/calls_video_incoming.cpp index 1c562bb005f024..a3f514b24b817e 100644 --- a/Telegram/SourceFiles/calls/calls_video_incoming.cpp +++ b/Telegram/SourceFiles/calls/calls_video_incoming.cpp @@ -465,9 +465,9 @@ void Panel::Incoming::RendererSW::paintFallback( } void Panel::Incoming::RendererSW::initBottomShadow() { - auto image = QImage( - QSize(1, st::callBottomShadowSize) * style::DevicePixelRatio(), + auto image = QImage(style::DevicePixels(QSize(1, st::callBottomShadowSize)), QImage::Format_ARGB32_Premultiplied); + image.setDevicePixelRatio(style::DevicePixelRatio()); const auto colorFrom = uint32(0); const auto colorTill = uint32(kBottomShadowAlphaMax); const auto rows = image.height(); diff --git a/Telegram/SourceFiles/calls/group/calls_group_members.cpp b/Telegram/SourceFiles/calls/group/calls_group_members.cpp index c3e4328e90063f..b3c44869697e2c 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members.cpp @@ -2100,8 +2100,8 @@ void Members::updateControlsGeometry() { void Members::setupFakeRoundCorners() { const auto size = st::roundRadiusLarge; const auto full = 3 * size; - const auto imagePartSize = size * style::DevicePixelRatio(); - const auto imageSize = full * style::DevicePixelRatio(); + const auto imagePartSize = style::DevicePixels(size); + const auto imageSize = style::DevicePixels(full); const auto image = std::make_shared( QImage(imageSize, imageSize, QImage::Format_ARGB32_Premultiplied)); image->setDevicePixelRatio(style::DevicePixelRatio()); diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp index 977d547ee1bb9a..244792c67de2bc 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp @@ -367,9 +367,9 @@ void MembersRow::ensureUserpicCache( const auto user = peer(); const auto key = user->userpicUniqueKey(view); - const auto full = QSize(size, size) - * kWideScale - * style::DevicePixelRatio(); + const auto full = style::DevicePixels( + QSize(size, size), + kWideScale * style::DevicePixelRatio()); auto &cache = _blobsAnimation->userpicCache; if (cache.isNull()) { cache = QImage(full, QImage::Format_ARGB32_Premultiplied); diff --git a/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp b/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp index 45d74c95694551..89ac3b50d6557e 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_messages_ui.cpp @@ -256,11 +256,10 @@ void ShowDeleteMessageConfirmation( [[nodiscard]] QImage CrownMask(int place) { const auto &icon = st::paidReactCrownSmall; const auto size = icon.size(); - const auto ratio = style::DevicePixelRatio(); - const auto full = size * ratio; + const auto full = style::DevicePixels(size); auto result = QImage(full, QImage::Format_ARGB32_Premultiplied); result.fill(Qt::transparent); - result.setDevicePixelRatio(ratio); + result.setDevicePixelRatio(style::DevicePixelRatio()); auto p = QPainter(&result); icon.paint(p, 0, 0, size.width(), QColor(255, 255, 255)); @@ -617,8 +616,7 @@ void MessagesUi::updatePinnedSize(PinnedView &entry) { const auto skip = st::groupCallMessageSkip; entry.realWidth = skip + leftSkip + inner + padding.right(); - const auto ratio = style::DevicePixelRatio(); - entry.requiresSmooth = (entry.realWidth * ratio * 1000 > entry.duration); + entry.requiresSmooth = (style::DevicePixels(entry.realWidth) * 1000 > entry.duration); } bool MessagesUi::updatePinnedWidth(PinnedView &entry) { @@ -1180,16 +1178,15 @@ void MessagesUi::setupMessagesWidget() { _messages->paintRequest() | rpl::on_next([=](QRect clip) { const auto start = scroll->scrollTop(); const auto end = start + scroll->height(); - const auto ratio = style::DevicePixelRatio(); const auto session = &_show->session(); const auto &colorings = session->appConfig().groupCallColorings(); - if ((_canvas.width() < scroll->width() * ratio) - || (_canvas.height() < scroll->height() * ratio)) { + if ((_canvas.width() < style::DevicePixels(scroll->width())) + || (_canvas.height() < style::DevicePixels(scroll->height()))) { _canvas = QImage( - scroll->size() * ratio, + style::DevicePixels(scroll->size()), QImage::Format_ARGB32_Premultiplied); - _canvas.setDevicePixelRatio(ratio); + _canvas.setDevicePixelRatio(style::DevicePixelRatio()); } auto p = Painter(&_canvas); @@ -1404,7 +1401,9 @@ void MessagesUi::setupMessagesWidget() { QPainter(_messages).drawImage( QRect(QPoint(0, start), scroll->size()), _canvas, - QRect(QPoint(), scroll->size() * ratio)); + QRect( + QPoint(), + style::DevicePixels(scroll->size()))); }, _messages->lifetime()); scroll->show(); @@ -1575,14 +1574,14 @@ void MessagesUi::setupPinnedWidget() { const auto &colorings = session->appConfig().groupCallColorings(); const auto start = scroll->scrollLeft(); const auto end = start + scroll->width(); - const auto ratio = style::DevicePixelRatio(); - if ((_pinnedCanvas.width() < scroll->width() * ratio) - || (_pinnedCanvas.height() < scroll->height() * ratio)) { + const auto pixelSize = style::DevicePixels(scroll->size()); + if ((_pinnedCanvas.width() < pixelSize.width()) + || (_pinnedCanvas.height() < pixelSize.height())) { _pinnedCanvas = QImage( - scroll->size() * ratio, + pixelSize, QImage::Format_ARGB32_Premultiplied); - _pinnedCanvas.setDevicePixelRatio(ratio); + _pinnedCanvas.setDevicePixelRatio(style::DevicePixelRatio()); } auto p = Painter(&_pinnedCanvas); @@ -1697,7 +1696,7 @@ void MessagesUi::setupPinnedWidget() { QPainter(_pinned).drawImage( QRect(QPoint(start, 0), scroll->size()), _pinnedCanvas, - QRect(QPoint(), scroll->size() * ratio)); + QRect(QPoint(), pixelSize)); }, _pinned->lifetime()); _pinned->setMouseTracking(true); diff --git a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp index 94ce5cded80ef0..6c24ef44d0ac2d 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_viewport_opengl.cpp @@ -1202,10 +1202,10 @@ void Viewport::RendererGL::validateDatas() { const auto &st = st::groupCallVideoTile; const auto count = int(tiles.size()); const auto factor = style::DevicePixelRatio(); - const auto nameHeight = st::semiboldFont->height * factor; + const auto nameHeight = style::DevicePixels(st::semiboldFont->height); const auto pausedText = tr::lng_group_call_video_paused(tr::now); const auto pausedBottom = nameHeight; - const auto pausedWidth = st::semiboldFont->width(pausedText) * factor; + const auto pausedWidth = style::DevicePixels(st::semiboldFont->width(pausedText)); struct Request { int index = 0; bool updating = false; @@ -1225,7 +1225,7 @@ void Viewport::RendererGL::validateDatas() { if (hasWidth < 1) { return 0; } - return std::clamp(row->name().maxWidth(), 1, hasWidth) * factor; + return style::DevicePixels(std::clamp(row->name().maxWidth(), 1, hasWidth)); }; for (auto i = 0; i != count; ++i) { tiles[i]->row()->lazyInitialize(st::groupCallMembersListItem); @@ -1317,18 +1317,18 @@ void Viewport::RendererGL::validateDatas() { p.drawImage(0, 0, image); if (paintToImage.width() > image.width()) { p.fillRect( - image.width() / factor, + qRound(image.width() / factor), 0, (paintToImage.width() - image.width()) / factor, - image.height() / factor, + qRound(image.height() / factor), Qt::transparent); } if (paintToImage.height() > image.height()) { p.fillRect( 0, - image.height() / factor, - paintToImage.width() / factor, - (paintToImage.height() - image.height()) / factor, + qRound(image.height() / factor), + qRound(paintToImage.width() / factor), + qRound((paintToImage.height() - image.height()) / factor), Qt::transparent); } p.setCompositionMode(QPainter::CompositionMode_SourceOver); @@ -1348,18 +1348,18 @@ void Viewport::RendererGL::validateDatas() { p.setCompositionMode(QPainter::CompositionMode_Source); p.fillRect( 0, - data.nameRect.y() / factor, - paintToImage.width() / factor, - nameHeight / factor, + qRound(data.nameRect.y() / factor), + qRound(paintToImage.width() / factor), + qRound(nameHeight / factor), Qt::transparent); p.setCompositionMode(QPainter::CompositionMode_SourceOver); } row->name().drawLeftElided( p, 0, - data.nameRect.y() / factor, - data.nameRect.width() / factor, - paintToImage.width() / factor); + qRound(data.nameRect.y() / factor), + qRound(data.nameRect.width() / factor), + qRound(paintToImage.width() / factor)); } } _names.setImage(std::move(paintToImage)); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp index 33b7c96b1fb085..c6675f7d0db3ee 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_list_widget.cpp @@ -53,6 +53,7 @@ For license and copyright information please follow this link: #include "settings/sections/settings_premium.h" #include "window/window_session_controller.h" #include "window/window_controller.h" +#include "ui/style/style_core_scale.h" #include "styles/style_chat_helpers.h" #include "styles/style_menu_icons.h" @@ -285,7 +286,8 @@ void EmojiColorPicker::setSingleSize(QSize size) { _areaPosition = QPoint( (_singleSize.width() - area.width()) / 2, (_singleSize.height() - area.height()) / 2); - const auto esize = Ui::Emoji::GetSizeLarge() / style::DevicePixelRatio(); + const auto esize = qRound( + Ui::Emoji::GetSizeLarge() / style::DevicePixelRatio()); _innerPosition = QPoint( (area.width() - esize) / 2, (area.height() - esize) / 2); @@ -1464,7 +1466,8 @@ void EmojiListWidget::setSingleSize(QSize size) { _areaPosition = QPoint( (_singleSize.width() - area.width()) / 2, (_singleSize.height() - area.height()) / 2); - const auto esize = Ui::Emoji::GetSizeLarge() / style::DevicePixelRatio(); + const auto esize = qRound( + Ui::Emoji::GetSizeLarge() / style::DevicePixelRatio()); _innerPosition = QPoint( (area.width() - esize) / 2, (area.height() - esize) / 2); @@ -1988,7 +1991,7 @@ void EmojiListWidget::drawRecent( if (_premiumMarkFrameCache.isNull()) { const auto ratio = style::DevicePixelRatio(); _premiumMarkFrameCache = QImage( - QSize(_customSingleSize, _customSingleSize) * ratio, + style::DevicePixels(QSize(_customSingleSize, _customSingleSize)), QImage::Format_ARGB32_Premultiplied); _premiumMarkFrameCache.setDevicePixelRatio(ratio); } @@ -3345,7 +3348,7 @@ void EmojiListWidget::initButton( const auto factor = style::DevicePixelRatio(); auto prepare = [&](QColor bg, QBrush fg) { auto image = QImage( - QSize(width, height) * factor, + style::DevicePixels(QSize(width, height)), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(factor); image.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp index 696541172c8502..fc4b79eaa2d182 100644 --- a/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/emoji_suggestions_widget.cpp @@ -430,7 +430,7 @@ void SuggestionsWidget::paintEvent(QPaintEvent *e) { const auto &row = _rows[i]; const auto emoji = row.emoji; const auto esize = Ui::Emoji::GetSizeLarge(); - const auto size = esize / style::DevicePixelRatio(); + const auto size = qRound(esize / style::DevicePixelRatio()); const auto x = i * _oneWidth + (_oneWidth - size) / 2; const auto y = (_oneWidth - size) / 2; if (row.custom) { diff --git a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp index 0dcef40550763c..e8cbcbbf0f8e38 100644 --- a/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp +++ b/Telegram/SourceFiles/chat_helpers/field_autocomplete.cpp @@ -41,6 +41,7 @@ For license and copyright information please follow this link: #include "ui/painter.h" #include "ui/ui_utility.h" #include "ui/cached_round_corners.h" +#include "ui/style/style_core_scale.h" #include "base/unixtime.h" #include "base/random.h" #include "base/qt/qt_key_modifiers.h" @@ -116,6 +117,7 @@ class FieldAutocomplete::Inner final : public Ui::RpWidget { private: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; + void devicePixelRatioChangedEvent() override; void enterEventHook(QEnterEvent *e) override; void leaveEventHook(QEvent *e) override; @@ -991,7 +993,7 @@ void FieldAutocomplete::Inner::paintEvent(QPaintEvent *e) { p.drawImage( QRect( ppos, - lottieFrame.size() / style::DevicePixelRatio()), + style::LogicalPixels(lottieFrame.size())), lottieFrame); if (!paused) { sticker.lottie->markFrameShown(); @@ -1178,6 +1180,15 @@ void FieldAutocomplete::Inner::resizeEvent(QResizeEvent *e) { _stickersPerRow = qMax(1, int32(width() - 2 * st::stickerPanPadding) / int32(st::stickerPanSize.width())); } +void FieldAutocomplete::Inner::devicePixelRatioChangedEvent() { + _stickersLifetime.destroy(); + for (auto &sticker : *_srows) { + sticker.lottie = nullptr; + sticker.webm = nullptr; + sticker.premiumLock = QImage(); + } +} + void FieldAutocomplete::Inner::mouseMoveEvent(QMouseEvent *e) { const auto globalPosition = e->globalPos(); if (!_lastMousePosition) { diff --git a/Telegram/SourceFiles/chat_helpers/message_field.cpp b/Telegram/SourceFiles/chat_helpers/message_field.cpp index 8e7db8f70a2aec..f4018e9170ec0a 100644 --- a/Telegram/SourceFiles/chat_helpers/message_field.cpp +++ b/Telegram/SourceFiles/chat_helpers/message_field.cpp @@ -737,8 +737,9 @@ void InitMessageFieldFade( const auto generateFade = [=] { const auto size = QSize(1, st::historyComposeFieldFadeHeight); - auto fade = QPixmap(size * style::DevicePixelRatio()); - fade.setDevicePixelRatio(style::DevicePixelRatio()); + const auto ratio = style::DevicePixelRatio(); + auto fade = QPixmap(style::DevicePixels(size)); + fade.setDevicePixelRatio(ratio); fade.fill(Qt::transparent); { auto p = QPainter(&fade); diff --git a/Telegram/SourceFiles/chat_helpers/stickers_emoji_image_loader.cpp b/Telegram/SourceFiles/chat_helpers/stickers_emoji_image_loader.cpp index b5f0b20f967c61..6e335025e59d61 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_emoji_image_loader.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_emoji_image_loader.cpp @@ -7,6 +7,7 @@ For license and copyright information please follow this link: */ #include "chat_helpers/stickers_emoji_image_loader.h" +#include "base/algorithm.h" #include "styles/style_chat.h" #include @@ -33,8 +34,9 @@ QImage EmojiImageLoader::prepare(EmojiPtr emoji) const { const auto factor = style::DevicePixelRatio(); const auto side = st::largeEmojiSize + 2 * st::largeEmojiOutline; auto tinted = QImage( - QSize(st::largeEmojiSize, st::largeEmojiSize) * factor, + style::DevicePixels(QSize(st::largeEmojiSize, st::largeEmojiSize)), QImage::Format_ARGB32_Premultiplied); + tinted.setDevicePixelRatio(factor); tinted.fill(Qt::white); if (loaded) { QPainter p(&tinted); @@ -42,17 +44,18 @@ QImage EmojiImageLoader::prepare(EmojiPtr emoji) const { _images->draw( p, emoji, - st::largeEmojiSize * factor, + style::DevicePixels(st::largeEmojiSize), 0, 0); } auto result = QImage( - QSize(side, side) * factor, + style::DevicePixels(QSize(side, side)), QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(factor); result.fill(Qt::transparent); if (loaded) { QPainter p(&result); - const auto delta = st::largeEmojiOutline * factor; + const auto delta = style::DevicePixels(st::largeEmojiOutline); const auto planar = std::array{ { { 0, -1 }, { -1, 0 }, @@ -79,7 +82,7 @@ QImage EmojiImageLoader::prepare(EmojiPtr emoji) const { _images->draw( p, emoji, - st::largeEmojiSize * factor, + style::DevicePixels(st::largeEmojiSize), delta, delta); } diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp index a0394d1ade60ed..131493094bd0d9 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.cpp @@ -343,9 +343,9 @@ void StickersListFooter::paintExpanding( } int StickersListFooter::IconFrameSize() { - return Data::FrameSizeFromTag( + return style::LogicalPixels(Data::FrameSizeFromTag( Data::CustomEmojiManager::SizeTag::SetIcon - ) / style::DevicePixelRatio(); + )); } void StickersListFooter::enumerateVisibleIcons( @@ -642,7 +642,7 @@ void StickersListFooter::paint( paintSelectionBg(p, context); const auto iconCacheSize = QSize(_singleWidth, st().footer); - const auto full = iconCacheSize * style::DevicePixelRatio(); + const auto full = style::DevicePixels(iconCacheSize); if (_setIconCache.size() != full) { _setIconCache = QImage(full, QImage::Format_ARGB32_Premultiplied); _setIconCache.setDevicePixelRatio(style::DevicePixelRatio()); @@ -933,6 +933,22 @@ bool StickersListFooter::eventHook(QEvent *e) { return InnerFooter::eventHook(e); } +void StickersListFooter::devicePixelRatioChangedEvent() { + _setIconCache = QImage(); + _fadeLeftCache = QImage(); + _fadeRightCache = QImage(); + _fadeMask = QImage(); + for (auto &icon : _icons) { + if (icon.custom) { + icon.custom->unload(); + icon.custom.reset(); + } + } + _iconState.animation.stop(); + _subiconState.animation.stop(); + update(); +} + void StickersListFooter::scrollByWheelEvent( not_null e) { auto horizontal = (e->angleDelta().x() != 0); @@ -1190,7 +1206,7 @@ void StickersListFooter::validateIconLottieAnimation( icon.thumbnailMedia.get(), icon.stickerMedia.get(), StickerLottieSize::StickersFooter, - QSize(icon.pixw, icon.pixh) * style::DevicePixelRatio(), + style::DevicePixels(QSize(icon.pixw, icon.pixh)), _renderer()); if (!player) { return; @@ -1356,11 +1372,9 @@ void StickersListFooter::paintSetIconToCache( }); } else if (icon.lottie && icon.lottie->ready()) { const auto frame = icon.lottie->frame(); - const auto size = frame.size() / style::DevicePixelRatio(); + const auto size = style::LogicalPixels(frame.size()); if (icon.savedFrame.isNull()) { icon.savedFrame = frame; - icon.savedFrame.setDevicePixelRatio( - style::DevicePixelRatio()); } p.drawImage( QRect( @@ -1382,6 +1396,10 @@ void StickersListFooter::paintSetIconToCache( style::DevicePixelRatio()); } p.drawImage(x, y, frame); + } else if (!icon.savedFrame.isNull() + && qAbs(icon.savedFrame.devicePixelRatio() + - style::DevicePixelRatio()) >= 0.001) { + icon.savedFrame = QImage(); } else if (!icon.savedFrame.isNull()) { p.drawImage(x, y, icon.savedFrame); } else if (thumb) { diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h index a76b1ee21ab032..7369bfbb33fe34 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_footer.h @@ -159,6 +159,7 @@ class StickersListFooter final : public TabbedSelector::InnerFooter { void mousePressEvent(QMouseEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; + void devicePixelRatioChangedEvent() override; bool eventHook(QEvent *e) override; void processHideFinished() override; diff --git a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp index 78002e3ee06d4a..5ead9d9fa7ac31 100644 --- a/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/stickers_list_widget.cpp @@ -1718,16 +1718,19 @@ void StickersListWidget::paintSticker( (_singleSize.height() - size.height()) / 2); auto lottieFrame = QImage(); + if (!sticker.savedFrame.isNull() + && qAbs(sticker.savedFrame.devicePixelRatio() + - style::DevicePixelRatio()) >= 0.001) { + sticker.savedFrame = QImage(); + sticker.savedFrameFor = QSize(); + } if (sticker.lottie && sticker.lottie->ready()) { auto request = Lottie::FrameRequest(); - request.box = boundingBoxSize() * style::DevicePixelRatio(); + request.box = style::DevicePixels(boundingBoxSize()); lottieFrame = sticker.lottie->frame(request); - p.drawImage( - QRect(ppos, lottieFrame.size() / style::DevicePixelRatio()), - lottieFrame); + p.drawImage(QRect(ppos, size), lottieFrame); if (sticker.savedFrame.isNull()) { sticker.savedFrame = lottieFrame; - sticker.savedFrame.setDevicePixelRatio(style::DevicePixelRatio()); sticker.savedFrameFor = _singleSize; } set.lottiePlayer->unpause(sticker.lottie); @@ -1740,7 +1743,7 @@ void StickersListWidget::paintSticker( sticker.savedFrame.setDevicePixelRatio(style::DevicePixelRatio()); sticker.savedFrameFor = _singleSize; } - p.drawImage(ppos, frame); + p.drawImage(QRect(ppos, size), frame); } else { const auto image = media->getStickerSmall(); const auto useSavedFrame = !sticker.savedFrame.isNull() @@ -1756,11 +1759,13 @@ void StickersListWidget::paintSticker( if (sticker.savedFrame.isNull()) { sticker.savedFrame = pixmap.toImage().convertToFormat( QImage::Format_ARGB32_Premultiplied); + sticker.savedFrame.setDevicePixelRatio(style::DevicePixelRatio()); sticker.savedFrameFor = _singleSize; } if (premium) { lottieFrame = pixmap.toImage().convertToFormat( QImage::Format_ARGB32_Premultiplied); + lottieFrame.setDevicePixelRatio(style::DevicePixelRatio()); } } else { p.setOpacity(1.); @@ -1802,7 +1807,9 @@ void StickersListWidget::paintSticker( const auto radius = st::roundRadiusSmall; const auto position = pos + QPoint(_singleSize.width(), _singleSize.height()) - - QPoint(size / ratio + radius, size / ratio + radius); + - QPoint( + base::SafeRound(size / ratio) + radius, + base::SafeRound(size / ratio) + radius); Ui::Emoji::Draw(p, emoji, size, position.x(), position.y()); cornerPainted = true; } diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp index 713efc111197b1..bf6266ad97e3a0 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_panel.cpp @@ -385,12 +385,10 @@ void TabbedPanel::startShowAnimation() { (_dropDown ? Ui::PanelAnimation::Origin::TopRight : Ui::PanelAnimation::Origin::BottomRight)); - auto inner = rect().marginsRemoved(st::emojiPanMargins); + const auto inner = rect().marginsRemoved(st::emojiPanMargins); _showAnimation->setFinalImage( std::move(image), - QRect( - inner.topLeft() * style::DevicePixelRatio(), - inner.size() * style::DevicePixelRatio()), + style::DevicePixels(inner), st::emojiPanRadius); _showAnimation->setCornerMasks(Images::CornersMask(st::emojiPanRadius)); _showAnimation->start(); @@ -409,7 +407,7 @@ QImage TabbedPanel::grabForAnimation() { Ui::SendPendingMoveResizeEvents(this); auto result = QImage( - size() * style::DevicePixelRatio(), + style::DevicePixels(size()), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(style::DevicePixelRatio()); result.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp index a44da34acece5b..172d5ef12fd0c6 100644 --- a/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp +++ b/Telegram/SourceFiles/chat_helpers/tabbed_selector.cpp @@ -88,10 +88,9 @@ void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage Assert(!_leftImage.isNull()); Assert(!_rightImage.isNull()); + const auto ratio = style::DevicePixelRatio(); _width = _leftImage.width(); _height = _rightImage.height(); - Assert(!(_width % style::DevicePixelRatio())); - Assert(!(_height % style::DevicePixelRatio())); Assert(_leftImage.devicePixelRatio() == _rightImage.devicePixelRatio()); Assert(_rightImage.width() == _width); Assert(_rightImage.height() == _height); @@ -100,19 +99,15 @@ void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage _innerTop = inner.y(); _innerWidth = inner.width(); _innerHeight = inner.height(); - Assert(!(_innerLeft % style::DevicePixelRatio())); - Assert(!(_innerTop % style::DevicePixelRatio())); - Assert(!(_innerWidth % style::DevicePixelRatio())); - Assert(!(_innerHeight % style::DevicePixelRatio())); _innerRight = _innerLeft + _innerWidth; _innerBottom = _innerTop + _innerHeight; - _painterInnerLeft = _innerLeft / style::DevicePixelRatio(); - _painterInnerTop = _innerTop / style::DevicePixelRatio(); - _painterInnerRight = _innerRight / style::DevicePixelRatio(); - _painterInnerBottom = _innerBottom / style::DevicePixelRatio(); - _painterInnerWidth = _innerWidth / style::DevicePixelRatio(); - _painterInnerHeight = _innerHeight / style::DevicePixelRatio(); + _painterInnerLeft = qRound(_innerLeft / ratio); + _painterInnerTop = qRound(_innerTop / ratio); + _painterInnerRight = qRound(_innerRight / ratio); + _painterInnerBottom = qRound(_innerBottom / ratio); + _painterInnerWidth = qRound(_innerWidth / ratio); + _painterInnerHeight = qRound(_innerHeight / ratio); _painterCategoriesTop = _painterInnerBottom - st::defaultEmojiPan.footer; _wasSectionIcons = wasSectionIcons; @@ -148,15 +143,18 @@ void TabbedSelector::SlideAnimation::paintFrame( auto easeOut = anim::easeOutCirc(1., dt); auto easeIn = anim::easeInCirc(1., dt); + const auto ratio = style::DevicePixelRatio(); + const auto alignDown = [ratio](int value) { + return qRound(std::floor(value / ratio) * ratio); + }; + const auto alignUp = [ratio](int value) { + return qRound(std::ceil(value / ratio) * ratio); + }; auto arrivingCoord = anim::interpolate(_innerWidth, 0, easeOut); auto departingCoord = anim::interpolate(0, _innerWidth, easeIn); - if (auto decrease = (arrivingCoord % style::DevicePixelRatio())) { - arrivingCoord -= decrease; - } - if (auto decrease = (departingCoord % style::DevicePixelRatio())) { - departingCoord -= decrease; - } + arrivingCoord = alignDown(arrivingCoord); + departingCoord = alignDown(departingCoord); auto arrivingAlpha = easeIn; auto departingAlpha = 1. - easeOut; auto leftCoord = (leftToRight ? arrivingCoord : departingCoord) * -1; @@ -168,7 +166,7 @@ void TabbedSelector::SlideAnimation::paintFrame( auto leftTo = _innerLeft + std::clamp(_innerWidth + leftCoord, 0, _innerWidth); auto rightFrom = _innerLeft + std::clamp(rightCoord, 0, _innerWidth); - auto painterRightFrom = rightFrom / style::DevicePixelRatio(); + auto painterRightFrom = qRound(rightFrom / ratio); if (opacity < 1.) { _frame.fill(Qt::transparent); } @@ -205,20 +203,16 @@ void TabbedSelector::SlideAnimation::paintFrame( outerRight += _shadow.extend.right(); outerBottom += _shadow.extend.bottom(); } - if (style::DevicePixelRatio() > 1) { - if (auto skipLeft = (outerLeft % style::DevicePixelRatio())) { - outerLeft -= skipLeft; - } - if (auto skipTop = (outerTop % style::DevicePixelRatio())) { - outerTop -= skipTop; - } - if (auto skipRight = (outerRight % style::DevicePixelRatio())) { - outerRight += (style::DevicePixelRatio() - skipRight); - } - if (auto skipBottom = (outerBottom % style::DevicePixelRatio())) { - outerBottom += (style::DevicePixelRatio() - skipBottom); - } + if (ratio > 1.) { + outerLeft = alignDown(outerLeft); + outerTop = alignDown(outerTop); + outerRight = alignUp(outerRight); + outerBottom = alignUp(outerBottom); } + outerLeft = std::clamp(outerLeft, 0, _width); + outerTop = std::clamp(outerTop, 0, _height); + outerRight = std::clamp(outerRight, 0, _width); + outerBottom = std::clamp(outerBottom, 0, _height); if (opacity == 1.) { // Fill above the frame top with transparent. @@ -266,8 +260,8 @@ void TabbedSelector::SlideAnimation::paintFrame( //} p.drawImage( - outerLeft / style::DevicePixelRatio(), - outerTop / style::DevicePixelRatio(), + style::LogicalPixels(outerLeft), + style::LogicalPixels(outerTop), _frame, outerLeft, outerTop, @@ -991,7 +985,7 @@ QImage TabbedSelector::grabForAnimation() { Ui::SendPendingMoveResizeEvents(this); auto result = QImage( - size() * style::DevicePixelRatio(), + style::DevicePixels(size()), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(style::DevicePixelRatio()); result.fill(Qt::transparent); @@ -1293,11 +1287,11 @@ void TabbedSelector::switchTab() { std::swap(wasCache, nowCache); } _slideAnimation = std::make_unique(); - const auto slidingRect = QRect( + const auto slidingRect = style::DevicePixels(QRect( 0, - _scroll->y() * style::DevicePixelRatio(), - width() * style::DevicePixelRatio(), - (height() - _scroll->y()) * style::DevicePixelRatio()); + _scroll->y(), + width(), + height() - _scroll->y())); _slideAnimation->setFinalImages( direction, std::move(wasCache), diff --git a/Telegram/SourceFiles/core/sandbox.cpp b/Telegram/SourceFiles/core/sandbox.cpp index 81ea4e4906ca7d..b1900c27689f84 100644 --- a/Telegram/SourceFiles/core/sandbox.cpp +++ b/Telegram/SourceFiles/core/sandbox.cpp @@ -180,7 +180,7 @@ void Sandbox::launchApplication() { } void Sandbox::setupScreenScale() { - const auto ratio = devicePixelRatio(); + auto ratio = devicePixelRatio(); LOG(("Global devicePixelRatio: %1").arg(ratio)); const auto logEnv = [](const char *name) { const auto value = qEnvironmentVariable(name); @@ -198,7 +198,7 @@ void Sandbox::setupScreenScale() { logEnv("QT_USE_PHYSICAL_DPI"); logEnv("QT_FONT_DPI"); - const auto useRatio = std::clamp(qCeil(ratio), 1, 3); + const auto useRatio = std::clamp(ratio, 1., 3.); style::SetDevicePixelRatio(useRatio); const auto screen = Sandbox::primaryScreen(); @@ -218,6 +218,7 @@ void Sandbox::setupScreenScale() { style::kScaleMin, style::MaxScaleForRatio(useRatio))); } + LOG(("DevicePixelRatio: %1").arg(style::DevicePixelRatio())); LOG(("DevicePixelRatio: %1").arg(useRatio)); LOG(("ScreenScale: %1").arg(cScreenScale())); } diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp index 1b3868ac50b059..75410c63d74e64 100644 --- a/Telegram/SourceFiles/data/data_forum_topic.cpp +++ b/Telegram/SourceFiles/data/data_forum_topic.cpp @@ -86,7 +86,7 @@ QImage ForumTopicIconBackground(int32 colorId, int size) { const auto ratio = style::DevicePixelRatio(); auto svg = QSvgRenderer(ForumTopicIconPath(ForumTopicIcon(colorId))); auto result = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); @@ -148,7 +148,7 @@ QImage ForumTopicGeneralIconFrame(int size, const QColor &color) { const auto ratio = style::DevicePixelRatio(); auto svg = QSvgRenderer(ForumTopicIconPath(u"general"_q)); auto result = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/data/data_message_reactions.cpp b/Telegram/SourceFiles/data/data_message_reactions.cpp index 8c9536807d07e7..390929df6f4e4c 100644 --- a/Telegram/SourceFiles/data/data_message_reactions.cpp +++ b/Telegram/SourceFiles/data/data_message_reactions.cpp @@ -811,38 +811,46 @@ QImage Reactions::resolveImageFor(const ReactionId &id) { preloadImageFor(id); i = _images.find(id); Assert(i != end(_images)); + } else if (!i->second.image.isNull() + && qAbs(i->second.image.devicePixelRatio() + - style::DevicePixelRatio()) >= 0.001) { + _images.erase(i); + preloadImageFor(id); + i = _images.find(id); + Assert(i != end(_images)); } auto &set = i->second; set.effect = (id.custom() != 0); const auto resolve = [&](QImage &image, int size) { - const auto factor = style::DevicePixelRatio(); const auto frameSize = set.fromSelectAnimation ? (size / 2) : size; // Must not be colored to text. image = set.icon->frame(QColor()).scaled( - frameSize * factor, - frameSize * factor, + style::DevicePixels(frameSize), + style::DevicePixels(frameSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + image.setDevicePixelRatio(style::DevicePixelRatio()); + if (set.fromSelectAnimation) { auto result = QImage( - size * factor, - size * factor, + style::DevicePixels(size), + style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); result.fill(Qt::transparent); + result.setDevicePixelRatio(style::DevicePixelRatio()); auto p = QPainter(&result); p.drawImage( - (size - frameSize) * factor / 2, - (size - frameSize) * factor / 2, + (size - frameSize) / 2, + (size - frameSize) / 2, image); p.end(); std::swap(result, image); } - image.setDevicePixelRatio(factor); }; if (set.image.isNull() && set.icon) { resolve( @@ -937,7 +945,7 @@ void Reactions::generateImage(ImageSet &set, const QString &emoji) { Ui::Emoji::Draw(p, e, large, 0, 0); } const auto size = st::effectInfoImage; - set.image = image.scaled(size * factor, size * factor); + set.image = image.scaled(style::DevicePixels(size), style::DevicePixels(size)); set.image.setDevicePixelRatio(factor); } diff --git a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp index a90656303c8ab5..be7d06443e4dd7 100644 --- a/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp +++ b/Telegram/SourceFiles/data/stickers/data_custom_emoji.cpp @@ -85,18 +85,16 @@ class CallbackListener final : public CustomEmojiManager::Listener { case SizeTag::Normal: return Ui::Emoji::GetSizeNormal(); case SizeTag::Large: return Ui::Emoji::GetSizeLarge(); case SizeTag::Isolated: - return (st::largeEmojiSize + 2 * st::largeEmojiOutline) - * style::DevicePixelRatio(); + return style::DevicePixels(st::largeEmojiSize + 2 * st::largeEmojiOutline); case SizeTag::SetIcon: - return int(style::ConvertScale(18 * 7 / 6., style::Scale())) - * style::DevicePixelRatio(); + return style::DevicePixels(style::ConvertScale(18 * 7 / 6., style::Scale())); } Unexpected("SizeTag value in CustomEmojiManager-SizeFromTag."); } [[nodiscard]] int FrameSizeFromTag(SizeTag tag, int sizeOverride) { return sizeOverride - ? (sizeOverride * style::DevicePixelRatio()) + ? style::DevicePixels(sizeOverride) : FrameSizeFromTag(tag); } @@ -567,7 +565,7 @@ std::unique_ptr CustomEmojiManager::create( create(original, std::move(update), tag, sizeOverride)); } else if (data.startsWith(UserpicEmojiPrefix())) { const auto ratio = style::DevicePixelRatio(); - const auto size = EmojiSizeFromTag(tag) / ratio; + const auto size = base::SafeRound(EmojiSizeFromTag(tag) / ratio); return userpic(data, std::move(update), size); } else if (data.startsWith(CollectiblePrefix())) { const auto id = data.mid(CollectiblePrefix().size()).toULongLong(); @@ -582,7 +580,7 @@ std::unique_ptr CustomEmojiManager::create( info->edgeColor, std::move(inner), std::move(update), - FrameSizeFromTag(tag) / style::DevicePixelRatio()); + base::SafeRound(FrameSizeFromTag(tag) / style::DevicePixelRatio())); } else if (const auto parsed = Data::ParseTopicIconEmojiEntity(data)) { return MakeTopicIconEmoji(parsed, std::move(update), tag); } @@ -1011,7 +1009,8 @@ uint64 CustomEmojiManager::coloredSetId() const { int FrameSizeFromTag(SizeTag tag) { const auto emoji = EmojiSizeFromTag(tag); const auto factor = style::DevicePixelRatio(); - return Ui::Text::AdjustCustomEmojiSize(emoji / factor) * factor; + return style::DevicePixels( + Ui::Text::AdjustCustomEmojiSize(base::SafeRound(emoji / factor))); } QString SerializeCustomEmojiId(DocumentId id) { @@ -1088,7 +1087,8 @@ Ui::Text::CustomEmojiFactory ReactedMenuFactory( const auto size = st::emojiSize * (i->centerIcon ? 2 : 1); const auto tag = Data::CustomEmojiManager::SizeTag::Normal; const auto ratio = style::DevicePixelRatio(); - const auto skip = (Data::FrameSizeFromTag(tag) / ratio - size) / 2; + const auto skip = ( + base::SafeRound(Data::FrameSizeFromTag(tag) / ratio) - size) / 2; return std::make_unique( std::make_unique( owner->customEmojiManager().create( diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index cbcc309442b80c..1ae4f5e1470e2b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -931,8 +931,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { more++; continue; } - const auto tagWidth = tag->width() - / style::DevicePixelRatio(); + const auto tagWidth = style::LogicalPixels(tag->width()); if (availableWidth < tagWidth) { more++; } else { @@ -944,8 +943,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { } if (more) { if (const auto tag = cacheChatsFilterTag({}, more, a)) { - const auto tagWidth = tag->width() - / style::DevicePixelRatio(); + const auto tagWidth = style::LogicalPixels(tag->width()); if (availableWidth < tagWidth) { more++; if (!chatsFilterTags.empty()) { @@ -1379,7 +1377,7 @@ void InnerWidget::fillRightButton( st.button.height); const auto generateBg = [&](const style::color &c) { auto bg = QImage( - style::DevicePixelRatio() * size, + style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); bg.setDevicePixelRatio(style::DevicePixelRatio()); bg.fill(Qt::transparent); @@ -1763,7 +1761,7 @@ void InnerWidget::performDrag() { } const auto &st = st::defaultDialogRow; - auto pixmap = QPixmap(Size(st.height * style::DevicePixelRatio())); + auto pixmap = QPixmap(style::DevicePixels(QSize(st.height, st.height))); pixmap.setDevicePixelRatio(style::DevicePixelRatio()); pixmap.fill(Qt::transparent); if (const auto draw = PaintUserpicCallback(history->peer, true)) { @@ -1843,7 +1841,7 @@ bool InnerWidget::lookupIsInRightButton( return false; } - const auto s = button.bg.size() / style::DevicePixelRatio(); + const auto s = style::LogicalPixels(button.bg.size()); const auto r = QRect( width() - s.width() - button.st->margin.right(), button.st->margin.top(), @@ -2186,8 +2184,7 @@ bool InnerWidget::addRightButtonRipple(QPoint origin, Fn updateCallback) if (!(_pressedRightButton && _pressedRightButtonData)) { return false; } - const auto size = _pressedRightButtonData->bg.size() - / style::DevicePixelRatio(); + const auto size = style::LogicalPixels(_pressedRightButtonData->bg.size()); if (!_pressedRightButtonData->ripple) { _pressedRightButtonData->ripple = std::make_unique( _pressedRightButtonData->st->button.ripple, diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 87ba11d6bb66a6..ab655235d0f810 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -20,6 +20,7 @@ For license and copyright information please follow this link: #include "ui/text/text_options.h" #include "ui/text/text_utilities.h" #include "ui/painter.h" +#include "ui/style/style_core_scale.h" #include "dialogs/dialogs_entry.h" #include "dialogs/ui/dialogs_video_userpic.h" #include "dialogs/ui/dialogs_layout.h" @@ -116,17 +117,14 @@ constexpr auto kBlurRadius = 24; if (!ttl) { return QImage(); } - const auto ratio = style::DevicePixelRatio(); const auto fullSize = photoSize; const auto partRect = CornerBadgeTTLRect(fullSize); const auto &partSize = partRect.width(); const auto partSkip = fullSize - partSize; auto result = Images::Circle(BlurredDarkenedPart( - PeerData::GenerateUserpicImage(peer, view, fullSize * ratio, 0), - QRect( - QPoint(partSkip, partSkip) * ratio, - QSize(partSize, partSize) * ratio))); - result.setDevicePixelRatio(ratio); + PeerData::GenerateUserpicImage(peer, view, style::DevicePixels(fullSize), 0), + style::DevicePixels(QRect(partSkip, partSkip, partSize, partSize)))); + result.setDevicePixelRatio(style::DevicePixelRatio()); auto q = QPainter(&result); PainterHighQualityEnabler hq(q); @@ -567,8 +565,8 @@ void Row::paintUserpic( -st::dialogsCallBadgeSkip.x(), -st::dialogsCallBadgeSkip.y(), st::lineWidth * 2 }); - const auto frameSide = (2 * framePadding + context.st->photoSize) - * ratio; + const auto frameSide = style::DevicePixels( + (2 * framePadding + context.st->photoSize)); const auto frameSize = QSize(frameSide, frameSide); const auto storiesSource = (storiesHas && storiesPeer) ? storiesPeer->owner().stories().source(storiesPeer->id) diff --git a/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp b/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp index 7cf7598fad5bd0..2949cb70fd2415 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_search_tags.cpp @@ -371,8 +371,10 @@ void SearchTags::paintBackground( QRect geometry, const Tag &tag) const { const auto &image = validateBg(tag.selected, tag.promo); - const auto ratio = int(image.devicePixelRatio()); - const auto size = image.size() / ratio; + const auto ratio = image.devicePixelRatio(); + const auto size = QSize( + qRound(image.width() / ratio), + qRound(image.height() / ratio)); if (const auto fill = geometry.width() - size.width(); fill > 0) { const auto left = size.width() / 2; const auto right = size.width() - left; @@ -381,14 +383,18 @@ void SearchTags::paintBackground( p.drawImage( QRect(x, y, left, size.height()), image, - QRect(QPoint(), QSize(left, size.height()) * ratio)); + style::DevicePixels(QRect( + QPoint(), + QSize(left, size.height())), + ratio)); p.fillRect( QRect(x + left, y, fill, size.height()), bgColor(tag.selected, tag.promo)); p.drawImage( QRect(x + left + fill, y, right, size.height()), image, - QRect(left * ratio, 0, right * ratio, size.height() * ratio)); + style::DevicePixels(QRect( + left, 0, right, size.height()), ratio)); } else { p.drawImage(geometry.topLeft(), image); } diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 390d370077ccea..5e6b28fc5f0985 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -109,19 +109,19 @@ int PaintRightButtonImpl(QPainter &p, const PaintContext &context) { if (const auto rightButton = context.rightButton) { Assert(rightButton->st != nullptr); - const auto size = rightButton->bg.size() / style::DevicePixelRatio(); + const auto bg = context.active + ? rightButton->activeBg + : context.selected + ? rightButton->selectedBg + : rightButton->bg; + const auto size = QSize( + qRound(bg.width() / bg.devicePixelRatio()), + qRound(bg.height() / bg.devicePixelRatio())); const auto left = context.width - size.width() - rightButton->st->margin.right(); const auto top = rightButton->st->margin.top(); - p.drawImage( - left, - top, - context.active - ? rightButton->activeBg - : context.selected - ? rightButton->selectedBg - : rightButton->bg); + p.drawImage(left, top, bg); if (rightButton->ripple) { rightButton->ripple->paint( p, @@ -624,7 +624,7 @@ void PaintRow( availableWidth, context.width, color, - context.paused)) { + context.now)) { auto &cache = thread->cloudDraftTextCache(); if (cache.isEmpty()) { using namespace TextUtilities; @@ -927,7 +927,7 @@ void PaintRow( for (const auto &tag : *tags) { p.drawImage(left, context.st->tagTop, *tag); left += st::dialogRowFilterTagSkip - + (tag->width() / style::DevicePixelRatio()); + + qRound(tag->width() / tag->devicePixelRatio()); } } if (swipeTranslation) { diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp index 10a4674319d547..746f794fe89789 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_stories_list.cpp @@ -383,11 +383,10 @@ void List::paintEvent(QPaintEvent *e) { } void List::ensureLayer() { - const auto ratio = style::DevicePixelRatio(); - const auto layer = size() * ratio; + const auto layer = style::DevicePixels(size()); if (_layer.size() != layer) { _layer = QImage(layer, QImage::Format_ARGB32_Premultiplied); - _layer.setDevicePixelRatio(ratio); + _layer.setDevicePixelRatio(style::DevicePixelRatio()); } _layer.fill(Qt::transparent); } @@ -744,12 +743,11 @@ void List::validateName(not_null item) { ? element.name : my; const auto text = Ui::Text::String(full.nameStyle, use); - const auto ratio = style::DevicePixelRatio(); item->nameCacheColor = color->c; item->nameCache = QImage( - QSize(available, font->height) * ratio, + style::DevicePixels(QSize(available, font->height)), QImage::Format_ARGB32_Premultiplied); - item->nameCache.setDevicePixelRatio(ratio); + item->nameCache.setDevicePixelRatio(style::DevicePixelRatio()); item->nameCache.fill(Qt::transparent); auto p = Painter(&item->nameCache); p.setPen(color); diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp index 450b4d3fa69246..547535062ad809 100644 --- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp +++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp @@ -18,6 +18,7 @@ For license and copyright information please follow this link: #include "ui/widgets/scroll_area.h" #include "ui/dynamic_image.h" #include "ui/painter.h" +#include "ui/style/style_core_scale.h" #include "ui/unread_badge_paint.h" #include "styles/style_dialogs.h" #include "styles/style_widgets.h" @@ -804,17 +805,16 @@ void TopPeersStrip::paintUserpic( return; } const auto simple = entry.userpic->image(size); - const auto ratio = style::DevicePixelRatio(); const auto renderFrame = (online > 0) || entry.badge || entry.unread; if (!renderFrame) { entry.userpicFrame = QImage(); p.drawImage(rect, simple); return; - } else if (entry.userpicFrame.size() != QSize(size, size) * ratio) { + } else if (entry.userpicFrame.size() != style::DevicePixels(QSize(size, size))) { entry.userpicFrame = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); - entry.userpicFrame.setDevicePixelRatio(ratio); + entry.userpicFrame.setDevicePixelRatio(style::DevicePixelRatio()); } entry.userpicFrame.fill(Qt::transparent); entry.userpicFrameDirty = 0; diff --git a/Telegram/SourceFiles/editor/editor_layer_widget.cpp b/Telegram/SourceFiles/editor/editor_layer_widget.cpp index 6c6d43f1c872ea..0e224abbaca8d2 100644 --- a/Telegram/SourceFiles/editor/editor_layer_widget.cpp +++ b/Telegram/SourceFiles/editor/editor_layer_widget.cpp @@ -94,11 +94,10 @@ void LayerWidget::start() { } void LayerWidget::checkBackgroundStale() { - const auto ratio = style::DevicePixelRatio(); const auto &ready = _backgroundNext.isNull() ? _background : _backgroundNext; - if (ready.size() == size() * ratio + if (ready.size() == style::DevicePixels(size()) && _backgroundNight == IsNightMode()) { _backgroundTimer.cancel(); } else if (!_backgroundCaching && !_backgroundTimer.isActive()) { @@ -113,7 +112,7 @@ QImage LayerWidget::renderBackground() { Ui::SendPendingMoveResizeEvents(target); const auto ratio = style::DevicePixelRatio(); - auto image = QImage(size() * ratio, QImage::Format_ARGB32_Premultiplied); + auto image = QImage(style::DevicePixels(size()), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(ratio); const auto shown = !parent->isHidden(); @@ -172,7 +171,7 @@ void LayerWidget::cacheBackground() { void LayerWidget::backgroundReady(QImage background, bool night) { _backgroundCaching = false; - const auto required = size() * style::DevicePixelRatio(); + const auto required = style::DevicePixels(size()); if (background.size() == required && night == IsNightMode()) { _backgroundNext = std::move(background); _backgroundNight = night; diff --git a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp index b96697a8ef9c19..d2115f175a2c54 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_compose_controls.cpp @@ -970,12 +970,11 @@ ComposeControls::StarEffect::StarEffect( const auto width = widthSkip + price.maxWidth(); const auto priceLeft = leftSkip; - const auto ratio = style::DevicePixelRatio(); badge = QImage( - QSize(width, height) * ratio, + style::DevicePixels(QSize(width, height)), QImage::Format_ARGB32_Premultiplied); badge.fill(Qt::transparent); - badge.setDevicePixelRatio(ratio); + badge.setDevicePixelRatio(style::DevicePixelRatio()); auto p = QPainter(&badge); auto hq = PainterHighQualityEnabler(p); diff --git a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp index 65dfe29a282c34..6cbcba7de665e1 100644 --- a/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp +++ b/Telegram/SourceFiles/history/view/controls/history_view_voice_record_bar.cpp @@ -115,7 +115,7 @@ QImage SoundedPreview::image(int size) { return {}; } - const auto full = QSize(size, size) * style::DevicePixelRatio(); + const auto full = style::DevicePixels(QSize(size, size)); if (_roundingMask.size() != full) { _roundingMask = Images::EllipseMask(full); } diff --git a/Telegram/SourceFiles/history/view/history_view_emoji_interactions.cpp b/Telegram/SourceFiles/history/view/history_view_emoji_interactions.cpp index 86fc4c17edd60c..4a8d607ca6ee41 100644 --- a/Telegram/SourceFiles/history/view/history_view_emoji_interactions.cpp +++ b/Telegram/SourceFiles/history/view/history_view_emoji_interactions.cpp @@ -408,7 +408,6 @@ QRect EmojiInteractions::computeRect(const Play &play) const { void EmojiInteractions::paint(not_null layer, QRect clip) { refreshLayerShift(); - const auto factor = style::DevicePixelRatio(); const auto whole = layer->rect(); auto p = QPainter(layer); @@ -434,7 +433,7 @@ void EmojiInteractions::paint(not_null layer, QRect clip) { continue; } auto request = Lottie::FrameRequest(); - request.box = play.outer * factor; + request.box = style::DevicePixels(play.outer); const auto rightAligned = play.view->hasRightLayout(); if (!rightAligned) { request.mirrorHorizontal = true; @@ -454,7 +453,7 @@ void EmojiInteractions::paint(not_null layer, QRect clip) { play.started = true; } p.drawImage( - QRect(target.topLeft(), frame.image.size() / factor), + QRect(target.topLeft(), play.outer), frame.image); play.lottie->markFrameShown(); play.lastTarget = target.translated(_layerShift); diff --git a/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp b/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp index 75abbbd0343888..8ffa3f959150e2 100644 --- a/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp +++ b/Telegram/SourceFiles/history/view/history_view_group_call_bar.cpp @@ -39,9 +39,10 @@ void GenerateUserpicsInRow( const auto shift = st.shift; const auto width = single + (limit - 1) * (single - shift); const auto ratio = style::DevicePixelRatio(); - if (result.width() != width * ratio) { + const auto full = style::DevicePixels(QSize(width, single)); + if (result.size() != full) { result = QImage( - QSize(width, single) * ratio, + full, QImage::Format_ARGB32_Premultiplied); } result.fill(Qt::transparent); @@ -71,6 +72,11 @@ bool NeedRegenerateUserpics( if (image.isNull()) { return true; } + + if (qAbs(image.devicePixelRatio() - style::DevicePixelRatio()) >= 0.001) { + return true; + } + for (auto &entry : list) { const auto peer = entry.peer; auto &view = entry.view; diff --git a/Telegram/SourceFiles/history/view/history_view_paid_reaction_toast.cpp b/Telegram/SourceFiles/history/view/history_view_paid_reaction_toast.cpp index 0d1abb053e71ed..3e2b9cc33e0958 100644 --- a/Telegram/SourceFiles/history/view/history_view_paid_reaction_toast.cpp +++ b/Telegram/SourceFiles/history/view/history_view_paid_reaction_toast.cpp @@ -405,10 +405,9 @@ void PaidReactionToast::setupLottiePreview( const auto bytes = document->createMediaView()->bytes(); const auto filepath = document->filepath(); - const auto ratio = style::DevicePixelRatio(); const auto player = widget->lifetime().make_state( Lottie::ReadContent(bytes, filepath), - Lottie::FrameRequest{ QSize(size, size) * ratio }, + Lottie::FrameRequest{ style::DevicePixels(QSize(size, size)) }, Lottie::Quality::Default); widget->paintRequest( @@ -417,8 +416,13 @@ void PaidReactionToast::setupLottiePreview( return; } const auto image = player->frame(); + const auto imageRatio = image.devicePixelRatio(); QPainter(widget).drawImage( - QRect(QPoint(), image.size() / ratio), + QRect( + QPoint(), + QSize( + qRound(image.width() / imageRatio), + qRound(image.height() / imageRatio))), image); if (player->frameIndex() + 1 != player->framesCount()) { player->markFrameShown(); diff --git a/Telegram/SourceFiles/history/view/history_view_reply.cpp b/Telegram/SourceFiles/history/view/history_view_reply.cpp index 859b6147ba4832..7491d39e127ae4 100644 --- a/Telegram/SourceFiles/history/view/history_view_reply.cpp +++ b/Telegram/SourceFiles/history/view/history_view_reply.cpp @@ -48,12 +48,11 @@ constexpr auto kNonExpandedLinesLimit = 5; const auto diameter = st::normalFont->ascent; const auto line = st::historyPollRadio.thickness; const auto size = 2 * line + diameter; - const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); result.fill(Qt::transparent); - result.setDevicePixelRatio(ratio); + result.setDevicePixelRatio(style::DevicePixelRatio()); auto p = QPainter(&result); PainterHighQualityEnabler hq(p); @@ -80,12 +79,11 @@ template const auto diameter = st::normalFont->ascent; const auto line = st::historyPollRadio.thickness; const auto size = 2 * line + diameter; - const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); result.fill(black); - result.setDevicePixelRatio(ratio); + result.setDevicePixelRatio(style::DevicePixelRatio()); auto p = QPainter(&result); PainterHighQualityEnabler hq(p); diff --git a/Telegram/SourceFiles/history/view/history_view_sticker_toast.cpp b/Telegram/SourceFiles/history/view/history_view_sticker_toast.cpp index 68446736c5e8a1..286223184082f0 100644 --- a/Telegram/SourceFiles/history/view/history_view_sticker_toast.cpp +++ b/Telegram/SourceFiles/history/view/history_view_sticker_toast.cpp @@ -328,10 +328,9 @@ void StickerToast::setupLottiePreview(not_null widget, int size) const auto bytes = _for->createMediaView()->bytes(); const auto filepath = _for->filepath(); - const auto ratio = style::DevicePixelRatio(); const auto player = widget->lifetime().make_state( Lottie::ReadContent(bytes, filepath), - Lottie::FrameRequest{ QSize(size, size) * ratio }, + Lottie::FrameRequest{ style::DevicePixels(QSize(size, size)) }, Lottie::Quality::Default); widget->paintRequest( @@ -340,8 +339,13 @@ void StickerToast::setupLottiePreview(not_null widget, int size) return; } const auto image = player->frame(); + const auto imageRatio = image.devicePixelRatio(); QPainter(widget).drawImage( - QRect(QPoint(), image.size() / ratio), + QRect( + QPoint(), + QSize( + qRound(image.width() / imageRatio), + qRound(image.height() / imageRatio))), image); player->markFrameShown(); }, widget->lifetime()); diff --git a/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.cpp b/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.cpp index 94de0a30c2f243..7756c50898ded1 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_custom_emoji.cpp @@ -273,7 +273,7 @@ void CustomEmoji::paintCustom( const auto paused = context.paused || On(PowerSaving::kEmojiChat); if (context.selected()) { const auto factor = style::DevicePixelRatio(); - const auto size = QSize(_singleSize, _singleSize) * factor; + const auto size = style::DevicePixels(QSize(_singleSize, _singleSize)); if (_selectedFrame.size() != size) { _selectedFrame = QImage( size, diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index c97db4250f6f4e..6d99a938f13713 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -1023,14 +1023,14 @@ void Document::validateThumbnail( return; } const auto outer = QSize(size, size); - if ((thumbed->thumbnail.size() == outer * style::DevicePixelRatio()) + if ((thumbed->thumbnail.size() == style::DevicePixels(outer)) && (thumbed->blurred == !normal) && (thumbed->rounding == rounding)) { return; } const auto small = (rounding == Ui::BubbleRounding()); auto image = normal ? normal : blurred; - const auto imageWidth = thumbed->thumbw * style::DevicePixelRatio(); + const auto imageWidth = style::DevicePixels(thumbed->thumbw); auto thumbnail = Images::Prepare(image->original(), imageWidth, { .options = (normal ? Images::Option() : Images::Option::Blur) | (small ? Images::Option::RoundSmall : Images::Option()), diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index 86ad412de255da..76a041d87c0fdb 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -541,7 +541,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const { if (drawStreamed && !skipDrawingContent && !fullHiddenBySpoiler) { auto paused = context.paused || !shouldBePlaying; auto request = ::Media::Streaming::FrameRequest{ - .outer = QSize(usew, painth) * style::DevicePixelRatio(), + .outer = style::DevicePixels(QSize(usew, painth)), .blurredBackground = true, }; if (isRound) { @@ -1023,8 +1023,8 @@ void Gif::validateThumbCache( && (normal->width() < kUseNonBlurredThreshold) && (normal->height() < kUseNonBlurredThreshold)) : !videothumb; - const auto ratio = style::DevicePixelRatio(); - if (_thumbCache.size() == (outer * ratio) + const auto target = style::DevicePixels(outer); + if (_thumbCache.size() == target && _thumbCacheRounding == rounding && _thumbCacheBlurred == blurred && _thumbIsEllipse == isEllipse) { @@ -1083,8 +1083,8 @@ void Gif::validateSpoilerImageCache( std::optional rounding) const { Expects(_spoiler != nullptr); - const auto ratio = style::DevicePixelRatio(); - if (_spoiler->background.size() == (outer * ratio) + const auto target = style::DevicePixels(outer); + if (_spoiler->background.size() == target && _spoiler->backgroundRounding == rounding) { return; } @@ -1463,8 +1463,8 @@ void Gif::drawGrouped( { originalWidth, originalHeight }, { geometry.width(), geometry.height() }); auto request = ::Media::Streaming::FrameRequest{ - .resize = pixSize * style::DevicePixelRatio(), - .outer = geometry.size() * style::DevicePixelRatio(), + .resize = style::DevicePixels(pixSize), + .outer = style::DevicePixels(geometry.size()), .rounding = MediaRoundingMask(rounding), }; if (activeOwnPlaying->instance.playerLocked()) { @@ -1843,12 +1843,10 @@ void Gif::validateGroupedCache( const auto pixSize = Ui::GetImageScaleSizeForGeometry( { originalWidth, originalHeight }, { width, height }); - const auto ratio = style::DevicePixelRatio(); - *cacheKey = key; auto scaled = Images::Prepare( (image ? image : Image::BlankMedia().get())->original(), - pixSize * ratio, + style::DevicePixels(pixSize), { .options = options, .outer = { width, height } }); auto rounded = Images::Round( std::move(scaled), diff --git a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp index 0f77af125f6801..228d3b52d89ad5 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_large_emoji.cpp @@ -139,7 +139,7 @@ void LargeEmoji::paintCustom( auto &textst = context.st->messageStyle(false, false); if (context.selected()) { const auto factor = style::DevicePixelRatio(); - const auto size = QSize(outer, outer) * factor; + const auto size = style::DevicePixels(QSize(outer, outer)); if (_selectedFrame.size() != size) { _selectedFrame = QImage( size, diff --git a/Telegram/SourceFiles/history/view/media/history_view_location.cpp b/Telegram/SourceFiles/history/view/media/history_view_location.cpp index 20e20a40b3cc20..0b91856e3f4aad 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_location.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_location.cpp @@ -555,12 +555,12 @@ void Location::validateImageCache( return; } const auto ratio = style::DevicePixelRatio(); - if (cache.size() == (outer * ratio) && cacheRounding == rounding) { + if (cache.size() == style::DevicePixels(outer) && cacheRounding == rounding) { return; } cache = Images::Round( source.scaled( - outer * ratio, + style::DevicePixels(outer), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), MediaRoundingMask(rounding)); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.cpp b/Telegram/SourceFiles/history/view/media/history_view_media.cpp index 54ce46a09dc536..811eb50e52e414 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media.cpp @@ -389,7 +389,7 @@ void Media::drawSpoilerTag( const auto ratio = style::DevicePixelRatio(); auto bg = generateBackground(); if (bg.isNull()) { - bg = QImage(ratio, ratio, QImage::Format_ARGB32_Premultiplied); + bg = QImage(style::DevicePixels(1), style::DevicePixels(1), QImage::Format_ARGB32_Premultiplied); bg.fill(Qt::black); } @@ -418,7 +418,7 @@ void Media::drawSpoilerTag( const auto size = outer.size(); const auto radius = std::min(size.width(), size.height()) / 2; auto cache = QImage( - size * ratio, + style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); cache.setDevicePixelRatio(ratio); cache.fill(Qt::black); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp index b46a9aa0a7e80a..7df41c73182a22 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_common.cpp @@ -205,12 +205,12 @@ QImage PrepareWithBlurredBackground( QImage blurred) { const auto ratio = style::DevicePixelRatio(); if (resize.expanding) { - return Images::Prepare(std::move(large), resize.result * ratio, { + return Images::Prepare(std::move(large), style::DevicePixels(resize.result), { .outer = outer, }); } auto background = QImage( - outer * ratio, + style::DevicePixels(outer), QImage::Format_ARGB32_Premultiplied); background.setDevicePixelRatio(ratio); if (blurred.isNull()) { @@ -226,7 +226,7 @@ QImage PrepareWithBlurredBackground( } if (!large.isNull()) { auto image = large.scaled( - resize.result * ratio, + style::DevicePixels(resize.result), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); image.setDevicePixelRatio(ratio); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp index 7f522d5a505417..cf42732cf76e80 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp @@ -646,9 +646,9 @@ void StickerWithBadgePart::validateBadge( const auto inner = QRect(0, 0, width, font->height); const auto rect = inner + st::chatGiveawayBadgePadding; const auto size = rect.size(); - const auto ratio = style::DevicePixelRatio(); - _badge = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied); - _badge.setDevicePixelRatio(ratio); + _badge = QImage(style::DevicePixels(size), + QImage::Format_ARGB32_Premultiplied); + _badge.setDevicePixelRatio(style::DevicePixelRatio()); _badge.fill(Qt::transparent); auto p = QPainter(&_badge); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp index a165cb1366cf58..5d59b11a1d8397 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -325,7 +325,7 @@ Media *GroupedMedia::lookupSpoilerTagMedia() const { QImage GroupedMedia::generateSpoilerTagBackground(QRect full) const { const auto ratio = style::DevicePixelRatio(); auto result = QImage( - full.size() * ratio, + style::DevicePixels(full.size()), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); auto p = QPainter(&result); diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 6d4eb7dc9d9ee5..a428c1ae19eebd 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -7,6 +7,8 @@ For license and copyright information please follow this link: */ #include "history/view/media/history_view_photo.h" +#include "base/debug_log.h" + #include "boxes/send_credits_box.h" #include "history/history_item_components.h" #include "history/history_item.h" @@ -447,9 +449,9 @@ void Photo::drawSpoilerTag( void Photo::validateUserpicImageCache(QSize size, bool forum) const { const auto forumValue = forum ? 1 : 0; const auto large = _dataMedia->image(PhotoSize::Large); - const auto ratio = style::DevicePixelRatio(); const auto blurredValue = large ? 0 : 1; - if (_imageCache.size() == (size * ratio) + const auto target = style::DevicePixels(size); + if (_imageCache.size() == target && _imageCacheForum == forumValue && _imageCacheBlurred == blurredValue) { return; @@ -473,7 +475,7 @@ void Photo::validateUserpicImageCache(QSize size, bool forum) const { if (blurredValue) { args = args.blurred(); } - original = Images::Prepare(std::move(original), size * ratio, args); + original = Images::Prepare(std::move(original), target, args); if (forumValue) { original = Images::Round( std::move(original), @@ -491,16 +493,33 @@ void Photo::validateImageCache( QSize outer, std::optional rounding) const { const auto large = _dataMedia->image(PhotoSize::Large); - const auto ratio = style::DevicePixelRatio(); const auto blurredValue = large ? 0 : 1; - if (_imageCache.size() == (outer * ratio) - && _imageCacheRounding == rounding - && _imageCacheBlurred == blurredValue) { + const auto target = style::DevicePixels(outer); + const auto sizeMatch = (_imageCache.size() == target); + const auto roundingMatch = (_imageCacheRounding == rounding); + const auto blurMatch = (_imageCacheBlurred == blurredValue); + if (sizeMatch && roundingMatch && blurMatch) { return; } + LOG(("Photo::validateImageCache MISS" + " outer=%1x%2" + " target=%3x%4" + " cache=%5x%6" + " sizeMatch=%7 roundingMatch=%8 blurMatch=%9" + " dpr=%10" + ).arg(outer.width()).arg(outer.height()) + .arg(target.width()).arg(target.height()) + .arg(_imageCache.width()).arg(_imageCache.height()) + .arg(sizeMatch).arg(roundingMatch).arg(blurMatch) + .arg(style::DevicePixelRatio())); _imageCache = Images::Round( prepareImageCache(outer), MediaRoundingMask(rounding)); + LOG(("Photo::validateImageCache rebuilt" + " -> cache=%1x%2 target=%3x%4 match=%5" + ).arg(_imageCache.width()).arg(_imageCache.height()) + .arg(target.width()).arg(target.height()) + .arg(_imageCache.size() == target)); _imageCacheRounding = rounding; _imageCacheBlurred = blurredValue; } @@ -510,14 +529,31 @@ void Photo::validateSpoilerImageCache( std::optional rounding) const { Expects(_spoiler != nullptr); - const auto ratio = style::DevicePixelRatio(); - if (_spoiler->background.size() == (outer * ratio) - && _spoiler->backgroundRounding == rounding) { + const auto target = style::DevicePixels(outer); + const auto sizeMatch = (_spoiler->background.size() == target); + const auto roundingMatch = (_spoiler->backgroundRounding == rounding); + if (sizeMatch && roundingMatch) { return; } + LOG(("Photo::validateSpoilerImageCache MISS" + " outer=%1x%2" + " target=%3x%4" + " cache=%5x%6" + " sizeMatch=%7 roundingMatch=%8" + " dpr=%9" + ).arg(outer.width()).arg(outer.height()) + .arg(target.width()).arg(target.height()) + .arg(_spoiler->background.width()).arg(_spoiler->background.height()) + .arg(sizeMatch).arg(roundingMatch) + .arg(style::DevicePixelRatio())); _spoiler->background = Images::Round( prepareImageCacheWithLarge(outer, nullptr), MediaRoundingMask(rounding)); + LOG(("Photo::validateSpoilerImageCache rebuilt" + " -> cache=%1x%2 target=%3x%4 match=%5" + ).arg(_spoiler->background.width()).arg(_spoiler->background.height()) + .arg(target.width()).arg(target.height()) + .arg(_spoiler->background.size() == target)); _spoiler->backgroundRounding = rounding; } @@ -565,13 +601,13 @@ void Photo::paintUserpicFrame( if (_streamed && _streamed->instance.player().ready() && !_streamed->instance.player().videoSize().isEmpty()) { - const auto ratio = style::DevicePixelRatio(); auto request = ::Media::Streaming::FrameRequest(); - request.outer = request.resize = size * ratio; + request.outer = request.resize = style::DevicePixels(size); if (forum) { const auto radius = int(std::min(size.width(), size.height()) * Ui::ForumUserpicRadiusMultiplier()); - if (_streamed->roundingCorners[0].width() != radius * ratio) { + if (_streamed->roundingCorners[0].width() + != style::DevicePixels(radius)) { _streamed->roundingCorners = Images::CornersMask(radius); } request.rounding = Images::CornersMaskRef( @@ -926,7 +962,6 @@ void Photo::validateGroupedCache( const auto pixSize = Ui::GetImageScaleSizeForGeometry( { originalWidth, originalHeight }, { width, height }); - const auto ratio = style::DevicePixelRatio(); const auto image = _dataMedia->image(PhotoSize::Large) ? _dataMedia->image(PhotoSize::Large) : _dataMedia->image(PhotoSize::Thumbnail) @@ -940,7 +975,7 @@ void Photo::validateGroupedCache( *cacheKey = key; auto scaled = Images::Prepare( image->original(), - pixSize * ratio, + style::DevicePixels(pixSize), { .options = options, .outer = { width, height } }); auto rounded = Images::Round( std::move(scaled), diff --git a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp index 2ffe81952f6dc7..0fd1f3d37d323c 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_poll.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_poll.cpp @@ -2374,8 +2374,8 @@ void Poll::Header::validateTopMediaCache(QSize size) const { } const auto sw = source.width(); const auto sh = source.height(); - const auto tw = size.width() * ratio; - const auto th = size.height() * ratio; + const auto tw = style::DevicePixels(size.width()); + const auto th = style::DevicePixels(size.height()); if (sw * th != sh * tw) { const auto cropW = std::min(sw, sh * tw / th); const auto cropH = std::min(sh, sw * th / tw); diff --git a/Telegram/SourceFiles/history/view/media/history_view_similar_channels.cpp b/Telegram/SourceFiles/history/view/media/history_view_similar_channels.cpp index 2309d67572147d..9a8884f9feba4b 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_similar_channels.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_similar_channels.cpp @@ -413,7 +413,7 @@ void SimilarChannels::validateCounterBg(const Channel &channel) const { const auto height = channel.counterRect.height(); const auto ratio = style::DevicePixelRatio(); auto result = QImage( - channel.counterRect.size() * ratio, + style::DevicePixels(channel.counterRect.size()), QImage::Format_ARGB32_Premultiplied); auto color = channel.more ? QColor(kMinLightness, kMinLightness, kMinLightness) @@ -466,15 +466,14 @@ ClickHandlerPtr SimilarChannels::ensureToggleLink() const { } void SimilarChannels::ensureCacheReady(QSize size) const { - const auto ratio = style::DevicePixelRatio(); - if (_roundedCache.size() != size * ratio) { - _roundedCache = QImage( - size * ratio, - QImage::Format_ARGB32_Premultiplied); - _roundedCache.setDevicePixelRatio(ratio); + const auto full = style::DevicePixels(size); + if (_roundedCache.size() != full) { + _roundedCache = QImage(full, QImage::Format_ARGB32_Premultiplied); + _roundedCache.setDevicePixelRatio(style::DevicePixelRatio()); } const auto radius = st::bubbleRadiusLarge; - if (_roundedCorners.front().size() != QSize(radius, radius) * ratio) { + const auto corner = style::DevicePixels(QSize(radius, radius)); + if (_roundedCorners.front().size() != corner) { _roundedCorners = Images::CornersMask(radius); } } diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp index a5871d4157d90a..ef6503c7db1658 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker.cpp @@ -349,7 +349,7 @@ void Sticker::paintAnimationFrame( base::duplicate(image), context.st->msgStickerOverlay()->c) : image; - const auto size = prepared.size() / style::DevicePixelRatio(); + const auto size = _size; p.drawImage( QRect( QPoint( @@ -452,7 +452,8 @@ QPixmap Sticker::paintedPixmap(const PaintContext &context) const { const auto sticker = _data->sticker(); const auto ratio = style::DevicePixelRatio(); const auto adjust = [&](int side) { - return (((side * ratio) / 8) * 8) / ratio; + const auto scaled = style::DevicePixels(side, ratio); + return qRound(((scaled / 8) * 8) / ratio); }; const auto useSize = (sticker && sticker->type == StickerType::Tgs) ? QSize(adjust(_size.width()), adjust(_size.height())) @@ -625,7 +626,8 @@ void Sticker::setupPlayer() { _dataMedia.get(), _replacements, _cachingTag, - countOptimalSize() * style::DevicePixelRatio(), + QSize(style::DevicePixels( + countOptimalSize())), Lottie::Quality::High)); } else if (_data->sticker()->isWebm()) { _player = std::make_unique( diff --git a/Telegram/SourceFiles/history/view/media/history_view_sticker_player.cpp b/Telegram/SourceFiles/history/view/media/history_view_sticker_player.cpp index 947681e16a971e..13c7dd570c0e42 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_sticker_player.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_sticker_player.cpp @@ -8,7 +8,6 @@ For license and copyright information please follow this link: #include "history/view/media/history_view_sticker_player.h" #include "core/file_location.h" - namespace HistoryView { namespace { @@ -47,11 +46,11 @@ int LottiePlayer::framesCount() { LottiePlayer::FrameInfo LottiePlayer::frame( QSize size, QColor colored, - bool mirrorHorizontal, - crl::time now, - bool paused) { + bool mirrorHorizontal, + crl::time now, + bool paused) { auto request = Lottie::FrameRequest(); - request.box = size * style::DevicePixelRatio(); + request.box = style::DevicePixels(size); request.colored = colored; request.mirrorHorizontal = mirrorHorizontal; const auto info = _lottie->frameInfo(request); @@ -108,7 +107,7 @@ WebmPlayer::FrameInfo WebmPlayer::frame( QColor colored, bool mirrorHorizontal, crl::time now, - bool paused) { + bool paused) { auto request = ::Media::Clip::FrameRequest(); request.frame = size; request.factor = style::DevicePixelRatio(); @@ -133,7 +132,7 @@ StaticStickerPlayer::StaticStickerPlayer( if (!_frame.isNull()) { size = _frame.size().scaled(size, Qt::KeepAspectRatio); const auto ratio = style::DevicePixelRatio(); - _frame = Images::Prepare(std::move(_frame), size * ratio, {}); + _frame = Images::Prepare(std::move(_frame), style::DevicePixels(size), {}); _frame.setDevicePixelRatio(ratio); } } diff --git a/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp index 12df63ef0233c3..e514444f56a4c3 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_theme_document.cpp @@ -373,7 +373,7 @@ QImage ThemeDocument::finishServiceThumbnail(QImage image) const { void ThemeDocument::generateThumbnail() const { auto image = Ui::GenerateBackgroundImage( - QSize(_pixw, _pixh) * style::DevicePixelRatio(), + style::DevicePixels(QSize(_pixw, _pixh)), _background, _gradientRotation, _patternOpacity); @@ -408,7 +408,7 @@ void ThemeDocument::prepareThumbnailFrom( : QSize(_pixw, (_pixw * th) / tw); original = Images::Prepare( std::move(original), - resizeTo * ratio, + style::DevicePixels(resizeTo), { .options = options, .outer = { _pixw, _pixh } }); if (isPattern) { original = Ui::PreparePatternImage( @@ -797,9 +797,9 @@ void GiftServiceBox::cacheUniqueBackground(int width, int height) { } const auto inner = QRect(0, 0, width, height); const auto ratio = style::DevicePixelRatio(); - if (_backgroundCache.size() != inner.size() * ratio) { + if (_backgroundCache.size() != style::DevicePixels(inner.size())) { _backgroundCache = QImage( - inner.size() * ratio, + style::DevicePixels(inner.size()), QImage::Format_ARGB32_Premultiplied); _backgroundCache.fill(Qt::transparent); _backgroundCache.setDevicePixelRatio(ratio); diff --git a/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.cpp b/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.cpp index 7eb6dd055ccdd5..6419015956728c 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_userpic_suggestion.cpp @@ -107,7 +107,7 @@ void ShowUserpicSuggestion( } const auto ratio = style::DevicePixelRatio(); auto frame = QImage( - QSize(strong->width(), strong->height()) * ratio, + style::DevicePixels(strong->currentSize()), QImage::Format_ARGB32_Premultiplied); frame.fill(Qt::transparent); frame.setDevicePixelRatio(ratio); @@ -134,12 +134,11 @@ void ShowSetToast( auto st = std::make_shared(st::historyPremiumToast); const auto skip = st->padding.top(); const auto size = st->style.font->height * 2; - const auto ratio = style::DevicePixelRatio(); auto copy = frame.scaled( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - copy.setDevicePixelRatio(ratio); + copy.setDevicePixelRatio(style::DevicePixelRatio()); st->padding.setLeft(skip + size + skip); st->palette.linkFg = st->palette.selectLinkFg = st::mediaviewTextLinkFg; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index 130b8eb778eb61..4f8f83d7bb2ddf 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -27,6 +27,7 @@ For license and copyright information please follow this link: #include "ui/effects/reaction_fly_animation.h" #include "ui/effects/ripple_animation.h" #include "ui/painter.h" +#include "ui/style/style_core_scale.h" #include "ui/rect.h" #include "ui/power_saving.h" #include "styles/style_chat.h" @@ -464,6 +465,9 @@ void InlineList::paint( QRect target; }; std::vector animations; + if (_dprKey != currentDprKey()) { + resetOnDevicePixelRatioChange(); + } auto finished = std::vector>(); const auto st = context.st; @@ -649,6 +653,23 @@ void InlineList::paint( } } +void InlineList::resetOnDevicePixelRatioChange() const { + _dprKey = currentDprKey(); + _tagBg = QImage(); + _customCache = QImage(); + _ripple.reset(); + for (auto &button : _buttons) { + button.image = QImage(); + if (button.userpics) { + button.userpics->image = QImage(); + } + } +} + +int InlineList::currentDprKey() const { + return qRound(style::DevicePixelRatio() * 1000.); +} + float64 InlineList::TagDotAlpha() { return 0.6; } @@ -664,7 +685,7 @@ QImage InlineList::PrepareTagBg(QColor tagBg, QColor dotBg) { const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(width, height) * ratio, + style::DevicePixels(QSize(width , height)), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); @@ -721,13 +742,13 @@ void InlineList::paintSingleBg( validateTagBg(color); const auto ratio = style::DevicePixelRatio(); const auto left = st::reactionInlineTagLeftRadius; - const auto right = (_tagBg.width() / ratio) - left; + const auto right = qRound(_tagBg.width() / ratio) - left; Assert(right > 0); const auto useLeft = std::min(fill.width(), left); p.drawImage( QRect(fill.x(), fill.y(), useLeft, fill.height()), _tagBg, - QRect(0, 0, useLeft * ratio, _tagBg.height())); + QRect(0, 0, style::DevicePixels(useLeft), _tagBg.height())); const auto middle = fill.width() - left - right; if (middle > 0) { p.fillRect(fill.x() + left, fill.y(), middle, fill.height(), color); @@ -740,10 +761,8 @@ void InlineList::paintSingleBg( useRight, fill.height()), _tagBg, - QRect(_tagBg.width() - useRight * ratio, - 0, - useRight * ratio, - _tagBg.height())); + QRect(_tagBg.width() - style::DevicePixels(useRight), + 0, style::DevicePixels(useRight), _tagBg.height())); } } @@ -862,7 +881,7 @@ void InlineList::paintCustomFrame( const auto factor = style::DevicePixelRatio(); const auto adjusted = AdjustCustomEmojiSize(size); _customCache = QImage( - QSize(adjusted, adjusted) * factor, + style::DevicePixels(QSize(adjusted , adjusted)), QImage::Format_ARGB32_Premultiplied); _customCache.setDevicePixelRatio(factor); _customSkip = (size - adjusted) / 2; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h index 44625784116898..89878c54c697bb 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.h @@ -139,6 +139,8 @@ class InlineList final : public Object { float64 opacity) const; void validateTagBg(const QColor &color) const; + void resetOnDevicePixelRatioChange() const; + [[nodiscard]] int currentDprKey() const; QSize countOptimalSize() override; [[nodiscard]] Dimension countDimension(int width) const; @@ -153,6 +155,7 @@ class InlineList final : public Object { mutable QColor _tagBgColor; mutable QImage _customCache; mutable int _customSkip = 0; + mutable int _dprKey = 0; bool _hasCustomEmoji = false; mutable std::unique_ptr _ripple; mutable QPoint _lastPoint; diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp index eb2bd2c58e01a9..4125d7e7dd15ac 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.cpp @@ -11,6 +11,7 @@ For license and copyright information please follow this link: #include "history/history_item.h" #include "history/history.h" #include "ui/chat/chat_style.h" +#include "ui/style/style_core_scale.h" #include "ui/widgets/popup_menu.h" #include "ui/ui_utility.h" #include "data/data_session.h" @@ -335,6 +336,7 @@ Manager::Manager( _expandedBuffer = _cachedRound.PrepareImage(QSize( _outer.width(), _outer.height() + st::reactionCornerAddedHeightMax)); + _expandedBuffer.setDevicePixelRatio(style::DevicePixelRatio()); if (wheelEventsTarget) { stealWheelEvents(wheelEventsTarget); } @@ -351,6 +353,20 @@ Manager::Manager( Manager::~Manager() = default; +void Manager::resetBackgroundCaches() { + _cachedRound = Ui::RoundAreaWithShadow( + st::reactionCornerSize, + st::reactionCornerShadow, + _inner.width()); + _expandedBuffer = _cachedRound.PrepareImage(QSize( + _outer.width(), + _outer.height() + st::reactionCornerAddedHeightMax)); + _expandedBuffer.setDevicePixelRatio(style::DevicePixelRatio()); + _gradientBackground = QColor(); + _topGradient = QImage(); + _bottomGradient = QImage(); +} + ChosenReaction Manager::lookupChosen(const ReactionId &id) const { auto result = ChosenReaction{ .context = _buttonContext, @@ -613,6 +629,10 @@ void Manager::paintButton( if (opacity == 0.) { return; } + if (!_expandedBuffer.isNull() + && _expandedBuffer.devicePixelRatio() != style::DevicePixelRatio()) { + resetBackgroundCaches(); + } const auto geometry = button->geometry(); const auto position = geometry.topLeft(); @@ -719,7 +739,9 @@ void Manager::paintButton( p.drawImage( geometry, _expandedBuffer, - QRect(QPoint(), size * style::DevicePixelRatio())); + QRect( + QPoint(), + style::DevicePixels(size))); } if (opacity != 1.) { p.setOpacity(1.); diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.h b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.h index 75e6d45384b07b..b2df2962463b9c 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.h +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_button.h @@ -201,6 +201,7 @@ class Manager final : public base::has_weak_ptr { not_null button, int scroll, float64 expandRatio); + void resetBackgroundCaches(); void clearAppearAnimations(); diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_list.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_list.cpp index c48b0ed6cd96a7..5c2cb279ea04a0 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_list.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_list.cpp @@ -17,6 +17,7 @@ For license and copyright information please follow this link: #include "ui/controls/who_reacted_context_action.h" #include "ui/text/text_custom_emoji.h" #include "ui/painter.h" +#include "ui/style/style_core_scale.h" #include "data/stickers/data_custom_emoji.h" #include "data/data_message_reaction_id.h" #include "main/main_session.h" @@ -159,7 +160,8 @@ Row::Row( } QSize Row::rightActionSize() const { - const auto size = Ui::Emoji::GetSizeNormal() / style::DevicePixelRatio(); + const auto size = qRound( + Ui::Emoji::GetSizeNormal() / style::DevicePixelRatio()); return _custom ? QSize(size, size) : QSize(); } @@ -167,7 +169,8 @@ QMargins Row::rightActionMargins() const { if (!_custom) { return QMargins(); } - const auto size = Ui::Emoji::GetSizeNormal() / style::DevicePixelRatio(); + const auto size = qRound( + Ui::Emoji::GetSizeNormal() / style::DevicePixelRatio()); return QMargins( size / 2, (st::defaultPeerList.item.height - size) / 2, @@ -189,7 +192,8 @@ void Row::rightActionPaint( if (!_custom) { return; } - const auto size = Ui::Emoji::GetSizeNormal() / style::DevicePixelRatio(); + const auto size = qRound( + Ui::Emoji::GetSizeNormal() / style::DevicePixelRatio()); const auto skip = (size - Ui::Text::AdjustCustomEmojiSize(size)) / 2; _custom->paint(p, { .textColor = st::windowFg->c, diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp index 8ea24cf6ecc689..ceebbef60ede98 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_selector.cpp @@ -18,6 +18,7 @@ For license and copyright information please follow this link: #include "ui/integration.h" #include "ui/painter.h" #include "ui/rect.h" +#include "ui/style/style_core_scale.h" #include "ui/ui_utility.h" #include "history/view/media/history_view_sticker.h" #include "history/history.h" @@ -566,8 +567,8 @@ void Selector::paintAppearing(QPainter &p) { Expects(_strip != nullptr); p.setOpacity(_appearOpacity); - const auto factor = style::DevicePixelRatio(); - if (_paintBuffer.size() != _outerWithBubble.size() * factor) { + const auto bufferSize = style::DevicePixels(_outerWithBubble.size()); + if (_paintBuffer.size() != bufferSize) { _paintBuffer = _cachedRound.PrepareImage(_outerWithBubble.size()); } _paintBuffer.fill(_st.bg->c); @@ -599,7 +600,12 @@ void Selector::paintAppearing(QPainter &p) { 1.); q.setCompositionMode(QPainter::CompositionMode_Source); q.fillRect( - QRect{ 0, size.height(), width(), height() - size.height() }, + QRect{ + 0, + size.height(), + _outerWithBubble.width(), + _outerWithBubble.height() - size.height() + }, Qt::transparent); q.setCompositionMode(QPainter::CompositionMode_SourceOver); paintBubble(q, appearedWidth); @@ -608,7 +614,9 @@ void Selector::paintAppearing(QPainter &p) { p.drawImage( _outer.topLeft(), _paintBuffer, - QRect(QPoint(), QSize(fullWidth, height()) * factor)); + QRect( + QPoint(), + style::DevicePixels(QSize(fullWidth, _outerWithBubble.height())))); const auto aboutRight = _inner.x() + appearedWidth; if (_about && _about->isHidden() && aboutRight > _about->x()) { @@ -616,7 +624,9 @@ void Selector::paintAppearing(QPainter &p) { p.drawImage( _about->geometry().topLeft(), _aboutCache, - QRect(QPoint(), QSize(aboutWidth, _about->height()) * factor)); + QRect( + QPoint(), + style::DevicePixels(QSize(aboutWidth, _about->height())))); } } @@ -625,7 +635,8 @@ void Selector::paintBackgroundToBuffer() { return; } const auto factor = style::DevicePixelRatio(); - if (_paintBuffer.size() != _outerWithBubble.size() * factor) { + const auto bufferSize = style::DevicePixels(_outerWithBubble.size()); + if (_paintBuffer.size() != bufferSize) { _paintBuffer = _cachedRound.PrepareImage(_outerWithBubble.size()); } _paintBuffer.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_strip.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_strip.cpp index e691cc38ef9b4c..069764fb53f112 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_strip.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_strip.cpp @@ -15,6 +15,7 @@ For license and copyright information please follow this link: #include "ui/effects/frame_generator.h" #include "ui/animated_icon.h" #include "ui/painter.h" +#include "ui/style/style_core_scale.h" #include "styles/style_chat.h" #include "styles/style_chat_helpers.h" @@ -507,6 +508,11 @@ bool Strip::onlyMainEmojiVisible() const { Ui::ImageSubrect Strip::validateEmoji(int frameIndex, float64 scale) { const auto area = _inner.size(); const auto size = int(base::SafeRound(_finalSize * scale)); + const auto ratio = style::DevicePixelRatio(); + if (!_emojiParts.isNull() && _emojiParts.devicePixelRatio() != ratio) { + _emojiParts = QImage(); + invalidateMainReactionImage(); + } const auto result = Ui::ImageSubrect{ &_emojiParts, Ui::RoundAreaWithShadow::FrameCacheRect( @@ -521,10 +527,11 @@ Ui::ImageSubrect Strip::validateEmoji(int frameIndex, float64 scale) { } auto p = QPainter(result.image); - const auto ratio = style::DevicePixelRatio(); - const auto position = result.rect.topLeft() / ratio; + const auto position = style::LogicalPixels(result.rect.topLeft()); p.setCompositionMode(QPainter::CompositionMode_Source); - p.fillRect(QRect(position, result.rect.size() / ratio), Qt::transparent); + p.fillRect(QRect( + position, + style::LogicalPixels(result.rect.size())), Qt::transparent); if (_mainReactionImage.isNull() && _mainReactionIcon) { _mainReactionImage = base::take(_mainReactionIcon)->frame( @@ -539,7 +546,7 @@ Ui::ImageSubrect Strip::validateEmoji(int frameIndex, float64 scale) { ).translated(position); p.drawImage(target, _mainReactionImage.scaled( - target.size() * ratio, + style::DevicePixels(target.size()), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_tabs.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_tabs.cpp index acaad5ba4b92c8..b4af547590b689 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions_tabs.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions_tabs.cpp @@ -13,6 +13,7 @@ For license and copyright information please follow this link: #include "ui/controls/who_reacted_context_action.h" #include "ui/painter.h" #include "ui/rp_widget.h" +#include "ui/style/style_core_scale.h" #include "styles/style_chat.h" #include "styles/style_widgets.h" @@ -68,7 +69,7 @@ not_null CreateTab( const auto icon = QRect(skip, 0, height, height); if (state->cache.isNull()) { state->cache = QImage( - result->size() * factor, + style::DevicePixels(QSize(result->width(), result->height())), QImage::Format_ARGB32_Premultiplied); state->cache.setDevicePixelRatio(factor); state->cache.fill(Qt::transparent); @@ -109,7 +110,7 @@ not_null CreateTab( p.drawImage(0, 0, state->cache); if (const auto custom = state->custom.get()) { using namespace Ui::Text; - const auto size = Ui::Emoji::GetSizeNormal() / factor; + const auto size = qRound(Ui::Emoji::GetSizeNormal() / factor); const auto shift = (height - size) / 2; const auto skip = (size - AdjustCustomEmojiSize(size)) / 2; custom->paint(p, { diff --git a/Telegram/SourceFiles/info/bot/starref/info_bot_starref_join_widget.cpp b/Telegram/SourceFiles/info/bot/starref/info_bot_starref_join_widget.cpp index 68e5de9ee14a0a..a43ae0e1f4d9fb 100644 --- a/Telegram/SourceFiles/info/bot/starref/info_bot_starref_join_widget.cpp +++ b/Telegram/SourceFiles/info/bot/starref/info_bot_starref_join_widget.cpp @@ -244,11 +244,10 @@ void Row::refreshStatus() { const auto width = font->width(text); const auto inner = QRect(0, 0, width, font->height); const auto outer = inner.marginsAdded(padding); - const auto ratio = style::DevicePixelRatio(); _badge = QImage( - outer.size() * ratio, + style::DevicePixels(outer.size()), QImage::Format_ARGB32_Premultiplied); - _badge.setDevicePixelRatio(ratio); + _badge.setDevicePixelRatio(style::DevicePixelRatio()); _badge.fill(Qt::transparent); auto p = QPainter(&_badge); @@ -323,7 +322,7 @@ void ListController::setupLinkBadge() { const auto size = QSize(side, side); const auto ratio = style::DevicePixelRatio(); - _linkBadge = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied); + _linkBadge = QImage(style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); _linkBadge.setDevicePixelRatio(ratio); _linkBadge.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp index df14f19bbdaa7e..df87fffdd4ab3f 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/create_giveaway_box.cpp @@ -595,7 +595,7 @@ void CreateGiveawayBox( (i + 1)); const auto textLeft = st.photoPosition.x() + (st.nameStyle.font->spacew * 2) - + (stars.width() / style::DevicePixelRatio()); + + qRound(stars.width() / style::DevicePixelRatio()); state->sliderValue.value( ) | rpl::on_next([=](int users) { const auto option = creditsOption(i); diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/boost_badge.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/boost_badge.cpp index 625fe22142e0a9..54abb5624076dc 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/boost_badge.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/boost_badge.cpp @@ -86,11 +86,12 @@ QImage CreateBadge( const auto badgeh = 0 + badgeHeight; const auto badgew = badgeTextWidth + rect::m::sum::h(textPadding); + const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(badgew, badgeh) * style::DevicePixelRatio(), + style::DevicePixels(QSize(badgew, badgeh)), QImage::Format_ARGB32_Premultiplied); result.fill(Qt::transparent); - result.setDevicePixelRatio(style::DevicePixelRatio()); + result.setDevicePixelRatio(ratio); { auto p = Painter(&result); diff --git a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.cpp b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.cpp index 7aa3ade27aa3a7..4efb9293c732b0 100644 --- a/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/boosts/giveaway/giveaway_type_row.cpp @@ -135,7 +135,7 @@ void GiveawayTypeRow::paintEvent(QPaintEvent *e) { const auto namey = _st.namePosition.y(); const auto namew = outerWidth - namex - skipRight; - const auto badgew = _badge.width() / style::DevicePixelRatio(); + const auto badgew = qRound(_badge.width() / style::DevicePixelRatio()); p.setPen(_st.nameFg); _name.drawLeftElided(p, namex, namey, namew - badgew, width()); diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/earn_icons.cpp b/Telegram/SourceFiles/info/channel_statistics/earn/earn_icons.cpp index a398532737a665..e0021ebc58f67c 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/earn_icons.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/earn/earn_icons.cpp @@ -53,7 +53,7 @@ QImage IconCurrencyColored(int size, const QColor &c) { const auto s = Size(size); auto svg = QSvgRenderer(CurrencySvg(c)); auto image = QImage( - s * style::DevicePixelRatio(), + style::DevicePixels(s), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(style::DevicePixelRatio()); image.fill(Qt::transparent); @@ -76,7 +76,7 @@ QByteArray CurrencySvgColored(const QColor &c) { QImage MenuIconCurrency(const QSize &size) { auto image = QImage( - size * style::DevicePixelRatio(), + style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(style::DevicePixelRatio()); image.fill(Qt::transparent); @@ -132,7 +132,7 @@ QImage MenuIconCredits() { + Margins(style::ConvertScale(kStrokeWidth))); auto image = QImage( - st::menuIconLinks.size() * style::DevicePixelRatio(), + style::DevicePixels(st::menuIconLinks.size()), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(style::DevicePixelRatio()); image.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp index 711abe465705a0..f77439587e76d9 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp @@ -602,8 +602,8 @@ bool GiftButton::makeCraftFrameIsFinal( QImage &frame, float64 progress) { const auto ratio = style::DevicePixelRatio(); - if (frame.size() != size() * ratio) { - frame = QImage(size() * ratio, QImage::Format_ARGB32_Premultiplied); + if (frame.size() != style::DevicePixels(size())) { + frame = QImage(style::DevicePixels(size()), QImage::Format_ARGB32_Premultiplied); frame.setDevicePixelRatio(ratio); } if (progress < 1.) { @@ -632,9 +632,9 @@ void GiftButton::cacheUniqueBackground( extend ).translated(-extend.left(), -extend.top()); const auto ratio = style::DevicePixelRatio(); - if (_uniqueBackgroundCache.size() != inner.size() * ratio) { + if (_uniqueBackgroundCache.size() != style::DevicePixels(inner.size())) { _uniqueBackgroundCache = QImage( - inner.size() * ratio, + style::DevicePixels(inner.size()), QImage::Format_ARGB32_Premultiplied); _uniqueBackgroundCache.fill(Qt::transparent); _uniqueBackgroundCache.setDevicePixelRatio(ratio); @@ -701,16 +701,15 @@ void GiftButton::paintEvent(QPaintEvent *e) { paint(p); return; } - const auto ratio = style::DevicePixelRatio(); - const auto w = width() * ratio; - const auto h = height() * ratio; + const auto w = style::DevicePixels(width()); + const auto h = style::DevicePixels(height()); auto cache = _delegate->craftUnavailableFrameCache(this, canCraftAt); if (cache.width() < w || cache.height() < h) { cache = QImage( std::max(w, cache.width()), std::max(h, cache.height()), QImage::Format_ARGB32_Premultiplied); - cache.setDevicePixelRatio(ratio); + cache.setDevicePixelRatio(style::DevicePixelRatio()); } cache.fill(Qt::transparent); auto q = QPainter(&cache); @@ -1403,13 +1402,13 @@ QImage ValidateRotatedBadge( } auto scaled = image.scaled( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); scaled.setDevicePixelRatio(ratio); auto result = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/info/profile/info_profile_badge.cpp b/Telegram/SourceFiles/info/profile/info_profile_badge.cpp index 496a0e1357cb18..6ef275c3d31288 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_badge.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_badge.cpp @@ -134,8 +134,8 @@ void Badge::setContent(Content content) { _customStatusLoopsLimit); } } - const auto width = emoji + (icon ? icon->width() : 0); - const auto height = std::max(emoji, icon ? icon->height() : 0); + const auto width = qRound(emoji) + (icon ? icon->width() : 0); + const auto height = std::max(qRound(emoji), icon ? icon->height() : 0); _view->resize(width, height); _view->paintRequest( ) | rpl::on_next([=, check = _view.data()]{ diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index ff58a0a7fc0107..8e271fce8888ac 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -25,9 +25,9 @@ namespace Info::Profile { QMargins LargeCustomEmojiMargins() { const auto ratio = style::DevicePixelRatio(); - const auto emoji = Ui::Emoji::GetSizeLarge() / ratio; - const auto size = Data::FrameSizeFromTag(Data::CustomEmojiSizeTag::Large) - / ratio; + const auto emoji = qRound(Ui::Emoji::GetSizeLarge() / ratio); + const auto size = qRound( + Data::FrameSizeFromTag(Data::CustomEmojiSizeTag::Large) / ratio); const auto left = (size - emoji) / 2; const auto right = size - emoji - left; return { left, left, right, right }; diff --git a/Telegram/SourceFiles/info/profile/info_profile_members_controllers.cpp b/Telegram/SourceFiles/info/profile/info_profile_members_controllers.cpp index 08fc0df47af869..9432dd19efc9c0 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_members_controllers.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_members_controllers.cpp @@ -273,7 +273,7 @@ const QImage &MemberListRow::ensurePillCircle(const QColor &color) const { const auto h = pillHeight(); const auto ratio = style::DevicePixelRatio(); auto image = QImage( - QSize(h, h) * ratio, + style::DevicePixels(QSize(h, h)), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(ratio); image.fill(Qt::transparent); @@ -295,13 +295,12 @@ void MemberListRow::paintPill( const QColor &bgColor) const { const auto h = pillHeight(); const auto &circle = ensurePillCircle(bgColor); - const auto ratio = style::DevicePixelRatio(); const auto half = h / 2; const auto otherHalf = h - half; p.drawImage( QRect(x, y, half, h), circle, - QRect(0, 0, half * ratio, h * ratio)); + style::DevicePixels(QRect(0, 0, half, h))); if (width > h) { p.fillRect( x + half, @@ -313,7 +312,7 @@ void MemberListRow::paintPill( p.drawImage( QRect(x + width - otherHalf, y, otherHalf, h), circle, - QRect(half * ratio, 0, otherHalf * ratio, h * ratio)); + style::DevicePixels(QRect(half, 0, otherHalf, h))); } void MemberListRow::paintColoredPill( diff --git a/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp b/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp index 691c37ba1634d9..89c907efc46571 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_top_bar.cpp @@ -1787,7 +1787,7 @@ void TopBar::paintUserpic(QPainter &p, const QRect &geometry) { _waitingUserpicCloudLoad = false; _userpicUniqueKey = key; const auto fullSize = st::infoProfileTopBarPhotoSize; - const auto scaled = fullSize * style::DevicePixelRatio(); + const auto scaled = style::DevicePixels(fullSize); auto image = QImage(); if (const auto broadcast = _peer->monoforumBroadcast()) { image = PeerData::GenerateUserpicImage( @@ -2183,7 +2183,7 @@ void TopBar::paintAnimatedPattern( const auto scale = 0.910; const auto size = st::emojiSize; _basePatternImage = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _basePatternImage.setDevicePixelRatio(ratio); _basePatternImage.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.cpp b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.cpp index b78c7c89f78587..fb7cb085ff3ece 100644 --- a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.cpp +++ b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_preview.cpp @@ -82,7 +82,7 @@ void PreviewPainter::setDocument( return; } _lifetime.destroy(); - const auto emojiSize = Size(_size * style::DevicePixelRatio()); + const auto emojiSize = Size(style::DevicePixels(_size )); if (sticker->isLottie()) { _player = std::make_unique( ChatHelpers::LottiePlayerFromDocument( diff --git a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp index 40f19bd7f030d3..1a39398e90c7d1 100644 --- a/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp +++ b/Telegram/SourceFiles/info/userpic/info_userpic_emoji_builder_widget.cpp @@ -67,7 +67,7 @@ void AlignChildren(not_null widget, int fullWidth) { const std::vector colors) { if (colors.empty()) { auto image = QImage( - Size(size * style::DevicePixelRatio()), + Size(style::DevicePixels(size )), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(style::DevicePixelRatio()); image.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp index b7d50a58dc8e78..66a37c592fc1cd 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_internal.cpp @@ -928,7 +928,9 @@ void Video::prepareThumbnail(QSize size) const { } } _thumb = thumb->pixNoCache( - QSize(w, h) * style::DevicePixelRatio(), + QSize( + style::DevicePixels(w ), + style::DevicePixels(h )), { .options = Images::Option::TransparentBackground, .outer = size, @@ -1263,7 +1265,7 @@ void Contact::prepareThumbnail(int width, int height) const { width, height); _thumb = Image(base::duplicate(*thumb)).pixNoCache( - scaled * style::DevicePixelRatio(), + style::DevicePixels(scaled), { .options = Images::Option::TransparentBackground, .outer = { width, height }, @@ -1571,7 +1573,7 @@ void Article::prepareThumbnail(int width, int height) const { width, height); _thumb = Image(base::duplicate(*thumb)).pixNoCache( - scaled * style::DevicePixelRatio(), + style::DevicePixels(scaled), { .options = Images::Option::TransparentBackground, .outer = { width, height }, @@ -1847,7 +1849,9 @@ void Game::validateThumbnail(Image *image, QSize size, bool good) const { } _thumbGood = good; _thumb = image->pixNoCache( - QSize(w, h) * style::DevicePixelRatio(), + QSize( + style::DevicePixels(w ), + style::DevicePixels(h )), { .options = (Images::Option::TransparentBackground | (good ? Images::Option() : Images::Option::Blur)), diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp index fa0d231089608a..6e858651d9713b 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_layout_item.cpp @@ -204,11 +204,14 @@ QPixmap ItemBase::getResultContactAvatar(int width, int height) const { BareId(qHash(_result->_id)))), _result->getLayoutTitle() ).generate(width); - if (result.height() != height * style::DevicePixelRatio()) { + const auto ratio = style::DevicePixelRatio(); + if (result.height() != style::DevicePixels(height) + || result.devicePixelRatio() != ratio) { result = result.scaled( - QSize(width, height) * style::DevicePixelRatio(), + style::DevicePixels(QSize(width, height)), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + result.setDevicePixelRatio(ratio); } return result; } diff --git a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp index 62372aad0c55cc..ceff3731e2a8eb 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp @@ -240,9 +240,7 @@ void Widget::startShowAnimation() { auto inner = rect().marginsRemoved(st::emojiPanMargins); _showAnimation->setFinalImage( std::move(image), - QRect( - inner.topLeft() * style::DevicePixelRatio(), - inner.size() * style::DevicePixelRatio()), + style::DevicePixels(inner), st::emojiPanRadius); _showAnimation->setCornerMasks(Images::CornersMask(ImageRoundRadius::Small)); _showAnimation->start(); diff --git a/Telegram/SourceFiles/intro/intro_step.cpp b/Telegram/SourceFiles/intro/intro_step.cpp index 3f4d8936b873d3..abe3490120ebdc 100644 --- a/Telegram/SourceFiles/intro/intro_step.cpp +++ b/Telegram/SourceFiles/intro/intro_step.cpp @@ -417,12 +417,16 @@ void Step::paintContentSnapshot(QPainter &p, const QPixmap &snapshot, float64 al void Step::prepareCoverMask() { if (!_coverMask.isNull()) return; - auto maskWidth = style::DevicePixelRatio(); - auto maskHeight = st::introCoverHeight * style::DevicePixelRatio(); + const auto maskWidth = std::max( + 1, + int(base::SafeRound(style::DevicePixelRatio()))); + const auto maskHeight = std::max( + 1, + int(base::SafeRound(st::introCoverHeight * style::DevicePixelRatio()))); auto mask = QImage(maskWidth, maskHeight, QImage::Format_ARGB32_Premultiplied); auto maskInts = reinterpret_cast(mask.bits()); Assert(mask.depth() == (sizeof(uint32) << 3)); - auto maskIntsPerLineAdded = (mask.bytesPerLine() >> 2) - maskWidth; + const auto maskIntsPerLineAdded = (mask.bytesPerLine() >> 2) - maskWidth; Assert(maskIntsPerLineAdded >= 0); auto realHeight = static_cast(maskHeight - 1); for (auto y = 0; y != maskHeight; ++y) { diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 0bfe98a19dea92..9836c408c9c970 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -48,7 +48,12 @@ For license and copyright information please follow this link: #include "styles/style_dialogs.h" #include "styles/style_layers.h" #include "styles/style_window.h" +#include "ui/style/style_core.h" +#include "ui/style/style_core_icon.h" +#include "ui/style/style_core_scale.h" +#include "ui/cached_round_corners.h" +#include #include namespace { @@ -77,6 +82,26 @@ base::options::toggle AutoScrollInactiveChat({ "even when the window is not in focus.", }); +void RefreshDevicePixelRatioFromWindow(not_null widget) { + const auto handle = widget->windowHandle(); + if (!handle) { + return; + } + const auto ratio = std::clamp(handle->devicePixelRatio(), 1., 3.); + if (qAbs(style::DevicePixelRatio() - ratio) < 0.001) { + return; + } + + LOG(("New DevicePixelRatio: %1").arg(ratio)); + style::SetDevicePixelRatio(ratio); + style::internal::ResetIcons(); + style::NotifyPaletteChanged(); + Ui::Tooltip::Hide(); + Ui::RefreshCachedCorners(); + Ui::Emoji::Refresh(); + Ui::ForceFullRepaint(widget); +} + } // namespace const char kOptionAutoScrollInactiveChat[] @@ -679,8 +704,14 @@ bool MainWindow::eventFilter(QObject *object, QEvent *e) { positionUpdated(); } } break; +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) + case QEvent::DevicePixelRatioChange: { + if (object == this) { + RefreshDevicePixelRatioFromWindow(this); + } + } break; } - +#endif return Platform::MainWindow::eventFilter(object, e); } diff --git a/Telegram/SourceFiles/media/clip/media_clip_reader.cpp b/Telegram/SourceFiles/media/clip/media_clip_reader.cpp index ee7487269bbcee..a4928589e1da70 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_reader.cpp +++ b/Telegram/SourceFiles/media/clip/media_clip_reader.cpp @@ -13,9 +13,8 @@ For license and copyright information please follow this link: #include "ui/painter.h" #include "core/file_location.h" #include "base/random.h" +#include "base/algorithm.h" #include "base/invoke_queued.h" -#include "logs.h" - #include #include #include @@ -71,24 +70,30 @@ QImage PrepareFrame( const auto outerw = size.width(); const auto frameh = request.frame.height(); const auto outerh = size.height(); + const auto logicalOuterWidth = cache.width() / factor; + const auto logicalOuterHeight = cache.height() / factor; + const auto logicalFrameWidth = framew / factor; + const auto logicalFrameHeight = frameh / factor; + const auto logicalDeltaX = (outerw - framew) / (2. * factor); + const auto logicalDeltaY = (outerh - frameh) / (2. * factor); if (needNewCache && (!hasAlpha || !request.keepAlpha)) { if (framew < outerw) { - p.fillRect(0, 0, (outerw - framew) / (2 * factor), cache.height() / factor, st::imageBg); - p.fillRect((outerw - framew) / (2 * factor) + (framew / factor), 0, (cache.width() / factor) - ((outerw - framew) / (2 * factor) + (framew / factor)), cache.height() / factor, st::imageBg); + p.fillRect(0., 0., logicalDeltaX, logicalOuterHeight, st::imageBg); + p.fillRect(logicalDeltaX + logicalFrameWidth, 0., logicalOuterWidth - (logicalDeltaX + logicalFrameWidth), logicalOuterHeight, st::imageBg); } if (frameh < outerh) { - p.fillRect(qMax(0, (outerw - framew) / (2 * factor)), 0, qMin(cache.width(), framew) / factor, (outerh - frameh) / (2 * factor), st::imageBg); - p.fillRect(qMax(0, (outerw - framew) / (2 * factor)), (outerh - frameh) / (2 * factor) + (frameh / factor), qMin(cache.width(), framew) / factor, (cache.height() / factor) - ((outerh - frameh) / (2 * factor) + (frameh / factor)), st::imageBg); + p.fillRect(std::max(0., logicalDeltaX), 0., std::min(logicalOuterWidth, logicalFrameWidth), logicalDeltaY, st::imageBg); + p.fillRect(std::max(0., logicalDeltaX), logicalDeltaY + logicalFrameHeight, std::min(logicalOuterWidth, logicalFrameWidth), logicalOuterHeight - (logicalDeltaY + logicalFrameHeight), st::imageBg); } } if (hasAlpha && !request.keepAlpha) { - p.fillRect(qMax(0, (outerw - framew) / (2 * factor)), qMax(0, (outerh - frameh) / (2 * factor)), qMin(cache.width(), framew) / factor, qMin(cache.height(), frameh) / factor, st::imageBgTransparent); + p.fillRect(std::max(0., logicalDeltaX), std::max(0., logicalDeltaY), std::min(logicalOuterWidth, logicalFrameWidth), std::min(logicalOuterHeight, logicalFrameHeight), st::imageBgTransparent); } - const auto position = QPoint((outerw - framew) / (2 * factor), (outerh - frameh) / (2 * factor)); + const auto position = QPointF(logicalDeltaX, logicalDeltaY); if (needResize) { PainterHighQualityEnabler hq(p); - const auto dst = QRect(position, QSize(framew / factor, frameh / factor)); + const auto dst = QRectF(position, QSizeF(logicalFrameWidth, logicalFrameHeight)); const auto src = QRect(0, 0, original.width(), original.height()); p.drawImage(dst, original, src, Qt::ColorOnly); } else { @@ -316,9 +321,9 @@ void Reader::start(FrameRequest request) { } const auto factor = style::DevicePixelRatio(); request.factor = factor; - request.frame *= factor; + request.frame = style::DevicePixels(request.frame); if (request.outer.isValid()) { - request.outer *= factor; + request.outer = style::DevicePixels(request.outer); } _frames[0].request = _frames[1].request = _frames[2].request = request; moveToNextShow(); @@ -350,9 +355,9 @@ Reader::FrameInfo Reader::frameInfo(FrameRequest request, crl::time now) { const auto factor = style::DevicePixelRatio(); request.factor = factor; - request.frame *= factor; + request.frame = style::DevicePixels(request.frame); if (request.outer.isValid()) { - request.outer *= factor; + request.outer = style::DevicePixels(request.outer); } const auto size = request.outer.isValid() ? request.outer diff --git a/Telegram/SourceFiles/media/clip/media_clip_reader.h b/Telegram/SourceFiles/media/clip/media_clip_reader.h index faa3f24a145d93..dec915745b5e3a 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_reader.h +++ b/Telegram/SourceFiles/media/clip/media_clip_reader.h @@ -36,7 +36,7 @@ struct FrameRequest { QSize frame; QSize outer; - int factor = 0; + double factor = 0.; ImageRoundRadius radius = ImageRoundRadius::None; RectParts corners = RectPart::AllCorners; QColor colored = QColor(0, 0, 0, 0); diff --git a/Telegram/SourceFiles/media/player/media_player_button.cpp b/Telegram/SourceFiles/media/player/media_player_button.cpp index 2fc6b8877f5d02..a2d7d65c2d1e3f 100644 --- a/Telegram/SourceFiles/media/player/media_player_button.cpp +++ b/Telegram/SourceFiles/media/player/media_player_button.cpp @@ -397,12 +397,10 @@ void SettingsButton::paintEvent(QPaintEvent *e) { } void SettingsButton::prepareFrame() { - const auto ratio = style::DevicePixelRatio(); - if (_frameCache.size() != _st.size * ratio) { - _frameCache = QImage( - _st.size * ratio, - QImage::Format_ARGB32_Premultiplied); - _frameCache.setDevicePixelRatio(ratio); + const auto size = style::DevicePixels(_st.size); + if (_frameCache.size() != size) { + _frameCache = QImage(size, QImage::Format_ARGB32_Premultiplied); + _frameCache.setDevicePixelRatio(style::DevicePixelRatio()); } _frameCache.fill(Qt::transparent); auto p = QPainter(&_frameCache); diff --git a/Telegram/SourceFiles/media/player/media_player_float.cpp b/Telegram/SourceFiles/media/player/media_player_float.cpp index 2fa095e364c220..39dca44e401d83 100644 --- a/Telegram/SourceFiles/media/player/media_player_float.cpp +++ b/Telegram/SourceFiles/media/player/media_player_float.cpp @@ -44,12 +44,16 @@ bool RoundPainter::fillFrame(const QSize &size) { const auto ratio = style::DevicePixelRatio(); if (creating) { _frame = QImage( - size * ratio, + style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); } auto frameInner = [&] { - return QRect(QPoint(), _frame.size() / ratio); + return QRect( + QPoint(), + QSize( + base::SafeRound(_frame.width() / ratio), + base::SafeRound(_frame.height() / ratio))); }; if (const auto streamed = instance()->roundVideoStreamed(_item)) { auto request = Streaming::FrameRequest::NonStrict(); @@ -213,7 +217,7 @@ void Float::detach() { void Float::prepareShadow() { const auto ratio = style::DevicePixelRatio(); auto shadow = QImage( - size() * ratio, + style::DevicePixels(size()), QImage::Format_ARGB32_Premultiplied); shadow.fill(Qt::transparent); shadow.setDevicePixelRatio(ratio); diff --git a/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp b/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp index 37fb107e46a23d..99c17cd4702261 100644 --- a/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp +++ b/Telegram/SourceFiles/media/stories/media_stories_sibling.cpp @@ -383,7 +383,7 @@ QImage Sibling::nameImage(const SiblingLayout &layout) { const auto h = _nameStyle->font->height; const auto ratio = style::DevicePixelRatio(); _nameImage = QImage( - QSize(w, h) * ratio, + style::DevicePixels(QSize(w, h)), QImage::Format_ARGB32_Premultiplied); _nameImage.setDevicePixelRatio(ratio); _nameImage.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp index 68ccc5537012ff..e6370fff0838ea 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_utility.cpp @@ -312,10 +312,9 @@ QImage PrepareBlurredBackground(QSize outer, QImage frame) { void FillBlurredBackground(QPainter &p, QSize outer, QImage bg) { auto hq = PainterHighQualityEnabler(p); const auto rect = QRect(QPoint(), outer); - const auto ratio = p.device()->devicePixelRatio(); p.drawImage( rect, - PrepareBlurredBackground(outer * ratio, std::move(bg))); + PrepareBlurredBackground(style::DevicePixels(outer), std::move(bg))); p.fillRect(rect, QColor(0, 0, 0, 48)); } diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp index 8092b2907823fc..fc5238bdf08247 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.cpp @@ -307,7 +307,7 @@ void OverlayWidget::RendererGL::paint( const auto factor = widget->devicePixelRatioF(); if (_factor != factor) { _factor = factor; - _ifactor = int(std::ceil(factor)); + //_ifactor = int(std::ceil(factor)); _controlsImage.invalidate(); // We use the fact that fade texture atlas @@ -856,19 +856,19 @@ void OverlayWidget::RendererGL::validateControls() { maxWidth = std::max(st::mediaviewIconOver, maxWidth); fullHeight += st::mediaviewIconOver; auto image = QImage( - QSize(maxWidth, fullHeight) * _ifactor, + style::DevicePixels(QSize(maxWidth, fullHeight), _factor), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); - image.setDevicePixelRatio(_ifactor); + image.setDevicePixelRatio(_factor); { auto p = QPainter(&image); auto index = 0; auto height = 0; for (const auto &meta : metas) { meta.icon->paint(p, 0, height, maxWidth); - _controlsTextures[index++] = QRect( - QPoint(0, height) * _ifactor, - meta.icon->size() * _ifactor); + _controlsTextures[index++] = style::DevicePixels(QRect( + QPoint(0, height), + meta.icon->size()), _factor); height += meta.icon->height(); } auto hq = PainterHighQualityEnabler(p); @@ -876,9 +876,9 @@ void OverlayWidget::RendererGL::validateControls() { p.setBrush(OverBackgroundColor()); p.drawEllipse( QRect(0, height, st::mediaviewIconOver, st::mediaviewIconOver)); - _controlsTextures[index++] = QRect( - QPoint(0, height) * _ifactor, - QSize(st::mediaviewIconOver, st::mediaviewIconOver) * _ifactor); + _controlsTextures[index++] = style::DevicePixels(QRect( + QPoint(0, height), + QSize(st::mediaviewIconOver, st::mediaviewIconOver)), _factor); height += st::mediaviewIconOver; } _controlsImage.setImage(std::move(image)); @@ -910,10 +910,10 @@ void OverlayWidget::RendererGL::validateControlsFade() { const auto height = bottomTop + bottom.height(); auto image = QImage( - QSize(width, height) * _ifactor, + style::DevicePixels(QSize(width, height), _factor), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); - image.setDevicePixelRatio(_ifactor); + image.setDevicePixelRatio(_factor); auto p = QPainter(&image); top.paint(p, 0, 0, width); @@ -1102,18 +1102,18 @@ void OverlayWidget::RendererGL::paintUsingRaster( int bufferOffset, bool transparent) { auto raster = image.takeImage(); - const auto size = rect.size() * _ifactor; + const auto size = style::DevicePixels(rect.size(), _factor); if (raster.width() < size.width() || raster.height() < size.height()) { raster = QImage(size, QImage::Format_ARGB32_Premultiplied); Assert(!raster.isNull()); - raster.setDevicePixelRatio(_ifactor); + raster.setDevicePixelRatio(_factor); if (!transparent && (raster.width() > size.width() || raster.height() > size.height())) { raster.fill(Qt::transparent); } - } else if (raster.devicePixelRatio() != _ifactor) { - raster.setDevicePixelRatio(_ifactor); + } else if (raster.devicePixelRatio() != _factor) { + raster.setDevicePixelRatio(_factor); } if (transparent) { @@ -1229,11 +1229,11 @@ void OverlayWidget::RendererGL::paintRecognitionOverlay( for (const auto &item : _owner->_recognitionResult.items) { const auto &r = item.rect; const auto lightRect = QRectF( - imageTopLeft.x() + r.left() * _ifactor * scale, + imageTopLeft.x() + r.left() * _factor * scale, imageTopLeft.y() - + (image.height() - (r.y() + r.height()) * _ifactor) * scale, - r.width() * _ifactor * scale, - r.height() * _ifactor * scale); + + (image.height() - (r.y() + r.height()) * _factor) * scale, + r.width() * _factor * scale, + r.height() * _factor * scale); const auto tl = rotated(lightRect.left(), lightRect.top()); const auto tr = rotated(lightRect.right(), lightRect.top()); const auto br = rotated(lightRect.right(), lightRect.bottom()); diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h index f0f36592c42e46..432cd18274855f 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_opengl.h @@ -118,7 +118,7 @@ class OverlayWidget::RendererGL final QOpenGLFunctions *_f = nullptr; QSize _viewport; float _factor = 1.; - int _ifactor = 1; + //int _ifactor = 1; QVector2D _uniformViewport; std::optional _contentBuffer; diff --git a/Telegram/SourceFiles/overview/overview_layout.cpp b/Telegram/SourceFiles/overview/overview_layout.cpp index d46518dc3ff2b3..04d6c197bfbc01 100644 --- a/Telegram/SourceFiles/overview/overview_layout.cpp +++ b/Telegram/SourceFiles/overview/overview_layout.cpp @@ -7,6 +7,8 @@ For license and copyright information please follow this link: */ #include "overview/overview_layout.h" +#include "base/debug_log.h" + #include "overview/overview_checkbox.h" #include "overview/overview_layout_delegate.h" #include "core/ui_integration.h" // TextContext @@ -72,29 +74,29 @@ constexpr auto kStoryRatio = 1.46; [[nodiscard]] QImage CropMediaFrame(QImage image, int width, int height) { const auto ratio = style::DevicePixelRatio(); - width *= ratio; - height *= ratio; + const auto w = style::DevicePixels(width); + const auto h = style::DevicePixels(height); const auto finalize = [&](QImage result) { result = result.scaled( - width, - height, + w, + h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); result.setDevicePixelRatio(ratio); return result; }; - if (image.width() * height == image.height() * width) { - if (image.width() != width) { + if (image.width() * h == image.height() * w) { + if (image.width() != w) { return finalize(std::move(image)); } image.setDevicePixelRatio(ratio); return image; - } else if (image.width() * height > image.height() * width) { - const auto use = (image.height() * width) / height; + } else if (image.width() * h > image.height() * w) { + const auto use = (image.height() * w) / h; const auto skip = (image.width() - use) / 2; return finalize(image.copy(skip, 0, use, image.height())); } else { - const auto use = (image.width() * height) / width; + const auto use = (image.width() * h) / w; const auto skip = (image.height() - use) / 2; return finalize(image.copy(0, skip, image.width(), use)); } @@ -347,8 +349,7 @@ int32 Photo::resizeGetHeight(int32 width) { void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const PaintContext *context) { const auto selected = (selection == FullSelection); - const auto widthChanged = (_pix.width() - != (_width * style::DevicePixelRatio())); + const auto widthChanged = (_pix.width() != style::DevicePixels(_width)); if (!_goodLoaded || widthChanged) { ensureDataMediaCreated(); const auto good = !_spoiler @@ -573,7 +574,7 @@ void Video::paint( const auto radialOpacity = radial ? _radial->opacity() : 0.; if ((blurred || thumbnail || good) - && ((_pix.width() != _width * style::DevicePixelRatio()) + && ((_pix.width() != style::DevicePixels(_width)) || (_pixBlurred && (thumbnail || good)))) { auto img = good ? good->original() @@ -1326,7 +1327,7 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con : Images::Option::Blur); const auto image = thumbnail ? thumbnail : blurred; _thumb = image->pixNoCache( - _thumbw * style::DevicePixelRatio(), + style::DevicePixels(_thumbw), { .options = options, .outer = QSize( @@ -1981,8 +1982,9 @@ void Link::validateThumbnail() { _documentMedia = nullptr; delegate()->unregisterHeavyItem(this); } else { - const auto size = QSize(st::linksPhotoSize, st::linksPhotoSize); - _thumbnail = QPixmap(size * style::DevicePixelRatio()); + const auto size = style::DevicePixels(QSize(st::linksPhotoSize, st::linksPhotoSize)); + _thumbnail = QPixmap(size); + _thumbnail.setDevicePixelRatio(style::DevicePixelRatio()); _thumbnail.fill(Qt::transparent); auto p = Painter(&_thumbnail); const auto index = _letter.isEmpty() @@ -2227,13 +2229,13 @@ void Gif::validateThumbnail( bool good) { if (!image || (_thumbGood && !good)) { return; - } else if ((_thumb.size() == size * style::DevicePixelRatio()) + } else if ((_thumb.size() == style::DevicePixels(size)) && (_thumbGood || !good)) { return; } _thumbGood = good; _thumb = image->pixNoCache( - frame * style::DevicePixelRatio(), + style::DevicePixels(frame), { .options = (good ? Images::Option() : Images::Option::Blur), .outer = size, diff --git a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp index 3c3b5358d697a6..60cc0d754107e1 100644 --- a/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp +++ b/Telegram/SourceFiles/payments/ui/payments_reaction_box.cpp @@ -700,7 +700,7 @@ QImage GenerateSmallBadgeImage( const auto add = borderSt ? borderSt->width : 0; const auto ratio = style::DevicePixelRatio(); auto result = QImage( - (rect + QMargins(add, add, add, add)).size() * ratio, + style::DevicePixels((rect + QMargins(add, add, add, add)).size()), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/settings/business/settings_chat_links.cpp b/Telegram/SourceFiles/settings/business/settings_chat_links.cpp index 784b643bda59d6..8365654cc592d5 100644 --- a/Telegram/SourceFiles/settings/business/settings_chat_links.cpp +++ b/Telegram/SourceFiles/settings/business/settings_chat_links.cpp @@ -676,11 +676,12 @@ void LinksController::rowPaintIcon( const auto inner = size - 2 * skip; const auto bg = &st::msgFile1Bg; if (_icon.isNull()) { + const auto ratio = style::DevicePixelRatio(); _icon = QImage( - QSize(inner, inner) * style::DevicePixelRatio(), + style::DevicePixels(QSize(inner, inner)), QImage::Format_ARGB32_Premultiplied); _icon.fill(Qt::transparent); - _icon.setDevicePixelRatio(style::DevicePixelRatio()); + _icon.setDevicePixelRatio(ratio); auto p = QPainter(&_icon); p.setPen(Qt::NoPen); diff --git a/Telegram/SourceFiles/settings/sections/settings_chat.cpp b/Telegram/SourceFiles/settings/sections/settings_chat.cpp index 2cac29431aa101..33830c7dc57861 100644 --- a/Telegram/SourceFiles/settings/sections/settings_chat.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_chat.cpp @@ -614,7 +614,7 @@ void BackgroundRow::radialAnimationCallback(crl::time now) { void BackgroundRow::updateImage() { const auto size = st::settingsBackgroundThumb; - const auto fullsize = size * style::DevicePixelRatio(); + const auto fullsize = qRound(size * style::DevicePixelRatio()); const auto &background = *Window::Theme::Background(); const auto &paper = background.paper(); @@ -2787,9 +2787,8 @@ void SetupThemeSettings( Window::Theme::DefaultChatThemeOn(container->lifetime())); const auto generateBg = [=] { const auto size = st::boxWidth; - const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); auto p = QPainter(&result); Window::SectionWidget::PaintBackground( diff --git a/Telegram/SourceFiles/settings/sections/settings_main.cpp b/Telegram/SourceFiles/settings/sections/settings_main.cpp index 52bb5fe4b26abe..ed2b93499fe48a 100644 --- a/Telegram/SourceFiles/settings/sections/settings_main.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_main.cpp @@ -1007,9 +1007,8 @@ void SetupInterfaceScale( const auto scaleMax = style::MaxScaleForRatio(ratio); const auto scaleConfig = cConfigScale(); const auto step = 5; - Assert(!((scaleMax - scaleMin) % step)); auto values = std::vector(); - for (auto i = scaleMin; i != scaleMax; i += step) { + for (auto i = scaleMin; i < scaleMax; i += step) { values.push_back(i); if (scaleConfig > i && scaleConfig < i + step) { values.push_back(scaleConfig); diff --git a/Telegram/SourceFiles/settings/sections/settings_notifications.cpp b/Telegram/SourceFiles/settings/sections/settings_notifications.cpp index 81242142adbcaa..e1b860ce28753b 100644 --- a/Telegram/SourceFiles/settings/sections/settings_notifications.cpp +++ b/Telegram/SourceFiles/settings/sections/settings_notifications.cpp @@ -412,10 +412,11 @@ int NotificationsCount::resizeGetHeight(int newWidth) { void NotificationsCount::prepareNotificationSampleSmall() { auto width = st::notificationSampleSize.width(); auto height = st::notificationSampleSize.height(); + const auto ratio = style::DevicePixelRatio(); auto sampleImage = QImage( - QSize(width, height) * style::DevicePixelRatio(), + style::DevicePixels(QSize(width, height)), QImage::Format_ARGB32_Premultiplied); - sampleImage.setDevicePixelRatio(style::DevicePixelRatio()); + sampleImage.setDevicePixelRatio(ratio); sampleImage.fill(st::notificationBg->c); { Painter p(&sampleImage); diff --git a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp index 9ac4584e403786..edc9c6aa20d20b 100644 --- a/Telegram/SourceFiles/settings/settings_credits_graphics.cpp +++ b/Telegram/SourceFiles/settings/settings_credits_graphics.cpp @@ -626,7 +626,7 @@ void FillCreditOptions( }; const auto stars = getStars(); const auto textLeft = diffBetweenTextAndStar - + stars.width() / style::DevicePixelRatio(); + + qRound(stars.width() / style::DevicePixelRatio()); inner->paintRequest( ) | rpl::on_next([=](const QRect &rect) { auto p = QPainter(inner); diff --git a/Telegram/SourceFiles/statistics/widgets/point_details_widget.cpp b/Telegram/SourceFiles/statistics/widgets/point_details_widget.cpp index b0cc6ba8abeed2..cbe8f5151e753b 100644 --- a/Telegram/SourceFiles/statistics/widgets/point_details_widget.cpp +++ b/Telegram/SourceFiles/statistics/widgets/point_details_widget.cpp @@ -144,7 +144,7 @@ PointDetailsWidget::PointDetailsWidget( const auto stroke = style::ConvertScaleExact( st::statisticsDetailsArrowStroke); _arrow = QImage( - QSize(w + stroke, w * 2 + stroke) * style::DevicePixelRatio(), + style::DevicePixels(QSize(w + stroke, w * 2 + stroke)), QImage::Format_ARGB32_Premultiplied); _arrow.setDevicePixelRatio(style::DevicePixelRatio()); _arrow.fill(Qt::transparent); @@ -265,7 +265,7 @@ PointDetailsWidget::PointDetailsWidget( const auto fullRect = s.isNull() ? Rect(Size(calculatedWidth)) : Rect(s); - _innerRect = fullRect - st::statisticsDetailsPopupPadding; + _innerRect = (fullRect - st::statisticsDetailsPopupPadding).toAlignedRect(); _textRect = _innerRect - st::statisticsDetailsPopupMargins; invalidateCache(); }, lifetime()); @@ -442,7 +442,7 @@ void PointDetailsWidget::paintEvent(QPaintEvent *e) { if (_cache.isNull()) { _cache = QImage( - size() * style::DevicePixelRatio(), + style::DevicePixels(size()), QImage::Format_ARGB32_Premultiplied); _cache.setDevicePixelRatio(style::DevicePixelRatio()); _cache.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/ui/boxes/about_cocoon_box.cpp b/Telegram/SourceFiles/ui/boxes/about_cocoon_box.cpp index 2e18360744c6cd..3801d387f84483 100644 --- a/Telegram/SourceFiles/ui/boxes/about_cocoon_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/about_cocoon_box.cpp @@ -43,7 +43,7 @@ void AddCocoonBoxCover(not_null container) { const auto logoSize = st::cocoonLogoSize; const auto ratio = style::DevicePixelRatio(); auto logo = QImage(u":/gui/art/cocoon.webp"_q).scaled( - QSize(logoSize, logoSize) * ratio, + style::DevicePixels(QSize(logoSize, logoSize)), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); logo.setDevicePixelRatio(ratio); diff --git a/Telegram/SourceFiles/ui/boxes/choose_font_box.cpp b/Telegram/SourceFiles/ui/boxes/choose_font_box.cpp index aa750570196b69..7225b0e88d31ef 100644 --- a/Telegram/SourceFiles/ui/boxes/choose_font_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/choose_font_box.cpp @@ -307,7 +307,7 @@ void Selector::validateCache(Entry &row) { if (row.cache.isNull()) { const auto ratio = style::DevicePixelRatio(); row.cache = QImage( - QSize(width(), _rowHeight) * ratio, + style::DevicePixels(QSize(width(), _rowHeight)), QImage::Format_ARGB32_Premultiplied); row.cache.setDevicePixelRatio(ratio); } else if (row.paletteVersion == version) { @@ -596,11 +596,10 @@ PreviewPainter::PreviewPainter(const QImage &bg, PreviewRequest request) layout(); - const auto ratio = style::DevicePixelRatio(); _result = QImage( - _outer * ratio, + style::DevicePixels(_outer), QImage::Format_ARGB32_Premultiplied); - _result.setDevicePixelRatio(ratio); + _result.setDevicePixelRatio(style::DevicePixelRatio()); auto p = Painter(&_result); p.drawImage(0, 0, bg); diff --git a/Telegram/SourceFiles/ui/boxes/emoji_stake_box.cpp b/Telegram/SourceFiles/ui/boxes/emoji_stake_box.cpp index 6b32fd3c0d5db6..cae76810fd86f8 100644 --- a/Telegram/SourceFiles/ui/boxes/emoji_stake_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/emoji_stake_box.cpp @@ -70,7 +70,7 @@ namespace { const auto ratio = style::DevicePixelRatio(); auto svg = QSvgRenderer(path); auto result = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/ui/boxes/peer_qr_box.cpp b/Telegram/SourceFiles/ui/boxes/peer_qr_box.cpp index 0f39d34155ba90..0cdd5c03d919c1 100644 --- a/Telegram/SourceFiles/ui/boxes/peer_qr_box.cpp +++ b/Telegram/SourceFiles/ui/boxes/peer_qr_box.cpp @@ -267,17 +267,23 @@ not_null PrepareQrWidget( const auto downTo = remainder ? qrMaxSize - remainder : qrMaxSize; + const auto scaledQrSide = int(base::SafeRound( + qrMaxSize * style::DevicePixelRatio())); + const auto scaledQrSize = QSize(scaledQrSide, scaledQrSide); state->qrImage = TelegramQr( Qr::Encode(link.toUtf8(), Qr::Redundancy::Default), st::introQrPixel, downTo, backgroundToggled).scaled( - Size(qrMaxSize * style::DevicePixelRatio()), + scaledQrSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } else { + const auto scaledQrSide = int(base::SafeRound( + qrMaxSize * style::DevicePixelRatio())); + const auto scaledQrSize = QSize(scaledQrSide, scaledQrSide); auto image = QImage( - Size(qrMaxSize * style::DevicePixelRatio()), + scaledQrSize, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::white); image.setDevicePixelRatio(style::DevicePixelRatio()); @@ -349,11 +355,14 @@ not_null PrepareQrWidget( return; } const auto photoSize = state->photoSize; + const auto scaledPhotoSide = int(base::SafeRound( + photoSize * style::DevicePixelRatio())); + const auto scaledPhotoSize = QSize(scaledPhotoSide, scaledPhotoSide); const auto top = Ui::GrabWidget( topWidget, QRect(), Qt::transparent).scaled( - Size(photoSize * style::DevicePixelRatio()), + scaledPhotoSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); p.drawPixmap((result->width() - photoSize) / 2, -photoSize / 2, top); diff --git a/Telegram/SourceFiles/ui/cached_round_corners.cpp b/Telegram/SourceFiles/ui/cached_round_corners.cpp index 7da69a2299a1fc..78c99fb11ba64a 100644 --- a/Telegram/SourceFiles/ui/cached_round_corners.cpp +++ b/Telegram/SourceFiles/ui/cached_round_corners.cpp @@ -28,7 +28,8 @@ rpl::lifetime PaletteChangedLifetime; std::array, kCachedCornerRadiusCount> CachedMasks; [[nodiscard]] std::array PrepareCorners(int32 radius, const QBrush &brush, const style::color *shadow = nullptr) { - int32 r = radius * style::DevicePixelRatio(), s = st::msgShadow * style::DevicePixelRatio(); + const auto r = radius * style::DevicePixelRatio(); + const auto s = st::msgShadow * style::DevicePixelRatio(); QImage rect(r * 3, r * 3 + (shadow ? s : 0), QImage::Format_ARGB32_Premultiplied); rect.fill(Qt::transparent); { @@ -110,18 +111,14 @@ void FinishCachedCorners() { PaletteChangedLifetime.destroy(); } +void RefreshCachedCorners() { + FinishCachedCorners(); + StartCachedCorners(); +} + void FillRoundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, const CornersPixmaps &corners) { using namespace Images; - const auto fillBg = [&](QRect rect) { - p.fillRect(rect, bg); - }; - const auto fillCorner = [&](int x, int y, int index) { - if (const auto &pix = corners.p[index]; !pix.isNull()) { - p.drawPixmap(x, y, pix); - } - }; - if (corners.p[kTopLeft].isNull() && corners.p[kTopRight].isNull() && corners.p[kBottomLeft].isNull() @@ -130,54 +127,68 @@ void FillRoundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color return; } const auto ratio = style::DevicePixelRatio(); - const auto cornerSize = [&](int index) { - return corners.p[index].isNull() - ? 0 - : (corners.p[index].width() / ratio); + const auto dx = qRound(x * ratio); + const auto dy = qRound(y * ratio); + const auto dw = qRound(w * ratio); + const auto dh = qRound(h * ratio); + + const auto devSize = [&](int index) { + return corners.p[index].isNull() ? 0 : corners.p[index].width(); }; - const auto verticalSkip = [&](int left, int right) { - return std::max(cornerSize(left), cornerSize(right)); + const auto topLeft = devSize(kTopLeft); + const auto topRight = devSize(kTopRight); + const auto bottomLeft = devSize(kBottomLeft); + const auto bottomRight = devSize(kBottomRight); + const auto topDev = std::max(topLeft, topRight); + const auto bottomDev = std::max(bottomLeft, bottomRight); + + const auto fillBg = [&](int fdx, int fdy, int fdw, int fdh) { + if (fdw <= 0 || fdh <= 0) { + return; + } + p.fillRect(QRectF(fdx / ratio, fdy / ratio, fdw / ratio, fdh / ratio), bg); }; - const auto top = verticalSkip(kTopLeft, kTopRight); - const auto bottom = verticalSkip(kBottomLeft, kBottomRight); - if (top) { - const auto left = cornerSize(kTopLeft); - const auto right = cornerSize(kTopRight); - if (left) { - fillCorner(x, y, kTopLeft); - if (const auto add = top - left) { - fillBg({ x, y + left, left, add }); + const auto fillCorner = [&](int cdx, int cdy, int index) { + if (const auto &pix = corners.p[index]; !pix.isNull()) { + p.drawPixmap(QPointF(cdx / ratio, cdy / ratio), pix); + } + }; + + if (topDev > 0) { + if (topLeft > 0) { + fillCorner(dx, dy, kTopLeft); + if (const auto add = topDev - topLeft; add > 0) { + fillBg(dx, dy + topLeft, topLeft, add); } } - if (const auto fill = w - left - right; fill > 0) { - fillBg({ x + left, y, fill, top }); + if (const auto fill = dw - topLeft - topRight; fill > 0) { + fillBg(dx + topLeft, dy, fill, topDev); } - if (right) { - fillCorner(x + w - right, y, kTopRight); - if (const auto add = top - right) { - fillBg({ x + w - right, y + right, right, add }); + if (topRight > 0) { + fillCorner(dx + dw - topRight, dy, kTopRight); + if (const auto add = topDev - topRight; add > 0) { + fillBg(dx + dw - topRight, dy + topRight, topRight, add); } } } - if (const auto fill = h - top - bottom; fill > 0) { - fillBg({ x, y + top, w, fill }); + if (const auto fill = dh - topDev - bottomDev; fill > 0) { + fillBg(dx, dy + topDev, dw, fill); } - if (bottom) { - const auto left = cornerSize(kBottomLeft); - const auto right = cornerSize(kBottomRight); - if (left) { - fillCorner(x, y + h - left, kBottomLeft); - if (const auto add = bottom - left) { - fillBg({ x, y + h - bottom, left, add }); + if (bottomDev > 0) { + const auto byDev = dy + dh - bottomDev; + if (bottomLeft > 0) { + fillCorner(dx, byDev + (bottomDev - bottomLeft), kBottomLeft); + if (const auto add = bottomDev - bottomLeft; add > 0) { + fillBg(dx, byDev, bottomLeft, add); } } - if (const auto fill = w - left - right; fill > 0) { - fillBg({ x + left, y + h - bottom, fill, bottom }); + if (const auto fill = dw - bottomLeft - bottomRight; fill > 0) { + fillBg(dx + bottomLeft, byDev, fill, bottomDev); } - if (right) { - fillCorner(x + w - right, y + h - right, kBottomRight); - if (const auto add = bottom - right) { - fillBg({ x + w - right, y + h - bottom, right, add }); + if (bottomRight > 0) { + fillCorner(dx + dw - bottomRight, byDev + (bottomDev - bottomRight), kBottomRight); + if (const auto add = bottomDev - bottomRight; add > 0) { + fillBg(dx + dw - bottomRight, byDev, bottomRight, add); } } } @@ -241,7 +252,7 @@ CornersPixmaps PrepareCornerPixmaps(ImageRoundRadius radius, style::color bg, co } CornersPixmaps PrepareInvertedCornerPixmaps(int radius, style::color bg) { - const auto size = radius * style::DevicePixelRatio(); + const auto size = style::DevicePixels(radius ); auto circle = style::colorizeImage( style::createInvertedCircleMask(radius * 2), bg); diff --git a/Telegram/SourceFiles/ui/cached_round_corners.h b/Telegram/SourceFiles/ui/cached_round_corners.h index f20a06a112f9a0..89b9140f8bbcc9 100644 --- a/Telegram/SourceFiles/ui/cached_round_corners.h +++ b/Telegram/SourceFiles/ui/cached_round_corners.h @@ -78,5 +78,6 @@ enum class CachedCornerRadius { void StartCachedCorners(); void FinishCachedCorners(); +void RefreshCachedCorners(); } // namespace Ui diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp index d312bbc458cbbc..6a163067088c0f 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_abstract_single_media_preview.cpp @@ -104,10 +104,9 @@ void AbstractSingleMediaPreview::preparePreview(QImage preview) { maxH = limitH; } } - const auto ratio = style::DevicePixelRatio(); preview = Images::Prepare( std::move(preview), - QSize(maxW, maxH) * ratio, + style::DevicePixels(QSize(maxW, maxH)), { .outer = { maxW, maxH } }); } auto originalWidth = preview.width(); @@ -136,8 +135,8 @@ void AbstractSingleMediaPreview::preparePreview(QImage preview) { } preview = std::move(preview).scaled( - _previewWidth * style::DevicePixelRatio(), - _previewHeight * style::DevicePixelRatio(), + style::DevicePixels(_previewWidth), + style::DevicePixels(_previewHeight), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); preview = Images::Opaque(std::move(preview)); diff --git a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp index 8b7186d8841f6f..0eab2132d43246 100644 --- a/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp +++ b/Telegram/SourceFiles/ui/chat/attach/attach_album_thumbnail.cpp @@ -54,15 +54,15 @@ AlbumThumbnail::AlbumThumbnail( const auto previewWidth = _fullPreview.width(); const auto previewHeight = _fullPreview.height(); const auto imageWidth = std::max( - previewWidth / style::DevicePixelRatio(), + previewWidth , st::minPhotoSize); const auto imageHeight = std::max( - previewHeight / style::DevicePixelRatio(), + previewHeight , st::minPhotoSize); _photo = PixmapFromImage(Images::Prepare( _fullPreview, QSize(previewWidth, previewHeight), - { + Images::PrepareArgs{ .options = Option::RoundLarge, .outer = { imageWidth, imageHeight }, })); @@ -344,12 +344,13 @@ void AlbumThumbnail::prepareCache(QSize size, int shrink) { const auto height = std::max( _layout.geometry.height(), _animateFromGeometry ? _animateFromGeometry->height() : 0); - const auto cacheSize = QSize(width, height) * style::DevicePixelRatio(); + const auto ratio = style::DevicePixelRatio(); + const auto cacheSize = style::DevicePixels(QSize(width, height)); if (_albumCache.width() < cacheSize.width() || _albumCache.height() < cacheSize.height()) { _albumCache = QImage(cacheSize, QImage::Format_ARGB32_Premultiplied); - _albumCache.setDevicePixelRatio(style::DevicePixelRatio()); + _albumCache.setDevicePixelRatio(ratio); } _albumCache.fill(Qt::transparent); { @@ -363,7 +364,9 @@ void AlbumThumbnail::prepareCache(QSize size, int shrink) { std::move(_albumCache), ImageRoundRadius::Large, _albumCorners, - QRect(QPoint(), size * style::DevicePixelRatio())); + QRect( + QPoint(), + style::DevicePixels(QSize(width, height)))); } void AlbumThumbnail::drawSimpleFrame(QPainter &p, QRect to, QSize size) const { diff --git a/Telegram/SourceFiles/ui/chat/chat_style.cpp b/Telegram/SourceFiles/ui/chat/chat_style.cpp index cde1d1af223a0e..6a5f09470240dc 100644 --- a/Telegram/SourceFiles/ui/chat/chat_style.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_style.cpp @@ -26,7 +26,17 @@ void EnsureCorners( int radius, const style::color &color, const style::color *shadow = nullptr) { - if (corners.p[0].isNull()) { + const auto ratio = style::DevicePixelRatio(); + const auto mismatch = [&] { + for (const auto &pix : corners.p) { + if (!pix.isNull() + && qAbs(pix.devicePixelRatio() - ratio) >= 0.001) { + return true; + } + } + return false; + }(); + if (corners.p[0].isNull() || mismatch) { corners = PrepareCornerPixmaps(radius, color, shadow); } } @@ -1201,7 +1211,7 @@ void FillComplexOverlayRect( using namespace Images; const auto pix = corners.p; - const auto fillRect = [&](QRect rect) { + const auto fillRect = [&](QRectF rect) { p.fillRect(rect, color); }; if (pix[kTopLeft].isNull() @@ -1212,13 +1222,12 @@ void FillComplexOverlayRect( return; } - const auto ratio = style::DevicePixelRatio(); - const auto fillCorner = [&](int left, int top, int index) { - p.drawPixmap(left, top, pix[index]); + const auto fillCorner = [&](qreal left, qreal top, int index) { + p.drawPixmap(QPointF(left, top), pix[index]); }; const auto cornerSize = [&](int index) { const auto &p = pix[index]; - return p.isNull() ? 0 : p.width() / ratio; + return p.isNull() ? 0. : p.deviceIndependentSize().width(); }; const auto verticalSkip = [&](int left, int right) { return std::max(cornerSize(left), cornerSize(right)); @@ -1230,19 +1239,19 @@ void FillComplexOverlayRect( const auto right = cornerSize(kTopRight); if (left) { fillCorner(rect.left(), rect.top(), kTopLeft); - if (const auto add = top - left) { - fillRect({ rect.left(), rect.top() + left, left, add }); + if (const auto add = top - left; add > 0.) { + fillRect({ qreal(rect.left()), rect.top() + left, left, add }); } } if (const auto fill = rect.width() - left - right; fill > 0) { - fillRect({ rect.left() + left, rect.top(), fill, top }); + fillRect({ rect.left() + left, qreal(rect.top()), fill, top }); } if (right) { fillCorner( rect.left() + rect.width() - right, rect.top(), kTopRight); - if (const auto add = top - right) { + if (const auto add = top - right; add > 0.) { fillRect({ rect.left() + rect.width() - right, rect.top() + right, @@ -1253,7 +1262,7 @@ void FillComplexOverlayRect( } } if (const auto h = rect.height() - top - bottom; h > 0) { - fillRect({ rect.left(), rect.top() + top, rect.width(), h }); + fillRect({ qreal(rect.left()), rect.top() + top, qreal(rect.width()), h }); } if (bottom) { const auto left = cornerSize(kBottomLeft); @@ -1263,9 +1272,9 @@ void FillComplexOverlayRect( rect.left(), rect.top() + rect.height() - left, kBottomLeft); - if (const auto add = bottom - left) { + if (const auto add = bottom - left; add > 0.) { fillRect({ - rect.left(), + qreal(rect.left()), rect.top() + rect.height() - bottom, left, add, @@ -1285,7 +1294,7 @@ void FillComplexOverlayRect( rect.left() + rect.width() - right, rect.top() + rect.height() - right, kBottomRight); - if (const auto add = bottom - right) { + if (const auto add = bottom - right; add > 0.) { fillRect({ rect.left() + rect.width() - right, rect.top() + rect.height() - bottom, diff --git a/Telegram/SourceFiles/ui/chat/chat_theme.cpp b/Telegram/SourceFiles/ui/chat/chat_theme.cpp index a06261eacb58e7..9bc29d5940e98b 100644 --- a/Telegram/SourceFiles/ui/chat/chat_theme.cpp +++ b/Telegram/SourceFiles/ui/chat/chat_theme.cpp @@ -1228,10 +1228,14 @@ ChatThemeBackground PrepareBackgroundImage( && !data.isPattern && data.forDarkMode && data.darkModeDimming > 0) { - const auto ratio = int(prepared.devicePixelRatio()); + const auto ratio = prepared.devicePixelRatio(); auto p = QPainter(&prepared); p.fillRect( - QRect(0, 0, prepared.width() / ratio, prepared.height() / ratio), + QRect( + 0, + 0, + base::SafeRound(prepared.width() / ratio), + base::SafeRound(prepared.height() / ratio)), QColor(0, 0, 0, 255 * data.darkModeDimming / 100)); } const auto imageMonoColor = (data.colors.size() < 2) @@ -1269,10 +1273,10 @@ ChatThemeBackground PrepareBackgroundImage( return QImage(); } const auto ratio = style::DevicePixelRatio(); - const auto esize = Ui::Emoji::GetSizeLarge() / ratio; + const auto esize = base::SafeRound(Ui::Emoji::GetSizeLarge() / ratio); const auto customSize = Ui::Text::AdjustCustomEmojiSize(esize); auto result = QImage( - QSize(customSize, customSize) * ratio, + style::DevicePixels(QSize(customSize, customSize)), QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/ui/chat/chats_filter_tag.cpp b/Telegram/SourceFiles/ui/chat/chats_filter_tag.cpp index 020ffa4b0d9e09..d4bb4a1151b2ba 100644 --- a/Telegram/SourceFiles/ui/chat/chats_filter_tag.cpp +++ b/Telegram/SourceFiles/ui/chat/chats_filter_tag.cpp @@ -87,7 +87,7 @@ void ScaledSimpleEmoji::paint(QPainter &p, const Context &context) { p.end(); _frame = _frame.scaled( - QSize(width(), width()) * ratio, + style::DevicePixels(QSize(width(), width())), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } @@ -126,8 +126,8 @@ void ScaledCustomEmoji::paint(QPainter &p, const Context &context) { } const auto ratio = style::DevicePixelRatio(); const auto large = Emoji::GetSizeLarge(); - const auto largeadjust = Text::AdjustCustomEmojiSize(large / ratio); - const auto size = QSize(largeadjust, largeadjust) * ratio; + const auto largeadjust = Text::AdjustCustomEmojiSize(base::SafeRound(large / ratio)); + const auto size = style::DevicePixels(QSize(largeadjust, largeadjust)); _frame = QImage(size, QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); _frame.fill(Qt::transparent); @@ -142,7 +142,7 @@ void ScaledCustomEmoji::paint(QPainter &p, const Context &context) { const auto smalladjust = Text::AdjustCustomEmojiSize(width()); _frame = _frame.scaled( - QSize(smalladjust, smalladjust) * ratio, + style::DevicePixels(QSize(smalladjust, smalladjust)), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); _wrapped->unload(); diff --git a/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp b/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp index 68d3770400ab8b..f3a8b8166255c0 100644 --- a/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp +++ b/Telegram/SourceFiles/ui/chat/choose_theme_controller.cpp @@ -82,11 +82,13 @@ struct Preview { small = Ui::InvertPatternImage(std::move(small)); } p.drawImage( - QRect(QPoint(), size * style::DevicePixelRatio()), + QRect( + QPoint(), + style::DevicePixels(size)), small); }; auto userpic = QRect(); - const auto fullsize = size * style::DevicePixelRatio(); + const auto fullsize = style::DevicePixels(size); auto result = background.waitingForNegativePattern() ? QImage( fullsize, @@ -121,7 +123,7 @@ struct Preview { p.setPen(Qt::NoPen); if (const auto pattern = theme->bubblesBackgroundPattern()) { auto bubble = pattern->pixmap.toImage().scaled( - sent.size() * style::DevicePixelRatio(), + style::DevicePixels(sent.size()), Qt::IgnoreAspectRatio, Qt::SmoothTransformation ).convertToFormat(QImage::Format_ARGB32_Premultiplied); @@ -159,7 +161,7 @@ struct Preview { [[nodiscard]] QImage GenerateEmptyPreview() { auto result = QImage( - st::chatThemePreviewSize * style::DevicePixelRatio(), + style::DevicePixels(st::chatThemePreviewSize), QImage::Format_ARGB32_Premultiplied); result.fill(st::settingsThemeNotSupportedBg->c); result.setDevicePixelRatio(style::DevicePixelRatio()); @@ -387,7 +389,7 @@ void ChooseThemeController::paintEntry(QPainter &p, const Entry &entry) { const auto size = Ui::Emoji::GetSizeLarge(); const auto factor = style::DevicePixelRatio(); - const auto esize = size / factor; + const auto esize = qRound(size / factor); const auto emojiLeft = geometry.x() + (geometry.width() - esize) / 2; const auto emojiTop = geometry.y() + geometry.height() diff --git a/Telegram/SourceFiles/ui/chat/message_bar.cpp b/Telegram/SourceFiles/ui/chat/message_bar.cpp index 0efe8eaa97d36b..e509aa31926ab4 100644 --- a/Telegram/SourceFiles/ui/chat/message_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/message_bar.cpp @@ -537,10 +537,12 @@ void MessageBar::ensureGradientsCreated(int size) { if (!_topBarGradient.isNull()) { return; } - const auto rows = size * style::DevicePixelRatio() - 2; + const auto pixelHeight = std::max(style::DevicePixels(size), 1); + const auto rows = std::max(pixelHeight - 2, 1); auto bottomMask = QImage( - QSize(1, size) * style::DevicePixelRatio(), + QSize(1, pixelHeight), QImage::Format_ARGB32_Premultiplied); + bottomMask.setDevicePixelRatio(style::DevicePixelRatio()); const auto step = ((1ULL << 24) - 1) / rows; const auto limit = step * rows; auto bits = bottomMask.bits(); diff --git a/Telegram/SourceFiles/ui/controls/chat_service_checkbox.cpp b/Telegram/SourceFiles/ui/controls/chat_service_checkbox.cpp index 5230a26f200732..38e45003db1a16 100644 --- a/Telegram/SourceFiles/ui/controls/chat_service_checkbox.cpp +++ b/Telegram/SourceFiles/ui/controls/chat_service_checkbox.cpp @@ -91,11 +91,12 @@ auto ServiceCheck::Generator::framesForStyle( const auto result = &_data.emplace(st, Frames()).first->second; const auto size = st->diameter; const auto count = (st->duration / kAnimationTimerDelta) + 2; + const auto ratio = style::DevicePixelRatio(); result->image = QImage( - QSize(count * size, size) * style::DevicePixelRatio(), + style::DevicePixels(QSize(count * size, size)), QImage::Format_ARGB32_Premultiplied); result->image.fill(Qt::transparent); - result->image.setDevicePixelRatio(style::DevicePixelRatio()); + result->image.setDevicePixelRatio(ratio); result->ready.resize(count); return result; } diff --git a/Telegram/SourceFiles/ui/controls/filter_link_header.cpp b/Telegram/SourceFiles/ui/controls/filter_link_header.cpp index 2d2c8b9fe1a528..7b675951fa59fa 100644 --- a/Telegram/SourceFiles/ui/controls/filter_link_header.cpp +++ b/Telegram/SourceFiles/ui/controls/filter_link_header.cpp @@ -172,7 +172,7 @@ class Widget final : public RpWidget { const auto size = st::filterLinkPreview; const auto ratio = style::DevicePixelRatio(); const auto radius = st::filterLinkPreviewRadius; - const auto full = QSize(size, size) * ratio; + const auto full = style::DevicePixels(QSize(size, size)); auto &result = state->bg; result = QImage(full, QImage::Format_ARGB32_Premultiplied); result.setDevicePixelRatio(ratio); diff --git a/Telegram/SourceFiles/ui/controls/labeled_emoji_tabs.cpp b/Telegram/SourceFiles/ui/controls/labeled_emoji_tabs.cpp index d60e5a77b6d13c..f0c03a54e9a697 100644 --- a/Telegram/SourceFiles/ui/controls/labeled_emoji_tabs.cpp +++ b/Telegram/SourceFiles/ui/controls/labeled_emoji_tabs.cpp @@ -111,7 +111,7 @@ LabeledEmojiTabs::Button::Button( const auto labelWidth = st::aiComposeStyleLabelFont->width( _descriptor.label); const auto emojiWidth = (_custom || _descriptor.emoji) - ? (Emoji::GetSizeLarge() / style::DevicePixelRatio()) + ? qRound(Emoji::GetSizeLarge() / style::DevicePixelRatio()) : 0; return padding.left() + std::max(labelWidth, emojiWidth) @@ -157,7 +157,7 @@ void LabeledEmojiTabs::Button::paintEvent(QPaintEvent *e) { paintRipple(p, 0, 0, &ripple); if (_custom) { - const auto size = Emoji::GetSizeLarge() / style::DevicePixelRatio(); + const auto size = qRound(Emoji::GetSizeLarge() / style::DevicePixelRatio()); const auto adjusted = Text::AdjustCustomEmojiSize(size); const auto skip = (size - adjusted) / 2; const auto left = (width() - size) / 2; diff --git a/Telegram/SourceFiles/ui/controls/location_picker.cpp b/Telegram/SourceFiles/ui/controls/location_picker.cpp index dd9c20334c5722..10edb5856bb8b4 100644 --- a/Telegram/SourceFiles/ui/controls/location_picker.cpp +++ b/Telegram/SourceFiles/ui/controls/location_picker.cpp @@ -290,7 +290,7 @@ void VenuesController::rowPaintIcon( data.icon = Images::Read({ .content = bytes }).image; if (!data.icon.isNull()) { data.icon = data.icon.scaled( - QSize(inner, inner) * ratio, + style::DevicePixels(QSize(inner, inner)), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); if (!data.icon.isNull()) { @@ -300,7 +300,7 @@ void VenuesController::rowPaintIcon( } } - const auto full = QSize(size, size) * ratio; + const auto full = style::DevicePixels(QSize(size, size)); auto image = (data.image.size() == full) ? base::take(data.image) : QImage(full, QImage::Format_ARGB32_Premultiplied); diff --git a/Telegram/SourceFiles/ui/controls/round_video_recorder.cpp b/Telegram/SourceFiles/ui/controls/round_video_recorder.cpp index 26743e07bfe675..65c56c5592ff2b 100644 --- a/Telegram/SourceFiles/ui/controls/round_video_recorder.cpp +++ b/Telegram/SourceFiles/ui/controls/round_video_recorder.cpp @@ -1189,7 +1189,7 @@ void RoundVideoRecorder::progressTo(float64 progress) { void RoundVideoRecorder::preparePlaceholder(const QImage &placeholder) { const auto ratio = style::DevicePixelRatio(); - const auto full = QSize(_side, _side) * ratio; + const auto full = style::DevicePixels(QSize(_side, _side)); _framePlaceholder = Images::Circle( (placeholder.isNull() ? QImage(u":/gui/art/round_placeholder.jpg"_q) @@ -1238,7 +1238,7 @@ void RoundVideoRecorder::prepareFrame(bool blurred) { _placeholderUpdates.fire(std::move(image)); } else { auto scaled = copy.scaled( - QSize(_side, _side) * ratio, + style::DevicePixels(QSize(_side, _side)), Qt::KeepAspectRatio, Qt::SmoothTransformation).mirrored(true, false); _framePrepared = Images::Circle(std::move(scaled)); @@ -1252,7 +1252,7 @@ void RoundVideoRecorder::createImages() { const auto side = _side + 2 * _extent; _shadow = QImage( - QSize(side, side) * ratio, + style::DevicePixels(QSize(side, side)), QImage::Format_ARGB32_Premultiplied); _shadow.fill(Qt::transparent); _shadow.setDevicePixelRatio(ratio); diff --git a/Telegram/SourceFiles/ui/controls/tabbed_search.cpp b/Telegram/SourceFiles/ui/controls/tabbed_search.cpp index 55b9edd481beeb..e2f9ecd66dae53 100644 --- a/Telegram/SourceFiles/ui/controls/tabbed_search.cpp +++ b/Telegram/SourceFiles/ui/controls/tabbed_search.cpp @@ -54,11 +54,14 @@ class GroupsStrip final : public RpWidget { void init(rpl::producer> groups); void set(std::vector list); + [[nodiscard]] std::unique_ptr makeIcon( + const QString &iconId); void paintEvent(QPaintEvent *e) override; void mouseMoveEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override; void mouseReleaseEvent(QMouseEvent *e) override; + void devicePixelRatioChangedEvent() override; void fireChosenGroup(); @@ -126,32 +129,15 @@ void GroupsStrip::set(std::vector list) { ? _buttons[_chosen].group.iconId : QString(); auto existing = std::move(_buttons); - const auto updater = [=](const QString &iconId) { - return [=] { - const auto i = FindById(_buttons, iconId); - if (i != end(_buttons)) { - const auto index = i - begin(_buttons); - const auto single = _st.groupWidth; - update(index * single, 0, single, height()); - } - }; - }; for (auto &group : list) { const auto i = FindById(existing, group.iconId); if (i != end(existing)) { _buttons.push_back(std::move(*i)); existing.erase(i); } else { - const auto loopCount = 1; - const auto stopAtLastFrame = true; _buttons.push_back({ .iconId = group.iconId, - .icon = std::make_unique( - _factory( - group.iconId, - { .repaint = updater(group.iconId) }), - loopCount, - stopAtLastFrame), + .icon = makeIcon(group.iconId), }); } _buttons.back().group = std::move(group); @@ -169,6 +155,24 @@ void GroupsStrip::set(std::vector list) { update(); } +std::unique_ptr GroupsStrip::makeIcon( + const QString &iconId) { + const auto updater = [=] { + const auto i = FindById(_buttons, iconId); + if (i != end(_buttons)) { + const auto index = i - begin(_buttons); + const auto single = _st.groupWidth; + update(index * single, 0, single, height()); + } + }; + const auto loopCount = 1; + const auto stopAtLastFrame = true; + return std::make_unique( + _factory(iconId, { .repaint = updater }), + loopCount, + stopAtLastFrame); +} + void GroupsStrip::paintEvent(QPaintEvent *e) { auto p = QPainter(this); auto index = 0; @@ -262,6 +266,16 @@ void GroupsStrip::mouseReleaseEvent(QMouseEvent *e) { } } +void GroupsStrip::devicePixelRatioChangedEvent() { + for (auto &button : _buttons) { + if (button.icon) { + button.icon->unload(); + button.icon = makeIcon(button.iconId); + } + } + update(); +} + void GroupsStrip::fireChosenGroup() { Expects(_chosen >= 0 && _chosen < _buttons.size()); @@ -529,6 +543,20 @@ void SearchWithGroups::ensureRounding(int size, float64 ratio) { _rounding.setDevicePixelRatio(ratio); } +void SearchWithGroups::devicePixelRatioChangedEvent() { + _rounding = QImage(); + _search->entity()->update(); + _search->update(); + _back->entity()->update(); + _back->update(); + _cancel->update(); + _field->update(); + _groups->entity()->update(); + _groups->update(); + _fade->update(); + update(); +} + rpl::producer<> SearchWithGroups::escapes() const { return _field->cancelled(); } diff --git a/Telegram/SourceFiles/ui/controls/tabbed_search.h b/Telegram/SourceFiles/ui/controls/tabbed_search.h index 2a5d67e40e8d28..a3782c6b45a87e 100644 --- a/Telegram/SourceFiles/ui/controls/tabbed_search.h +++ b/Telegram/SourceFiles/ui/controls/tabbed_search.h @@ -74,6 +74,7 @@ class SearchWithGroups final : public RpWidget { private: int resizeGetHeight(int newWidth) override; void wheelEvent(QWheelEvent *e) override; + void devicePixelRatioChangedEvent() override; [[nodiscard]] int clampGroupsLeft(int width, int desiredLeft) const; void moveGroupsBy(int width, int delta); diff --git a/Telegram/SourceFiles/ui/controls/userpic_button.cpp b/Telegram/SourceFiles/ui/controls/userpic_button.cpp index b114c15cfe6b99..dc5a2a395fa52a 100644 --- a/Telegram/SourceFiles/ui/controls/userpic_button.cpp +++ b/Telegram/SourceFiles/ui/controls/userpic_button.cpp @@ -121,9 +121,10 @@ void CameraBox( template QPixmap CreateSquarePixmap(int width, Callback &&paintCallback) { - const auto size = QSize(width, width) * style::DevicePixelRatio(); + const auto ratio = style::DevicePixelRatio(); + const auto size = style::DevicePixels(QSize(width, width)); auto image = QImage(size, QImage::Format_ARGB32_Premultiplied); - image.setDevicePixelRatio(style::DevicePixelRatio()); + image.setDevicePixelRatio(ratio); image.fill(Qt::transparent); { Painter p(&image); @@ -1226,9 +1227,8 @@ void UserpicButton::prepareUserpicPixmap() { } else if (_nonPersonalView) { using Size = Data::PhotoSize; if (const auto full = _nonPersonalView->image(Size::Large)) { - const auto ratio = style::DevicePixelRatio(); auto image = full->original().scaled( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); image = useForumShape() diff --git a/Telegram/SourceFiles/ui/controls/who_reacted_context_action.cpp b/Telegram/SourceFiles/ui/controls/who_reacted_context_action.cpp index c0aa82fd188a69..9a9ac760338207 100644 --- a/Telegram/SourceFiles/ui/controls/who_reacted_context_action.cpp +++ b/Telegram/SourceFiles/ui/controls/who_reacted_context_action.cpp @@ -802,7 +802,10 @@ void WhoReactedEntryAction::setData(Data &&data) { const auto goodWidth = st::defaultWhoRead.nameLeft + textWidth + rightSkip; - const auto w = std::clamp(goodWidth, _st.widthMin, _st.widthMax); + const auto w = std::clamp( + qRound(goodWidth), + _st.widthMin, + _st.widthMax); _textWidth = w - (goodWidth - textWidth); setMinWidth(w); update(); diff --git a/Telegram/SourceFiles/ui/dynamic_thumbnails.cpp b/Telegram/SourceFiles/ui/dynamic_thumbnails.cpp index b6a6514ead1f82..f5e283ffcc9523 100644 --- a/Telegram/SourceFiles/ui/dynamic_thumbnails.cpp +++ b/Telegram/SourceFiles/ui/dynamic_thumbnails.cpp @@ -309,7 +309,8 @@ std::shared_ptr PeerUserpic::clone() { QImage PeerUserpic::image(int size) { Expects(_subscribed != nullptr); - const auto good = (_frame.width() == size * _frame.devicePixelRatio()); + const auto expected = style::DevicePixels(size); + const auto good = (_frame.width() == expected); const auto key = _peer->userpicUniqueKey(_subscribed->view); const auto paletteVersion = style::PaletteVersion(); if (!good @@ -322,7 +323,7 @@ QImage PeerUserpic::image(int size) { const auto ratio = style::DevicePixelRatio(); if (!good) { _frame = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); } @@ -392,10 +393,11 @@ MediaThumbnail::MediaThumbnail( QImage MediaThumbnail::image(int size) { const auto ratio = style::DevicePixelRatio(); - if (_prepared.width() != size * ratio) { + const auto expected = style::DevicePixels(size); + if (_prepared.width() != expected) { if (_full.isNull()) { _prepared = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _prepared.fill(Qt::black); } else { @@ -411,7 +413,7 @@ QImage MediaThumbnail::image(int size) { source = QRect(0, skip, width, width); } _prepared = _full.copy(source).scaled( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } @@ -545,7 +547,7 @@ std::shared_ptr CallThumbnail::clone() { QImage CallThumbnail::image(int size) { const auto ratio = style::DevicePixelRatio(); - const auto full = QSize(size, size) * ratio; + const auto full = style::DevicePixels(QSize(size, size)); if (_prepared.size() != full) { _prepared = QImage(full, QImage::Format_ARGB32_Premultiplied); _prepared.fill(Qt::black); @@ -567,7 +569,7 @@ QImage EmptyThumbnail::image(int size) { const auto ratio = style::DevicePixelRatio(); if (_cached.width() != size * ratio) { _cached = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _cached.fill(Qt::black); _cached.setDevicePixelRatio(ratio); @@ -591,7 +593,7 @@ QImage SavedMessagesUserpic::image(int size) { const auto ratio = style::DevicePixelRatio(); if (!good) { _frame = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); } @@ -622,7 +624,7 @@ QImage RepliesUserpic::image(int size) { const auto ratio = style::DevicePixelRatio(); if (!good) { _frame = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); } @@ -653,7 +655,7 @@ QImage HiddenAuthorUserpic::image(int size) { const auto ratio = style::DevicePixelRatio(); if (!good) { _frame = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); } @@ -687,7 +689,7 @@ QImage IconThumbnail::image(int size) { const auto ratio = style::DevicePixelRatio(); if (!good) { _frame = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); } @@ -752,7 +754,7 @@ QImage EmojiThumbnail::image(int size) { const auto good = (_frame.width() == size * _frame.devicePixelRatio()); if (!good) { _frame = QImage( - QSize(size, size) * ratio, + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); } diff --git a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp index abf7a7965a446f..9c6449e745473b 100644 --- a/Telegram/SourceFiles/ui/effects/credits_graphics.cpp +++ b/Telegram/SourceFiles/ui/effects/credits_graphics.cpp @@ -59,7 +59,7 @@ PaintRoundImageCallback MultiThumbnail( } const auto smaller = size - shift; const auto ratio = style::DevicePixelRatio(); - const auto full = QSize(size, size) * ratio; + const auto full = style::DevicePixels(QSize(size, size)); if (cache->size() != full) { *cache = QImage(full, QImage::Format_ARGB32_Premultiplied); cache->setDevicePixelRatio(ratio); @@ -468,7 +468,7 @@ PaintRoundImageCallback GeneratePaidPhotoPaintCallback( const auto media = photo->createMediaView(); const auto thumbnail = media->thumbnailInline(); const auto ratio = style::DevicePixelRatio(); - const auto scaled = QSize(size, size) * ratio; + const auto scaled = style::DevicePixels(QSize(size, size)); auto image = thumbnail ? Images::Blur(thumbnail->original(), true) : QImage(scaled, QImage::Format_ARGB32_Premultiplied); diff --git a/Telegram/SourceFiles/ui/effects/premium_graphics.cpp b/Telegram/SourceFiles/ui/effects/premium_graphics.cpp index cb967aab2cfbe9..d1d4a4ecbbc524 100644 --- a/Telegram/SourceFiles/ui/effects/premium_graphics.cpp +++ b/Telegram/SourceFiles/ui/effects/premium_graphics.cpp @@ -347,8 +347,9 @@ void Line::recache(const QSize &s) { return QRect(0, 0, width, s.height()); }; const auto pixmap = [&](int width) { - auto result = QPixmap(r(width).size() * style::DevicePixelRatio()); - result.setDevicePixelRatio(style::DevicePixelRatio()); + const auto ratio = style::DevicePixelRatio(); + auto result = QPixmap(style::DevicePixels(QSize(r(width).width(), r(width).height()))); + result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); return result; }; @@ -549,8 +550,9 @@ void AddAccountsRow( + QSize( padding.left() + padding.right(), padding.top() + padding.bottom()); - auto badge = QPixmap(size * style::DevicePixelRatio()); - badge.setDevicePixelRatio(style::DevicePixelRatio()); + const auto ratio = style::DevicePixelRatio(); + auto badge = QPixmap(style::DevicePixels(size)); + badge.setDevicePixelRatio(ratio); badge.fill(Qt::transparent); auto p = QPainter(&badge); diff --git a/Telegram/SourceFiles/ui/effects/premium_stars_colored.cpp b/Telegram/SourceFiles/ui/effects/premium_stars_colored.cpp index 73d76ef4efc762..5490c31cbb9648 100644 --- a/Telegram/SourceFiles/ui/effects/premium_stars_colored.cpp +++ b/Telegram/SourceFiles/ui/effects/premium_stars_colored.cpp @@ -156,7 +156,7 @@ void CollectibleEmoji::prepareFrame() { const auto clip = QSize(_size, _size); if (_frame.isNull()) { const auto ratio = style::DevicePixelRatio(); - _frame = QImage(clip * ratio, QImage::Format_ARGB32_Premultiplied); + _frame = QImage(style::DevicePixels(clip), QImage::Format_ARGB32_Premultiplied); _frame.setDevicePixelRatio(ratio); } _frame.fill(Qt::transparent); diff --git a/Telegram/SourceFiles/ui/effects/round_checkbox.cpp b/Telegram/SourceFiles/ui/effects/round_checkbox.cpp index ff426e0e9aaa22..6f16082a577dd6 100644 --- a/Telegram/SourceFiles/ui/effects/round_checkbox.cpp +++ b/Telegram/SourceFiles/ui/effects/round_checkbox.cpp @@ -73,10 +73,11 @@ class CheckCaches : public QObject { QPixmap PrepareOuterWide(const style::RoundCheckbox *st) { const auto size = st->size; const auto wideSize = size * kWideScale; + const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(wideSize, wideSize) * style::DevicePixelRatio(), + style::DevicePixels(QSize(wideSize, wideSize)), QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(style::DevicePixelRatio()); + result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); { auto p = QPainter(&result); @@ -96,10 +97,11 @@ QPixmap PrepareOuterWide(const style::RoundCheckbox *st) { QPixmap PrepareInner(const style::RoundCheckbox *st, bool displayInactive) { const auto size = st->size; + const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(size, size) * style::DevicePixelRatio(), + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(style::DevicePixelRatio()); + result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); { auto p = QPainter(&result); @@ -119,10 +121,11 @@ QPixmap PrepareInner(const style::RoundCheckbox *st, bool displayInactive) { QPixmap PrepareCheck(const style::RoundCheckbox *st) { const auto size = st->size; + const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(size, size) * style::DevicePixelRatio(), + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(style::DevicePixelRatio()); + result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); { auto p = QPainter(&result); @@ -199,8 +202,10 @@ QPixmap CheckCaches::paintFrame( const auto size = st->size; const auto wideSize = size * kWideScale; const auto skip = (wideSize - size) / 2; - auto result = QImage(wideSize * style::DevicePixelRatio(), wideSize * style::DevicePixelRatio(), QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(style::DevicePixelRatio()); + const auto ratio = style::DevicePixelRatio(); + auto result = QImage( + style::DevicePixels(QSize(wideSize,wideSize)), QImage::Format_ARGB32_Premultiplied); + result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); const auto roundProgress = (progress >= st->bgDuration) @@ -218,9 +223,8 @@ QPixmap CheckCaches::paintFrame( const auto outerScale = roundProgress + (1. - roundProgress) * outerMaxScale; const auto outerTo = WideDestRect(st, skip, skip, outerScale); - const auto outerFrom = QRect( - QPoint(0, 0), - QSize(wideSize, wideSize) * style::DevicePixelRatio()); + const auto outerFrom = QRect(QPoint(0, 0), + style::DevicePixels(QSize(wideSize, wideSize))); p.drawPixmap(outerTo, frames.outerWide, outerFrom); } p.drawPixmap(skip, skip, frames.inner); @@ -229,7 +233,7 @@ QPixmap CheckCaches::paintFrame( const auto checkTo = QRect(skip, skip, divider, st->size); const auto checkFrom = QRect( QPoint(0, 0), - QSize(divider, st->size) * style::DevicePixelRatio()); + style::DevicePixels(QSize(divider, st->size))); p.drawPixmap(checkTo, frames.check, checkFrom); p.setCompositionMode(QPainter::CompositionMode_Source); @@ -271,7 +275,7 @@ void RoundCheckbox::paint(QPainter &p, int x, int y, int outerWidth, float64 mas return; } - auto cacheSize = kWideScale * _st.size * style::DevicePixelRatio(); + auto cacheSize = style::DevicePixels(kWideScale * _st.size); auto cacheFrom = QRect(0, 0, cacheSize, cacheSize); auto inactiveTo = WideDestRect(&_st, x, y, masterScale); @@ -336,8 +340,10 @@ void RoundCheckbox::prepareInactiveCache() { auto wideSize = _st.size * kWideScale; auto ellipse = QRect((wideSize - _st.size) / 2, (wideSize - _st.size) / 2, _st.size, _st.size); - auto cacheBg = QImage(wideSize * style::DevicePixelRatio(), wideSize * style::DevicePixelRatio(), QImage::Format_ARGB32_Premultiplied); - cacheBg.setDevicePixelRatio(style::DevicePixelRatio()); + const auto ratio = style::DevicePixelRatio(); + auto cacheBg = QImage( + style::DevicePixels(QSize(wideSize, wideSize)), QImage::Format_ARGB32_Premultiplied); + cacheBg.setDevicePixelRatio(ratio); cacheBg.fill(Qt::transparent); auto cacheFg = cacheBg; if (_st.bgInactive) { @@ -385,15 +391,14 @@ void RoundImageCheckbox::paint( int y, int outerWidth) const { if (_liveBadge) { - const auto ratio = style::DevicePixelRatio(); const auto added = _st.selectWidth; const auto cacheSize = (added + _st.imageRadius) * 2; - const auto fullCacheSize = cacheSize * ratio; - if (_liveBadgeCache.width() != fullCacheSize) { + const auto fullCacheSize = style::DevicePixels(QSize(cacheSize, cacheSize)); + if (_liveBadgeCache.width() != fullCacheSize.width()) { _liveBadgeCache = QImage( - QSize(fullCacheSize, fullCacheSize), + fullCacheSize, QImage::Format_ARGB32_Premultiplied); - _liveBadgeCache.setDevicePixelRatio(ratio); + _liveBadgeCache.setDevicePixelRatio(style::DevicePixelRatio()); } _liveBadgeCache.fill(Qt::transparent); auto q = Painter(&_liveBadgeCache); diff --git a/Telegram/SourceFiles/ui/empty_userpic.cpp b/Telegram/SourceFiles/ui/empty_userpic.cpp index e731062b677979..8d02c9fc407f1e 100644 --- a/Telegram/SourceFiles/ui/empty_userpic.cpp +++ b/Telegram/SourceFiles/ui/empty_userpic.cpp @@ -243,10 +243,11 @@ void PaintInaccessibleAccountInner( } [[nodiscard]] QImage Generate(int size, Fn callback) { + const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(size, size) * style::DevicePixelRatio(), + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(style::DevicePixelRatio()); + result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); { Painter p(&result); @@ -585,10 +586,11 @@ std::pair EmptyUserpic::uniqueKey() const { } QPixmap EmptyUserpic::generate(int size) { + const auto ratio = style::DevicePixelRatio(); auto result = QImage( - QSize(size, size) * style::DevicePixelRatio(), + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); - result.setDevicePixelRatio(style::DevicePixelRatio()); + result.setDevicePixelRatio(ratio); result.fill(Qt::transparent); { auto p = QPainter(&result); diff --git a/Telegram/SourceFiles/ui/filter_icon_panel.cpp b/Telegram/SourceFiles/ui/filter_icon_panel.cpp index 031146c127af07..6e763ee47f5e1b 100644 --- a/Telegram/SourceFiles/ui/filter_icon_panel.cpp +++ b/Telegram/SourceFiles/ui/filter_icon_panel.cpp @@ -376,9 +376,7 @@ void FilterIconPanel::startShowAnimation() { auto inner = rect().marginsRemoved(st::emojiPanMargins); _showAnimation->setFinalImage( std::move(image), - QRect( - inner.topLeft() * style::DevicePixelRatio(), - inner.size() * style::DevicePixelRatio()), + style::DevicePixels(inner), st::emojiPanRadius); _showAnimation->setCornerMasks(Images::CornersMask(ImageRoundRadius::Small)); _showAnimation->start(); diff --git a/Telegram/SourceFiles/ui/image/image.cpp b/Telegram/SourceFiles/ui/image/image.cpp index 1ef41f67a6c1d5..afb43f9b07a755 100644 --- a/Telegram/SourceFiles/ui/image/image.cpp +++ b/Telegram/SourceFiles/ui/image/image.cpp @@ -11,12 +11,12 @@ For license and copyright information please follow this link: #include "data/data_session.h" #include "main/main_session.h" #include "ui/ui_utility.h" - using namespace Images; namespace Images { namespace { + [[nodiscard]] uint64 PixKey(int width, int height, Options options) { return static_cast(width) | (static_cast(height) << 24) @@ -58,7 +58,7 @@ Image::Image(QImage &&data) not_null Image::Empty() { static auto result = Image([] { - const auto factor = style::DevicePixelRatio(); + const auto factor = style::DevicePixels(1); auto data = QImage( factor, factor, @@ -72,7 +72,7 @@ not_null Image::Empty() { not_null Image::BlankMedia() { static auto result = Image([] { - const auto factor = style::DevicePixelRatio(); + const auto factor = style::DevicePixels(1); auto data = QImage( factor, factor, @@ -93,18 +93,17 @@ const QPixmap &Image::cached( int h, const Images::PrepareArgs &args, bool single) const { - const auto ratio = style::DevicePixelRatio(); if (w <= 0 || !width() || !height()) { w = width(); } else if (h <= 0) { - h = std::max(int(int64(height()) * w / width()), 1) * ratio; - w *= ratio; + h = style::DevicePixels(std::max(int(int64(height()) * w / width()), 1)); + w = style::DevicePixels(w); } else { - w *= ratio; - h *= ratio; + w = style::DevicePixels(w); + h = style::DevicePixels(h); } const auto outer = args.outer; - const auto size = outer.isEmpty() ? QSize(w, h) : outer * ratio; + const auto size = outer.isEmpty() ? QSize(w, h) : style::DevicePixels(outer); const auto k = single ? SinglePixKey(args) : PixKey(w, h, args); const auto i = _cache.find(k); return (i != _cache.cend() && i->second.size() == size) @@ -126,8 +125,8 @@ QPixmap Image::prepare(int w, int h, const Images::PrepareArgs &args) const { } const auto ratio = style::DevicePixelRatio(); - const auto outerw = outer.width() * ratio; - const auto outerh = outer.height() * ratio; + const auto outerw = style::DevicePixels(outer.width()); + const auto outerh = style::DevicePixels(outer.height()); auto result = QImage( QSize(outerw, outerh), diff --git a/Telegram/SourceFiles/ui/top_background_gradient.cpp b/Telegram/SourceFiles/ui/top_background_gradient.cpp index ac39872dc7dcde..4f65213b342e08 100644 --- a/Telegram/SourceFiles/ui/top_background_gradient.cpp +++ b/Telegram/SourceFiles/ui/top_background_gradient.cpp @@ -36,7 +36,7 @@ void PrepareImage( const auto ratio = style::DevicePixelRatio(); const auto size = Emoji::GetSizeNormal() / ratio; image = QImage( - 2 * QSize(size, size) * ratio, + 2 * style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(ratio); image.fill(Qt::transparent); @@ -65,7 +65,7 @@ QImage CreateTopBgGradient( bool rounded, QPoint offset) { const auto ratio = style::DevicePixelRatio(); - auto result = QImage(size * ratio, QImage::Format_ARGB32_Premultiplied); + auto result = QImage(style::DevicePixels(size), QImage::Format_ARGB32_Premultiplied); if (!rounded) { result.fill(Qt::transparent); } diff --git a/Telegram/SourceFiles/ui/unread_badge_paint.cpp b/Telegram/SourceFiles/ui/unread_badge_paint.cpp index df0e6ac01ed2e1..2d4aed80876293 100644 --- a/Telegram/SourceFiles/ui/unread_badge_paint.cpp +++ b/Telegram/SourceFiles/ui/unread_badge_paint.cpp @@ -8,20 +8,14 @@ For license and copyright information please follow this link: #include "ui/unread_badge_paint.h" #include "ui/ui_utility.h" +#include "ui/painter.h" #include "styles/style_dialogs.h" namespace Ui { namespace { -struct UnreadBadgeSizeData { - QImage circle; - QPixmap left[6], right[6]; -}; class UnreadBadgeStyleData { public: - UnreadBadgeStyleData(); - - UnreadBadgeSizeData sizes[static_cast(UnreadBadgeSize::kCount)]; style::color bg[6] = { st::dialogsUnreadBg, st::dialogsUnreadBgOver, @@ -69,7 +63,8 @@ UnreadBadgeStyleData &UnreadBadgeStyles() { } void CreateCircleMask(UnreadBadgeSizeData *data, int size) { - if (!data->circle.isNull()) { + if (!data->circle.isNull() + && qAbs(data->circle.devicePixelRatio() - style::DevicePixelRatio()) < 0.001) { return; } data->circle = style::createCircleMask(size); @@ -98,8 +93,7 @@ void PaintUnreadBadge(QPainter &p, const QRect &rect, const UnreadBadgeStyle &st Assert(rect.height() == st.size); int index = (st.muted ? 0x03 : 0x00) + (st.active ? 0x02 : (st.selected ? 0x01 : 0x00)); - int size = st.size, sizehalf = size / 2; - + int size = st.size; auto &styles = UnreadBadgeStyles(); auto badgeData = styles.sizes; if (st.sizeId > UnreadBadgeSize()) { @@ -111,9 +105,12 @@ void PaintUnreadBadge(QPainter &p, const QRect &rect, const UnreadBadgeStyle &st : (st.sizeId == UnreadBadgeSize::PollInDialogs) ? styles.pollBg[index] : styles.bg[index]; - if (badgeData->left[index].isNull()) { - const auto ratio = style::DevicePixelRatio(); - int imgsize = size * ratio, imgsizehalf = sizehalf * ratio; + if (badgeData->left[index].isNull() + || qAbs( + badgeData->left[index].devicePixelRatio() + - style::DevicePixelRatio()) >= 0.001) { + const auto imgsize = style::DevicePixels(size); + const auto imgsizehalf = style::DevicePixels(sizehalf); CreateCircleMask(badgeData, size); badgeData->left[index] = PixmapFromImage( ColorizeCircleHalf(badgeData, imgsize, imgsizehalf, 0, bg)); diff --git a/Telegram/SourceFiles/ui/widgets/color_editor.cpp b/Telegram/SourceFiles/ui/widgets/color_editor.cpp index 78a0e06d4cc484..8bc2c801007fab 100644 --- a/Telegram/SourceFiles/ui/widgets/color_editor.cpp +++ b/Telegram/SourceFiles/ui/widgets/color_editor.cpp @@ -71,10 +71,11 @@ QCursor ColorEditor::Picker::generateCursor() { const auto line = style::ConvertScale(1); const auto size = ((diameter + 2 * line) >= 32) ? 64 : 32; const auto diff = (size - diameter) / 2; + const auto ratio = style::DevicePixelRatio(); auto cursor = QImage( - QSize(size, size) * style::DevicePixelRatio(), + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); - cursor.setDevicePixelRatio(style::DevicePixelRatio()); + cursor.setDevicePixelRatio(ratio); cursor.fill(Qt::transparent); { auto p = QPainter(&cursor); @@ -437,11 +438,12 @@ void ColorEditor::Slider::mouseReleaseEvent(QMouseEvent *e) { } void ColorEditor::Slider::generatePixmap() { - const auto size = (isHorizontal() ? width() : height()) - * style::DevicePixelRatio(); + const auto deviceRatio = std::max(1, qRound(style::DevicePixelRatio())); + const auto size = qRound((isHorizontal() ? width() : height()) + * style::DevicePixelRatio()); auto image = QImage( size, - style::DevicePixelRatio(), + deviceRatio, QImage::Format_ARGB32_Premultiplied); image.setDevicePixelRatio(style::DevicePixelRatio()); auto ints = reinterpret_cast(image.bits()); @@ -456,7 +458,7 @@ void ColorEditor::Slider::generatePixmap() { for (auto x = 0; x != size; ++x) { const auto color = QColor::fromHsv(x * 360 / size, 255, 255); const auto value = anim::getPremultiplied(color.toRgb()); - for (auto y = 0; y != style::DevicePixelRatio(); ++y) { + for (auto y = 0; y != deviceRatio; ++y) { ints[y * intsPerLine] = value; } ++ints; @@ -469,7 +471,7 @@ void ColorEditor::Slider::generatePixmap() { } else if (_type == Type::Opacity) { auto color = anim::shifted(QColor(255, 255, 255, 255)); auto transparent = anim::shifted(QColor(255, 255, 255, 0)); - for (auto y = 0; y != style::DevicePixelRatio(); ++y) { + for (auto y = 0; y != deviceRatio; ++y) { auto xAccumulated = 0; for (auto x = 0; x != size; ++x, xAccumulated += part) { const auto xRatio = xAccumulated >> (kLargeBit - 8); diff --git a/Telegram/SourceFiles/ui/widgets/gradient_round_button.cpp b/Telegram/SourceFiles/ui/widgets/gradient_round_button.cpp index 7ce0953dc72bed..772e59202133f2 100644 --- a/Telegram/SourceFiles/ui/widgets/gradient_round_button.cpp +++ b/Telegram/SourceFiles/ui/widgets/gradient_round_button.cpp @@ -58,10 +58,11 @@ void GradientButton::paintGlare(QPainter &p) { if (x > edgeWidth && x < (width() - edgeWidth)) { p.drawTiledPixmap(x, 0, _glare.width, h, _glare.pixmap, 0, 0); } else { + const auto ratio = style::DevicePixelRatio(); auto frame = QImage( - QSize(_glare.width, h) * style::DevicePixelRatio(), + style::DevicePixels(QSize(_glare.width, h)), QImage::Format_ARGB32_Premultiplied); - frame.setDevicePixelRatio(style::DevicePixelRatio()); + frame.setDevicePixelRatio(ratio); frame.fill(Qt::transparent); { diff --git a/Telegram/SourceFiles/ui/widgets/middle_click_autoscroll.cpp b/Telegram/SourceFiles/ui/widgets/middle_click_autoscroll.cpp index fb8c2b89b6c500..2ad92ef9d79b40 100644 --- a/Telegram/SourceFiles/ui/widgets/middle_click_autoscroll.cpp +++ b/Telegram/SourceFiles/ui/widgets/middle_click_autoscroll.cpp @@ -160,7 +160,7 @@ QCursor MiddleClickAutoscroll::makeCursor(CursorMode mode) { struct CachedCursor { CursorMode mode = CursorMode::Neutral; int size = 0; - int factor = 0; + qreal factor = 0; QColor inner; QColor indicator; QCursor cursor; diff --git a/Telegram/SourceFiles/ui/widgets/multi_select.cpp b/Telegram/SourceFiles/ui/widgets/multi_select.cpp index 33f4b8e382e99d..d2f61ada7116ce 100644 --- a/Telegram/SourceFiles/ui/widgets/multi_select.cpp +++ b/Telegram/SourceFiles/ui/widgets/multi_select.cpp @@ -368,11 +368,10 @@ void Item::prepareCache() { if (!_cache.isNull()) return; Assert(!_visibility.animating()); - auto cacheWidth = _width * kWideScale * style::DevicePixelRatio(); - auto cacheHeight = _st.height * kWideScale * style::DevicePixelRatio(); + auto cacheWidth = style::DevicePixels(_width * kWideScale); auto data = QImage( cacheWidth, - cacheHeight, + style::DevicePixels(_st.height * kWideScale), QImage::Format_ARGB32_Premultiplied); data.fill(Qt::transparent); data.setDevicePixelRatio(style::DevicePixelRatio()); diff --git a/Telegram/SourceFiles/window/section_widget.cpp b/Telegram/SourceFiles/window/section_widget.cpp index b417c4a2bbabc3..178f50b0ae4263 100644 --- a/Telegram/SourceFiles/window/section_widget.cpp +++ b/Telegram/SourceFiles/window/section_widget.cpp @@ -30,7 +30,6 @@ For license and copyright information please follow this link: #include "window/window_slide_animation.h" #include "window/window_session_controller.h" #include "window/themes/window_theme.h" - #include namespace Window { diff --git a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp index 3c050bd5b68a3f..7129c3df163227 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_editor_box.cpp @@ -155,10 +155,11 @@ int BackgroundSelector::resizeGetHeight(int newWidth) { void BackgroundSelector::updateThumbnail() { const auto size = _thumbnailSize; + const auto ratio = style::DevicePixelRatio(); auto back = QImage( - QSize(size, size) * style::DevicePixelRatio(), + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); - back.setDevicePixelRatio(style::DevicePixelRatio()); + back.setDevicePixelRatio(ratio); { Painter p(&back); PainterHighQualityEnabler hq(p); diff --git a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp index 0130e318a07ccb..3732a8c02c0f88 100644 --- a/Telegram/SourceFiles/window/themes/window_theme_preview.cpp +++ b/Telegram/SourceFiles/window/themes/window_theme_preview.cpp @@ -1039,10 +1039,11 @@ void Generator::paintUserpic(int x, int y, Row::Type type, int index, QString le auto userpic = Ui::EmptyUserpic(colors, letters); const auto size = st::defaultDialogRow.photoSize; + const auto ratio = style::DevicePixelRatio(); auto image = QImage( - QSize(size, size) * style::DevicePixelRatio(), + style::DevicePixels(QSize(size, size)), QImage::Format_ARGB32_Premultiplied); - image.setDevicePixelRatio(style::DevicePixelRatio()); + image.setDevicePixelRatio(ratio); image.fill(Qt::transparent); { Painter p(&image); @@ -1175,10 +1176,13 @@ void DefaultPreviewWindowFramePaint(QImage &preview, const style::palette &palet currentInt = *lastLineInts; ++maxSize; } - if (maxSize % style::DevicePixelRatio()) { - maxSize -= (maxSize % style::DevicePixelRatio()); + const auto ratio = std::max( + 1, + int(base::SafeRound(style::DevicePixelRatio()))); + if (maxSize % ratio) { + maxSize -= (maxSize % ratio); } - auto size = maxSize / style::DevicePixelRatio(); + auto size = maxSize / ratio; auto bottom = size; auto left = size - st::windowShadowShift; auto right = left; diff --git a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp index 245c4f102c1907..446d2243bb487c 100644 --- a/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp +++ b/Telegram/SourceFiles/window/themes/window_themes_cloud_list.cpp @@ -130,7 +130,9 @@ CloudListColors ColorsFromScheme(const EmbeddedScheme &scheme) { result.radiobuttonActive = scheme.radiobuttonActive; result.radiobuttonInactive = scheme.radiobuttonInactive; result.background = QImage( - QSize(1, 1) * style::DevicePixelRatio(), + QSize( + qRound(style::DevicePixelRatio()), + qRound(style::DevicePixelRatio())), QImage::Format_ARGB32_Premultiplied); result.background.fill(scheme.background); return result; @@ -183,9 +185,7 @@ void CloudListCheck::ensureContrast() { const auto y = getSize().height() - radio.height() - st::settingsThemeRadioBottom; - const auto under = QRect( - QPoint(x, y) * style::DevicePixelRatio(), - radio * style::DevicePixelRatio()); + const auto under = style::DevicePixels(QRect(QPoint(x, y), radio)); const auto image = _backgroundFull.copy(under).convertToFormat( QImage::Format_ARGB32_Premultiplied); const auto active = style::internal::EnsureContrast( diff --git a/Telegram/SourceFiles/window/window_media_preview.cpp b/Telegram/SourceFiles/window/window_media_preview.cpp index e81ece340a79b0..28f20f5fda4c8a 100644 --- a/Telegram/SourceFiles/window/window_media_preview.cpp +++ b/Telegram/SourceFiles/window/window_media_preview.cpp @@ -43,7 +43,7 @@ MediaPreviewWidget::MediaPreviewWidget( not_null controller) : RpWidget(parent) , _controller(controller) -, _emojiSize(Ui::Emoji::GetSizeLarge() / style::DevicePixelRatio()) { +, _emojiSize(style::LogicalPixels(Ui::Emoji::GetSizeLarge())) { setAttribute(Qt::WA_TransparentForMouseEvents); _controller->session().downloaderTaskFinished( ) | rpl::on_next([=] { @@ -92,14 +92,14 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) { const auto dimensions = currentDimensions(); const auto frame = (_lottie && _lottie->ready()) ? _lottie->frameInfo({ - .box = dimensions * factor, + .box = style::DevicePixels(dimensions), .colored = ((_document && _document->emojiUsesTextColor()) ? st::windowFg->c : QColor(0, 0, 0, 0)), }) : Lottie::Animation::FrameInfo(); const auto effect = (_effect && _effect->ready()) - ? _effect->frameInfo({ dimensions * kPremiumMultiplier * factor }) + ? _effect->frameInfo({ style::DevicePixels(dimensions, kPremiumMultiplier * factor) }) : Lottie::Animation::FrameInfo(); const auto image = frame.image; const auto effectImage = effect.image; @@ -109,8 +109,11 @@ void MediaPreviewWidget::paintEvent(QPaintEvent *e) { // : 1; const auto pixmap = image.isNull() ? currentImage() : QPixmap(); const auto size = image.isNull() ? pixmap.size() : image.size(); - const auto w = size.width() / factor; - const auto h = size.height() / factor; + const auto sizeFactor = image.isNull() + ? pixmap.devicePixelRatio() + : factor; + const auto w = int(base::SafeRound(size.width() / sizeFactor)); + const auto h = int(base::SafeRound(size.height() / sizeFactor)); const auto shown = _a_shown.value(_hiding ? 0. : 1.); if (!_a_shown.animating()) { if (_hiding) { @@ -177,6 +180,11 @@ void MediaPreviewWidget::resizeEvent(QResizeEvent *e) { update(); } +void MediaPreviewWidget::devicePixelRatioChangedEvent() { + _cache = QPixmap(); + resetGifAndCache(); +} + QPoint MediaPreviewWidget::innerPosition(QSize size) const { if (!_document || !_document->isPremiumSticker()) { return QPoint( diff --git a/Telegram/SourceFiles/window/window_media_preview.h b/Telegram/SourceFiles/window/window_media_preview.h index f7361d3fddade5..7d0bb34f15b6e6 100644 --- a/Telegram/SourceFiles/window/window_media_preview.h +++ b/Telegram/SourceFiles/window/window_media_preview.h @@ -51,6 +51,7 @@ class MediaPreviewWidget final : public Ui::RpWidget { protected: void paintEvent(QPaintEvent *e) override; void resizeEvent(QResizeEvent *e) override; + void devicePixelRatioChangedEvent() override; private: void validateGifAnimation(); diff --git a/Telegram/build/audit_dpr.py b/Telegram/build/audit_dpr.py new file mode 100644 index 00000000000000..ed6571543f026e --- /dev/null +++ b/Telegram/build/audit_dpr.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 + +import argparse +import collections +import pathlib +import re +import subprocess +import sys + + +ROOT = pathlib.Path(__file__).resolve().parents[2] +DEFAULT_GLOBS = [ + "*.cpp", + "*.h", +] +PATTERN = ( + r"DevicePixelRatio(Exact)?\(\)" + r"|setDevicePixelRatio\(" + r"|QImage\(" + r"|QPixmap\(" + r"|drawImage\(" + r"|drawPixmap\(" + r"|QSize\(" + r"|QRect\(" + r"|qRound\(" + r"|qCeil\(" + r"|qFloor\(" + r"|int\s*\(" + r"|\bratio\b" +) + + +def run_rg(globs: list[str], path_filters: list[str]) -> list[str]: + cmd = ["rg", "-n", "-H", "-S", PATTERN] + for glob in globs: + cmd.extend(["-g", glob]) + cmd.extend(path_filters or ["Telegram", "cmake"]) + result = subprocess.run( + cmd, + cwd=ROOT, + text=True, + capture_output=True, + check=False, + ) + if result.returncode not in (0, 1): + print(result.stderr.strip(), file=sys.stderr) + raise SystemExit(result.returncode) + return [line for line in result.stdout.splitlines() if line] + + +def classify(text: str) -> tuple[str, list[str]]: + reasons: list[str] = [] + score = 0 + + has_dpr = bool(re.search(r"DevicePixelRatio(Exact)?\(\)", text)) + has_ratio_var = bool(re.search(r"\bratio\b", text)) + if not has_dpr and not has_ratio_var: + return ("", []) + + ratio_decl_only = bool(re.search( + r"^\s*(const\s+)?auto\s+ratio\s*=\s*.*(DevicePixelRatio(Exact)?\(\)|devicePixelRatio(F)?\(\))\s*;\s*$", + text)) + ratio_derived = bool(re.search( + r"\bratio\b\s*=\s*.*(DevicePixelRatio(Exact)?\(\)|devicePixelRatio(F)?\(\))", + text)) + uses_ratio_math = bool(re.search(r"[*\/]\s*ratio\b|\bratio\s*[*\/]", text)) + uses_ratio_in_constructor = bool(re.search( + r"(QSize|QRect|QPoint|QMargins|QImage|QPixmap)\s*\([^;\n]*\bratio\b", + text)) + uses_dpr_in_constructor = bool(re.search( + r"(QSize|QRect|QPoint|QMargins|QImage|QPixmap)\s*\([^;\n]*DevicePixelRatio(Exact)?\(\)", + text)) + uses_per_image_dpr = bool(re.search( + r"image\.devicePixelRatio\(\)|pixmap\.devicePixelRatio\(\)|maskImage\.devicePixelRatio\(\)|_pixmap\.devicePixelRatio\(\)", + text)) + already_rounded_ratio = bool(re.search( + r"(qRound|base::SafeRound)\s*\([^)]*\bratio\b", + text)) + already_rounded_dpr = bool(re.search( + r"(qRound|base::SafeRound)\s*\([^)]*DevicePixelRatio(Exact)?\(\)", + text)) + constructor_guarded_by_rounding = ( + (uses_ratio_in_constructor or uses_dpr_in_constructor) + and ("qRound(" in text or "base::SafeRound(" in text)) + + if uses_dpr_in_constructor or uses_ratio_in_constructor: + score += 4 + reasons.append("DPR used inside Qt integer geometry/image constructor") + + if re.search(r"\b(int|uint|auto)\s+\w+\s*=\s*.*DevicePixelRatio", text): + score += 2 + reasons.append("DPR value assigned into likely integral sizing path") + + if re.search(r"\bint\s*\([^)]*DevicePixelRatio", text): + score += 4 + reasons.append("explicit int cast around DPR expression") + + if re.search(r"\bint\s*\([^)]*\bratio\b", text): + score += 4 + reasons.append("explicit int cast around local ratio expression") + + if re.search(r"(qCeil|qFloor)\s*\([^)]*DevicePixelRatio", text): + score += 4 + reasons.append("explicit rounding of DPR expression") + + if re.search(r"(qCeil|qFloor)\s*\([^)]*\bratio\b", text): + score += 4 + reasons.append("explicit rounding of local ratio expression") + + if re.search(r"/\s*style::DevicePixelRatio(Exact)?\(\)", text): + score += 3 + reasons.append("physical-to-logical conversion using global DPR") + + if re.search(r"\*\s*style::DevicePixelRatio(Exact)?\(\)", text): + score += 2 + reasons.append("logical-to-physical conversion using global DPR") + + if ratio_derived: + score += 1 + reasons.append("local ratio derived from DPR source") + + if uses_ratio_math: + score += 2 + reasons.append("local ratio used in scale conversion math") + + if re.search(r"setDevicePixelRatio\s*\(", text): + score += 2 + reasons.append("image/pixmap DPR tagging site") + + if re.search(r"(drawImage|drawPixmap)\s*\(", text): + score += 2 + reasons.append("paint site using DPR-sensitive raster content") + + if already_rounded_dpr: + score -= 2 + reasons.append("already uses explicit rounding") + + if already_rounded_ratio: + score -= 2 + reasons.append("already uses explicit rounding with local ratio") + + if uses_per_image_dpr: + score -= 3 + reasons.append("uses per-image/pixmap DPR") + + if ratio_decl_only and not uses_ratio_math and not uses_ratio_in_constructor: + score -= 3 + reasons.append("plain local DPR ratio declaration") + + if uses_ratio_in_constructor and already_rounded_ratio: + score -= 4 + reasons.append("constructor use already guarded by explicit rounding") + + if uses_dpr_in_constructor and already_rounded_dpr: + score -= 4 + reasons.append("constructor use already guarded by explicit rounding") + + if constructor_guarded_by_rounding: + score -= 4 + reasons.append("constructor use already guarded by explicit rounding") + + if (uses_ratio_in_constructor or uses_dpr_in_constructor) and uses_per_image_dpr: + score -= 2 + reasons.append("constructor use already guarded by per-image DPR") + + if score >= 6: + return ("high", reasons) + if score >= 3: + return ("medium", reasons) + return ("low", reasons) + + +def parse_line(line: str) -> tuple[str, int, str]: + path, lineno, text = line.split(":", 2) + return (path, int(lineno), text.strip()) + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("paths", nargs="*", help="Optional paths to limit the audit.") + parser.add_argument("--max-per-level", type=int, default=80) + parser.add_argument("--level", choices=["high", "medium", "low", "all"], default="all") + args = parser.parse_args() + + results = collections.defaultdict(list) + for raw in run_rg(DEFAULT_GLOBS, args.paths): + path, lineno, text = parse_line(raw) + level, reasons = classify(text) + if not level: + continue + if args.level != "all" and level != args.level: + continue + results[level].append((path, lineno, text, reasons)) + + order = ["high", "medium", "low"] + for level in order: + entries = sorted(results[level], key=lambda item: (item[0], item[1])) + if not entries: + continue + print(f"[{level.upper()}] {len(entries)}") + for path, lineno, text, reasons in entries[:args.max_per_level]: + unique = list(dict.fromkeys(reasons)) + reason_text = "; ".join(unique[:3]) + print(f"{path}:{lineno}: {text}") + if reason_text: + print(f" -> {reason_text}") + if len(entries) > args.max_per_level: + print(f" ... {len(entries) - args.max_per_level} more") + print() + + total = sum(len(results[level]) for level in order) + print(f"Total flagged sites: {total}") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/Telegram/lib_lottie b/Telegram/lib_lottie index 49d67cf66d3573..179ad65f8092f8 160000 --- a/Telegram/lib_lottie +++ b/Telegram/lib_lottie @@ -1 +1 @@ -Subproject commit 49d67cf66d3573cd71a3228af47a4ac59b64fc90 +Subproject commit 179ad65f8092f8bc948566c9787fb36e48073780 diff --git a/Telegram/lib_ui b/Telegram/lib_ui index bcb18cb15d913e..c509854b0d084f 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit bcb18cb15d913ec0735ae3b3bbb15941d5772f5b +Subproject commit c509854b0d084f377ae8e7843c6940bddd0ade33