Not rounding images (photos/videos/gifs) that continue to a bubble.

This commit is contained in:
John Preston 2016-11-21 23:26:54 +03:00
parent 9155591e8a
commit eb05e62422
16 changed files with 337 additions and 198 deletions

View File

@ -2726,6 +2726,37 @@ namespace {
#endif // !TDESKTOP_DISABLE_NETWORK_PROXY #endif // !TDESKTOP_DISABLE_NETWORK_PROXY
} }
void complexAdjustRect(ImageRoundCorners corners, QRect &rect, RectParts &parts) {
if (corners & ImageRoundCorner::TopLeft) {
if (!(corners & ImageRoundCorner::BottomLeft)) {
parts = RectPart::NoTopBottom | RectPart::TopFull;
rect.setHeight(rect.height() + msgRadius());
}
} else if (corners & ImageRoundCorner::BottomLeft) {
parts = RectPart::NoTopBottom | RectPart::BottomFull;
rect.setTop(rect.y() - msgRadius());
} else {
parts = RectPart::NoTopBottom;
rect.setTop(rect.y() - msgRadius());
rect.setHeight(rect.height() + msgRadius());
}
}
void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners) {
auto overlayCorners = (radius == ImageRoundRadius::Small) ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
auto overlayParts = RectPart::Full | RectPart::None;
if (radius == ImageRoundRadius::Large) {
complexAdjustRect(corners, rect, overlayParts);
}
roundRect(p, rect, textstyleCurrent()->selectOverlay, overlayCorners, nullptr, overlayParts);
}
void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners) {
auto parts = RectPart::Full | RectPart::None;
complexAdjustRect(corners, rect, parts);
roundRect(p, rect, st::msgInBg, MessageInCorners, nullptr, parts);
}
QImage **cornersMask(ImageRoundRadius radius) { QImage **cornersMask(ImageRoundRadius radius) {
switch (radius) { switch (radius) {
case ImageRoundRadius::Large: return ::cornersMaskLarge; case ImageRoundRadius::Large: return ::cornersMaskLarge;

View File

@ -280,6 +280,7 @@ namespace App {
void setProxySettings(QTcpSocket &socket); void setProxySettings(QTcpSocket &socket);
enum class RectPart { enum class RectPart {
None = 0x000,
TopLeft = 0x001, TopLeft = 0x001,
Top = 0x002, Top = 0x002,
TopRight = 0x004, TopRight = 0x004,
@ -300,6 +301,9 @@ namespace App {
Q_DECLARE_FLAGS(RectParts, RectPart); Q_DECLARE_FLAGS(RectParts, RectPart);
Q_DECLARE_OPERATORS_FOR_FLAGS(RectParts); Q_DECLARE_OPERATORS_FOR_FLAGS(RectParts);
void complexOverlayRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners);
void complexLocationRect(Painter &p, QRect rect, ImageRoundRadius radius, ImageRoundCorners corners);
QImage **cornersMask(ImageRoundRadius radius); QImage **cornersMask(ImageRoundRadius radius);
void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full); void roundRect(Painter &p, int32 x, int32 y, int32 w, int32 h, const style::color &bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full);
inline void roundRect(Painter &p, const QRect &rect, const style::color &bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) { inline void roundRect(Painter &p, const QRect &rect, const style::color &bg, RoundCorners index, const style::color *shadow = nullptr, RectParts parts = RectPart::Full) {

View File

@ -87,7 +87,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
maxH = limitH; maxH = limitH;
} }
} }
_thumb = imagePix(_file->thumb.toImage(), maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth | ImagePixBlurred, maxW, maxH); _thumb = imagePix(_file->thumb.toImage(), maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixOption::Smooth | ImagePixOption::Blurred, maxW, maxH);
} else { } else {
for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) { for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) {
if (i->width() >= maxW && i->height() >= maxH) { if (i->width() >= maxW && i->height() >= maxH) {
@ -129,7 +129,8 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
} else { } else {
_thumbw = st::msgFileThumbSize; _thumbw = st::msgFileThumbSize;
} }
_thumb = imagePix(_thumb.toImage(), _thumbw * cIntRetinaFactor(), 0, ImagePixSmooth | ImagePixRoundedSmall, st::msgFileThumbSize, st::msgFileThumbSize); auto options = ImagePixOption::Smooth | ImagePixOption::RoundedSmall | ImagePixOption::RoundedTopLeft | ImagePixOption::RoundedTopRight | ImagePixOption::RoundedBottomLeft | ImagePixOption::RoundedBottomRight;
_thumb = imagePix(_thumb.toImage(), _thumbw * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize);
} }
_name.setText(st::semiboldFont, _file->filename, _textNameOptions); _name.setText(st::semiboldFont, _file->filename, _textNameOptions);
@ -420,7 +421,8 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
} else { } else {
_thumbw = st::msgFileThumbSize; _thumbw = st::msgFileThumbSize;
} }
_thumb = imagePix(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, ImagePixSmooth | ImagePixRoundedSmall, st::msgFileThumbSize, st::msgFileThumbSize); auto options = ImagePixOption::Smooth | ImagePixOption::RoundedSmall | ImagePixOption::RoundedTopLeft | ImagePixOption::RoundedTopRight | ImagePixOption::RoundedBottomLeft | ImagePixOption::RoundedBottomRight;
_thumb = imagePix(image->pix().toImage(), _thumbw * cIntRetinaFactor(), 0, options, st::msgFileThumbSize, st::msgFileThumbSize);
} }
if (doc) { if (doc) {
@ -451,11 +453,11 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
maxH = limitH; maxH = limitH;
} }
} }
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth | ImagePixBlurred, maxW, maxH); _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixOption::Smooth | ImagePixOption::Blurred, maxW, maxH);
} else { } else {
maxW = dimensions.width(); maxW = dimensions.width();
maxH = dimensions.height(); maxH = dimensions.height();
_thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixSmooth, maxW, maxH); _thumb = image->pixNoCache(maxW * cIntRetinaFactor(), maxH * cIntRetinaFactor(), ImagePixOption::Smooth, maxW, maxH);
} }
int32 tw = _thumb.width(), th = _thumb.height(); int32 tw = _thumb.width(), th = _thumb.height();
if (!tw || !th) { if (!tw || !th) {

View File

@ -396,17 +396,18 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, uin
auto inWebPage = (_parent->getMedia() != this); auto inWebPage = (_parent->getMedia() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
auto roundCorners = inWebPage ? ImageRoundCorner::All : ((isBubbleTop() ? (ImageRoundCorner::TopLeft | ImageRoundCorner::TopRight) : ImageRoundCorner::None)
| ((isBubbleBottom() && _caption.isEmpty()) ? (ImageRoundCorner::BottomLeft | ImageRoundCorner::BottomRight) : ImageRoundCorner::None));
QPixmap pix; QPixmap pix;
if (loaded) { if (loaded) {
pix = _data->full->pixSingle(roundRadius, _pixw, _pixh, width, height); pix = _data->full->pixSingle(_pixw, _pixh, width, height, roundRadius, roundCorners);
} else { } else {
pix = _data->thumb->pixBlurredSingle(roundRadius, _pixw, _pixh, width, height); pix = _data->thumb->pixBlurredSingle(_pixw, _pixh, width, height, roundRadius, roundCorners);
} }
QRect rthumb(rtlrect(skipx, skipy, width, height, _width)); QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
p.drawPixmap(rthumb.topLeft(), pix); p.drawPixmap(rthumb.topLeft(), pix);
if (selected) { if (selected) {
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners; App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
} }
if (radial || (!loaded && !_data->loading())) { if (radial || (!loaded && !_data->loading())) {
@ -742,11 +743,12 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, uin
auto inWebPage = (_parent->getMedia() != this); auto inWebPage = (_parent->getMedia() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
auto roundCorners = inWebPage ? ImageRoundCorner::All : ((isBubbleTop() ? (ImageRoundCorner::TopLeft | ImageRoundCorner::TopRight) : ImageRoundCorner::None)
| ((isBubbleBottom() && _caption.isEmpty()) ? (ImageRoundCorner::BottomLeft | ImageRoundCorner::BottomRight) : ImageRoundCorner::None));
QRect rthumb(rtlrect(skipx, skipy, width, height, _width)); QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(roundRadius, _thumbw, 0, width, height)); p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_thumbw, 0, width, height, roundRadius, roundCorners));
if (selected) { if (selected) {
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners; App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
} }
QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize); QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
@ -1094,7 +1096,12 @@ void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection,
auto inWebPage = (_parent->getMedia() != this); auto inWebPage = (_parent->getMedia() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width)); QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width));
QPixmap thumb = loaded ? _data->thumb->pixSingle(roundRadius, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(roundRadius, thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize); QPixmap thumb;
if (loaded) {
thumb = _data->thumb->pixSingle(thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
} else {
thumb = _data->thumb->pixBlurredSingle(thumbed->_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize, roundRadius);
}
p.drawPixmap(rthumb.topLeft(), thumb); p.drawPixmap(rthumb.topLeft(), thumb);
if (selected) { if (selected) {
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners; auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
@ -1642,7 +1649,9 @@ int HistoryGif::resizeGetHeight(int width) {
if (!_gif->started()) { if (!_gif->started()) {
auto inWebPage = (_parent->getMedia() != this); auto inWebPage = (_parent->getMedia() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
_gif->start(_thumbw, _thumbh, _width, _height, roundRadius); auto roundCorners = inWebPage ? ImageRoundCorner::All : ((isBubbleTop() ? (ImageRoundCorner::TopLeft | ImageRoundCorner::TopRight) : ImageRoundCorner::None)
| ((isBubbleBottom() && _caption.isEmpty()) ? (ImageRoundCorner::BottomLeft | ImageRoundCorner::BottomRight) : ImageRoundCorner::None));
_gif->start(_thumbw, _thumbh, _width, _height, roundRadius, roundCorners);
} }
} else { } else {
_width = qMax(_width, gifMaxStatusWidth(_data) + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x())); _width = qMax(_width, gifMaxStatusWidth(_data) + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x()));
@ -1710,17 +1719,17 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6
QRect rthumb(rtlrect(skipx, skipy, width, height, _width)); QRect rthumb(rtlrect(skipx, skipy, width, height, _width));
if (animating) {
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isInlineItemBeingChosen()) ? 0 : ms));
} else {
auto inWebPage = (_parent->getMedia() != this); auto inWebPage = (_parent->getMedia() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(roundRadius, _thumbw, _thumbh, width, height)); auto roundCorners = inWebPage ? ImageRoundCorner::All : ((isBubbleTop() ? (ImageRoundCorner::TopLeft | ImageRoundCorner::TopRight) : ImageRoundCorner::None)
| ((isBubbleBottom() && _caption.isEmpty()) ? (ImageRoundCorner::BottomLeft | ImageRoundCorner::BottomRight) : ImageRoundCorner::None));
if (animating) {
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, roundRadius, roundCorners, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isInlineItemBeingChosen()) ? 0 : ms));
} else {
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_thumbw, _thumbh, width, height, roundRadius, roundCorners));
} }
if (selected) { if (selected) {
auto inWebPage = (_parent->getMedia() != this); App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
} }
if (radial || _gif.isBad() || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif()))) { if (radial || _gif.isBad() || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif()))) {
@ -2670,9 +2679,9 @@ void HistoryWebPage::draw(Painter &p, const QRect &r, TextSelection selection, u
pixw = qRound(pixw * coef); pixw = qRound(pixw * coef);
} }
if (full) { if (full) {
pix = _data->photo->medium->pixSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph); pix = _data->photo->medium->pixSingle(pixw, pixh, pw, ph, ImageRoundRadius::Small);
} else { } else {
pix = _data->photo->thumb->pixBlurredSingle(ImageRoundRadius::Small, pixw, pixh, pw, ph); pix = _data->photo->thumb->pixBlurredSingle(pixw, pixh, pw, ph, ImageRoundRadius::Small);
} }
p.drawPixmapLeft(padding.left() + width - pw, tshift, _width, pix); p.drawPixmapLeft(padding.left() + width - pw, tshift, _width, pix);
if (selected) { if (selected) {
@ -3397,25 +3406,28 @@ void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection,
} }
_data->load(); _data->load();
QPixmap toDraw; auto roundRadius = ImageRoundRadius::Large;
auto roundCorners = ((isBubbleTop() && _title.isEmpty() && _description.isEmpty()) ? (ImageRoundCorner::TopLeft | ImageRoundCorner::TopRight) : ImageRoundCorner::None)
| (isBubbleBottom() ? (ImageRoundCorner::BottomLeft | ImageRoundCorner::BottomRight) : ImageRoundCorner::None);
auto rthumb = QRect(skipx, skipy, width, height);
if (_data && !_data->thumb->isNull()) { if (_data && !_data->thumb->isNull()) {
int32 w = _data->thumb->width(), h = _data->thumb->height(); int32 w = _data->thumb->width(), h = _data->thumb->height();
QPixmap pix; QPixmap pix;
if (width * h == height * w || (w == fullWidth() && h == fullHeight())) { if (width * h == height * w || (w == fullWidth() && h == fullHeight())) {
pix = _data->thumb->pixSingle(ImageRoundRadius::Large, width, height, width, height); pix = _data->thumb->pixSingle(width, height, width, height, roundRadius, roundCorners);
} else if (width * h > height * w) { } else if (width * h > height * w) {
int32 nw = height * w / h; int32 nw = height * w / h;
pix = _data->thumb->pixSingle(ImageRoundRadius::Large, nw, height, width, height); pix = _data->thumb->pixSingle(nw, height, width, height, roundRadius, roundCorners);
} else { } else {
int32 nh = width * h / w; int32 nh = width * h / w;
pix = _data->thumb->pixSingle(ImageRoundRadius::Large, width, nh, width, height); pix = _data->thumb->pixSingle(width, nh, width, height, roundRadius, roundCorners);
} }
p.drawPixmap(QPoint(skipx, skipy), pix); p.drawPixmap(rthumb.topLeft(), pix);
} else { } else {
App::roundRect(p, skipx, skipy, width, height, st::msgInBg, MessageInCorners); App::complexLocationRect(p, rthumb, roundRadius, roundCorners);
} }
if (selected) { if (selected) {
App::roundRect(p, skipx, skipy, width, height, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners); App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
} }
if (_parent->getMedia() == this) { if (_parent->getMedia() == this) {

View File

@ -261,7 +261,7 @@ void HistoryMessageReply::paint(Painter &p, const HistoryItem *holder, int x, in
ImagePtr replyPreview = replyToMsg->getMedia()->replyPreview(); ImagePtr replyPreview = replyToMsg->getMedia()->replyPreview();
if (!replyPreview->isNull()) { if (!replyPreview->isNull()) {
QRect to(rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x)); QRect to(rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x));
p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(ImageRoundRadius::Small, replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height())); p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height(), ImageRoundRadius::Small));
if (selected) { if (selected) {
App::roundRect(p, to, textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners); App::roundRect(p, to, textstyleCurrent()->selectOverlay, SelectedOverlaySmallCorners);
} }

View File

@ -8587,7 +8587,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
ImagePtr replyPreview = drawMsgText->getMedia()->replyPreview(); ImagePtr replyPreview = drawMsgText->getMedia()->replyPreview();
if (!replyPreview->isNull()) { if (!replyPreview->isNull()) {
QRect to(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height()); QRect to(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(ImageRoundRadius::Small, replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height())); p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height(), ImageRoundRadius::Small));
} }
replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
} }
@ -8754,7 +8754,7 @@ void HistoryWidget::drawPinnedBar(Painter &p) {
ImagePtr replyPreview = _pinnedBar->msg->getMedia()->replyPreview(); ImagePtr replyPreview = _pinnedBar->msg->getMedia()->replyPreview();
if (!replyPreview->isNull()) { if (!replyPreview->isNull()) {
QRect to(left, st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height()); QRect to(left, st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(ImageRoundRadius::Small, replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height())); p.drawPixmap(to.x(), to.y(), replyPreview->pixSingle(replyPreview->width() / cIntRetinaFactor(), replyPreview->height() / cIntRetinaFactor(), to.width(), to.height(), ImageRoundRadius::Small));
} }
left += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); left += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
} }

View File

@ -159,7 +159,7 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
QRect r(0, 0, _width, height); QRect r(0, 0, _width, height);
if (animating) { if (animating) {
if (!_thumb.isNull()) _thumb = QPixmap(); if (!_thumb.isNull()) _thumb = QPixmap();
p.drawPixmap(r.topLeft(), _gif->current(frame.width(), frame.height(), _width, height, context->paused ? 0 : context->ms)); p.drawPixmap(r.topLeft(), _gif->current(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, ImageRoundCorner::None, context->paused ? 0 : context->ms));
} else { } else {
prepareThumb(_width, height, frame); prepareThumb(_width, height, frame);
if (_thumb.isNull()) { if (_thumb.isNull()) {
@ -282,7 +282,7 @@ void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (!document->thumb->isNull()) { if (!document->thumb->isNull()) {
if (document->thumb->loaded()) { if (document->thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = document->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = document->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
} else { } else {
document->thumb->load(); document->thumb->load();
@ -293,7 +293,7 @@ void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (!thumb->isNull()) { if (!thumb->isNull()) {
if (thumb->loaded()) { if (thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
} else { } else {
thumb->load(); thumb->load();
@ -338,7 +338,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
} else if (_gif->ready() && !_gif->started()) { } else if (_gif->ready() && !_gif->started()) {
int32 height = st::inlineMediaHeight; int32 height = st::inlineMediaHeight;
QSize frame = countFrameSize(); QSize frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None); _gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, ImageRoundCorner::None);
} else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) { } else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) {
_gif.reset(); _gif.reset();
getShownDocument()->forget(); getShownDocument()->forget();
@ -529,13 +529,13 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (PhotoData *photo = getShownPhoto()) { if (PhotoData *photo = getShownPhoto()) {
if (photo->medium->loaded()) { if (photo->medium->loaded()) {
if (!_thumbLoaded || _thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { if (!_thumbLoaded || _thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = photo->medium->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = photo->medium->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
_thumbLoaded = true; _thumbLoaded = true;
} else { } else {
if (photo->thumb->loaded()) { if (photo->thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = photo->thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
} }
photo->medium->load(); photo->medium->load();
@ -544,7 +544,7 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const {
ImagePtr thumb = getResultThumb(); ImagePtr thumb = getResultThumb();
if (thumb->loaded()) { if (thumb->loaded()) {
if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) { if (_thumb.width() != width * cIntRetinaFactor() || _thumb.height() != height * cIntRetinaFactor()) {
_thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = thumb->pixNoCache(frame.width() * cIntRetinaFactor(), frame.height() * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
} else { } else {
thumb->load(); thumb->load();
@ -654,7 +654,7 @@ void Video::prepareThumb(int32 width, int32 height) const {
w = width; w = width;
} }
} }
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
} else { } else {
thumb->load(); thumb->load();
@ -985,7 +985,7 @@ void Contact::prepareThumb(int width, int height) const {
w = width; w = width;
} }
} }
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
} else { } else {
thumb->load(); thumb->load();
@ -1132,7 +1132,7 @@ void Article::prepareThumb(int width, int height) const {
w = width; w = width;
} }
} }
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
} else { } else {
thumb->load(); thumb->load();
@ -1233,7 +1233,7 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
if (animating) { if (animating) {
if (!_thumb.isNull()) _thumb = QPixmap(); if (!_thumb.isNull()) _thumb = QPixmap();
auto animationThumb = _gif->current(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, context->paused ? 0 : context->ms); auto animationThumb = _gif->current(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None, ImageRoundCorner::None, context->paused ? 0 : context->ms);
p.drawPixmapLeft(rthumb.topLeft(), _width, animationThumb); p.drawPixmapLeft(rthumb.topLeft(), _width, animationThumb);
thumbDisplayed = true; thumbDisplayed = true;
} }
@ -1312,7 +1312,7 @@ void Game::prepareThumb(int width, int height) const {
w = width; w = width;
} }
} }
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height); _thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
} }
} else { } else {
thumb->load(); thumb->load();
@ -1347,7 +1347,7 @@ void Game::clipCallback(Media::Clip::Notification notification) {
_gif.setBad(); _gif.setBad();
getResultDocument()->forget(); getResultDocument()->forget();
} else if (_gif->ready() && !_gif->started()) { } else if (_gif->ready() && !_gif->started()) {
_gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None); _gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None, ImageRoundCorner::None);
} else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) { } else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) {
_gif.reset(); _gif.reset();
getResultDocument()->forget(); getResultDocument()->forget();

View File

@ -824,7 +824,7 @@ QPixmap MediaPreviewWidget::currentImage() const {
} }
if (_gif && _gif->started()) { if (_gif && _gif->started()) {
QSize s = currentDimensions(); QSize s = currentDimensions();
return _gif->current(s.width(), s.height(), s.width(), s.height(), getms()); return _gif->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, ImageRoundCorner::None, getms());
} }
if (_cacheStatus != CacheThumbLoaded && _document->thumb->loaded()) { if (_cacheStatus != CacheThumbLoaded && _document->thumb->loaded()) {
QSize s = currentDimensions(); QSize s = currentDimensions();
@ -863,7 +863,7 @@ void MediaPreviewWidget::clipCallback(Media::Clip::Notification notification) {
if (_gif && _gif->ready() && !_gif->started()) { if (_gif && _gif->ready() && !_gif->started()) {
QSize s = currentDimensions(); QSize s = currentDimensions();
_gif->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None); _gif->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, ImageRoundCorner::None);
} }
update(); update();

View File

@ -76,7 +76,7 @@ QPixmap _prepareFrame(const FrameRequest &request, const QImage &original, bool
} }
} }
if (request.radius != ImageRoundRadius::None) { if (request.radius != ImageRoundRadius::None) {
imageRound(cache, request.radius); imageRound(cache, request.radius, request.corners);
} }
return QPixmap::fromImage(cache, Qt::ColorOnly); return QPixmap::fromImage(cache, Qt::ColorOnly);
} }
@ -185,7 +185,7 @@ void Reader::callback(Reader *reader, int32 threadIndex, Notification notificati
} }
} }
void Reader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, ImageRoundRadius radius) { void Reader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners) {
if (managers.size() <= _threadIndex) error(); if (managers.size() <= _threadIndex) error();
if (_state == State::Error) return; if (_state == State::Error) return;
@ -198,13 +198,14 @@ void Reader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, Image
request.outerw = outerw * factor; request.outerw = outerw * factor;
request.outerh = outerh * factor; request.outerh = outerh * factor;
request.radius = radius; request.radius = radius;
request.corners = corners;
_frames[0].request = _frames[1].request = _frames[2].request = request; _frames[0].request = _frames[1].request = _frames[2].request = request;
moveToNextShow(); moveToNextShow();
managers.at(_threadIndex)->start(this); managers.at(_threadIndex)->start(this);
} }
} }
QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh, uint64 ms) { QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners, uint64 ms) {
auto frame = frameToShow(); auto frame = frameToShow();
t_assert(frame != nullptr); t_assert(frame != nullptr);
@ -223,7 +224,10 @@ QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh,
} }
auto factor = cIntRetinaFactor(); auto factor = cIntRetinaFactor();
if (frame->pix.width() == outerw * factor && frame->pix.height() == outerh * factor) { if (frame->pix.width() == outerw * factor
&& frame->pix.height() == outerh * factor
&& frame->request.radius == radius
&& frame->request.corners == corners) {
moveToNextShow(); moveToNextShow();
return frame->pix; return frame->pix;
} }
@ -238,7 +242,7 @@ QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh,
frame->pix = QPixmap(); frame->pix = QPixmap();
frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize); frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize);
Frame *other = frameToWriteNext(true); auto other = frameToWriteNext(true);
if (other) other->request = frame->request; if (other) other->request = frame->request;
moveToNextShow(); moveToNextShow();
@ -254,7 +258,7 @@ QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh,
bool Reader::ready() const { bool Reader::ready() const {
if (_width && _height) return true; if (_width && _height) return true;
Frame *frame = frameToShow(); auto frame = frameToShow();
if (frame) { if (frame) {
_width = frame->original.width(); _width = frame->original.width();
_height = frame->original.height(); _height = frame->original.height();

View File

@ -41,6 +41,7 @@ struct FrameRequest {
int outerw = 0; int outerw = 0;
int outerh = 0; int outerh = 0;
ImageRoundRadius radius = ImageRoundRadius::None; ImageRoundRadius radius = ImageRoundRadius::None;
ImageRoundCorners corners = ImageRoundCorner::TopLeft | ImageRoundCorner::TopRight | ImageRoundCorner::BottomLeft | ImageRoundCorner::BottomRight;
}; };
enum ReaderSteps { enum ReaderSteps {
@ -75,8 +76,8 @@ public:
return _seekPositionMs; return _seekPositionMs;
} }
void start(int framew, int frameh, int outerw, int outerh, ImageRoundRadius radius); void start(int framew, int frameh, int outerw, int outerh, ImageRoundRadius radius, ImageRoundCorners corners);
QPixmap current(int framew, int frameh, int outerw, int outerh, uint64 ms); QPixmap current(int framew, int frameh, int outerw, int outerh, ImageRoundRadius radius, ImageRoundCorners corners, uint64 ms);
QPixmap frameOriginal() const { QPixmap frameOriginal() const {
if (auto frame = frameToShow()) { if (auto frame = frameToShow()) {
auto result = QPixmap::fromImage(frame->original); auto result = QPixmap::fromImage(frame->original);

View File

@ -201,7 +201,7 @@ bool MediaView::gifShown() const {
_gif->pauseResumeVideo(); _gif->pauseResumeVideo();
const_cast<MediaView*>(this)->_videoPaused = _gif->videoPaused(); const_cast<MediaView*>(this)->_videoPaused = _gif->videoPaused();
} }
_gif->start(_gif->width(), _gif->height(), _gif->width(), _gif->height(), ImageRoundRadius::None); _gif->start(_gif->width(), _gif->height(), _gif->width(), _gif->height(), ImageRoundRadius::None, ImageRoundCorner::None);
const_cast<MediaView*>(this)->_current = QPixmap(); const_cast<MediaView*>(this)->_current = QPixmap();
} }
return true;// _gif->state() != Media::Clip::State::Error; return true;// _gif->state() != Media::Clip::State::Error;
@ -1329,10 +1329,10 @@ void MediaView::initAnimation() {
} else if (_doc->dimensions.width() && _doc->dimensions.height()) { } else if (_doc->dimensions.width() && _doc->dimensions.height()) {
int w = _doc->dimensions.width(); int w = _doc->dimensions.width();
int h = _doc->dimensions.height(); int h = _doc->dimensions.height();
_current = _doc->thumb->pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred, w / cIntRetinaFactor(), h / cIntRetinaFactor()); _current = _doc->thumb->pixNoCache(w, h, ImagePixOption::Smooth | ImagePixOption::Blurred, w / cIntRetinaFactor(), h / cIntRetinaFactor());
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
} else { } else {
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixSmooth | ImagePixBlurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize); _current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixOption::Smooth | ImagePixOption::Blurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize);
} }
} }
@ -1345,10 +1345,10 @@ void MediaView::createClipReader() {
if (_doc->dimensions.width() && _doc->dimensions.height()) { if (_doc->dimensions.width() && _doc->dimensions.height()) {
int w = _doc->dimensions.width(); int w = _doc->dimensions.width();
int h = _doc->dimensions.height(); int h = _doc->dimensions.height();
_current = _doc->thumb->pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred, w / cIntRetinaFactor(), h / cIntRetinaFactor()); _current = _doc->thumb->pixNoCache(w, h, ImagePixOption::Smooth | ImagePixOption::Blurred, w / cIntRetinaFactor(), h / cIntRetinaFactor());
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
} else { } else {
_current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixSmooth | ImagePixBlurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize); _current = _doc->thumb->pixNoCache(_doc->thumb->width(), _doc->thumb->height(), ImagePixOption::Smooth | ImagePixOption::Blurred, st::mediaviewFileIconSize, st::mediaviewFileIconSize);
} }
auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif; auto mode = _doc->isVideo() ? Media::Clip::Reader::Mode::Video : Media::Clip::Reader::Mode::Gif;
_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) { _gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
@ -1422,7 +1422,7 @@ void MediaView::restartVideoAtSeekPosition(int64 positionMs) {
_autoplayVideoDocument = _doc; _autoplayVideoDocument = _doc;
if (_current.isNull()) { if (_current.isNull()) {
_current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), getms()); _current = _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), ImageRoundRadius::None, ImageRoundCorner::None, getms());
} }
_gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) { _gif = std_::make_unique<Media::Clip::Reader>(_doc->location(), _doc->data(), [this](Media::Clip::Notification notification) {
clipCallback(notification); clipCallback(notification);
@ -1543,17 +1543,17 @@ void MediaView::paintEvent(QPaintEvent *e) {
int32 w = _width * cIntRetinaFactor(); int32 w = _width * cIntRetinaFactor();
if (_full <= 0 && _photo->loaded()) { if (_full <= 0 && _photo->loaded()) {
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999); int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
_current = _photo->full->pixNoCache(w, h, ImagePixSmooth); _current = _photo->full->pixNoCache(w, h, ImagePixOption::Smooth);
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
_full = 1; _full = 1;
} else if (_full < 0 && _photo->medium->loaded()) { } else if (_full < 0 && _photo->medium->loaded()) {
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999); int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
_current = _photo->medium->pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred); _current = _photo->medium->pixNoCache(w, h, ImagePixOption::Smooth | ImagePixOption::Blurred);
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
_full = 0; _full = 0;
} else if (_current.isNull() && _photo->thumb->loaded()) { } else if (_current.isNull() && _photo->thumb->loaded()) {
int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999); int32 h = int((_photo->full->height() * (qreal(w) / qreal(_photo->full->width()))) + 0.9999);
_current = _photo->thumb->pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred); _current = _photo->thumb->pixNoCache(w, h, ImagePixOption::Smooth | ImagePixOption::Blurred);
if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) _current.setDevicePixelRatio(cRetinaFactor());
} else if (_current.isNull()) { } else if (_current.isNull()) {
_current = _photo->thumb->pix(); _current = _photo->thumb->pix();
@ -1563,7 +1563,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
if (_photo || fileShown()) { if (_photo || fileShown()) {
QRect imgRect(_x, _y, _w, _h); QRect imgRect(_x, _y, _w, _h);
if (imgRect.intersects(r)) { if (imgRect.intersects(r)) {
QPixmap toDraw = _current.isNull() ? _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), ms) : _current; QPixmap toDraw = _current.isNull() ? _gif->current(_gif->width(), _gif->height(), _gif->width(), _gif->height(), ImageRoundRadius::None, ImageRoundCorner::None, ms) : _current;
if (!_gif && (!_doc || !_doc->sticker() || _doc->sticker()->img->isNull()) && toDraw.hasAlpha()) { if (!_gif && (!_doc || !_doc->sticker() || _doc->sticker()->img->isNull()) && toDraw.hasAlpha()) {
p.fillRect(imgRect, _transparentBrush); p.fillRect(imgRect, _transparentBrush);
} }

View File

@ -797,8 +797,8 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
if (_data->thumb->loaded()) { if (_data->thumb->loaded()) {
if (_thumb.isNull() || loaded != _thumbForLoaded) { if (_thumb.isNull() || loaded != _thumbForLoaded) {
_thumbForLoaded = loaded; _thumbForLoaded = loaded;
ImagePixOptions options = ImagePixSmooth; auto options = ImagePixOption::Smooth | ImagePixOption::None;
if (!_thumbForLoaded) options |= ImagePixBlurred; if (!_thumbForLoaded) options |= ImagePixOption::Blurred;
_thumb = _data->thumb->pixNoCache(_thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize); _thumb = _data->thumb->pixNoCache(_thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize);
} }
p.drawPixmap(rthumb.topLeft(), _thumb); p.drawPixmap(rthumb.topLeft(), _thumb);
@ -1131,15 +1131,15 @@ void Link::paint(Painter &p, const QRect &clip, TextSelection selection, const P
if (_page && _page->photo) { if (_page && _page->photo) {
QPixmap pix; QPixmap pix;
if (_page->photo->medium->loaded()) { if (_page->photo->medium->loaded()) {
pix = _page->photo->medium->pixSingle(ImageRoundRadius::Small, _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize); pix = _page->photo->medium->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else if (_page->photo->loaded()) { } else if (_page->photo->loaded()) {
pix = _page->photo->full->pixSingle(ImageRoundRadius::Small, _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize); pix = _page->photo->full->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} else { } else {
pix = _page->photo->thumb->pixSingle(ImageRoundRadius::Small, _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize); pix = _page->photo->thumb->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small);
} }
p.drawPixmapLeft(0, top, _width, pix); p.drawPixmapLeft(0, top, _width, pix);
} else if (_page && _page->document && !_page->document->thumb->isNull()) { } else if (_page && _page->document && !_page->document->thumb->isNull()) {
p.drawPixmapLeft(0, top, _width, _page->document->thumb->pixSingle(ImageRoundRadius::Small, _pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize)); p.drawPixmapLeft(0, top, _width, _page->document->thumb->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small));
} else { } else {
int32 index = _letter.isEmpty() ? 0 : (_letter.at(0).unicode() % 4); int32 index = _letter.isEmpty() ? 0 : (_letter.at(0).unicode() % 4);
switch (index) { switch (index) {

View File

@ -198,11 +198,11 @@ StorageKey PeerData::userpicUniqueKey() const {
} }
void PeerData::saveUserpic(const QString &path, int size) const { void PeerData::saveUserpic(const QString &path, int size) const {
currentUserpic()->pixRounded(ImageRoundRadius::Small, size, size).save(path, "PNG"); currentUserpic()->pixRounded(size, size, ImageRoundRadius::Small).save(path, "PNG");
} }
QPixmap PeerData::genUserpic(int size) const { QPixmap PeerData::genUserpic(int size) const {
return currentUserpic()->pixRounded(ImageRoundRadius::Small, size, size); return currentUserpic()->pixRounded(size, size, ImageRoundRadius::Small);
} }
const Text &BotCommand::descriptionText() const { const Text &BotCommand::descriptionText() const {

View File

@ -51,11 +51,11 @@ StorageImages storageImages;
int64 globalAcquiredSize = 0; int64 globalAcquiredSize = 0;
constexpr uint64 BlurredCacheSkip = 0x1000000000000000LLU; constexpr uint64 BlurredCacheSkip = 0x1000000000000000ULL;
constexpr uint64 ColoredCacheSkip = 0x2000000000000000LLU; constexpr uint64 ColoredCacheSkip = 0x2000000000000000ULL;
constexpr uint64 BlurredColoredCacheSkip = 0x3000000000000000LLU; constexpr uint64 BlurredColoredCacheSkip = 0x3000000000000000ULL;
constexpr uint64 RoundedCacheSkip = 0x4000000000000000LLU; constexpr uint64 RoundedCacheSkip = 0x4000000000000000ULL;
constexpr uint64 CircledCacheSkip = 0x5000000000000000LLU; constexpr uint64 CircledCacheSkip = 0x5000000000000000ULL;
} // namespace } // namespace
@ -116,17 +116,18 @@ const QPixmap &Image::pix(int32 w, int32 h) const {
uint64 k = (uint64(w) << 32) | uint64(h); uint64 k = (uint64(w) << 32) | uint64(h);
Sizes::const_iterator i = _sizesCache.constFind(k); Sizes::const_iterator i = _sizesCache.constFind(k);
if (i == _sizesCache.cend()) { if (i == _sizesCache.cend()) {
QPixmap p(pixNoCache(w, h, ImagePixSmooth)); auto options = ImagePixOption::Smooth | ImagePixOption::None;
auto p = pixNoCache(w, h, ImagePixOption::Smooth);
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p); i = _sizesCache.insert(k, { p, options });
if (!p.isNull()) { if (!p.isNull()) {
globalAcquiredSize += int64(p.width()) * p.height() * 4; globalAcquiredSize += int64(p.width()) * p.height() * 4;
} }
} }
return i.value(); return i.value().pix;
} }
const QPixmap &Image::pixRounded(ImageRoundRadius radius, int32 w, int32 h) const { const QPixmap &Image::pixRounded(int32 w, int32 h, ImageRoundRadius radius, ImageRoundCorners corners) const {
checkload(); checkload();
if (w <= 0 || !width() || !height()) { if (w <= 0 || !width() || !height()) {
@ -135,18 +136,29 @@ const QPixmap &Image::pixRounded(ImageRoundRadius radius, int32 w, int32 h) cons
w *= cIntRetinaFactor(); w *= cIntRetinaFactor();
h *= cIntRetinaFactor(); h *= cIntRetinaFactor();
} }
uint64 k = RoundedCacheSkip | (uint64(w) << 32) | uint64(h); auto k = RoundedCacheSkip | (uint64(w) << 32) | uint64(h);
Sizes::const_iterator i = _sizesCache.constFind(k); auto i = _sizesCache.constFind(k);
if (i == _sizesCache.cend()) { if (i == _sizesCache.cend()) {
auto options = ImagePixSmooth | (radius == ImageRoundRadius::Large ? ImagePixRoundedLarge : ImagePixRoundedSmall); auto options = ImagePixOption::Smooth | ImagePixOption::None;
QPixmap p(pixNoCache(w, h, options)); auto cornerOptions = [](ImageRoundCorners corners) {
return (corners & ImageRoundCorner::TopLeft ? ImagePixOption::RoundedTopLeft : ImagePixOption::None)
| (corners & ImageRoundCorner::TopRight ? ImagePixOption::RoundedTopRight : ImagePixOption::None)
| (corners & ImageRoundCorner::BottomLeft ? ImagePixOption::RoundedBottomLeft : ImagePixOption::None)
| (corners & ImageRoundCorner::BottomRight ? ImagePixOption::RoundedBottomRight : ImagePixOption::None);
};
if (radius == ImageRoundRadius::Large) {
options |= ImagePixOption::RoundedLarge | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Small) {
options |= ImagePixOption::RoundedSmall | cornerOptions(corners);
}
auto p = pixNoCache(w, h, options);
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p); i = _sizesCache.insert(k, { p, options });
if (!p.isNull()) { if (!p.isNull()) {
globalAcquiredSize += int64(p.width()) * p.height() * 4; globalAcquiredSize += int64(p.width()) * p.height() * 4;
} }
} }
return i.value(); return i.value().pix;
} }
const QPixmap &Image::pixCircled(int32 w, int32 h) const { const QPixmap &Image::pixCircled(int32 w, int32 h) const {
@ -158,17 +170,18 @@ const QPixmap &Image::pixCircled(int32 w, int32 h) const {
w *= cIntRetinaFactor(); w *= cIntRetinaFactor();
h *= cIntRetinaFactor(); h *= cIntRetinaFactor();
} }
uint64 k = CircledCacheSkip | (uint64(w) << 32) | uint64(h); auto k = CircledCacheSkip | (uint64(w) << 32) | uint64(h);
Sizes::const_iterator i = _sizesCache.constFind(k); auto i = _sizesCache.constFind(k);
if (i == _sizesCache.cend()) { if (i == _sizesCache.cend()) {
QPixmap p(pixNoCache(w, h, ImagePixSmooth | ImagePixCircled)); auto options = ImagePixOption::Smooth | ImagePixOption::Circled;
auto p = pixNoCache(w, h, options);
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p); i = _sizesCache.insert(k, { p, options });
if (!p.isNull()) { if (!p.isNull()) {
globalAcquiredSize += int64(p.width()) * p.height() * 4; globalAcquiredSize += int64(p.width()) * p.height() * 4;
} }
} }
return i.value(); return i.value().pix;
} }
const QPixmap &Image::pixBlurred(int32 w, int32 h) const { const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
@ -180,17 +193,18 @@ const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
w *= cIntRetinaFactor(); w *= cIntRetinaFactor();
h *= cIntRetinaFactor(); h *= cIntRetinaFactor();
} }
uint64 k = BlurredCacheSkip | (uint64(w) << 32) | uint64(h); auto k = BlurredCacheSkip | (uint64(w) << 32) | uint64(h);
Sizes::const_iterator i = _sizesCache.constFind(k); auto i = _sizesCache.constFind(k);
if (i == _sizesCache.cend()) { if (i == _sizesCache.cend()) {
QPixmap p(pixNoCache(w, h, ImagePixSmooth | ImagePixBlurred)); auto options = ImagePixOption::Smooth | ImagePixOption::Blurred;
auto p = pixNoCache(w, h, options);
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p); i = _sizesCache.insert(k, { p, options });
if (!p.isNull()) { if (!p.isNull()) {
globalAcquiredSize += int64(p.width()) * p.height() * 4; globalAcquiredSize += int64(p.width()) * p.height() * 4;
} }
} }
return i.value(); return i.value().pix;
} }
const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) const { const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) const {
@ -202,17 +216,17 @@ const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) cons
w *= cIntRetinaFactor(); w *= cIntRetinaFactor();
h *= cIntRetinaFactor(); h *= cIntRetinaFactor();
} }
uint64 k = ColoredCacheSkip | (uint64(w) << 32) | uint64(h); auto k = ColoredCacheSkip | (uint64(w) << 32) | uint64(h);
Sizes::const_iterator i = _sizesCache.constFind(k); auto i = _sizesCache.constFind(k);
if (i == _sizesCache.cend()) { if (i == _sizesCache.cend()) {
QPixmap p(pixColoredNoCache(add, w, h, true)); auto p = pixColoredNoCache(add, w, h, true);
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p); i = _sizesCache.insert(k, { p, ImagePixOption::Smooth | ImagePixOption::None });
if (!p.isNull()) { if (!p.isNull()) {
globalAcquiredSize += int64(p.width()) * p.height() * 4; globalAcquiredSize += int64(p.width()) * p.height() * 4;
} }
} }
return i.value(); return i.value().pix;
} }
const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32 h) const { const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32 h) const {
@ -224,20 +238,20 @@ const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32
w *= cIntRetinaFactor(); w *= cIntRetinaFactor();
h *= cIntRetinaFactor(); h *= cIntRetinaFactor();
} }
uint64 k = BlurredColoredCacheSkip | (uint64(w) << 32) | uint64(h); auto k = BlurredColoredCacheSkip | (uint64(w) << 32) | uint64(h);
Sizes::const_iterator i = _sizesCache.constFind(k); auto i = _sizesCache.constFind(k);
if (i == _sizesCache.cend()) { if (i == _sizesCache.cend()) {
QPixmap p(pixBlurredColoredNoCache(add, w, h)); auto p = pixBlurredColoredNoCache(add, w, h);
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p); i = _sizesCache.insert(k, { p, ImagePixOption::Blurred | ImagePixOption::Smooth });
if (!p.isNull()) { if (!p.isNull()) {
globalAcquiredSize += int64(p.width()) * p.height() * 4; globalAcquiredSize += int64(p.width()) * p.height() * 4;
} }
} }
return i.value(); return i.value().pix;
} }
const QPixmap &Image::pixSingle(ImageRoundRadius radius, int32 w, int32 h, int32 outerw, int32 outerh) const { const QPixmap &Image::pixSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners) const {
checkload(); checkload();
if (w <= 0 || !width() || !height()) { if (w <= 0 || !width() || !height()) {
@ -246,24 +260,37 @@ const QPixmap &Image::pixSingle(ImageRoundRadius radius, int32 w, int32 h, int32
w *= cIntRetinaFactor(); w *= cIntRetinaFactor();
h *= cIntRetinaFactor(); h *= cIntRetinaFactor();
} }
uint64 k = 0LL;
Sizes::const_iterator i = _sizesCache.constFind(k); auto options = ImagePixOption::Smooth | ImagePixOption::None;
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) { auto cornerOptions = [](ImageRoundCorners corners) {
if (i != _sizesCache.cend()) { return (corners & ImageRoundCorner::TopLeft ? ImagePixOption::RoundedTopLeft : ImagePixOption::None)
globalAcquiredSize -= int64(i->width()) * i->height() * 4; | (corners & ImageRoundCorner::TopRight ? ImagePixOption::RoundedTopRight : ImagePixOption::None)
| (corners & ImageRoundCorner::BottomLeft ? ImagePixOption::RoundedBottomLeft : ImagePixOption::None)
| (corners & ImageRoundCorner::BottomRight ? ImagePixOption::RoundedBottomRight : ImagePixOption::None);
};
if (radius == ImageRoundRadius::Large) {
options |= ImagePixOption::RoundedLarge | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Small) {
options |= ImagePixOption::RoundedSmall | cornerOptions(corners);
} }
auto options = ImagePixSmooth | (radius == ImageRoundRadius::Large ? ImagePixRoundedLarge : ImagePixRoundedSmall);
QPixmap p(pixNoCache(w, h, options, outerw, outerh)); auto k = 0ULL;
auto i = _sizesCache.constFind(k);
if (i == _sizesCache.cend() || i->pix.width() != (outerw * cIntRetinaFactor()) || i->pix.height() != (outerh * cIntRetinaFactor()) || i->options != options) {
if (i != _sizesCache.cend()) {
globalAcquiredSize -= int64(i->pix.width()) * i->pix.height() * 4;
}
auto p = pixNoCache(w, h, options, outerw, outerh);
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p); i = _sizesCache.insert(k, { p, options });
if (!p.isNull()) { if (!p.isNull()) {
globalAcquiredSize += int64(p.width()) * p.height() * 4; globalAcquiredSize += int64(p.width()) * p.height() * 4;
} }
} }
return i.value(); return i.value().pix;
} }
const QPixmap &Image::pixBlurredSingle(ImageRoundRadius radius, int w, int h, int32 outerw, int32 outerh) const { const QPixmap &Image::pixBlurredSingle(int w, int h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners) const {
checkload(); checkload();
if (w <= 0 || !width() || !height()) { if (w <= 0 || !width() || !height()) {
@ -272,21 +299,34 @@ const QPixmap &Image::pixBlurredSingle(ImageRoundRadius radius, int w, int h, in
w *= cIntRetinaFactor(); w *= cIntRetinaFactor();
h *= cIntRetinaFactor(); h *= cIntRetinaFactor();
} }
uint64 k = BlurredCacheSkip | 0LL;
Sizes::const_iterator i = _sizesCache.constFind(k); auto options = ImagePixOption::Smooth | ImagePixOption::Blurred;
if (i == _sizesCache.cend() || i->width() != (outerw * cIntRetinaFactor()) || i->height() != (outerh * cIntRetinaFactor())) { auto cornerOptions = [](ImageRoundCorners corners) {
if (i != _sizesCache.cend()) { return (corners & ImageRoundCorner::TopLeft ? ImagePixOption::RoundedTopLeft : ImagePixOption::None)
globalAcquiredSize -= int64(i->width()) * i->height() * 4; | (corners & ImageRoundCorner::TopRight ? ImagePixOption::RoundedTopRight : ImagePixOption::None)
| (corners & ImageRoundCorner::BottomLeft ? ImagePixOption::RoundedBottomLeft : ImagePixOption::None)
| (corners & ImageRoundCorner::BottomRight ? ImagePixOption::RoundedBottomRight : ImagePixOption::None);
};
if (radius == ImageRoundRadius::Large) {
options |= ImagePixOption::RoundedLarge | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Small) {
options |= ImagePixOption::RoundedSmall | cornerOptions(corners);
} }
auto options = ImagePixSmooth | ImagePixBlurred | (radius == ImageRoundRadius::Large ? ImagePixRoundedLarge : ImagePixRoundedSmall);
QPixmap p(pixNoCache(w, h, options, outerw, outerh)); auto k = BlurredCacheSkip | 0ULL;
auto i = _sizesCache.constFind(k);
if (i == _sizesCache.cend() || i->pix.width() != (outerw * cIntRetinaFactor()) || i->pix.height() != (outerh * cIntRetinaFactor()) || i->options != options) {
if (i != _sizesCache.cend()) {
globalAcquiredSize -= int64(i->pix.width()) * i->pix.height() * 4;
}
auto p = pixNoCache(w, h, options, outerw, outerh);
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor()); if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
i = _sizesCache.insert(k, p); i = _sizesCache.insert(k, { p, options });
if (!p.isNull()) { if (!p.isNull()) {
globalAcquiredSize += int64(p.width()) * p.height() * 4; globalAcquiredSize += int64(p.width()) * p.height() * 4;
} }
} }
return i.value(); return i.value().pix;
} }
namespace { namespace {
@ -447,46 +487,63 @@ void imageCircle(QImage &img) {
p.drawPixmap(0, 0, mask); p.drawPixmap(0, 0, mask);
} }
void imageRound(QImage &img, ImageRoundRadius radius) { void imageRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corners) {
t_assert(!img.isNull()); if (!static_cast<int>(corners)) {
return;
}
t_assert(!image.isNull());
img.setDevicePixelRatio(cRetinaFactor()); image.setDevicePixelRatio(cRetinaFactor());
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied); image = std_::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied);
t_assert(!img.isNull()); t_assert(!image.isNull());
QImage **masks = App::cornersMask(radius); QImage **masks = App::cornersMask(radius);
int32 w = masks[0]->width(), h = masks[0]->height(); auto cornerWidth = masks[0]->width();
int32 tw = img.width(), th = img.height(); auto cornerHeight = masks[0]->height();
if (tw < 2 * w || th < 2 * h) { auto imageWidth = image.width();
auto imageHeight = image.height();
if (imageWidth < 2 * cornerWidth || imageHeight < 2 * cornerHeight) {
if (radius == ImageRoundRadius::Large) { if (radius == ImageRoundRadius::Large) {
return imageRound(img, ImageRoundRadius::Small); return imageRound(image, ImageRoundRadius::Small, corners);
} }
return; return;
} }
constexpr auto imageIntsPerPixel = 1;
auto imageIntsPerLine = (image.bytesPerLine() >> 2);
t_assert(image.depth() == static_cast<int>((imageIntsPerPixel * sizeof(uint32)) << 3));
t_assert(image.bytesPerLine() == (imageIntsPerLine << 2));
uchar *bits = img.bits(); auto ints = reinterpret_cast<uint32*>(image.bits());
const uchar *c0 = masks[0]->constBits(), *c1 = masks[1]->constBits(), *c2 = masks[2]->constBits(), *c3 = masks[3]->constBits(); auto intsTopLeft = ints;
auto intsTopRight = ints + imageWidth - cornerWidth;
int32 s0 = 0, s1 = (tw - w) * 4, s2 = (th - h) * tw * 4, s3 = ((th - h + 1) * tw - w) * 4; auto intsBottomLeft = ints + (imageHeight - cornerHeight) * imageWidth;
for (int32 i = 0; i < w; ++i) { auto intsBottomRight = ints + (imageHeight - cornerHeight + 1) * imageWidth - cornerWidth;
for (int32 j = 0; j < h; ++j) { auto maskCorner = [imageWidth, imageHeight, imageIntsPerPixel, imageIntsPerLine](uint32 *imageInts, const QImage *mask) {
#define update(s, c) \ auto maskWidth = mask->width();
{ \ auto maskHeight = mask->height();
uint64 color = _blurGetColors(bits + s + (j * tw + i) * 4); \ auto maskBytesPerPixel = (mask->depth() >> 3);
color *= (c[(j * w + i) * 4 + 3] + 1); \ auto maskBytesPerLine = mask->bytesPerLine();
color = (color >> 8); \ auto maskBytesAdded = maskBytesPerLine - maskWidth * maskBytesPerPixel;
bits[s + (j * tw + i) * 4] = color & 0xFF; \ auto maskBytes = mask->constBits();
bits[s + (j * tw + i) * 4 + 1] = (color >> 16) & 0xFF; \ t_assert(maskBytesAdded >= 0);
bits[s + (j * tw + i) * 4 + 2] = (color >> 32) & 0xFF; \ t_assert(mask->depth() == (maskBytesPerPixel << 3));
bits[s + (j * tw + i) * 4 + 3] = (color >> 48) & 0xFF; \ auto imageIntsAdded = imageIntsPerLine - maskWidth * imageIntsPerPixel;
} t_assert(imageIntsAdded >= 0);
update(s0, c0); for (auto y = 0; y != maskHeight; ++y) {
update(s1, c1); for (auto x = 0; x != maskWidth; ++x) {
update(s2, c2); auto opacity = static_cast<anim::ShiftedMultiplier>(*maskBytes) + 1;
update(s3, c3); *imageInts = anim::unshifted(anim::shifted(*imageInts) * opacity);
#undef update maskBytes += maskBytesPerPixel;
imageInts += imageIntsPerPixel;
} }
maskBytes += maskBytesAdded;
imageInts += imageIntsAdded;
} }
};
if (corners & ImageRoundCorner::TopLeft) maskCorner(intsTopLeft, masks[0]);
if (corners & ImageRoundCorner::TopRight) maskCorner(intsTopRight, masks[1]);
if (corners & ImageRoundCorner::BottomLeft) maskCorner(intsBottomLeft, masks[2]);
if (corners & ImageRoundCorner::BottomRight) maskCorner(intsBottomRight, masks[3]);
} }
QImage imageColored(const style::color &add, QImage img) { QImage imageColored(const style::color &add, QImage img) {
@ -512,16 +569,16 @@ QImage imageColored(const style::color &add, QImage img) {
QPixmap imagePix(QImage img, int32 w, int32 h, ImagePixOptions options, int32 outerw, int32 outerh) { QPixmap imagePix(QImage img, int32 w, int32 h, ImagePixOptions options, int32 outerw, int32 outerh) {
t_assert(!img.isNull()); t_assert(!img.isNull());
if (options.testFlag(ImagePixBlurred)) { if (options.testFlag(ImagePixOption::Blurred)) {
img = imageBlur(img); img = imageBlur(img);
t_assert(!img.isNull()); t_assert(!img.isNull());
} }
if (w <= 0 || (w == img.width() && (h <= 0 || h == img.height()))) { if (w <= 0 || (w == img.width() && (h <= 0 || h == img.height()))) {
} else if (h <= 0) { } else if (h <= 0) {
img = img.scaledToWidth(w, options.testFlag(ImagePixSmooth) ? Qt::SmoothTransformation : Qt::FastTransformation); img = img.scaledToWidth(w, options.testFlag(ImagePixOption::Smooth) ? Qt::SmoothTransformation : Qt::FastTransformation);
t_assert(!img.isNull()); t_assert(!img.isNull());
} else { } else {
img = img.scaled(w, h, Qt::IgnoreAspectRatio, options.testFlag(ImagePixSmooth) ? Qt::SmoothTransformation : Qt::FastTransformation); img = img.scaled(w, h, Qt::IgnoreAspectRatio, options.testFlag(ImagePixOption::Smooth) ? Qt::SmoothTransformation : Qt::FastTransformation);
t_assert(!img.isNull()); t_assert(!img.isNull());
} }
if (outerw > 0 && outerh > 0) { if (outerw > 0 && outerh > 0) {
@ -542,14 +599,20 @@ QPixmap imagePix(QImage img, int32 w, int32 h, ImagePixOptions options, int32 ou
t_assert(!img.isNull()); t_assert(!img.isNull());
} }
} }
if (options.testFlag(ImagePixCircled)) { auto corners = [](ImagePixOptions options) {
return (options.testFlag(ImagePixOption::RoundedTopLeft) ? ImageRoundCorner::TopLeft : ImageRoundCorner::None)
| (options.testFlag(ImagePixOption::RoundedTopRight) ? ImageRoundCorner::TopRight : ImageRoundCorner::None)
| (options.testFlag(ImagePixOption::RoundedBottomLeft) ? ImageRoundCorner::BottomLeft : ImageRoundCorner::None)
| (options.testFlag(ImagePixOption::RoundedBottomRight) ? ImageRoundCorner::BottomRight : ImageRoundCorner::None);
};
if (options.testFlag(ImagePixOption::Circled)) {
imageCircle(img); imageCircle(img);
t_assert(!img.isNull()); t_assert(!img.isNull());
} else if (options.testFlag(ImagePixRoundedLarge)) { } else if (options.testFlag(ImagePixOption::RoundedLarge)) {
imageRound(img, ImageRoundRadius::Large); imageRound(img, ImageRoundRadius::Large, corners(options));
t_assert(!img.isNull()); t_assert(!img.isNull());
} else if (options.testFlag(ImagePixRoundedSmall)) { } else if (options.testFlag(ImagePixOption::RoundedSmall)) {
imageRound(img, ImageRoundRadius::Small); imageRound(img, ImageRoundRadius::Small, corners(options));
} }
img.setDevicePixelRatio(cRetinaFactor()); img.setDevicePixelRatio(cRetinaFactor());
return App::pixmapFromImageInPlace(std_::move(img)); return App::pixmapFromImageInPlace(std_::move(img));
@ -586,12 +649,18 @@ QPixmap Image::pixNoCache(int w, int h, ImagePixOptions options, int outerw, int
p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::imageBgTransparent); p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::imageBgTransparent);
} }
if (options.testFlag(ImagePixCircled)) { auto corners = [](ImagePixOptions options) {
return (options.testFlag(ImagePixOption::RoundedTopLeft) ? ImageRoundCorner::TopLeft : ImageRoundCorner::None)
| (options.testFlag(ImagePixOption::RoundedTopRight) ? ImageRoundCorner::TopRight : ImageRoundCorner::None)
| (options.testFlag(ImagePixOption::RoundedBottomLeft) ? ImageRoundCorner::BottomLeft : ImageRoundCorner::None)
| (options.testFlag(ImagePixOption::RoundedBottomRight) ? ImageRoundCorner::BottomRight : ImageRoundCorner::None);
};
if (options.testFlag(ImagePixOption::Circled)) {
imageCircle(result); imageCircle(result);
} else if (options.testFlag(ImagePixRoundedLarge)) { } else if (options.testFlag(ImagePixOption::RoundedLarge)) {
imageRound(result, ImageRoundRadius::Large); imageRound(result, ImageRoundRadius::Large, corners(options));
} else if (options.testFlag(ImagePixRoundedSmall)) { } else if (options.testFlag(ImagePixOption::RoundedSmall)) {
imageRound(result, ImageRoundRadius::Small); imageRound(result, ImageRoundRadius::Small, corners(options));
} }
return App::pixmapFromImageInPlace(std_::move(result)); return App::pixmapFromImageInPlace(std_::move(result));
} }
@ -665,9 +734,9 @@ void Image::restore() const {
} }
void Image::invalidateSizeCache() const { void Image::invalidateSizeCache() const {
for (Sizes::const_iterator i = _sizesCache.cbegin(), e = _sizesCache.cend(); i != e; ++i) { for (auto &size : _sizesCache) {
if (!i->isNull()) { if (!size.pix.isNull()) {
globalAcquiredSize -= int64(i->width()) * i->height() * 4; globalAcquiredSize -= int64(size.pix.width()) * size.pix.height() * 4;
} }
} }
_sizesCache.clear(); _sizesCache.clear();
@ -681,21 +750,18 @@ Image::~Image() {
} }
void clearStorageImages() { void clearStorageImages() {
for (StorageImages::const_iterator i = storageImages.cbegin(), e = storageImages.cend(); i != e; ++i) { for (auto image : base::take(storageImages)) {
delete i.value(); delete image;
} }
storageImages.clear(); for (auto image : base::take(webImages)) {
for (WebImages::const_iterator i = webImages.cbegin(), e = webImages.cend(); i != e; ++i) { delete image;
delete i.value();
} }
webImages.clear();
} }
void clearAllImages() { void clearAllImages() {
for (LocalImages::const_iterator i = localImages.cbegin(), e = localImages.cend(); i != e; ++i) { for (auto image : base::take(localImages)) {
delete i.value(); delete image;
} }
localImages.clear();
clearStorageImages(); clearStorageImages();
} }

View File

@ -27,10 +27,20 @@ enum class ImageRoundRadius {
Large, Large,
Small, Small,
}; };
enum class ImageRoundCorner {
None = 0x00,
TopLeft = 0x01,
TopRight = 0x02,
BottomLeft = 0x04,
BottomRight = 0x08,
All = 0x0f,
};
Q_DECLARE_FLAGS(ImageRoundCorners, ImageRoundCorner);
Q_DECLARE_OPERATORS_FOR_FLAGS(ImageRoundCorners);
QImage imageBlur(QImage img); QImage imageBlur(QImage image);
void imageRound(QImage &img, ImageRoundRadius radius); void imageRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All);
void imageCircle(QImage &img); void imageCircle(QImage &image);
inline uint32 packInt(int32 a) { inline uint32 packInt(int32 a) {
return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(a); return (a < 0) ? uint32(int64(a) + 0x100000000LL) : uint32(a);
@ -114,12 +124,17 @@ inline bool operator!=(const StorageImageLocation &a, const StorageImageLocation
return !(a == b); return !(a == b);
} }
enum ImagePixOption { enum class ImagePixOption {
ImagePixSmooth = 0x01, None = 0x000,
ImagePixBlurred = 0x02, Smooth = 0x001,
ImagePixCircled = 0x04, Blurred = 0x002,
ImagePixRoundedLarge = 0x08, Circled = 0x004,
ImagePixRoundedSmall = 0x10, RoundedLarge = 0x008,
RoundedSmall = 0x010,
RoundedTopLeft = 0x020,
RoundedTopRight = 0x040,
RoundedBottomLeft = 0x080,
RoundedBottomRight = 0x100,
}; };
Q_DECLARE_FLAGS(ImagePixOptions, ImagePixOption); Q_DECLARE_FLAGS(ImagePixOptions, ImagePixOption);
Q_DECLARE_OPERATORS_FOR_FLAGS(ImagePixOptions); Q_DECLARE_OPERATORS_FOR_FLAGS(ImagePixOptions);
@ -160,13 +175,13 @@ public:
} }
const QPixmap &pix(int32 w = 0, int32 h = 0) const; const QPixmap &pix(int32 w = 0, int32 h = 0) const;
const QPixmap &pixRounded(ImageRoundRadius radius, int32 w = 0, int32 h = 0) const; const QPixmap &pixRounded(int32 w = 0, int32 h = 0, ImageRoundRadius radius = ImageRoundRadius::None, ImageRoundCorners corners = ImageRoundCorner::All) const;
const QPixmap &pixCircled(int32 w = 0, int32 h = 0) const; const QPixmap &pixCircled(int32 w = 0, int32 h = 0) const;
const QPixmap &pixBlurred(int32 w = 0, int32 h = 0) const; const QPixmap &pixBlurred(int32 w = 0, int32 h = 0) const;
const QPixmap &pixColored(const style::color &add, int32 w = 0, int32 h = 0) const; const QPixmap &pixColored(const style::color &add, int32 w = 0, int32 h = 0) const;
const QPixmap &pixBlurredColored(const style::color &add, int32 w = 0, int32 h = 0) const; const QPixmap &pixBlurredColored(const style::color &add, int32 w = 0, int32 h = 0) const;
const QPixmap &pixSingle(ImageRoundRadius radius, int32 w, int32 h, int32 outerw, int32 outerh) const; const QPixmap &pixSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All) const;
const QPixmap &pixBlurredSingle(ImageRoundRadius radius, int32 w, int32 h, int32 outerw, int32 outerh) const; const QPixmap &pixBlurredSingle(int32 w, int32 h, int32 outerw, int32 outerh, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All) const;
QPixmap pixNoCache(int w = 0, int h = 0, ImagePixOptions options = 0, int outerw = -1, int outerh = -1) const; QPixmap pixNoCache(int w = 0, int h = 0, ImagePixOptions options = 0, int outerw = -1, int outerh = -1) const;
QPixmap pixColoredNoCache(const style::color &add, int32 w = 0, int32 h = 0, bool smooth = false) const; QPixmap pixColoredNoCache(const style::color &add, int32 w = 0, int32 h = 0, bool smooth = false) const;
QPixmap pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h = 0) const; QPixmap pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h = 0) const;
@ -234,7 +249,11 @@ protected:
private: private:
typedef QMap<uint64, QPixmap> Sizes; struct Size {
QPixmap pix;
ImagePixOptions options;
};
typedef QMap<uint64, Size> Sizes;
mutable Sizes _sizesCache; mutable Sizes _sizesCache;
}; };

View File

@ -88,7 +88,7 @@ void colorizeImage(const QImage &src, QColor c, QImage *outResult, QRect srcRect
auto pattern = anim::shifted(c); auto pattern = anim::shifted(c);
auto resultBytesPerPixel = (src.depth() >> 3); auto resultBytesPerPixel = (src.depth() >> 3);
auto resultIntsPerPixel = 1; constexpr auto resultIntsPerPixel = 1;
auto resultIntsPerLine = (outResult->bytesPerLine() >> 2); auto resultIntsPerLine = (outResult->bytesPerLine() >> 2);
auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel; auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel;
auto resultInts = reinterpret_cast<uint32*>(outResult->bits()) + dstPoint.y() * resultIntsPerLine + dstPoint.x() * resultIntsPerPixel; auto resultInts = reinterpret_cast<uint32*>(outResult->bits()) + dstPoint.y() * resultIntsPerLine + dstPoint.x() * resultIntsPerPixel;
@ -104,7 +104,7 @@ void colorizeImage(const QImage &src, QColor c, QImage *outResult, QRect srcRect
t_assert(src.depth() == (maskBytesPerPixel << 3)); t_assert(src.depth() == (maskBytesPerPixel << 3));
for (int y = 0; y != height; ++y) { for (int y = 0; y != height; ++y) {
for (int x = 0; x != width; ++x) { for (int x = 0; x != width; ++x) {
auto maskOpacity = static_cast<uint64>(*maskBytes) + 1; auto maskOpacity = static_cast<anim::ShiftedMultiplier>(*maskBytes) + 1;
*resultInts = anim::unshifted(pattern * maskOpacity); *resultInts = anim::unshifted(pattern * maskOpacity);
maskBytes += maskBytesPerPixel; maskBytes += maskBytesPerPixel;
resultInts += resultIntsPerPixel; resultInts += resultIntsPerPixel;