Support new rounding for GIFs / videos.

This commit is contained in:
John Preston 2022-10-03 11:35:11 +04:00
parent b2302d35fe
commit 8268e9f872
17 changed files with 170 additions and 193 deletions

View File

@ -626,19 +626,24 @@ struct VideoPreviewDocument {
}; };
check(); check();
const auto corners = alignToBottom
? (RectPart::TopLeft | RectPart::TopRight)
: (RectPart::BottomLeft | RectPart::BottomRight);
const auto ready = state->instance.player().ready() const auto ready = state->instance.player().ready()
&& !state->instance.player().videoSize().isEmpty(); && !state->instance.player().videoSize().isEmpty();
const auto size = QSize(width, height) * style::DevicePixelRatio(); const auto size = QSize(width, height) * style::DevicePixelRatio();
using namespace Images;
auto rounding = CornersMaskRef(
Images::CornersMask(ImageRoundRadius::Large));
if (alignToBottom) {
rounding.p[kBottomLeft] = rounding.p[kBottomRight] = nullptr;
} else {
rounding.p[kTopLeft] = rounding.p[kTopRight] = nullptr;
}
const auto frame = !ready const auto frame = !ready
? state->blurred ? state->blurred
: state->instance.frame({ : state->instance.frame({
.resize = size, .resize = size,
.outer = size, .outer = size,
.radius = ImageRoundRadius::Large, .rounding = rounding,
.corners = corners,
}); });
paintFrame(QColor(0, 0, 0, 128), 12.); paintFrame(QColor(0, 0, 0, 128), 12.);
p.drawImage(QRect(left, top, width, height), frame); p.drawImage(QRect(left, top, width, height), frame);

View File

@ -274,6 +274,32 @@ QSize Gif::videoSize() const {
} }
} }
void Gif::validateRoundingMask(QSize size) const {
if (_roundingMask.size() != size) {
const auto ratio = style::DevicePixelRatio();
_roundingMask = Images::EllipseMask(size / ratio);
}
}
Images::CornersMaskRef Gif::prepareRoundingRef(
std::optional<Ui::BubbleRounding> 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 { bool Gif::downloadInCorner() const {
return _data->isVideoFile() return _data->isVideoFile()
&& (_data->loading() || !autoplayEnabled()) && (_data->loading() || !autoplayEnabled())
@ -349,6 +375,9 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
const auto radial = isRadialAnimation() const auto radial = isRadialAnimation()
|| (streamedForWaiting && streamedForWaiting->waitingShown()); || (streamedForWaiting && streamedForWaiting->waitingShown());
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);
@ -356,9 +385,6 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
painth -= st::msgPadding.bottom(); painth -= st::msgPadding.bottom();
} }
} }
} else if (!unwrapped) {
// #TODO rounding
Ui::FillRoundShadow(p, 0, 0, paintw, height(), sti->msgShadow, sti->msgShadowCornersSmall);
} }
auto usex = 0, usew = paintw; auto usex = 0, usew = paintw;
@ -381,42 +407,30 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
QRect rthumb(style::rtlrect(usex + paintx, painty, usew, painth, width())); QRect rthumb(style::rtlrect(usex + paintx, painty, usew, painth, width()));
const auto roundRadius = isRound if (!bubble && !unwrapped) {
? ImageRoundRadius::Ellipse Assert(rounding.has_value());
: unwrapped fillImageShadow(p, rthumb, *rounding, context);
? ImageRoundRadius::None }
: inWebPage
? ImageRoundRadius::Small
: ImageRoundRadius::Large;
const auto roundCorners = isRound
? RectPart::AllCorners
: unwrapped
? RectPart::None
: inWebPage
? RectPart::AllCorners
: ((isBubbleTop()
? (RectPart::TopLeft | RectPart::TopRight)
: RectPart::None)
| ((isRoundedInBubbleBottom() && _caption.isEmpty())
? (RectPart::BottomLeft | RectPart::BottomRight)
: RectPart::None));
const auto skipDrawingContent = context.skipDrawingParts const auto skipDrawingContent = context.skipDrawingParts
== PaintContext::SkipDrawingParts::Content; == PaintContext::SkipDrawingParts::Content;
if (streamed && !skipDrawingContent) { if (streamed && !skipDrawingContent) {
auto paused = context.paused; auto paused = context.paused;
auto request = ::Media::Streaming::FrameRequest{
.outer = QSize(usew, painth) * cIntRetinaFactor(),
.blurredBackground = true,
};
if (isRound) { if (isRound) {
if (activeRoundStreamed()) { if (activeRoundStreamed()) {
paused = false; paused = false;
} else { } else {
displayMute = true; displayMute = true;
} }
validateRoundingMask(request.outer);
request.mask = _roundingMask;
} else {
request.rounding = prepareRoundingRef(rounding);
} }
auto request = ::Media::Streaming::FrameRequest{
.outer = QSize(usew, painth) * cIntRetinaFactor(),
.radius = roundRadius,
.corners = roundCorners,
.blurredBackground = true,
};
if (!activeRoundPlaying && activeOwnPlaying->instance.playerLocked()) { if (!activeRoundPlaying && activeOwnPlaying->instance.playerLocked()) {
if (activeOwnPlaying->frozenFrame.isNull()) { if (activeOwnPlaying->frozenFrame.isNull()) {
activeOwnPlaying->frozenRequest = request; activeOwnPlaying->frozenRequest = request;
@ -465,12 +479,16 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
} }
} else if (!skipDrawingContent) { } else if (!skipDrawingContent) {
ensureDataMediaCreated(); ensureDataMediaCreated();
validateThumbCache({ usew, painth }, roundRadius, roundCorners); validateThumbCache({ usew, painth }, isRound, rounding);
p.drawImage(rthumb, _thumbCache); p.drawImage(rthumb, _thumbCache);
} }
if (context.selected()) { if (context.selected()) {
Ui::FillComplexOverlayRect(p, st, rthumb, roundRadius, roundCorners); if (isRound) {
Ui::FillComplexEllipse(p, st, rthumb);
} else {
fillImageOverlay(p, rthumb, rounding, context);
}
} }
if (radial if (radial
@ -691,10 +709,8 @@ void Gif::validateVideoThumbnail() const {
void Gif::validateThumbCache( void Gif::validateThumbCache(
QSize outer, QSize outer,
ImageRoundRadius radius, bool isEllipse,
RectParts corners) const { std::optional<Ui::BubbleRounding> rounding) const {
const auto intRadius = static_cast<int>(radius);
const auto intCorners = static_cast<int>(corners);
const auto good = _dataMedia->goodThumbnail(); const auto good = _dataMedia->goodThumbnail();
const auto normal = good ? good : _dataMedia->thumbnail(); const auto normal = good ? good : _dataMedia->thumbnail();
if (!normal) { if (!normal) {
@ -708,24 +724,18 @@ void Gif::validateThumbCache(
&& (normal->height() < kUseNonBlurredThreshold)) && (normal->height() < kUseNonBlurredThreshold))
: !videothumb; : !videothumb;
const auto ratio = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
const auto shouldBeBlurred = blurred ? 1 : 0;
if (_thumbCache.size() == (outer * ratio) if (_thumbCache.size() == (outer * ratio)
&& _thumbCacheRoundRadius == intRadius && _thumbCacheRounding == rounding
&& _thumbCacheRoundCorners == intCorners && _thumbCacheBlurred == blurred
&& _thumbCacheBlurred == shouldBeBlurred) { && _thumbIsEllipse == isEllipse) {
return; return;
} }
_thumbCache = prepareThumbCache(outer, radius, corners); auto cache = prepareThumbCache(outer);
_thumbCacheRoundRadius = intRadius; _thumbCache = isEllipse
_thumbCacheRoundCorners = intCorners; ? Images::Circle(std::move(cache))
_thumbCacheBlurred = shouldBeBlurred; : Images::Round(std::move(cache), MediaRoundingMask(rounding));
} _thumbCacheRounding = rounding;
_thumbCacheBlurred = blurred;
QImage Gif::prepareThumbCache(
QSize outer,
ImageRoundRadius radius,
RectParts corners) const {
return Images::Round(prepareThumbCache(outer), radius, corners);
} }
QImage Gif::prepareThumbCache(QSize outer) const { QImage Gif::prepareThumbCache(QSize outer) const {
@ -1071,8 +1081,8 @@ void Gif::drawGrouped(
auto request = ::Media::Streaming::FrameRequest{ auto request = ::Media::Streaming::FrameRequest{
.resize = pixSize * cIntRetinaFactor(), .resize = pixSize * cIntRetinaFactor(),
.outer = geometry.size() * cIntRetinaFactor(), .outer = geometry.size() * cIntRetinaFactor(),
.radius = roundRadius, //.radius = roundRadius, // #TODO rounding
.corners = corners, //.corners = corners,
}; };
if (activeOwnPlaying->instance.playerLocked()) { if (activeOwnPlaying->instance.playerLocked()) {
if (activeOwnPlaying->frozenFrame.isNull()) { if (activeOwnPlaying->frozenFrame.isNull()) {
@ -1104,10 +1114,11 @@ void Gif::drawGrouped(
: highlightOpacity; : highlightOpacity;
if (overlayOpacity > 0.) { if (overlayOpacity > 0.) {
p.setOpacity(overlayOpacity); p.setOpacity(overlayOpacity);
Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); // #TODO rounding
if (!context.selected()) { //Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners);
Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); //if (!context.selected()) {
} // Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners);
//}
p.setOpacity(1.); p.setOpacity(1.);
} }

View File

@ -163,12 +163,8 @@ private:
void validateThumbCache( void validateThumbCache(
QSize outer, QSize outer,
ImageRoundRadius radius, bool isEllipse,
RectParts corners) const; std::optional<Ui::BubbleRounding> rounding) const;
[[nodiscard]] QImage prepareThumbCache(
QSize outer,
ImageRoundRadius radius,
RectParts corners) const;
[[nodiscard]] QImage prepareThumbCache(QSize outer) const; [[nodiscard]] QImage prepareThumbCache(QSize outer) const;
void validateGroupedCache( void validateGroupedCache(
@ -180,6 +176,10 @@ private:
void updateStatusText() const; void updateStatusText() const;
[[nodiscard]] QSize sizeForAspectRatio() const; [[nodiscard]] QSize sizeForAspectRatio() const;
void validateRoundingMask(QSize size) const;
[[nodiscard]] Images::CornersMaskRef prepareRoundingRef(
std::optional<Ui::BubbleRounding> rounding) const;
[[nodiscard]] bool downloadInCorner() const; [[nodiscard]] bool downloadInCorner() const;
void drawCornerStatus( void drawCornerStatus(
Painter &p, Painter &p,
@ -197,9 +197,10 @@ private:
mutable std::unique_ptr<Image> _videoThumbnailFrame; mutable std::unique_ptr<Image> _videoThumbnailFrame;
QString _downloadSize; QString _downloadSize;
mutable QImage _thumbCache; mutable QImage _thumbCache;
mutable int _thumbCacheRoundRadius : 4 = 0; mutable QImage _roundingMask;
mutable int _thumbCacheRoundCorners : 12 = 0; mutable std::optional<Ui::BubbleRounding> _thumbCacheRounding;
mutable int _thumbCacheBlurred : 1 = 0; mutable bool _thumbCacheBlurred = false;
mutable bool _thumbIsEllipse = false;
}; };

View File

@ -32,7 +32,6 @@ struct ColorReplacements;
namespace Ui { namespace Ui {
struct BubbleSelectionInterval; struct BubbleSelectionInterval;
struct ChatPaintContext; struct ChatPaintContext;
struct CornersMaskRef;
} // namespace Ui } // namespace Ui
namespace Images { namespace Images {

View File

@ -44,6 +44,7 @@ using Data::PhotoSize;
struct Photo::Streamed { struct Photo::Streamed {
explicit Streamed(std::shared_ptr<::Media::Streaming::Document> shared); explicit Streamed(std::shared_ptr<::Media::Streaming::Document> shared);
::Media::Streaming::Instance instance; ::Media::Streaming::Instance instance;
QImage roundingMask;
QImage frozenFrame; QImage frozenFrame;
}; };
@ -410,7 +411,10 @@ void Photo::paintUserpicFrame(
auto request = ::Media::Streaming::FrameRequest(); auto request = ::Media::Streaming::FrameRequest();
request.outer = size * cIntRetinaFactor(); request.outer = size * cIntRetinaFactor();
request.resize = size * cIntRetinaFactor(); request.resize = size * cIntRetinaFactor();
request.radius = ImageRoundRadius::Ellipse; if (_streamed->roundingMask.size() != request.outer) {
_streamed->roundingMask = Images::EllipseMask(size);
}
request.mask = _streamed->roundingMask;
if (_streamed->instance.playerLocked()) { if (_streamed->instance.playerLocked()) {
if (_streamed->frozenFrame.isNull()) { if (_streamed->frozenFrame.isNull()) {
_streamed->frozenFrame = _streamed->instance.frame(request); _streamed->frozenFrame = _streamed->instance.frame(request);
@ -569,10 +573,11 @@ void Photo::drawGrouped(
if (overlayOpacity > 0.) { if (overlayOpacity > 0.) {
p.setOpacity(overlayOpacity); p.setOpacity(overlayOpacity);
const auto roundRadius = ImageRoundRadius::Large; const auto roundRadius = ImageRoundRadius::Large;
Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); // #TODO rounding
if (!context.selected()) { //Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners);
Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); //if (!context.selected()) {
} // Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners);
//}
p.setOpacity(1.); p.setOpacity(1.);
} }

View File

@ -244,7 +244,10 @@ bool Float::fillFrame() {
if (const auto streamed = getStreamed()) { if (const auto streamed = getStreamed()) {
auto request = Streaming::FrameRequest::NonStrict(); auto request = Streaming::FrameRequest::NonStrict();
request.outer = request.resize = _frame.size(); request.outer = request.resize = _frame.size();
request.radius = ImageRoundRadius::Ellipse; if (_roundingMask.size() != request.outer) {
_roundingMask = Images::EllipseMask(frameInner().size());
}
request.mask = _roundingMask;
auto frame = streamed->frame(request); auto frame = streamed->frame(request);
if (!frame.isNull()) { if (!frame.isNull()) {
_frame.fill(Qt::transparent); _frame.fill(Qt::transparent);

View File

@ -96,6 +96,7 @@ private:
float64 _opacity = 1.; float64 _opacity = 1.;
QPixmap _shadow; QPixmap _shadow;
QImage _roundingMask;
QImage _frame; QImage _frame;
bool _down = false; bool _down = false;
QPoint _downPoint; QPoint _downPoint;

View File

@ -8,10 +8,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "data/data_audio_msg_id.h" #include "data/data_audio_msg_id.h"
#include "ui/image/image_prepare.h"
#include "ui/rect_part.h" #include "ui/rect_part.h"
enum class ImageRoundRadius;
namespace Media { namespace Media {
inline constexpr auto kTimeUnknown = std::numeric_limits<crl::time>::min(); inline constexpr auto kTimeUnknown = std::numeric_limits<crl::time>::min();
@ -120,8 +119,8 @@ enum class Error {
struct FrameRequest { struct FrameRequest {
QSize resize; QSize resize;
QSize outer; QSize outer;
ImageRoundRadius radius = ImageRoundRadius(); Images::CornersMaskRef rounding;
RectParts corners = RectPart::AllCorners; QImage mask;
QColor colored = QColor(0, 0, 0, 0); QColor colored = QColor(0, 0, 0, 0);
bool blurredBackground = false; bool blurredBackground = false;
bool requireARGB32 = true; bool requireARGB32 = true;
@ -141,8 +140,8 @@ struct FrameRequest {
[[nodiscard]] bool operator==(const FrameRequest &other) const { [[nodiscard]] bool operator==(const FrameRequest &other) const {
return (resize == other.resize) return (resize == other.resize)
&& (outer == other.outer) && (outer == other.outer)
&& (radius == other.radius) && (rounding == other.rounding)
&& (corners == other.corners) && (mask.constBits() == other.mask.constBits())
&& (colored == other.colored) && (colored == other.colored)
&& (keepAlpha == other.keepAlpha) && (keepAlpha == other.keepAlpha)
&& (requireARGB32 == other.requireARGB32) && (requireARGB32 == other.requireARGB32)

View File

@ -101,8 +101,7 @@ bool GoodForRequest(
return true; return true;
} else if (rotation != 0) { } else if (rotation != 0) {
return false; return false;
} else if ((request.radius != ImageRoundRadius::None) } else if (!request.rounding.empty() || !request.mask.isNull()) {
&& ((request.corners & RectPart::AllCorners) != 0)) {
return false; return false;
} }
const auto size = request.blurredBackground const auto size = request.blurredBackground
@ -348,14 +347,15 @@ void PaintFrameContent(
} }
void ApplyFrameRounding(QImage &storage, const FrameRequest &request) { void ApplyFrameRounding(QImage &storage, const FrameRequest &request) {
if (!(request.corners & RectPart::AllCorners) if (!request.mask.isNull()) {
|| (request.radius == ImageRoundRadius::None)) { auto p = QPainter(&storage);
return; p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.drawImage(
QRect(QPoint(), storage.size() / storage.devicePixelRatio()),
request.mask);
} else if (!request.rounding.empty()) {
storage = Images::Round(std::move(storage), request.rounding);
} }
storage = Images::Round(
std::move(storage),
request.radius,
request.corners);
} }
ExpandDecision DecideFrameResize( ExpandDecision DecideFrameResize(

View File

@ -21,45 +21,43 @@ namespace {
if (!rotation) { if (!rotation) {
return request; return request;
} }
const auto unrotatedCorner = [&](RectPart corner) { const auto unrotatedCorner = [&](int index) {
if (!(request.corners & corner)) { using namespace Images;
return RectPart(0); switch (index) {
} case kTopLeft:
switch (corner) {
case RectPart::TopLeft:
return (rotation == 90) return (rotation == 90)
? RectPart::BottomLeft ? kBottomLeft
: (rotation == 180) : (rotation == 180)
? RectPart::BottomRight ? kBottomRight
: RectPart::TopRight; : kTopRight;
case RectPart::TopRight: case kTopRight:
return (rotation == 90) return (rotation == 90)
? RectPart::TopLeft ? kTopLeft
: (rotation == 180) : (rotation == 180)
? RectPart::BottomLeft ? kBottomLeft
: RectPart::BottomRight; : kBottomRight;
case RectPart::BottomRight: case kBottomRight:
return (rotation == 90) return (rotation == 90)
? RectPart::TopRight ? kTopRight
: (rotation == 180) : (rotation == 180)
? RectPart::TopLeft ? kTopLeft
: RectPart::BottomLeft; : kBottomLeft;
case RectPart::BottomLeft: case kBottomLeft:
return (rotation == 90) return (rotation == 90)
? RectPart::BottomRight ? kBottomRight
: (rotation == 180) : (rotation == 180)
? RectPart::TopRight ? kTopRight
: RectPart::TopLeft; : kTopLeft;
} }
Unexpected("Corner in rotateCorner."); Unexpected("Corner in rotateCorner.");
}; };
auto result = request; auto result = request;
result.outer = FlipSizeByRotation(request.outer, rotation); result.outer = FlipSizeByRotation(request.outer, rotation);
result.resize = FlipSizeByRotation(request.resize, rotation); result.resize = FlipSizeByRotation(request.resize, rotation);
result.corners = unrotatedCorner(RectPart::TopLeft) auto rounding = result.rounding;
| unrotatedCorner(RectPart::TopRight) for (auto i = 0; i != 4; ++i) {
| unrotatedCorner(RectPart::BottomRight) result.rounding.p[unrotatedCorner(i)] = rounding.p[i];
| unrotatedCorner(RectPart::BottomLeft); }
return result; return result;
} }
@ -137,23 +135,23 @@ void Pip::RendererSW::paintButton(
Pip::FrameRequest Pip::RendererSW::frameRequest( Pip::FrameRequest Pip::RendererSW::frameRequest(
ContentGeometry geometry) const { ContentGeometry geometry) const {
using namespace Images;
auto result = FrameRequest(); auto result = FrameRequest();
result.outer = geometry.inner.size() * style::DevicePixelRatio(); result.outer = geometry.inner.size() * style::DevicePixelRatio();
result.resize = result.outer; result.resize = result.outer;
result.corners = RectPart(0) result.rounding = CornersMaskRef(CornersMask(ImageRoundRadius::Large));
| ((geometry.attached & (RectPart::Left | RectPart::Top)) if (geometry.attached & (RectPart::Top | RectPart::Left)) {
? RectPart(0) result.rounding.p[kTopLeft] = nullptr;
: RectPart::TopLeft) }
| ((geometry.attached & (RectPart::Top | RectPart::Right)) if (geometry.attached & (RectPart::Top | RectPart::Right)) {
? RectPart(0) result.rounding.p[kTopRight] = nullptr;
: RectPart::TopRight) }
| ((geometry.attached & (RectPart::Right | RectPart::Bottom)) if (geometry.attached & (RectPart::Bottom | RectPart::Left)) {
? RectPart(0) result.rounding.p[kBottomLeft] = nullptr;
: RectPart::BottomRight) }
| ((geometry.attached & (RectPart::Bottom | RectPart::Left)) if (geometry.attached & (RectPart::Bottom | RectPart::Right)) {
? RectPart(0) result.rounding.p[kBottomRight] = nullptr;
: RectPart::BottomLeft); }
result.radius = ImageRoundRadius::Large;
return UnrotateRequest(result, geometry.rotation); return UnrotateRequest(result, geometry.rotation);
} }
@ -175,19 +173,11 @@ QImage Pip::RendererSW::staticContentByRequest(
// _instance.info().video.rotation, // _instance.info().video.rotation,
// request, // request,
// std::move(_preparedCoverStorage)); // std::move(_preparedCoverStorage));
using Option = Images::Option; _preparedStaticContent = Images::Round(Images::Prepare(
const auto corner = [&](RectPart part, Option skip) {
return !(request.corners & part) ? skip : Option();
};
const auto options = Option::RoundLarge
| corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
| corner(RectPart::TopRight, Option::RoundSkipTopRight)
| corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
| corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
_preparedStaticContent = Images::Prepare(
image, image,
request.resize, request.resize,
{ .options = options, .outer = request.outer }); { .outer = request.outer }), request.rounding);
return _preparedStaticContent; return _preparedStaticContent;
} }

View File

@ -161,10 +161,6 @@ 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) {
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 &corners) { void FillRoundShadow(QPainter &p, int32 x, int32 y, int32 w, int32 h, style::color shadow, const CornersPixmaps &corners) {
constexpr auto kLeft = 2; constexpr auto kLeft = 2;
constexpr auto kRight = 3; constexpr auto kRight = 3;

View File

@ -40,10 +40,6 @@ 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);
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);
}
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) {
FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts); FillRoundRect(p, rect.x(), rect.y(), rect.width(), rect.height(), bg, radius, parts);

View File

@ -693,10 +693,7 @@ void FillComplexOverlayRect(
QRect rect, QRect rect,
const style::color &color, const style::color &color,
const CornersPixmaps &corners) { const CornersPixmaps &corners) {
constexpr auto kTopLeft = 0; using namespace Images;
constexpr auto kTopRight = 1;
constexpr auto kBottomLeft = 2;
constexpr auto kBottomRight = 3;
const auto pix = corners.p; const auto pix = corners.p;
const auto fillRect = [&](QRect rect) { const auto fillRect = [&](QRect rect) {
@ -795,36 +792,14 @@ void FillComplexOverlayRect(
} }
} }
void FillComplexOverlayRect( void FillComplexEllipse(
QPainter &p, QPainter &p,
not_null<const ChatStyle*> st, not_null<const ChatStyle*> st,
QRect rect, QRect rect) {
ImageRoundRadius radius, PainterHighQualityEnabler hq(p);
RectParts roundCorners) { p.setPen(Qt::NoPen);
const auto bg = st->msgSelectOverlay(); p.setBrush(st->msgSelectOverlay());
if (radius == ImageRoundRadius::Ellipse) { p.drawEllipse(rect);
PainterHighQualityEnabler hq(p);
p.setPen(Qt::NoPen);
p.setBrush(bg);
p.drawEllipse(rect);
} else {
// #TODO rounding
//const auto &corners = (radius == ImageRoundRadius::Small)
// ? st->msgSelectOverlayCornersSmall()
// : st->msgSelectOverlayCornersLarge();
//RectWithCorners(p, rect, bg, corners, roundCorners);
}
}
void FillComplexLocationRect(
QPainter &p,
not_null<const ChatStyle*> st,
QRect rect,
ImageRoundRadius radius,
RectParts roundCorners) {
const auto stm = &st->messageStyle(false, false);
// #TODO rounding
RectWithCorners(p, rect, stm->msgBg, stm->msgBgCornersSmall, roundCorners);
} }
} // namespace Ui } // namespace Ui

View File

@ -360,17 +360,9 @@ void FillComplexOverlayRect(
const style::color &color, const style::color &color,
const CornersPixmaps &corners); const CornersPixmaps &corners);
void FillComplexOverlayRect( void FillComplexEllipse(
QPainter &p, QPainter &p,
not_null<const ChatStyle*> st, not_null<const ChatStyle*> st,
QRect rect, QRect rect);
ImageRoundRadius radius,
RectParts roundCorners);
void FillComplexLocationRect(
QPainter &p,
not_null<const ChatStyle*> st,
QRect rect,
ImageRoundRadius radius,
RectParts roundCorners);
} // namespace Ui } // namespace Ui

View File

@ -478,7 +478,10 @@ void UserpicButton::paintUserpicFrame(Painter &p, QPoint photoPosition) {
auto size = QSize{ _st.photoSize, _st.photoSize }; auto size = QSize{ _st.photoSize, _st.photoSize };
request.outer = size * cIntRetinaFactor(); request.outer = size * cIntRetinaFactor();
request.resize = size * cIntRetinaFactor(); request.resize = size * cIntRetinaFactor();
request.radius = ImageRoundRadius::Ellipse; if (_ellipseMask.size() != request.outer) {
_ellipseMask = Images::EllipseMask(size);
}
request.mask = _ellipseMask;
p.drawImage(QRect(photoPosition, size), _streamed->frame(request)); p.drawImage(QRect(photoPosition, size), _streamed->frame(request));
if (!paused) { if (!paused) {
_streamed->markFrameShown(); _streamed->markFrameShown();

View File

@ -170,6 +170,7 @@ private:
InMemoryKey _userpicUniqueKey; InMemoryKey _userpicUniqueKey;
Ui::Animations::Simple _a_appearance; Ui::Animations::Simple _a_appearance;
QImage _result; QImage _result;
QImage _ellipseMask;
std::unique_ptr<Media::Streaming::Instance> _streamed; std::unique_ptr<Media::Streaming::Instance> _streamed;
PhotoData *_streamedPhoto = nullptr; PhotoData *_streamedPhoto = nullptr;

@ -1 +1 @@
Subproject commit cec09b0260ba19639bf9abc7df373569aa1509e7 Subproject commit 2c2a7887e644dff7130d764c5a7b04aaa0463056