diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.cpp b/Telegram/SourceFiles/history/view/media/history_view_document.cpp index fa272149c..f2e2e3f81 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_document.cpp @@ -421,13 +421,7 @@ QSize Document::countCurrentSize(int newWidth) { } void Document::draw(Painter &p, const PaintContext &context) const { - const auto corners = (isBubbleTop() - ? (RectPart::TopLeft | RectPart::TopRight) - : RectParts()) - | ((isRoundedInBubbleBottom() && !Has()) - ? (RectPart::BottomLeft | RectPart::BottomRight) - : RectParts()); - draw(p, context, width(), LayoutMode::Full, corners); + draw(p, context, width(), LayoutMode::Full, adjustedBubbleRounding()); } void Document::draw( @@ -435,7 +429,7 @@ void Document::draw( const PaintContext &context, int width, LayoutMode mode, - RectParts corners) const { + Ui::BubbleRounding outsideRounding) const { if (width < st::msgPadding.left() + st::msgPadding.right() + 1) return; ensureDataMediaCreated(); @@ -476,7 +470,7 @@ void Document::draw( const auto inner = QRect(rthumb.x() + (rthumb.width() - innerSize) / 2, rthumb.y() + (rthumb.height() - innerSize) / 2, innerSize, innerSize); const auto radialOpacity = radial ? _animation->radial.opacity() : 1.; if (thumbed) { - const auto rounding = thumbRounding(mode, corners); + const auto rounding = thumbRounding(mode, outsideRounding); validateThumbnail(thumbed, st.thumbSize, rounding); p.drawImage(rthumb, thumbed->thumbnail); if (context.selected()) { @@ -703,19 +697,20 @@ void Document::draw( Ui::BubbleRounding Document::thumbRounding( LayoutMode mode, - RectParts corners) const { - auto result = bubbleRounding(); + Ui::BubbleRounding outsideRounding) const { using Corner = Ui::BubbleCornerRounding; if (mode != LayoutMode::Grouped && _parent->media() != this) { return {}; // In a WebPage preview. } - const auto adjust = [&](RectPart corner, Corner already) { - return (already == Corner::Large && (corners & corner)) + const auto hasCaption = Has(); + const auto adjust = [&](Corner already, bool skip = false) { + return (already == Corner::Large && !skip) ? Corner::Large : Corner::Small; }; - result.topLeft = adjust(RectPart::TopLeft, result.topLeft); - result.bottomLeft = adjust(RectPart::BottomLeft, result.bottomLeft); + auto result = Ui::BubbleRounding(); + result.topLeft = adjust(outsideRounding.topLeft); + result.bottomLeft = adjust(outsideRounding.bottomLeft, hasCaption); result.topRight = result.bottomRight = Corner::Small; return result; } @@ -1280,7 +1275,7 @@ void Document::drawGrouped( const PaintContext &context, const QRect &geometry, RectParts sides, - RectParts corners, + Ui::BubbleRounding rounding, float64 highlightOpacity, not_null cacheKey, not_null cache) const { @@ -1290,7 +1285,7 @@ void Document::drawGrouped( context.translated(-geometry.topLeft()), geometry.width(), LayoutMode::Grouped, - corners); + rounding); p.translate(-geometry.topLeft()); } diff --git a/Telegram/SourceFiles/history/view/media/history_view_document.h b/Telegram/SourceFiles/history/view/media/history_view_document.h index d45993d61..643ba24fd 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_document.h +++ b/Telegram/SourceFiles/history/view/media/history_view_document.h @@ -69,7 +69,7 @@ public: const PaintContext &context, const QRect &geometry, RectParts sides, - RectParts corners, + Ui::BubbleRounding rounding, float64 highlightOpacity, not_null cacheKey, not_null cache) const override; @@ -110,7 +110,7 @@ private: const PaintContext &context, int width, LayoutMode mode, - RectParts corners) const; + Ui::BubbleRounding outsideRounding) const; [[nodiscard]] TextState textState( QPoint point, QSize layout, @@ -128,7 +128,7 @@ private: [[nodiscard]] Ui::BubbleRounding thumbRounding( LayoutMode mode, - RectParts corners) const; + Ui::BubbleRounding outsideRounding) const; void validateThumbnail( not_null thumbed, int size, diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp index c01fcfdb0..6366d1f0b 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.cpp @@ -281,25 +281,6 @@ void Gif::validateRoundingMask(QSize size) const { } } -Images::CornersMaskRef Gif::prepareRoundingRef( - std::optional rounding) const { - using namespace Ui; - using namespace Images; - if (!rounding) { - return CornersMaskRef(CachedCornersMasks(CachedCornerRadius::Small)); - } - auto result = CornersMaskRef(); - for (auto i = 0; i != 4; ++i) { - const auto corner = (*rounding)[i]; - result.p[i] = (corner == BubbleCornerRounding::Large) - ? &CachedCornersMasks(CachedCornerRadius::BubbleLarge)[i] - : (corner == BubbleCornerRounding::Small) - ? &CachedCornersMasks(CachedCornerRadius::BubbleSmall)[i] - : nullptr; - } - return result; -} - bool Gif::downloadInCorner() const { return _data->isVideoFile() && (_data->loading() || !autoplayEnabled()) @@ -429,7 +410,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const { validateRoundingMask(request.outer); request.mask = _roundingMask; } else { - request.rounding = prepareRoundingRef(rounding); + request.rounding = MediaRoundingMask(rounding); } if (!activeRoundPlaying && activeOwnPlaying->instance.playerLocked()) { if (activeOwnPlaying->frozenFrame.isNull()) { @@ -1020,7 +1001,7 @@ void Gif::drawGrouped( const PaintContext &context, const QRect &geometry, RectParts sides, - RectParts corners, + Ui::BubbleRounding rounding, float64 highlightOpacity, not_null cacheKey, not_null cache) const { @@ -1081,8 +1062,7 @@ void Gif::drawGrouped( auto request = ::Media::Streaming::FrameRequest{ .resize = pixSize * cIntRetinaFactor(), .outer = geometry.size() * cIntRetinaFactor(), - //.radius = roundRadius, // #TODO rounding - //.corners = corners, + .rounding = MediaRoundingMask(rounding), }; if (activeOwnPlaying->instance.playerLocked()) { if (activeOwnPlaying->frozenFrame.isNull()) { @@ -1105,7 +1085,7 @@ void Gif::drawGrouped( } } } else { - validateGroupedCache(geometry, corners, cacheKey, cache); + validateGroupedCache(geometry, rounding, cacheKey, cache); p.drawPixmap(geometry, *cache); } @@ -1114,11 +1094,10 @@ void Gif::drawGrouped( : highlightOpacity; if (overlayOpacity > 0.) { p.setOpacity(overlayOpacity); - // #TODO rounding - //Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); - //if (!context.selected()) { - // Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); - //} + fillImageOverlay(p, geometry, rounding, context); + if (!context.selected()) { + fillImageOverlay(p, geometry, rounding, context); + } p.setOpacity(1.); } @@ -1355,7 +1334,7 @@ bool Gif::isUnwrapped() const { void Gif::validateGroupedCache( const QRect &geometry, - RectParts corners, + Ui::BubbleRounding rounding, not_null cacheKey, not_null cache) const { using Option = Images::Option; @@ -1377,18 +1356,11 @@ void Gif::validateGroupedCache( const auto loadLevel = good ? 3 : thumb ? 2 : image ? 1 : 0; const auto width = geometry.width(); const auto height = geometry.height(); - const auto corner = [&](RectPart part, Option skip) { - return !(corners & part) ? skip : Option(); - }; - const auto options = Option::RoundLarge - | (blur ? Option::Blur : Option(0)) - | corner(RectPart::TopLeft, Option::RoundSkipTopLeft) - | corner(RectPart::TopRight, Option::RoundSkipTopRight) - | corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft) - | corner(RectPart::BottomRight, Option::RoundSkipBottomRight); + const auto options = (blur ? Option::Blur : Option(0)); const auto key = (uint64(width) << 48) | (uint64(height) << 32) | (uint64(options) << 16) + | (uint64(rounding.key()) << 8) | (uint64(loadLevel)); if (*cacheKey == key) { return; @@ -1403,9 +1375,14 @@ void Gif::validateGroupedCache( const auto ratio = style::DevicePixelRatio(); *cacheKey = key; - *cache = (image ? image : Image::BlankMedia().get())->pixNoCache( + auto scaled = Images::Prepare( + (image ? image : Image::BlankMedia().get())->original(), pixSize * ratio, { .options = options, .outer = { width, height } }); + auto rounded = Images::Round( + std::move(scaled), + MediaRoundingMask(rounding)); + *cache = Ui::PixmapFromImage(std::move(rounded)); } void Gif::setStatusSize(int64 newSize) const { diff --git a/Telegram/SourceFiles/history/view/media/history_view_gif.h b/Telegram/SourceFiles/history/view/media/history_view_gif.h index 4f39aab7f..3b9b3bf46 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_gif.h +++ b/Telegram/SourceFiles/history/view/media/history_view_gif.h @@ -76,7 +76,7 @@ public: const PaintContext &context, const QRect &geometry, RectParts sides, - RectParts corners, + Ui::BubbleRounding rounding, float64 highlightOpacity, not_null cacheKey, not_null cache) const override; @@ -169,7 +169,7 @@ private: void validateGroupedCache( const QRect &geometry, - RectParts corners, + Ui::BubbleRounding rounding, not_null cacheKey, not_null cache) const; void setStatusSize(int64 newSize) const; @@ -177,8 +177,6 @@ private: [[nodiscard]] QSize sizeForAspectRatio() const; void validateRoundingMask(QSize size) const; - [[nodiscard]] Images::CornersMaskRef prepareRoundingRef( - std::optional rounding) const; [[nodiscard]] bool downloadInCorner() const; void drawCornerStatus( diff --git a/Telegram/SourceFiles/history/view/media/history_view_media.h b/Telegram/SourceFiles/history/view/media/history_view_media.h index 7bc36e184..0e86bb67d 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media.h @@ -189,7 +189,7 @@ public: const PaintContext &context, const QRect &geometry, RectParts sides, - RectParts corners, + Ui::BubbleRounding rounding, float64 highlightOpacity, not_null cacheKey, not_null cache) const { 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 e1346857a..aaa16181f 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.cpp @@ -245,15 +245,23 @@ void GroupedMedia::refreshParentId( } } -RectParts GroupedMedia::cornersFromSides(RectParts sides) const { +Ui::BubbleRounding GroupedMedia::applyRoundingSides( + Ui::BubbleRounding already, + RectParts sides) const { auto result = Ui::GetCornersFromSides(sides); - if (!isBubbleTop()) { - result &= ~(RectPart::TopLeft | RectPart::TopRight); + if (!(result & RectPart::TopLeft)) { + already.topLeft = Ui::BubbleCornerRounding::None; } - if (!isRoundedInBubbleBottom() || !_caption.isEmpty()) { - result &= ~(RectPart::BottomLeft | RectPart::BottomRight); + if (!(result & RectPart::TopRight)) { + already.topRight = Ui::BubbleCornerRounding::None; } - return result; + if (!(result & RectPart::BottomLeft)) { + already.bottomLeft = Ui::BubbleCornerRounding::None; + } + if (!(result & RectPart::BottomRight)) { + already.bottomRight = Ui::BubbleCornerRounding::None; + } + return already; } QMargins GroupedMedia::groupedPadding() const { @@ -302,6 +310,11 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { const auto textSelection = (_mode == Mode::Column) && !fullSelection && !IsSubGroupSelection(selection); + const auto inWebPage = (_parent->media() != this); + constexpr auto kSmall = Ui::BubbleCornerRounding::Small; + const auto rounding = inWebPage + ? Ui::BubbleRounding{ kSmall, kSmall, kSmall, kSmall } + : adjustedBubbleRoundingWithCaption(_caption); for (auto i = 0, count = int(_parts.size()); i != count; ++i) { const auto &part = _parts[i]; const auto partContext = context.withSelection(fullSelection @@ -325,7 +338,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const { partContext, part.geometry.translated(0, groupPadding.top()), part.sides, - cornersFromSides(part.sides), + applyRoundingSides(rounding, part.sides), highlightOpacity, &part.cacheKey, &part.cache); diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h index 508f79f0b..3ad6974b6 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h +++ b/Telegram/SourceFiles/history/view/media/history_view_media_grouped.h @@ -141,7 +141,9 @@ private: void refreshCaption(); - [[nodiscard]] RectParts cornersFromSides(RectParts sides) const; + [[nodiscard]] Ui::BubbleRounding applyRoundingSides( + Ui::BubbleRounding already, + RectParts sides) const; [[nodiscard]] QMargins groupedPadding() const; Ui::Text::String _caption; diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 5effea82e..28abf6b98 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -543,14 +543,14 @@ void Photo::drawGrouped( const PaintContext &context, const QRect &geometry, RectParts sides, - RectParts corners, + Ui::BubbleRounding rounding, float64 highlightOpacity, not_null cacheKey, not_null cache) const { ensureDataMediaCreated(); _dataMedia->automaticLoad(_realParent->fullId(), _parent->data()); - validateGroupedCache(geometry, corners, cacheKey, cache); + validateGroupedCache(geometry, rounding, cacheKey, cache); const auto st = context.st; const auto sti = context.imageStyle(); @@ -573,11 +573,10 @@ void Photo::drawGrouped( if (overlayOpacity > 0.) { p.setOpacity(overlayOpacity); const auto roundRadius = ImageRoundRadius::Large; - // #TODO rounding - //Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); - //if (!context.selected()) { - // Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); - //} + fillImageOverlay(p, geometry, rounding, context); + if (!context.selected()) { + fillImageOverlay(p, geometry, rounding, context); + } p.setOpacity(1.); } @@ -680,7 +679,7 @@ bool Photo::needInfoDisplay() const { void Photo::validateGroupedCache( const QRect &geometry, - RectParts corners, + Ui::BubbleRounding rounding, not_null cacheKey, not_null cache) const { using Option = Images::Option; @@ -697,18 +696,11 @@ void Photo::validateGroupedCache( : 0; const auto width = geometry.width(); const auto height = geometry.height(); - const auto corner = [&](RectPart part, Option skip) { - return !(corners & part) ? skip : Option(); - }; - const auto options = Option::RoundLarge - | (loaded ? Option() : Option::Blur) - | corner(RectPart::TopLeft, Option::RoundSkipTopLeft) - | corner(RectPart::TopRight, Option::RoundSkipTopRight) - | corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft) - | corner(RectPart::BottomRight, Option::RoundSkipBottomRight); + const auto options = (loaded ? Option() : Option::Blur); const auto key = (uint64(width) << 48) | (uint64(height) << 32) | (uint64(options) << 16) + | (uint64(rounding.key()) << 8) | (uint64(loadLevel)); if (*cacheKey == key) { return; @@ -731,9 +723,14 @@ void Photo::validateGroupedCache( : Image::BlankMedia().get(); *cacheKey = key; - *cache = image->pixNoCache( + auto scaled = Images::Prepare( + image->original(), pixSize * ratio, { .options = options, .outer = { width, height } }); + auto rounded = Images::Round( + std::move(scaled), + MediaRoundingMask(rounding)); + *cache = Ui::PixmapFromImage(std::move(rounded)); } bool Photo::createStreamingObjects() { diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.h b/Telegram/SourceFiles/history/view/media/history_view_photo.h index 23f8c8d3d..c9aa130e9 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.h +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.h @@ -67,7 +67,7 @@ public: const PaintContext &context, const QRect &geometry, RectParts sides, - RectParts corners, + Ui::BubbleRounding rounding, float64 highlightOpacity, not_null cacheKey, not_null cache) const override; @@ -123,7 +123,7 @@ private: bool needInfoDisplay() const; void validateGroupedCache( const QRect &geometry, - RectParts corners, + Ui::BubbleRounding rounding, not_null cacheKey, not_null cache) const; void validateImageCache( diff --git a/Telegram/SourceFiles/ui/chat/message_bubble.h b/Telegram/SourceFiles/ui/chat/message_bubble.h index 57fd49adf..fa4f821a0 100644 --- a/Telegram/SourceFiles/ui/chat/message_bubble.h +++ b/Telegram/SourceFiles/ui/chat/message_bubble.h @@ -72,6 +72,11 @@ struct BubbleRounding { return { this, index }; } + [[nodiscard]] uchar key() const { + static_assert(sizeof(*this) == sizeof(uchar)); + return uchar(*reinterpret_cast(this)); + } + inline friend constexpr auto operator<=>( BubbleRounding, BubbleRounding) = default;