Round correctly distinct photos and extended media.

This commit is contained in:
John Preston 2022-09-30 23:03:44 +04:00
parent f3662f4873
commit abdd126dcf
15 changed files with 268 additions and 169 deletions

View file

@ -424,7 +424,7 @@ void Document::draw(Painter &p, const PaintContext &context) const {
const auto corners = (isBubbleTop() const auto corners = (isBubbleTop()
? (RectPart::TopLeft | RectPart::TopRight) ? (RectPart::TopLeft | RectPart::TopRight)
: RectParts()) : RectParts())
| ((isBubbleBottom() && !Has<HistoryDocumentCaptioned>()) | ((isRoundedInBubbleBottom() && !Has<HistoryDocumentCaptioned>())
? (RectPart::BottomLeft | RectPart::BottomRight) ? (RectPart::BottomLeft | RectPart::BottomRight)
: RectParts()); : RectParts());
draw(p, context, width(), LayoutMode::Full, corners); draw(p, context, width(), LayoutMode::Full, corners);
@ -767,21 +767,19 @@ void Document::fillThumbnailOverlay(
Ui::BubbleRounding rounding, Ui::BubbleRounding rounding,
const PaintContext &context) const { const PaintContext &context) const {
using Corner = Ui::BubbleCornerRounding; using Corner = Ui::BubbleCornerRounding;
using Radius = Ui::CachedCornerRadius;
auto corners = Ui::CornersPixmaps(); auto corners = Ui::CornersPixmaps();
const auto &st = context.st; const auto &st = context.st;
const auto set = [&](int index, const Ui::CornersPixmaps &from) { const auto lookup = [&](Corner corner) {
corners.p[index] = from.p[index];
};
const auto lookup = [&](Corner corner) -> const Ui::CornersPixmaps & {
switch (corner) { switch (corner) {
case Corner::None: return st->msgSelectOverlayCornersSmall(); case Corner::None: return Radius::Small;
case Corner::Small: return st->msgSelectOverlayCornersThumbSmall(); case Corner::Small: return Radius::ThumbSmall;
case Corner::Large: return st->msgSelectOverlayCornersThumbLarge(); case Corner::Large: return Radius::ThumbLarge;
} }
Unexpected("Corner value in Document::fillThumbnailOverlay."); Unexpected("Corner value in Document::fillThumbnailOverlay.");
}; };
for (auto i = 0; i != 4; ++i) { for (auto i = 0; i != 4; ++i) {
corners.p[i] = lookup(rounding[i]).p[i]; corners.p[i] = st->msgSelectOverlayCorners(lookup(rounding[i])).p[i];
} }
Ui::FillComplexOverlayRect(p, rect, st->msgSelectOverlay(), corners); Ui::FillComplexOverlayRect(p, rect, st->msgSelectOverlay(), corners);
} }

View file

@ -90,7 +90,7 @@ void ExtendedPreview::ensureThumbnailRead() const {
} }
_inlineThumbnail = Images::FromInlineBytes(bytes); _inlineThumbnail = Images::FromInlineBytes(bytes);
if (_inlineThumbnail.isNull()) { if (_inlineThumbnail.isNull()) {
_imageCacheInvalid = 1; _imageCacheInvalid = true;
} else { } else {
history()->owner().registerHeavyViewPart(_parent); history()->owner().registerHeavyViewPart(_parent);
} }
@ -202,6 +202,10 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const {
auto bubble = _parent->hasBubble(); auto bubble = _parent->hasBubble();
auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right(); auto captionw = paintw - st::msgPadding.left() - st::msgPadding.right();
auto rthumb = style::rtlrect(paintx, painty, paintw, painth, width()); auto rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
const auto inWebPage = (_parent->media() != this);
const auto rounding = inWebPage
? std::optional<Ui::BubbleRounding>()
: adjustedBubbleRoundingWithCaption(_caption);
if (bubble) { if (bubble) {
if (!_caption.isEmpty()) { if (!_caption.isEmpty()) {
painth -= st::mediaCaptionSkip + _caption.countHeight(captionw); painth -= st::mediaCaptionSkip + _caption.countHeight(captionw);
@ -211,21 +215,15 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const {
rthumb = style::rtlrect(paintx, painty, paintw, painth, width()); rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
} }
} else { } else {
// #TODO rounding Assert(rounding.has_value());
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCornersSmall); fillImageShadow(p, rthumb, *rounding, context);
} }
const auto inWebPage = (_parent->media() != this); validateImageCache(rthumb.size(), rounding);
const auto roundRadius = inWebPage
? ImageRoundRadius::Small
: ImageRoundRadius::Large;
const auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
| ((isRoundedInBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None));
validateImageCache(rthumb.size(), roundRadius, roundCorners);
p.drawImage(rthumb.topLeft(), _imageCache); p.drawImage(rthumb.topLeft(), _imageCache);
fillSpoilerMess(p, rthumb, roundRadius, roundCorners, context); fillSpoilerMess(p, rthumb, rounding, context);
paintButton(p, rthumb, context); paintButton(p, rthumb, context);
if (context.selected()) { if (context.selected()) {
Ui::FillComplexOverlayRect(p, st, rthumb, roundRadius, roundCorners); fillImageOverlay(p, rthumb, rounding, context);
} }
// date // date
@ -265,26 +263,16 @@ void ExtendedPreview::draw(Painter &p, const PaintContext &context) const {
void ExtendedPreview::validateImageCache( void ExtendedPreview::validateImageCache(
QSize outer, QSize outer,
ImageRoundRadius radius, std::optional<Ui::BubbleRounding> rounding) const {
RectParts corners) const {
const auto intRadius = static_cast<int>(radius);
const auto intCorners = static_cast<int>(corners);
const auto ratio = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
if (_imageCache.size() == (outer * ratio) if (_imageCache.size() == (outer * ratio)
&& _imageCacheRoundRadius == intRadius && _imageCacheRounding == rounding) {
&& _imageCacheRoundCorners == intCorners) {
return; return;
} }
_imageCache = prepareImageCache(outer, radius, corners); _imageCache = Images::Round(
_imageCacheRoundRadius = intRadius; prepareImageCache(outer),
_imageCacheRoundCorners = intCorners; MediaRoundingMask(rounding));
} _imageCacheRounding = rounding;
QImage ExtendedPreview::prepareImageCache(
QSize outer,
ImageRoundRadius radius,
RectParts corners) const {
return Images::Round(prepareImageCache(outer), radius, corners);
} }
QImage ExtendedPreview::prepareImageCache(QSize outer) const { QImage ExtendedPreview::prepareImageCache(QSize outer) const {
@ -295,8 +283,7 @@ QImage ExtendedPreview::prepareImageCache(QSize outer) const {
void ExtendedPreview::fillSpoilerMess( void ExtendedPreview::fillSpoilerMess(
QPainter &p, QPainter &p,
QRect rect, QRect rect,
ImageRoundRadius radius, std::optional<Ui::BubbleRounding> rounding,
RectParts corners,
const PaintContext &context) const { const PaintContext &context) const {
if (!_animation) { if (!_animation) {
_animation = std::make_unique<Ui::SpoilerAnimation>([=] { _animation = std::make_unique<Ui::SpoilerAnimation>([=] {
@ -310,8 +297,7 @@ void ExtendedPreview::fillSpoilerMess(
Ui::FillSpoilerRect( Ui::FillSpoilerRect(
p, p,
rect, rect,
radius, MediaRoundingMask(rounding),
corners,
spoiler.frame(index), spoiler.frame(index),
_cornerCache); _cornerCache);
} }

View file

@ -80,12 +80,7 @@ private:
bool needInfoDisplay() const; bool needInfoDisplay() const;
void validateImageCache( void validateImageCache(
QSize outer, QSize outer,
ImageRoundRadius radius, std::optional<Ui::BubbleRounding> rounding) const;
RectParts corners) const;
[[nodiscard]] QImage prepareImageCache(
QSize outer,
ImageRoundRadius radius,
RectParts corners) const;
[[nodiscard]] QImage prepareImageCache(QSize outer) const; [[nodiscard]] QImage prepareImageCache(QSize outer) const;
void paintButton( void paintButton(
Painter &p, Painter &p,
@ -95,8 +90,7 @@ private:
void fillSpoilerMess( void fillSpoilerMess(
QPainter &p, QPainter &p,
QRect rect, QRect rect,
ImageRoundRadius radius, std::optional<Ui::BubbleRounding> rounding,
RectParts corners,
const PaintContext &context) const; const PaintContext &context) const;
const not_null<Data::Invoice*> _invoice; const not_null<Data::Invoice*> _invoice;
@ -109,9 +103,8 @@ private:
mutable QImage _buttonBackground; mutable QImage _buttonBackground;
mutable QColor _buttonBackgroundOverlay; mutable QColor _buttonBackgroundOverlay;
mutable Ui::Text::String _buttonText; mutable Ui::Text::String _buttonText;
mutable int _imageCacheRoundRadius : 4 = 0; mutable std::optional<Ui::BubbleRounding> _imageCacheRounding;
mutable int _imageCacheRoundCorners : 12 = 0; mutable bool _imageCacheInvalid = false;
mutable int _imageCacheInvalid : 1 = 0;
}; };

View file

@ -163,8 +163,11 @@ void Location::draw(Painter &p, const PaintContext &context) const {
const auto sti = context.imageStyle(); const auto sti = context.imageStyle();
const auto stm = context.messageStyle(); const auto stm = context.messageStyle();
const auto hasText = !_title.isEmpty() || !_description.isEmpty();
const auto rounding = adjustedBubbleRounding(
hasText ? RectPart::FullTop : RectPart());
if (bubble) { if (bubble) {
if (!_title.isEmpty() || !_description.isEmpty()) { if (hasText) {
if (isBubbleTop()) { if (isBubbleTop()) {
painty += st::msgPadding.top(); painty += st::msgPadding.top();
} }
@ -185,26 +188,34 @@ void Location::draw(Painter &p, const PaintContext &context) const {
painty += st::mediaInBubbleSkip; painty += st::mediaInBubbleSkip;
} }
painth -= painty; painth -= painty;
} else { }
// #TODO rounding auto rthumb = QRect(paintx, painty, paintw, painth);
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCornersSmall); if (!bubble) {
fillImageShadow(p, rthumb, rounding, context);
} }
auto roundRadius = ImageRoundRadius::Large;
auto roundCorners = ((isBubbleTop() && _title.isEmpty() && _description.isEmpty()) ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
| (isRoundedInBubbleBottom() ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None);
auto rthumb = QRect(paintx, painty, paintw, painth);
ensureMediaCreated(); ensureMediaCreated();
if (const auto thumbnail = _media->image()) { //if (const auto thumbnail = _media->image()) {
p.drawPixmap(rthumb.topLeft(), thumbnail->pixSingle( // p.drawPixmap(rthumb.topLeft(), thumbnail->pixSingle(
rthumb.size(), // rthumb.size(),
{ // {
.options = Images::RoundOptions(roundRadius, roundCorners), // .options = Images::RoundOptions(roundRadius, roundCorners),
.outer = rthumb.size(), // .outer = rthumb.size(),
})); // }));
} else { //} else if (!bubble) {
Ui::FillComplexLocationRect(p, st, rthumb, roundRadius, roundCorners); Ui::PaintBubble(
} p,
Ui::SimpleBubble{
.st = context.st,
.geometry = rthumb,
.pattern = context.bubblesPattern,
.patternViewport = context.viewport,
.outerWidth = width(),
.selected = context.selected(),
.outbg = context.outbg,
.rounding = rounding,
});
//}
const auto paintMarker = [&](const style::icon &icon) { const auto paintMarker = [&](const style::icon &icon) {
icon.paint( icon.paint(
p, p,
@ -215,7 +226,7 @@ void Location::draw(Painter &p, const PaintContext &context) const {
paintMarker(st->historyMapPoint()); paintMarker(st->historyMapPoint());
paintMarker(st->historyMapPointInner()); paintMarker(st->historyMapPointInner());
if (context.selected()) { if (context.selected()) {
Ui::FillComplexOverlayRect(p, st, rthumb, roundRadius, roundCorners); fillImageOverlay(p, rthumb, rounding, context);
} }
if (_parent->media() == this) { if (_parent->media() == this) {

View file

@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/item_text_options.h" #include "ui/item_text_options.h"
#include "ui/chat/chat_style.h" #include "ui/chat/chat_style.h"
#include "ui/chat/message_bubble.h" #include "ui/chat/message_bubble.h"
#include "ui/image/image_prepare.h"
#include "core/ui_integration.h" #include "core/ui_integration.h"
#include "styles/style_chat.h" #include "styles/style_chat.h"
@ -187,6 +188,60 @@ QSize Media::countCurrentSize(int newWidth) {
return QSize(qMin(newWidth, maxWidth()), minHeight()); return QSize(qMin(newWidth, maxWidth()), minHeight());
} }
void Media::fillImageShadow(
QPainter &p,
QRect rect,
Ui::BubbleRounding rounding,
const PaintContext &context) const {
const auto sti = context.imageStyle();
auto corners = Ui::CornersPixmaps();
const auto choose = [&](int index) -> QPixmap {
using Corner = Ui::BubbleCornerRounding;
switch (rounding[index]) {
case Corner::Large: return sti->msgShadowCornersLarge.p[index];
case Corner::Small: return sti->msgShadowCornersSmall.p[index];
}
return QPixmap();
};
corners.p[2] = choose(2);
corners.p[3] = choose(3);
Ui::FillRoundShadow(p, rect, sti->msgShadow, corners);
}
void Media::fillImageOverlay(
QPainter &p,
QRect rect,
std::optional<Ui::BubbleRounding> rounding,
const PaintContext &context) const {
using Radius = Ui::CachedCornerRadius;
const auto &st = context.st;
if (!rounding) {
Ui::FillComplexOverlayRect(
p,
rect,
st->msgSelectOverlay(),
st->msgSelectOverlayCorners(Radius::Small));
return;
}
using Corner = Ui::BubbleCornerRounding;
auto corners = Ui::CornersPixmaps();
const auto lookup = [&](Corner corner) {
switch (corner) {
case Corner::None: return Radius::kCount;
case Corner::Small: return Radius::BubbleSmall;
case Corner::Large: return Radius::BubbleLarge;
}
Unexpected("Corner value in Document::fillThumbnailOverlay.");
};
for (auto i = 0; i != 4; ++i) {
const auto radius = lookup((*rounding)[i]);
corners.p[i] = (radius == Radius::kCount)
? QPixmap()
: st->msgSelectOverlayCorners(radius).p[i];
}
Ui::FillComplexOverlayRect(p, rect, st->msgSelectOverlay(), corners);
}
void Media::repaint() const { void Media::repaint() const {
history()->owner().requestViewRepaint(_parent); history()->owner().requestViewRepaint(_parent);
} }
@ -257,10 +312,59 @@ TextState Media::getStateGrouped(
Unexpected("Grouping method call."); Unexpected("Grouping method call.");
} }
Ui::BubbleRounding Media::adjustedBubbleRounding(RectParts square) const {
auto result = bubbleRounding();
using Corner = Ui::BubbleCornerRounding;
const auto adjust = [&](bool round, Corner already, RectPart corner) {
return (already == Corner::Tail || !round || (square & corner))
? Corner::None
: already;
};
const auto top = isBubbleTop();
const auto bottom = isRoundedInBubbleBottom();
result.topLeft = adjust(top, result.topLeft, RectPart::TopLeft);
result.topRight = adjust(top, result.topRight, RectPart::TopRight);
result.bottomLeft = adjust(
bottom,
result.bottomLeft,
RectPart::BottomLeft);
result.bottomRight = adjust(
bottom,
result.bottomRight,
RectPart::BottomRight);
return result;
}
Ui::BubbleRounding Media::adjustedBubbleRoundingWithCaption(
const Ui::Text::String &caption) const {
return adjustedBubbleRounding(
caption.isEmpty() ? RectParts() : RectPart::FullBottom);
}
bool Media::isRoundedInBubbleBottom() const { bool Media::isRoundedInBubbleBottom() const {
return isBubbleBottom() return isBubbleBottom()
&& !_parent->data()->repliesAreComments() && !_parent->data()->repliesAreComments()
&& !_parent->data()->externalReply(); && !_parent->data()->externalReply();
} }
Images::CornersMaskRef MediaRoundingMask(
std::optional<Ui::BubbleRounding> rounding) {
using Radius = Ui::CachedCornerRadius;
if (!rounding) {
return Images::CornersMaskRef(Ui::CachedCornersMasks(Radius::Small));
}
using Corner = Ui::BubbleCornerRounding;
auto result = Images::CornersMaskRef();
const auto &small = Ui::CachedCornersMasks(Radius::BubbleSmall);
const auto &large = Ui::CachedCornersMasks(Radius::BubbleLarge);
for (auto i = 0; i != 4; ++i) {
switch ((*rounding)[i]) {
case Corner::Small: result.p[i] = &small[i]; break;
case Corner::Large: result.p[i] = &large[i]; break;
}
}
return result;
}
} // namespace HistoryView } // namespace HistoryView

View file

@ -32,8 +32,13 @@ struct ColorReplacements;
namespace Ui { namespace Ui {
struct BubbleSelectionInterval; struct BubbleSelectionInterval;
struct ChatPaintContext; struct ChatPaintContext;
struct CornersMaskRef;
} // namespace Ui } // namespace Ui
namespace Images {
struct CornersMaskRef;
} // namespace Images
namespace HistoryView { namespace HistoryView {
enum class PointState : char; enum class PointState : char;
@ -246,6 +251,10 @@ public:
[[nodiscard]] Ui::BubbleRounding bubbleRounding() const { [[nodiscard]] Ui::BubbleRounding bubbleRounding() const {
return _bubbleRounding; return _bubbleRounding;
} }
[[nodiscard]] Ui::BubbleRounding adjustedBubbleRounding(
RectParts square = {}) const;
[[nodiscard]] Ui::BubbleRounding adjustedBubbleRoundingWithCaption(
const Ui::Text::String &caption) const;
[[nodiscard]] bool isBubbleTop() const { [[nodiscard]] bool isBubbleTop() const {
return (_inBubbleState == MediaInBubbleState::Top) return (_inBubbleState == MediaInBubbleState::Top)
|| (_inBubbleState == MediaInBubbleState::None); || (_inBubbleState == MediaInBubbleState::None);
@ -321,6 +330,17 @@ protected:
[[nodiscard]] bool usesBubblePattern(const PaintContext &context) const; [[nodiscard]] bool usesBubblePattern(const PaintContext &context) const;
void fillImageShadow(
QPainter &p,
QRect rect,
Ui::BubbleRounding rounding,
const PaintContext &context) const;
void fillImageOverlay(
QPainter &p,
QRect rect,
std::optional<Ui::BubbleRounding> rounding, // nullopt if in WebPage.
const PaintContext &context) const;
void repaint() const; void repaint() const;
const not_null<Element*> _parent; const not_null<Element*> _parent;
@ -329,4 +349,7 @@ protected:
}; };
[[nodiscard]] Images::CornersMaskRef MediaRoundingMask(
std::optional<Ui::BubbleRounding> rounding);
} // namespace HistoryView } // namespace HistoryView

View file

@ -258,6 +258,9 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
if (_serviceWidth > 0) { if (_serviceWidth > 0) {
paintUserpicFrame(p, context, rthumb.topLeft()); paintUserpicFrame(p, context, rthumb.topLeft());
} else { } else {
const auto rounding = inWebPage
? std::optional<Ui::BubbleRounding>()
: adjustedBubbleRoundingWithCaption(_caption);
if (bubble) { if (bubble) {
if (!_caption.isEmpty()) { if (!_caption.isEmpty()) {
painth -= st::mediaCaptionSkip + _caption.countHeight(captionw); painth -= st::mediaCaptionSkip + _caption.countHeight(captionw);
@ -267,19 +270,13 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
rthumb = style::rtlrect(paintx, painty, paintw, painth, width()); rthumb = style::rtlrect(paintx, painty, paintw, painth, width());
} }
} else { } else {
// #TODO rounding Assert(rounding.has_value());
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCornersSmall); fillImageShadow(p, rthumb, *rounding, context);
} }
const auto inWebPage = (_parent->media() != this); validateImageCache(rthumb.size(), rounding);
const auto roundRadius = inWebPage
? ImageRoundRadius::Small
: ImageRoundRadius::Large;
const auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
| ((isRoundedInBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None));
validateImageCache(rthumb.size(), roundRadius, roundCorners);
p.drawImage(rthumb.topLeft(), _imageCache); p.drawImage(rthumb.topLeft(), _imageCache);
if (context.selected()) { if (context.selected()) {
Ui::FillComplexOverlayRect(p, st, rthumb, roundRadius, roundCorners); fillImageOverlay(p, rthumb, rounding, context);
} }
} }
if (radial || (!loaded && !_data->loading())) { if (radial || (!loaded && !_data->loading())) {
@ -355,32 +352,22 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
void Photo::validateImageCache( void Photo::validateImageCache(
QSize outer, QSize outer,
ImageRoundRadius radius, std::optional<Ui::BubbleRounding> rounding) const {
RectParts corners) const {
const auto intRadius = static_cast<int>(radius);
const auto intCorners = static_cast<int>(corners);
const auto large = _dataMedia->image(PhotoSize::Large); const auto large = _dataMedia->image(PhotoSize::Large);
const auto ratio = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
const auto shouldBeBlurred = (large != nullptr) ? 0 : 1; const auto shouldBeBlurred = !large;
if (_imageCache.size() == (outer * ratio) if (_imageCache.size() == (outer * ratio)
&& _imageCacheRoundRadius == intRadius && _imageCacheRounding == rounding
&& _imageCacheRoundCorners == intCorners
&& _imageCacheBlurred == shouldBeBlurred) { && _imageCacheBlurred == shouldBeBlurred) {
return; return;
} }
_imageCache = prepareImageCache(outer, radius, corners); _imageCache = Images::Round(
_imageCacheRoundRadius = intRadius; prepareImageCache(outer),
_imageCacheRoundCorners = intCorners; MediaRoundingMask(rounding));
_imageCacheRounding = rounding;
_imageCacheBlurred = shouldBeBlurred; _imageCacheBlurred = shouldBeBlurred;
} }
QImage Photo::prepareImageCache(
QSize outer,
ImageRoundRadius radius,
RectParts corners) const {
return Images::Round(prepareImageCache(outer), radius, corners);
}
QImage Photo::prepareImageCache(QSize outer) const { QImage Photo::prepareImageCache(QSize outer) const {
using Size = PhotoSize; using Size = PhotoSize;
const auto large = _dataMedia->image(Size::Large); const auto large = _dataMedia->image(Size::Large);

View file

@ -128,12 +128,7 @@ private:
not_null<QPixmap*> cache) const; not_null<QPixmap*> cache) const;
void validateImageCache( void validateImageCache(
QSize outer, QSize outer,
ImageRoundRadius radius, std::optional<Ui::BubbleRounding> rounding) const;
RectParts corners) const;
[[nodiscard]] QImage prepareImageCache(
QSize outer,
ImageRoundRadius radius,
RectParts corners) const;
[[nodiscard]] QImage prepareImageCache(QSize outer) const; [[nodiscard]] QImage prepareImageCache(QSize outer) const;
bool videoAutoplayEnabled() const; bool videoAutoplayEnabled() const;
@ -155,9 +150,8 @@ private:
mutable std::unique_ptr<Streamed> _streamed; mutable std::unique_ptr<Streamed> _streamed;
mutable QImage _imageCache; mutable QImage _imageCache;
int _serviceWidth = 0; int _serviceWidth = 0;
mutable int _imageCacheRoundRadius : 4 = 0; mutable std::optional<Ui::BubbleRounding> _imageCacheRounding;
mutable int _imageCacheRoundCorners : 12 = 0; mutable bool _imageCacheBlurred = false;
mutable int _imageCacheBlurred : 1 = 0;
}; };

View file

@ -185,7 +185,7 @@ void ThemeDocument::draw(Painter &p, const PaintContext &context) const {
p, p,
rthumb, rthumb,
st->msgSelectOverlay(), st->msgSelectOverlay(),
st->msgSelectOverlayCornersSmall()); st->msgSelectOverlayCorners(Ui::CachedCornerRadius::Small));
} }
if (_data) { if (_data) {

View file

@ -536,7 +536,7 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
p, p,
style::rtlrect(padding.left() + paintw - pw, tshift, pw, _pixh, width()), style::rtlrect(padding.left() + paintw - pw, tshift, pw, _pixh, width()),
st->msgSelectOverlay(), st->msgSelectOverlay(),
st->msgSelectOverlayCornersSmall()); st->msgSelectOverlayCorners(Ui::CachedCornerRadius::Small));
} }
paintw -= pw + st::webPagePhotoDelta; paintw -= pw + st::webPagePhotoDelta;
} }

View file

@ -161,24 +161,35 @@ void FillRoundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color
FillRoundRect(p, x, y, w, h, bg, Corners[index], shadow, parts); FillRoundRect(p, x, y, w, h, bg, Corners[index], shadow, parts);
} }
void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, CachedRoundCorners index, RectParts parts) { void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, CachedRoundCorners index) {
FillRoundShadow(p, x, y, w, h, shadow, Corners[index], parts); FillRoundShadow(p, x, y, w, h, shadow, Corners[index]);
} }
void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, const CornersPixmaps &corner, RectParts parts) { void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, const CornersPixmaps &corners) {
auto cornerWidth = corner.p[0].width() / style::DevicePixelRatio(); constexpr auto kLeft = 2;
auto cornerHeight = corner.p[0].height() / style::DevicePixelRatio(); constexpr auto kRight = 3;
if (parts & RectPart::Bottom) {
p.fillRect(x + cornerWidth, y + h, w - 2 * cornerWidth, st::msgShadow, shadow); const auto ratio = style::DevicePixelRatio();
} const auto size = [&](int index) {
if (parts & RectPart::BottomLeft) { const auto &pix = corners.p[index];
p.fillRect(x, y + h - cornerHeight, cornerWidth, st::msgShadow, shadow); return pix.isNull() ? 0 : (pix.width() / ratio);
p.drawPixmap(x, y + h - cornerHeight + st::msgShadow, corner.p[2]); };
} const auto fillCorner = [&](int left, int bottom, int index) {
if (parts & RectPart::BottomRight) { const auto &pix = corners.p[index];
p.fillRect(x + w - cornerWidth, y + h - cornerHeight, cornerWidth, st::msgShadow, shadow); if (pix.isNull()) {
p.drawPixmap(x + w - cornerWidth, y + h - cornerHeight + st::msgShadow, corner.p[3]); return;
}
const auto size = pix.width() / ratio;
p.drawPixmap(left, bottom - size, pix);
};
const auto left = size(kLeft);
const auto right = size(kRight);
const auto from = x + left;
fillCorner(x, y + h + st::msgShadow, kLeft);
if (const auto width = w - left - right; width > 0) {
p.fillRect(from, y + h, width, st::msgShadow, shadow);
} }
fillCorner(x + w - right, y + h + st::msgShadow, kRight);
} }
CornersPixmaps PrepareCornerPixmaps(int32 radius, style::color bg, const style::color *sh) { CornersPixmaps PrepareCornerPixmaps(int32 radius, style::color bg, const style::color *sh) {
@ -219,21 +230,26 @@ void FillRoundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color
FillRoundRect(p, x, y, w, h, bg, i->second, nullptr, parts); FillRoundRect(p, x, y, w, h, bg, i->second, nullptr, parts);
} }
[[nodiscard]] int CachedCornerRadiusValue(CachedCornerRadius tag) {
using Radius = CachedCornerRadius;
switch (tag) {
case Radius::Small: return st::roundRadiusSmall;
case Radius::ThumbSmall: return st::msgFileThumbRadiusSmall;
case Radius::ThumbLarge: return st::msgFileThumbRadiusLarge;
case Radius::BubbleSmall: return st::bubbleRadiusSmall;
case Radius::BubbleLarge: return st::bubbleRadiusLarge;
}
Unexpected("Radius tag in CachedCornerRadiusValue.");
}
[[nodiscard]] const std::array<QImage, 4> &CachedCornersMasks( [[nodiscard]] const std::array<QImage, 4> &CachedCornersMasks(
CachedCornerRadius radius) { CachedCornerRadius radius) {
const auto index = static_cast<int>(radius); const auto index = static_cast<int>(radius);
Assert(index >= 0 && index < kCachedCornerRadiusCount); Assert(index >= 0 && index < kCachedCornerRadiusCount);
if (CachedMasks[index][0].isNull()) { if (CachedMasks[index][0].isNull()) {
using Radius = CachedCornerRadius; CachedMasks[index] = Images::CornersMask(
const auto set = [](Radius key, int radius) { CachedCornerRadiusValue(CachedCornerRadius(index)));
CachedMasks[static_cast<int>(key)] = Images::CornersMask(radius);
};
set(Radius::Small, st::roundRadiusSmall);
set(Radius::ThumbSmall, st::msgFileThumbRadiusSmall);
set(Radius::ThumbLarge, st::msgFileThumbRadiusLarge);
set(Radius::BubbleSmall, st::bubbleRadiusSmall);
set(Radius::BubbleLarge, st::bubbleRadiusLarge);
} }
return CachedMasks[index]; return CachedMasks[index];
} }

View file

@ -40,9 +40,9 @@ void FillRoundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color
inline void FillRoundRect(QPainter &p, const QRect &rect, style::color bg, CachedRoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) { inline void FillRoundRect(QPainter &p, const QRect &rect, style::color bg, CachedRoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) {
FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, index, shadow, parts); FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, index, shadow, parts);
} }
void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, CachedRoundCorners index, RectParts parts = RectPart::Full); void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, CachedRoundCorners index);
inline void FillRoundShadow(QPainter &p, const QRect &rect, style::color shadow, CachedRoundCorners index, RectParts parts = RectPart::Full) { inline void FillRoundShadow(QPainter &p, const QRect &rect, style::color shadow, CachedRoundCorners index) {
FillRoundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), shadow, index, parts); FillRoundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), shadow, index);
} }
void FillRoundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, ImageRoundRadius radius, RectParts parts = RectPart::Full); void FillRoundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color bg, ImageRoundRadius radius, RectParts parts = RectPart::Full);
inline void FillRoundRect(QPainter &p, const QRect &rect, style::color bg, ImageRoundRadius radius, RectParts parts = RectPart::Full) { inline void FillRoundRect(QPainter &p, const QRect &rect, style::color bg, ImageRoundRadius radius, RectParts parts = RectPart::Full) {
@ -61,9 +61,9 @@ void FillRoundRect(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color
inline void FillRoundRect(QPainter &p, const QRect &rect, style::color bg, const CornersPixmaps &corner, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) { inline void FillRoundRect(QPainter &p, const QRect &rect, style::color bg, const CornersPixmaps &corner, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) {
return FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, corner, shadow, parts); return FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, corner, shadow, parts);
} }
void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, const CornersPixmaps &corner, RectParts parts = RectPart::Full); void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, const CornersPixmaps &corners);
inline void FillRoundShadow(QPainter &p, const QRect &rect, style::color shadow, const CornersPixmaps &corner, RectParts parts = RectPart::Full) { inline void FillRoundShadow(QPainter &p, const QRect &rect, style::color shadow, const CornersPixmaps &corners) {
FillRoundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), shadow, corner, parts); FillRoundShadow(p, rect.x(), rect.y(), rect.width(), rect.height(), shadow, corners);
} }
enum class CachedCornerRadius { enum class CachedCornerRadius {
@ -75,6 +75,7 @@ enum class CachedCornerRadius {
kCount, kCount,
}; };
[[nodiscard]] int CachedCornerRadiusValue(CachedCornerRadius tag);
[[nodiscard]] const std::array<QImage, 4> &CachedCornersMasks( [[nodiscard]] const std::array<QImage, 4> &CachedCornersMasks(
CachedCornerRadius radius); CachedCornerRadius radius);

View file

@ -492,7 +492,9 @@ void ChatStyle::assignPalette(not_null<const style::palette*> palette) {
_serviceBgCornersNormal = {}; _serviceBgCornersNormal = {};
_serviceBgCornersInverted = {}; _serviceBgCornersInverted = {};
_msgBotKbOverBgAddCorners = {}; _msgBotKbOverBgAddCorners = {};
_msgSelectOverlayCornersSmall = {}; for (auto &corners : _msgSelectOverlayCorners) {
corners = {};
}
for (auto &stm : _messageStyles) { for (auto &stm : _messageStyles) {
const auto same = (stm.textPalette.linkFg->c == stm.historyTextFg->c); const auto same = (stm.textPalette.linkFg->c == stm.historyTextFg->c);
@ -550,7 +552,7 @@ const MessageImageStyle &ChatStyle::imageStyle(bool selected) const {
auto &result = imageStyleRaw(selected); auto &result = imageStyleRaw(selected);
EnsureCorners( EnsureCorners(
result.msgDateImgBgCorners, result.msgDateImgBgCorners,
st::dateRadius, (st::msgDateImgPadding.y() * 2 + st::normalFont->height) / 2,
result.msgDateImgBg); result.msgDateImgBg);
EnsureCorners( EnsureCorners(
result.msgServiceBgCorners, result.msgServiceBgCorners,
@ -575,28 +577,16 @@ const CornersPixmaps &ChatStyle::msgBotKbOverBgAddCorners() const {
return _msgBotKbOverBgAddCorners; return _msgBotKbOverBgAddCorners;
} }
const CornersPixmaps &ChatStyle::msgSelectOverlayCornersSmall() const { const CornersPixmaps &ChatStyle::msgSelectOverlayCorners(
EnsureCorners( CachedCornerRadius radius) const {
_msgSelectOverlayCornersSmall, const auto index = static_cast<int>(radius);
st::roundRadiusSmall, Assert(index >= 0 && index < int(CachedCornerRadius::kCount));
msgSelectOverlay());
return _msgSelectOverlayCornersSmall;
}
const CornersPixmaps &ChatStyle::msgSelectOverlayCornersThumbSmall() const {
EnsureCorners( EnsureCorners(
_msgSelectOverlayCornersThumbSmall, _msgSelectOverlayCorners[index],
st::msgFileThumbRadiusSmall, CachedCornerRadiusValue(radius),
msgSelectOverlay()); msgSelectOverlay());
return _msgSelectOverlayCornersThumbSmall; return _msgSelectOverlayCorners[index];
}
const CornersPixmaps &ChatStyle::msgSelectOverlayCornersThumbLarge() const {
EnsureCorners(
_msgSelectOverlayCornersThumbLarge,
st::msgFileThumbRadiusLarge,
msgSelectOverlay());
return _msgSelectOverlayCornersThumbLarge;
} }
MessageStyle &ChatStyle::messageStyleRaw(bool outbg, bool selected) const { MessageStyle &ChatStyle::messageStyleRaw(bool outbg, bool selected) const {

View file

@ -192,11 +192,8 @@ public:
[[nodiscard]] const MessageImageStyle &imageStyle(bool selected) const; [[nodiscard]] const MessageImageStyle &imageStyle(bool selected) const;
[[nodiscard]] const CornersPixmaps &msgBotKbOverBgAddCorners() const; [[nodiscard]] const CornersPixmaps &msgBotKbOverBgAddCorners() const;
[[nodiscard]] const CornersPixmaps &msgSelectOverlayCornersSmall() const; [[nodiscard]] const CornersPixmaps &msgSelectOverlayCorners(
[[nodiscard]] auto msgSelectOverlayCornersThumbSmall() const CachedCornerRadius radius) const;
-> const CornersPixmaps &;
[[nodiscard]] auto msgSelectOverlayCornersThumbLarge() const
-> const CornersPixmaps &;
[[nodiscard]] const style::TextPalette &historyPsaForwardPalette() const { [[nodiscard]] const style::TextPalette &historyPsaForwardPalette() const {
return _historyPsaForwardPalette; return _historyPsaForwardPalette;
@ -322,9 +319,8 @@ private:
mutable std::array<MessageImageStyle, 2> _imageStyles; mutable std::array<MessageImageStyle, 2> _imageStyles;
mutable CornersPixmaps _msgBotKbOverBgAddCorners; mutable CornersPixmaps _msgBotKbOverBgAddCorners;
mutable CornersPixmaps _msgSelectOverlayCornersSmall; mutable CornersPixmaps _msgSelectOverlayCorners[
mutable CornersPixmaps _msgSelectOverlayCornersThumbSmall; int(CachedCornerRadius::kCount)];
mutable CornersPixmaps _msgSelectOverlayCornersThumbLarge;
style::TextPalette _historyPsaForwardPalette; style::TextPalette _historyPsaForwardPalette;
style::TextPalette _imgReplyTextPalette; style::TextPalette _imgReplyTextPalette;

@ -1 +1 @@
Subproject commit f49ec866c11fc887d9b16435f67f756d523a9b5b Subproject commit cec09b0260ba19639bf9abc7df373569aa1509e7