Fix crash in EditCaptionBox.

This commit is contained in:
John Preston 2019-02-17 12:31:04 +04:00
parent 771a51224e
commit 7c1704e68b
8 changed files with 86 additions and 39 deletions

View File

@ -115,6 +115,9 @@ EditCaptionBox::EditCaptionBox(
_refreshThumbnail();
}
} else {
if (!image) {
image = Image::BlankMedia();
}
int32 maxW = 0, maxH = 0;
if (_animated) {
int32 limitW = st::sendMediaPreviewSize;
@ -201,7 +204,9 @@ EditCaptionBox::EditCaptionBox(
? _thumbnailImage->loaded()
: true;
subscribe(Auth().downloaderTaskFinished(), [=] {
if (!_thumbnailImageLoaded && _thumbnailImage->loaded()) {
if (!_thumbnailImageLoaded
&& _thumbnailImage
&& _thumbnailImage->loaded()) {
_thumbnailImageLoaded = true;
_refreshThumbnail();
update();

View File

@ -347,12 +347,22 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
if (good) {
good->load({});
}
if (const auto normal = _data->thumbnail()) {
if (normal->loaded()) {
p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
} else if (const auto blurred = _data->thumbnailInline()) {
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
}
const auto normal = _data->thumbnail();
if (normal && normal->loaded()) {
p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners));
} else if (const auto blurred = _data->thumbnailInline()) {
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners));
} else if (!isRound) {
const auto roundTop = (roundCorners & RectPart::TopLeft);
const auto roundBottom = (roundCorners & RectPart::BottomLeft);
const auto margin = inWebPage
? st::buttonRadius
: st::historyMessageRadius;
const auto parts = roundCorners
| RectPart::NoTopBottom
| (roundTop ? RectPart::Top : RectPart::None)
| (roundBottom ? RectPart::Bottom : RectPart::None);
App::roundRect(p, rthumb.marginsAdded({ 0, roundTop ? 0 : margin, 0, roundBottom ? 0 : margin }), st::imageBg, roundRadius, parts);
}
}
}

View File

@ -528,7 +528,7 @@ void HistoryPhoto::validateGroupedCache(
? _data->thumbnailSmall().get()
: _data->thumbnailInline()
? _data->thumbnailInline()
: Image::Blank().get();
: Image::BlankMedia().get();
*cacheKey = key;
*cache = image->pixNoCache(_realParent->fullId(), pixWidth, pixHeight, options, width, height);

View File

@ -183,11 +183,22 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, Tim
if (good) {
good->load({});
}
if (const auto normal = _data->thumbnail()) {
const auto use = (normal->loaded() || !_data->thumbnailInline())
? normal
: _data->thumbnailInline();
p.drawPixmap(rthumb.topLeft(), use->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners));
const auto normal = _data->thumbnail();
if (normal && normal->loaded()) {
p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners));
} else if (const auto blurred = _data->thumbnailInline()) {
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_realParent->fullId(), _thumbw, _thumbh, paintw, painth, roundRadius, roundCorners));
} else {
const auto roundTop = (roundCorners & RectPart::TopLeft);
const auto roundBottom = (roundCorners & RectPart::BottomLeft);
const auto margin = inWebPage
? st::buttonRadius
: st::historyMessageRadius;
const auto parts = roundCorners
| RectPart::NoTopBottom
| (roundTop ? RectPart::Top : RectPart::None)
| (roundBottom ? RectPart::Bottom : RectPart::None);
App::roundRect(p, rthumb.marginsAdded({ 0, roundTop ? 0 : margin, 0, roundBottom ? 0 : margin }), st::imageBg, roundRadius, parts);
}
}
if (selected) {
@ -496,7 +507,13 @@ void HistoryVideo::validateGroupedCache(
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
*cacheKey = key;
*cache = (image ? image : Image::Blank().get())->pixNoCache(_realParent->fullId(), pixWidth, pixHeight, options, width, height);
*cache = (image ? image : Image::BlankMedia().get())->pixNoCache(
_realParent->fullId(),
pixWidth,
pixHeight,
options,
width,
height);
}
void HistoryVideo::setStatusSize(int newSize) const {

View File

@ -1810,12 +1810,12 @@ void OverlayWidget::initAnimation() {
auto h = _doc->dimensions.height();
_current = (_doc->hasThumbnail()
? _doc->thumbnail()
: Image::Blank().get())->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
: Image::Empty().get())->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
_current.setDevicePixelRatio(cRetinaFactor());
} else if (_doc->hasThumbnail()) {
_current = _doc->thumbnail()->pixNoCache(fileOrigin(), _doc->thumbnail()->width(), _doc->thumbnail()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
} else {
_current = Image::Blank().get()->pixNoCache({}, Image::Blank()->width(), Image::Blank()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
_current = Image::Empty()->pixNoCache({}, Image::Empty()->width(), Image::Empty()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
}
}
@ -1830,12 +1830,12 @@ void OverlayWidget::createClipReader() {
int h = _doc->dimensions.height();
_current = (_doc->hasThumbnail()
? _doc->thumbnail()
: Image::Blank().get())->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
: Image::Empty().get())->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
_current.setDevicePixelRatio(cRetinaFactor());
} else if (_doc->hasThumbnail()) {
_current = _doc->thumbnail()->pixNoCache(fileOrigin(), _doc->thumbnail()->width(), _doc->thumbnail()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
} else {
_current = Image::Blank()->pixNoCache({}, Image::Blank()->width(), Image::Blank()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
_current = Image::Empty()->pixNoCache({}, Image::Empty()->width(), Image::Empty()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
}
auto mode = (_doc->isVideoFile() || _doc->isVideoMessage())
? Media::Clip::Reader::Mode::Video
@ -2100,7 +2100,7 @@ void OverlayWidget::validatePhotoCurrentImage() {
validatePhotoImage(_photo->thumbnailInline(), true);
if (_current.isNull()) {
_photo->loadThumbnailSmall(fileOrigin());
validatePhotoImage(Image::Blank().get(), true);
validatePhotoImage(Image::Empty(), true);
}
}

View File

@ -40,7 +40,7 @@ int64 ComputeUsage(const QImage &image) {
return ComputeUsage(image.size());
}
Core::MediaActiveCache<const Image> &ActiveCache() {
[[nodiscard]] Core::MediaActiveCache<const Image> &ActiveCache() {
static auto Instance = Core::MediaActiveCache<const Image>(
kMemoryForCache,
[](const Image *image) { image->unload(); });
@ -85,7 +85,7 @@ void ClearAll() {
ImagePtr Create(const QString &file, QByteArray format) {
if (file.startsWith(qstr("http://"), Qt::CaseInsensitive)
|| file.startsWith(qstr("https://"), Qt::CaseInsensitive)) {
const auto key = file;
const auto &key = file;
auto i = WebUrlImages.constFind(key);
if (i == WebUrlImages.cend()) {
i = WebUrlImages.insert(
@ -208,7 +208,7 @@ QSize getImageSize(const QVector<MTPDocumentAttribute> &attributes) {
ImagePtr Create(const MTPDwebDocument &document) {
const auto size = getImageSize(document.vattributes.v);
if (size.isEmpty()) {
return Image::Blank();
return ImagePtr();
}
// We don't use size from WebDocument, because it is not reliable.
@ -227,7 +227,7 @@ ImagePtr Create(const MTPDwebDocument &document) {
ImagePtr Create(const MTPDwebDocumentNoProxy &document) {
const auto size = getImageSize(document.vattributes.v);
if (size.isEmpty()) {
return Image::Blank();
return ImagePtr();
}
return Create(qs(document.vurl), size.width(), size.height());
@ -236,7 +236,7 @@ ImagePtr Create(const MTPDwebDocumentNoProxy &document) {
ImagePtr Create(const MTPDwebDocument &document, QSize box) {
//const auto size = getImageSize(document.vattributes.v);
//if (size.isEmpty()) {
// return Image::Blank();
// return ImagePtr();
//}
// We don't use size from WebDocument, because it is not reliable.
@ -254,7 +254,7 @@ ImagePtr Create(const MTPDwebDocument &document, QSize box) {
ImagePtr Create(const MTPDwebDocumentNoProxy &document, QSize box) {
//const auto size = getImageSize(document.vattributes.v);
//if (size.isEmpty()) {
// return Image::Blank();
// return ImagePtr();
//}
return Create(qs(document.vurl), box);
@ -337,8 +337,8 @@ void Image::replaceSource(std::unique_ptr<Source> &&source) {
_source = std::move(source);
}
ImagePtr Image::Blank() {
static const auto blankImage = [] {
not_null<Image*> Image::Empty() {
static auto result = [] {
const auto factor = cIntRetinaFactor();
auto data = QImage(
factor,
@ -346,15 +346,27 @@ ImagePtr Image::Blank() {
QImage::Format_ARGB32_Premultiplied);
data.fill(Qt::transparent);
data.setDevicePixelRatio(cRetinaFactor());
return Create(
std::move(data),
"GIF");
return Image(std::make_unique<ImageSource>(std::move(data), "GIF"));
}();
return blankImage;
return &result;
}
not_null<Image*> Image::BlankMedia() {
static auto result = [] {
const auto factor = cIntRetinaFactor();
auto data = QImage(
factor,
factor,
QImage::Format_ARGB32_Premultiplied);
data.fill(Qt::black);
data.setDevicePixelRatio(cRetinaFactor());
return Image(std::make_unique<ImageSource>(std::move(data), "GIF"));
}();
return &result;
}
bool Image::isNull() const {
return (this == Blank().get());
return (this == Empty());
}
const QPixmap &Image::pix(
@ -655,7 +667,7 @@ QPixmap Image::pixNoCache(
if (h <= 0 && height() > 0) {
h = qRound(width() * w / float64(height()));
}
return Blank()->pixNoCache(origin, w, h, options, outerw, outerh);
return Empty()->pixNoCache(origin, w, h, options, outerw, outerh);
}
if (isNull() && outerw > 0 && outerh > 0) {
@ -713,7 +725,7 @@ QPixmap Image::pixColoredNoCache(
checkSource();
if (_data.isNull()) {
return Blank()->pix(origin);
return Empty()->pix(origin);
}
auto img = _data;
@ -737,7 +749,7 @@ QPixmap Image::pixBlurredColoredNoCache(
checkSource();
if (_data.isNull()) {
return Blank()->pix(origin);
return Empty()->pix(origin);
}
auto img = prepareBlur(_data);
@ -828,6 +840,8 @@ void Image::invalidateSizeCache() const {
}
Image::~Image() {
unload();
ActiveCache().remove(this);
if (this != Empty() && this != BlankMedia()) {
unload();
ActiveCache().remove(this);
}
}

View File

@ -100,7 +100,8 @@ public:
void replaceSource(std::unique_ptr<Images::Source> &&source);
static ImagePtr Blank();
static not_null<Image*> Empty(); // 1x1 transparent
static not_null<Image*> BlankMedia(); // 1x1 black
QImage original() const;

View File

@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "platform/platform_specific.h"
ImagePtr::ImagePtr() : _data(Image::Blank().get()) {
ImagePtr::ImagePtr() : _data(Image::Empty()) {
}
ImagePtr::ImagePtr(not_null<Image*> data) : _data(data) {