Support new rounding for albums.

This commit is contained in:
John Preston 2022-10-03 12:41:51 +04:00
parent 8268e9f872
commit 9cab06e17d
10 changed files with 80 additions and 93 deletions

View File

@ -421,13 +421,7 @@ QSize Document::countCurrentSize(int newWidth) {
} }
void Document::draw(Painter &p, const PaintContext &context) const { void Document::draw(Painter &p, const PaintContext &context) const {
const auto corners = (isBubbleTop() draw(p, context, width(), LayoutMode::Full, adjustedBubbleRounding());
? (RectPart::TopLeft | RectPart::TopRight)
: RectParts())
| ((isRoundedInBubbleBottom() && !Has<HistoryDocumentCaptioned>())
? (RectPart::BottomLeft | RectPart::BottomRight)
: RectParts());
draw(p, context, width(), LayoutMode::Full, corners);
} }
void Document::draw( void Document::draw(
@ -435,7 +429,7 @@ void Document::draw(
const PaintContext &context, const PaintContext &context,
int width, int width,
LayoutMode mode, LayoutMode mode,
RectParts corners) const { Ui::BubbleRounding outsideRounding) const {
if (width < st::msgPadding.left() + st::msgPadding.right() + 1) return; if (width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
ensureDataMediaCreated(); 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 inner = QRect(rthumb.x() + (rthumb.width() - innerSize) / 2, rthumb.y() + (rthumb.height() - innerSize) / 2, innerSize, innerSize);
const auto radialOpacity = radial ? _animation->radial.opacity() : 1.; const auto radialOpacity = radial ? _animation->radial.opacity() : 1.;
if (thumbed) { if (thumbed) {
const auto rounding = thumbRounding(mode, corners); const auto rounding = thumbRounding(mode, outsideRounding);
validateThumbnail(thumbed, st.thumbSize, rounding); validateThumbnail(thumbed, st.thumbSize, rounding);
p.drawImage(rthumb, thumbed->thumbnail); p.drawImage(rthumb, thumbed->thumbnail);
if (context.selected()) { if (context.selected()) {
@ -703,19 +697,20 @@ void Document::draw(
Ui::BubbleRounding Document::thumbRounding( Ui::BubbleRounding Document::thumbRounding(
LayoutMode mode, LayoutMode mode,
RectParts corners) const { Ui::BubbleRounding outsideRounding) const {
auto result = bubbleRounding();
using Corner = Ui::BubbleCornerRounding; using Corner = Ui::BubbleCornerRounding;
if (mode != LayoutMode::Grouped && _parent->media() != this) { if (mode != LayoutMode::Grouped && _parent->media() != this) {
return {}; // In a WebPage preview. return {}; // In a WebPage preview.
} }
const auto adjust = [&](RectPart corner, Corner already) { const auto hasCaption = Has<HistoryDocumentCaptioned>();
return (already == Corner::Large && (corners & corner)) const auto adjust = [&](Corner already, bool skip = false) {
return (already == Corner::Large && !skip)
? Corner::Large ? Corner::Large
: Corner::Small; : Corner::Small;
}; };
result.topLeft = adjust(RectPart::TopLeft, result.topLeft); auto result = Ui::BubbleRounding();
result.bottomLeft = adjust(RectPart::BottomLeft, result.bottomLeft); result.topLeft = adjust(outsideRounding.topLeft);
result.bottomLeft = adjust(outsideRounding.bottomLeft, hasCaption);
result.topRight = result.bottomRight = Corner::Small; result.topRight = result.bottomRight = Corner::Small;
return result; return result;
} }
@ -1280,7 +1275,7 @@ void Document::drawGrouped(
const PaintContext &context, const PaintContext &context,
const QRect &geometry, const QRect &geometry,
RectParts sides, RectParts sides,
RectParts corners, Ui::BubbleRounding rounding,
float64 highlightOpacity, float64 highlightOpacity,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const { not_null<QPixmap*> cache) const {
@ -1290,7 +1285,7 @@ void Document::drawGrouped(
context.translated(-geometry.topLeft()), context.translated(-geometry.topLeft()),
geometry.width(), geometry.width(),
LayoutMode::Grouped, LayoutMode::Grouped,
corners); rounding);
p.translate(-geometry.topLeft()); p.translate(-geometry.topLeft());
} }

View File

@ -69,7 +69,7 @@ public:
const PaintContext &context, const PaintContext &context,
const QRect &geometry, const QRect &geometry,
RectParts sides, RectParts sides,
RectParts corners, Ui::BubbleRounding rounding,
float64 highlightOpacity, float64 highlightOpacity,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const override; not_null<QPixmap*> cache) const override;
@ -110,7 +110,7 @@ private:
const PaintContext &context, const PaintContext &context,
int width, int width,
LayoutMode mode, LayoutMode mode,
RectParts corners) const; Ui::BubbleRounding outsideRounding) const;
[[nodiscard]] TextState textState( [[nodiscard]] TextState textState(
QPoint point, QPoint point,
QSize layout, QSize layout,
@ -128,7 +128,7 @@ private:
[[nodiscard]] Ui::BubbleRounding thumbRounding( [[nodiscard]] Ui::BubbleRounding thumbRounding(
LayoutMode mode, LayoutMode mode,
RectParts corners) const; Ui::BubbleRounding outsideRounding) const;
void validateThumbnail( void validateThumbnail(
not_null<const HistoryDocumentThumbed*> thumbed, not_null<const HistoryDocumentThumbed*> thumbed,
int size, int size,

View File

@ -281,25 +281,6 @@ void Gif::validateRoundingMask(QSize size) const {
} }
} }
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())
@ -429,7 +410,7 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
validateRoundingMask(request.outer); validateRoundingMask(request.outer);
request.mask = _roundingMask; request.mask = _roundingMask;
} else { } else {
request.rounding = prepareRoundingRef(rounding); request.rounding = MediaRoundingMask(rounding);
} }
if (!activeRoundPlaying && activeOwnPlaying->instance.playerLocked()) { if (!activeRoundPlaying && activeOwnPlaying->instance.playerLocked()) {
if (activeOwnPlaying->frozenFrame.isNull()) { if (activeOwnPlaying->frozenFrame.isNull()) {
@ -1020,7 +1001,7 @@ void Gif::drawGrouped(
const PaintContext &context, const PaintContext &context,
const QRect &geometry, const QRect &geometry,
RectParts sides, RectParts sides,
RectParts corners, Ui::BubbleRounding rounding,
float64 highlightOpacity, float64 highlightOpacity,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const { not_null<QPixmap*> cache) const {
@ -1081,8 +1062,7 @@ 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, // #TODO rounding .rounding = MediaRoundingMask(rounding),
//.corners = corners,
}; };
if (activeOwnPlaying->instance.playerLocked()) { if (activeOwnPlaying->instance.playerLocked()) {
if (activeOwnPlaying->frozenFrame.isNull()) { if (activeOwnPlaying->frozenFrame.isNull()) {
@ -1105,7 +1085,7 @@ void Gif::drawGrouped(
} }
} }
} else { } else {
validateGroupedCache(geometry, corners, cacheKey, cache); validateGroupedCache(geometry, rounding, cacheKey, cache);
p.drawPixmap(geometry, *cache); p.drawPixmap(geometry, *cache);
} }
@ -1114,11 +1094,10 @@ void Gif::drawGrouped(
: highlightOpacity; : highlightOpacity;
if (overlayOpacity > 0.) { if (overlayOpacity > 0.) {
p.setOpacity(overlayOpacity); p.setOpacity(overlayOpacity);
// #TODO rounding fillImageOverlay(p, geometry, rounding, context);
//Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); if (!context.selected()) {
//if (!context.selected()) { fillImageOverlay(p, geometry, rounding, context);
// Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); }
//}
p.setOpacity(1.); p.setOpacity(1.);
} }
@ -1355,7 +1334,7 @@ bool Gif::isUnwrapped() const {
void Gif::validateGroupedCache( void Gif::validateGroupedCache(
const QRect &geometry, const QRect &geometry,
RectParts corners, Ui::BubbleRounding rounding,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const { not_null<QPixmap*> cache) const {
using Option = Images::Option; using Option = Images::Option;
@ -1377,18 +1356,11 @@ void Gif::validateGroupedCache(
const auto loadLevel = good ? 3 : thumb ? 2 : image ? 1 : 0; const auto loadLevel = good ? 3 : thumb ? 2 : image ? 1 : 0;
const auto width = geometry.width(); const auto width = geometry.width();
const auto height = geometry.height(); const auto height = geometry.height();
const auto corner = [&](RectPart part, Option skip) { const auto options = (blur ? Option::Blur : Option(0));
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 key = (uint64(width) << 48) const auto key = (uint64(width) << 48)
| (uint64(height) << 32) | (uint64(height) << 32)
| (uint64(options) << 16) | (uint64(options) << 16)
| (uint64(rounding.key()) << 8)
| (uint64(loadLevel)); | (uint64(loadLevel));
if (*cacheKey == key) { if (*cacheKey == key) {
return; return;
@ -1403,9 +1375,14 @@ void Gif::validateGroupedCache(
const auto ratio = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
*cacheKey = key; *cacheKey = key;
*cache = (image ? image : Image::BlankMedia().get())->pixNoCache( auto scaled = Images::Prepare(
(image ? image : Image::BlankMedia().get())->original(),
pixSize * ratio, pixSize * ratio,
{ .options = options, .outer = { width, height } }); { .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 { void Gif::setStatusSize(int64 newSize) const {

View File

@ -76,7 +76,7 @@ public:
const PaintContext &context, const PaintContext &context,
const QRect &geometry, const QRect &geometry,
RectParts sides, RectParts sides,
RectParts corners, Ui::BubbleRounding rounding,
float64 highlightOpacity, float64 highlightOpacity,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const override; not_null<QPixmap*> cache) const override;
@ -169,7 +169,7 @@ private:
void validateGroupedCache( void validateGroupedCache(
const QRect &geometry, const QRect &geometry,
RectParts corners, Ui::BubbleRounding rounding,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const; not_null<QPixmap*> cache) const;
void setStatusSize(int64 newSize) const; void setStatusSize(int64 newSize) const;
@ -177,8 +177,6 @@ private:
[[nodiscard]] QSize sizeForAspectRatio() const; [[nodiscard]] QSize sizeForAspectRatio() const;
void validateRoundingMask(QSize size) 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(

View File

@ -189,7 +189,7 @@ public:
const PaintContext &context, const PaintContext &context,
const QRect &geometry, const QRect &geometry,
RectParts sides, RectParts sides,
RectParts corners, Ui::BubbleRounding rounding,
float64 highlightOpacity, float64 highlightOpacity,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const { not_null<QPixmap*> cache) const {

View File

@ -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); auto result = Ui::GetCornersFromSides(sides);
if (!isBubbleTop()) { if (!(result & RectPart::TopLeft)) {
result &= ~(RectPart::TopLeft | RectPart::TopRight); already.topLeft = Ui::BubbleCornerRounding::None;
} }
if (!isRoundedInBubbleBottom() || !_caption.isEmpty()) { if (!(result & RectPart::TopRight)) {
result &= ~(RectPart::BottomLeft | RectPart::BottomRight); 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 { QMargins GroupedMedia::groupedPadding() const {
@ -302,6 +310,11 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
const auto textSelection = (_mode == Mode::Column) const auto textSelection = (_mode == Mode::Column)
&& !fullSelection && !fullSelection
&& !IsSubGroupSelection(selection); && !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) { for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
const auto &part = _parts[i]; const auto &part = _parts[i];
const auto partContext = context.withSelection(fullSelection const auto partContext = context.withSelection(fullSelection
@ -325,7 +338,7 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
partContext, partContext,
part.geometry.translated(0, groupPadding.top()), part.geometry.translated(0, groupPadding.top()),
part.sides, part.sides,
cornersFromSides(part.sides), applyRoundingSides(rounding, part.sides),
highlightOpacity, highlightOpacity,
&part.cacheKey, &part.cacheKey,
&part.cache); &part.cache);

View File

@ -141,7 +141,9 @@ private:
void refreshCaption(); void refreshCaption();
[[nodiscard]] RectParts cornersFromSides(RectParts sides) const; [[nodiscard]] Ui::BubbleRounding applyRoundingSides(
Ui::BubbleRounding already,
RectParts sides) const;
[[nodiscard]] QMargins groupedPadding() const; [[nodiscard]] QMargins groupedPadding() const;
Ui::Text::String _caption; Ui::Text::String _caption;

View File

@ -543,14 +543,14 @@ void Photo::drawGrouped(
const PaintContext &context, const PaintContext &context,
const QRect &geometry, const QRect &geometry,
RectParts sides, RectParts sides,
RectParts corners, Ui::BubbleRounding rounding,
float64 highlightOpacity, float64 highlightOpacity,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const { not_null<QPixmap*> cache) const {
ensureDataMediaCreated(); ensureDataMediaCreated();
_dataMedia->automaticLoad(_realParent->fullId(), _parent->data()); _dataMedia->automaticLoad(_realParent->fullId(), _parent->data());
validateGroupedCache(geometry, corners, cacheKey, cache); validateGroupedCache(geometry, rounding, cacheKey, cache);
const auto st = context.st; const auto st = context.st;
const auto sti = context.imageStyle(); const auto sti = context.imageStyle();
@ -573,11 +573,10 @@ 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;
// #TODO rounding fillImageOverlay(p, geometry, rounding, context);
//Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); if (!context.selected()) {
//if (!context.selected()) { fillImageOverlay(p, geometry, rounding, context);
// Ui::FillComplexOverlayRect(p, st, geometry, roundRadius, corners); }
//}
p.setOpacity(1.); p.setOpacity(1.);
} }
@ -680,7 +679,7 @@ bool Photo::needInfoDisplay() const {
void Photo::validateGroupedCache( void Photo::validateGroupedCache(
const QRect &geometry, const QRect &geometry,
RectParts corners, Ui::BubbleRounding rounding,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const { not_null<QPixmap*> cache) const {
using Option = Images::Option; using Option = Images::Option;
@ -697,18 +696,11 @@ void Photo::validateGroupedCache(
: 0; : 0;
const auto width = geometry.width(); const auto width = geometry.width();
const auto height = geometry.height(); const auto height = geometry.height();
const auto corner = [&](RectPart part, Option skip) { const auto options = (loaded ? Option() : Option::Blur);
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 key = (uint64(width) << 48) const auto key = (uint64(width) << 48)
| (uint64(height) << 32) | (uint64(height) << 32)
| (uint64(options) << 16) | (uint64(options) << 16)
| (uint64(rounding.key()) << 8)
| (uint64(loadLevel)); | (uint64(loadLevel));
if (*cacheKey == key) { if (*cacheKey == key) {
return; return;
@ -731,9 +723,14 @@ void Photo::validateGroupedCache(
: Image::BlankMedia().get(); : Image::BlankMedia().get();
*cacheKey = key; *cacheKey = key;
*cache = image->pixNoCache( auto scaled = Images::Prepare(
image->original(),
pixSize * ratio, pixSize * ratio,
{ .options = options, .outer = { width, height } }); { .options = options, .outer = { width, height } });
auto rounded = Images::Round(
std::move(scaled),
MediaRoundingMask(rounding));
*cache = Ui::PixmapFromImage(std::move(rounded));
} }
bool Photo::createStreamingObjects() { bool Photo::createStreamingObjects() {

View File

@ -67,7 +67,7 @@ public:
const PaintContext &context, const PaintContext &context,
const QRect &geometry, const QRect &geometry,
RectParts sides, RectParts sides,
RectParts corners, Ui::BubbleRounding rounding,
float64 highlightOpacity, float64 highlightOpacity,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const override; not_null<QPixmap*> cache) const override;
@ -123,7 +123,7 @@ private:
bool needInfoDisplay() const; bool needInfoDisplay() const;
void validateGroupedCache( void validateGroupedCache(
const QRect &geometry, const QRect &geometry,
RectParts corners, Ui::BubbleRounding rounding,
not_null<uint64*> cacheKey, not_null<uint64*> cacheKey,
not_null<QPixmap*> cache) const; not_null<QPixmap*> cache) const;
void validateImageCache( void validateImageCache(

View File

@ -72,6 +72,11 @@ struct BubbleRounding {
return { this, index }; return { this, index };
} }
[[nodiscard]] uchar key() const {
static_assert(sizeof(*this) == sizeof(uchar));
return uchar(*reinterpret_cast<const std::byte*>(this));
}
inline friend constexpr auto operator<=>( inline friend constexpr auto operator<=>(
BubbleRounding, BubbleRounding,
BubbleRounding) = default; BubbleRounding) = default;