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
}
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) {
switch (radius) {
case ImageRoundRadius::Large: return ::cornersMaskLarge;

View File

@ -280,6 +280,7 @@ namespace App {
void setProxySettings(QTcpSocket &socket);
enum class RectPart {
None = 0x000,
TopLeft = 0x001,
Top = 0x002,
TopRight = 0x004,
@ -300,6 +301,9 @@ namespace App {
Q_DECLARE_FLAGS(RectParts, RectPart);
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);
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) {

View File

@ -87,7 +87,7 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
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 {
for (PreparedPhotoThumbs::const_iterator i = _file->photoThumbs.cbegin(), e = _file->photoThumbs.cend(); i != e; ++i) {
if (i->width() >= maxW && i->height() >= maxH) {
@ -129,7 +129,8 @@ PhotoSendBox::PhotoSendBox(const FileLoadResultPtr &file) : AbstractBox(st::boxW
} else {
_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);
@ -420,7 +421,8 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
} else {
_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) {
@ -451,11 +453,11 @@ EditCaptionBox::EditCaptionBox(HistoryItem *msg) : AbstractBox(st::boxWideWidth)
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 {
maxW = dimensions.width();
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();
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 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;
if (loaded) {
pix = _data->full->pixSingle(roundRadius, _pixw, _pixh, width, height);
pix = _data->full->pixSingle(_pixw, _pixh, width, height, roundRadius, roundCorners);
} 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));
p.drawPixmap(rthumb.topLeft(), pix);
if (selected) {
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
}
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 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));
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) {
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
}
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 roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
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);
if (selected) {
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
@ -1642,7 +1649,9 @@ int HistoryGif::resizeGetHeight(int width) {
if (!_gif->started()) {
auto inWebPage = (_parent->getMedia() != this);
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 {
_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));
auto inWebPage = (_parent->getMedia() != this);
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));
if (animating) {
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isInlineItemBeingChosen()) ? 0 : ms));
p.drawPixmap(rthumb.topLeft(), _gif->current(_thumbw, _thumbh, width, height, roundRadius, roundCorners, (Ui::isLayerShown() || Ui::isMediaViewShown() || Ui::isInlineItemBeingChosen()) ? 0 : ms));
} else {
auto inWebPage = (_parent->getMedia() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(roundRadius, _thumbw, _thumbh, width, height));
p.drawPixmap(rthumb.topLeft(), _data->thumb->pixBlurredSingle(_thumbw, _thumbh, width, height, roundRadius, roundCorners));
}
if (selected) {
auto inWebPage = (_parent->getMedia() != this);
auto overlayCorners = inWebPage ? SelectedOverlaySmallCorners : SelectedOverlayLargeCorners;
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
}
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);
}
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 {
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);
if (selected) {
@ -3397,25 +3406,28 @@ void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection,
}
_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()) {
int32 w = _data->thumb->width(), h = _data->thumb->height();
QPixmap pix;
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) {
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 {
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 {
App::roundRect(p, skipx, skipy, width, height, st::msgInBg, MessageInCorners);
App::complexLocationRect(p, rthumb, roundRadius, roundCorners);
}
if (selected) {
App::roundRect(p, skipx, skipy, width, height, textstyleCurrent()->selectOverlay, SelectedOverlayLargeCorners);
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
}
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();
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));
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) {
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();
if (!replyPreview->isNull()) {
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();
}
@ -8754,7 +8754,7 @@ void HistoryWidget::drawPinnedBar(Painter &p) {
ImagePtr replyPreview = _pinnedBar->msg->getMedia()->replyPreview();
if (!replyPreview->isNull()) {
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();
}

View File

@ -159,7 +159,7 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
QRect r(0, 0, _width, height);
if (animating) {
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 {
prepareThumb(_width, height, frame);
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->loaded()) {
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 {
document->thumb->load();
@ -293,7 +293,7 @@ void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (!thumb->isNull()) {
if (thumb->loaded()) {
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 {
thumb->load();
@ -338,7 +338,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
} else if (_gif->ready() && !_gif->started()) {
int32 height = st::inlineMediaHeight;
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)) {
_gif.reset();
getShownDocument()->forget();
@ -529,13 +529,13 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (PhotoData *photo = getShownPhoto()) {
if (photo->medium->loaded()) {
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;
} else {
if (photo->thumb->loaded()) {
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();
@ -544,7 +544,7 @@ void Photo::prepareThumb(int32 width, int32 height, const QSize &frame) const {
ImagePtr thumb = getResultThumb();
if (thumb->loaded()) {
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 {
thumb->load();
@ -654,7 +654,7 @@ void Video::prepareThumb(int32 width, int32 height) const {
w = width;
}
}
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height);
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
}
} else {
thumb->load();
@ -985,7 +985,7 @@ void Contact::prepareThumb(int width, int height) const {
w = width;
}
}
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height);
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
}
} else {
thumb->load();
@ -1132,7 +1132,7 @@ void Article::prepareThumb(int width, int height) const {
w = width;
}
}
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height);
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
}
} else {
thumb->load();
@ -1233,7 +1233,7 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
if (animating) {
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);
thumbDisplayed = true;
}
@ -1312,7 +1312,7 @@ void Game::prepareThumb(int width, int height) const {
w = width;
}
}
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixSmooth, width, height);
_thumb = thumb->pixNoCache(w * cIntRetinaFactor(), h * cIntRetinaFactor(), ImagePixOption::Smooth, width, height);
}
} else {
thumb->load();
@ -1347,7 +1347,7 @@ void Game::clipCallback(Media::Clip::Notification notification) {
_gif.setBad();
getResultDocument()->forget();
} 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)) {
_gif.reset();
getResultDocument()->forget();

View File

@ -824,7 +824,7 @@ QPixmap MediaPreviewWidget::currentImage() const {
}
if (_gif && _gif->started()) {
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()) {
QSize s = currentDimensions();
@ -863,7 +863,7 @@ void MediaPreviewWidget::clipCallback(Media::Clip::Notification notification) {
if (_gif && _gif->ready() && !_gif->started()) {
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();

View File

@ -76,7 +76,7 @@ QPixmap _prepareFrame(const FrameRequest &request, const QImage &original, bool
}
}
if (request.radius != ImageRoundRadius::None) {
imageRound(cache, request.radius);
imageRound(cache, request.radius, request.corners);
}
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 (_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.outerh = outerh * factor;
request.radius = radius;
request.corners = corners;
_frames[0].request = _frames[1].request = _frames[2].request = request;
moveToNextShow();
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();
t_assert(frame != nullptr);
@ -223,7 +224,10 @@ QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh,
}
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();
return frame->pix;
}
@ -238,7 +242,7 @@ QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh,
frame->pix = QPixmap();
frame->pix = _prepareFrame(frame->request, frame->original, true, cacheForResize);
Frame *other = frameToWriteNext(true);
auto other = frameToWriteNext(true);
if (other) other->request = frame->request;
moveToNextShow();
@ -254,7 +258,7 @@ QPixmap Reader::current(int32 framew, int32 frameh, int32 outerw, int32 outerh,
bool Reader::ready() const {
if (_width && _height) return true;
Frame *frame = frameToShow();
auto frame = frameToShow();
if (frame) {
_width = frame->original.width();
_height = frame->original.height();

View File

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

View File

@ -201,7 +201,7 @@ bool MediaView::gifShown() const {
_gif->pauseResumeVideo();
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();
}
return true;// _gif->state() != Media::Clip::State::Error;
@ -1329,10 +1329,10 @@ void MediaView::initAnimation() {
} else if (_doc->dimensions.width() && _doc->dimensions.height()) {
int w = _doc->dimensions.width();
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());
} 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()) {
int w = _doc->dimensions.width();
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());
} 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;
_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;
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) {
clipCallback(notification);
@ -1543,17 +1543,17 @@ void MediaView::paintEvent(QPaintEvent *e) {
int32 w = _width * cIntRetinaFactor();
if (_full <= 0 && _photo->loaded()) {
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());
_full = 1;
} else if (_full < 0 && _photo->medium->loaded()) {
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());
_full = 0;
} else if (_current.isNull() && _photo->thumb->loaded()) {
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());
} else if (_current.isNull()) {
_current = _photo->thumb->pix();
@ -1563,7 +1563,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
if (_photo || fileShown()) {
QRect imgRect(_x, _y, _w, _h);
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()) {
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 (_thumb.isNull() || loaded != _thumbForLoaded) {
_thumbForLoaded = loaded;
ImagePixOptions options = ImagePixSmooth;
if (!_thumbForLoaded) options |= ImagePixBlurred;
auto options = ImagePixOption::Smooth | ImagePixOption::None;
if (!_thumbForLoaded) options |= ImagePixOption::Blurred;
_thumb = _data->thumb->pixNoCache(_thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize);
}
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) {
QPixmap pix;
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()) {
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 {
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);
} 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 {
int32 index = _letter.isEmpty() ? 0 : (_letter.at(0).unicode() % 4);
switch (index) {

View File

@ -198,11 +198,11 @@ StorageKey PeerData::userpicUniqueKey() 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 {
return currentUserpic()->pixRounded(ImageRoundRadius::Small, size, size);
return currentUserpic()->pixRounded(size, size, ImageRoundRadius::Small);
}
const Text &BotCommand::descriptionText() const {

View File

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

View File

@ -27,10 +27,20 @@ enum class ImageRoundRadius {
Large,
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);
void imageRound(QImage &img, ImageRoundRadius radius);
void imageCircle(QImage &img);
QImage imageBlur(QImage image);
void imageRound(QImage &image, ImageRoundRadius radius, ImageRoundCorners corners = ImageRoundCorner::All);
void imageCircle(QImage &image);
inline uint32 packInt(int32 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);
}
enum ImagePixOption {
ImagePixSmooth = 0x01,
ImagePixBlurred = 0x02,
ImagePixCircled = 0x04,
ImagePixRoundedLarge = 0x08,
ImagePixRoundedSmall = 0x10,
enum class ImagePixOption {
None = 0x000,
Smooth = 0x001,
Blurred = 0x002,
Circled = 0x004,
RoundedLarge = 0x008,
RoundedSmall = 0x010,
RoundedTopLeft = 0x020,
RoundedTopRight = 0x040,
RoundedBottomLeft = 0x080,
RoundedBottomRight = 0x100,
};
Q_DECLARE_FLAGS(ImagePixOptions, ImagePixOption);
Q_DECLARE_OPERATORS_FOR_FLAGS(ImagePixOptions);
@ -160,13 +175,13 @@ public:
}
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 &pixBlurred(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 &pixSingle(ImageRoundRadius radius, int32 w, int32 h, int32 outerw, int32 outerh) const;
const QPixmap &pixBlurredSingle(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(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 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;
@ -234,7 +249,11 @@ protected:
private:
typedef QMap<uint64, QPixmap> Sizes;
struct Size {
QPixmap pix;
ImagePixOptions options;
};
typedef QMap<uint64, Size> Sizes;
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 resultBytesPerPixel = (src.depth() >> 3);
auto resultIntsPerPixel = 1;
constexpr auto resultIntsPerPixel = 1;
auto resultIntsPerLine = (outResult->bytesPerLine() >> 2);
auto resultIntsAdded = resultIntsPerLine - width * 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));
for (int y = 0; y != height; ++y) {
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);
maskBytes += maskBytesPerPixel;
resultInts += resultIntsPerPixel;