diff --git a/ui/effects/spoiler_mess.cpp b/ui/effects/spoiler_mess.cpp index dc0cb1a..a4d8b8d 100644 --- a/ui/effects/spoiler_mess.cpp +++ b/ui/effects/spoiler_mess.cpp @@ -505,10 +505,7 @@ void FillSpoilerRect( const SpoilerMessFrame &frame, QImage &cornerCache, QPoint originShift) { - constexpr auto kTopLeft = 0; - constexpr auto kTopRight = 1; - constexpr auto kBottomLeft = 2; - constexpr auto kBottomRight = 3; + using namespace Images; if ((!mask.p[kTopLeft] || mask.p[kTopLeft]->isNull()) && (!mask.p[kTopRight] || mask.p[kTopRight]->isNull()) diff --git a/ui/image/image_prepare.cpp b/ui/image/image_prepare.cpp index 013707c..2e8ea6b 100644 --- a/ui/image/image_prepare.cpp +++ b/ui/image/image_prepare.cpp @@ -51,7 +51,7 @@ TG_FORCE_INLINE uint64 BlurGetColors(const uchar *p) { + ((uint64)p[3] << 48); } -const QImage &CircleMask(QSize size) { +const QImage &EllipseMaskCached(QSize size) { const auto key = (uint64(uint32(size.width())) << 32) | uint64(uint32(size.height())); @@ -64,17 +64,7 @@ const QImage &CircleMask(QSize size) { } lock.unlock(); - auto mask = QImage( - size, - QImage::Format_ARGB32_Premultiplied); - mask.fill(Qt::transparent); - { - QPainter p(&mask); - PainterHighQualityEnabler hq(p); - p.setBrush(Qt::white); - p.setPen(Qt::NoPen); - p.drawEllipse(QRect(QPoint(), size)); - } + auto mask = EllipseMask(size); lock.relock(); return Masks.emplace(key, std::move(mask)).first->second; @@ -345,6 +335,24 @@ std::array CornersMask(int radius) { return PrepareCornersMask(radius); } +QImage EllipseMask(QSize size) { + const auto ratio = style::DevicePixelRatio(); + + size *= ratio; + auto result = QImage(size, QImage::Format_ARGB32_Premultiplied); + result.fill(Qt::transparent); + + QPainter p(&result); + PainterHighQualityEnabler hq(p); + p.setBrush(Qt::white); + p.setPen(Qt::NoPen); + p.drawEllipse(QRect(QPoint(), size)); + p.end(); + + result.setDevicePixelRatio(ratio); + return result; +} + std::array PrepareCorners( int radius, const style::color &color) { @@ -987,7 +995,7 @@ QImage Circle(QImage &&image, QRect target) { Expects(!image.isNull()); if (target.isNull()) { - target = QRect(QPoint(), image.size()); + target = QRect(QPoint( ), image.size()); } else { Assert(QRect(QPoint(), image.size()).contains(target)); } @@ -1001,7 +1009,7 @@ QImage Circle(QImage &&image, QRect target) { p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.drawImage( QRectF(target.topLeft() / ratio, target.size() / ratio), - CircleMask(target.size())); + EllipseMaskCached(target.size())); p.end(); return std::move(image); diff --git a/ui/image/image_prepare.h b/ui/image/image_prepare.h index 42d34cf..3ede8dc 100644 --- a/ui/image/image_prepare.h +++ b/ui/image/image_prepare.h @@ -46,6 +46,11 @@ namespace Images { int bottomAlpha, QColor color = QColor(0, 0, 0)); +inline constexpr auto kTopLeft = 0; +inline constexpr auto kTopRight = 1; +inline constexpr auto kBottomLeft = 2; +inline constexpr auto kBottomRight = 3; + struct CornersMaskRef { CornersMaskRef() = default; explicit CornersMaskRef(gsl::span masks) @@ -61,7 +66,27 @@ struct CornersMaskRef { : p{ masks[0], masks[1], masks[2], masks[3] } { } + [[nodiscard]] bool empty() const { + return !p[0] && !p[1] && !p[2] && !p[3]; + } + std::array p{}; + + friend inline constexpr std::strong_ordering operator<=>( + CornersMaskRef a, + CornersMaskRef b) noexcept { + for (auto i = 0; i != 4; ++i) { + if (a.p[i] < b.p[i]) { + return std::strong_ordering::less; + } else if (a.p[i] > b.p[i]) { + return std::strong_ordering::greater; + } + } + return std::strong_ordering::equal; + } + friend inline constexpr bool operator==( + CornersMaskRef a, + CornersMaskRef b) noexcept = default; }; [[nodiscard]] const std::array &CornersMask( @@ -71,6 +96,8 @@ struct CornersMaskRef { const style::color &color); [[nodiscard]] std::array CornersMask(int radius); +[[nodiscard]] QImage EllipseMask(QSize size); + [[nodiscard]] std::array PrepareCorners( int radius, const style::color &color);