Media::Clip::Reader owners use Media::Clip::ReaderPointer smartptr.

This commit is contained in:
John Preston 2016-09-28 23:28:53 +03:00
parent 344890c533
commit 78815800d0
8 changed files with 132 additions and 107 deletions

View File

@ -1522,10 +1522,7 @@ ImagePtr HistoryDocument::replyPreview() {
HistoryGif::HistoryGif(HistoryItem *parent, DocumentData *document, const QString &caption) : HistoryFileMedia(parent)
, _data(document)
, _thumbw(1)
, _thumbh(1)
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right())
, _gif(nullptr) {
, _caption(st::minPhotoSize - st::msgPadding.left() - st::msgPadding.right()) {
setDocumentLinks(_data, true);
setStatusSize(FileStatusSizeReady);
@ -1541,8 +1538,7 @@ HistoryGif::HistoryGif(HistoryItem *parent, const HistoryGif &other) : HistoryFi
, _data(other._data)
, _thumbw(other._thumbw)
, _thumbh(other._thumbh)
, _caption(other._caption)
, _gif(nullptr) {
, _caption(other._caption) {
setDocumentLinks(_data, true);
setStatusSize(other._statusSize);
@ -1555,16 +1551,15 @@ void HistoryGif::initDimensions() {
bool bubble = _parent->hasBubble();
int32 tw = 0, th = 0;
if (gif() && _gif->state() == Media::Clip::State::Error) {
if (_gif && _gif->state() == Media::Clip::State::Error) {
if (!_gif->autoplay()) {
Ui::showLayer(new InformBox(lang(lng_gif_error)));
}
App::unregGifItem(_gif);
delete _gif;
_gif = Media::Clip::BadReader;
App::unregGifItem(_gif.get());
_gif.setBad();
}
if (gif() && _gif->ready()) {
if (_gif && _gif->ready()) {
tw = convertScale(_gif->width());
th = convertScale(_gif->height());
} else {
@ -1590,7 +1585,7 @@ void HistoryGif::initDimensions() {
_maxw = qMax(tw, int32(st::minPhotoSize));
_minh = qMax(th, int32(st::minPhotoSize));
_maxw = qMax(_maxw, _parent->infoWidth() + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x()));
if (!gif() || !_gif->ready()) {
if (!_gif || !_gif->ready()) {
_maxw = qMax(_maxw, gifMaxStatusWidth(_data) + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x()));
}
if (bubble) {
@ -1610,7 +1605,7 @@ int HistoryGif::resizeGetHeight(int width) {
bool bubble = _parent->hasBubble();
int tw = 0, th = 0;
if (gif() && _gif->ready()) {
if (_gif && _gif->ready()) {
tw = convertScale(_gif->width());
th = convertScale(_gif->height());
} else {
@ -1645,7 +1640,7 @@ int HistoryGif::resizeGetHeight(int width) {
_width = qMax(tw, int32(st::minPhotoSize));
_height = qMax(th, int32(st::minPhotoSize));
_width = qMax(_width, _parent->infoWidth() + 2 * int32(st::msgDateImgDelta + st::msgDateImgPadding.x()));
if (gif() && _gif->ready()) {
if (_gif && _gif->ready()) {
if (!_gif->started()) {
auto inWebPage = (_parent->getMedia() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
@ -1676,7 +1671,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6
bool loaded = _data->loaded(), displayLoading = (_parent->id < 0) || _data->displayLoading();
bool selected = (selection == FullSelection);
if (loaded && !gif() && _gif != Media::Clip::BadReader && cAutoPlayGif()) {
if (loaded && !_gif && !_gif.isBad() && cAutoPlayGif()) {
Ui::autoplayMediaInlineAsync(_parent->fullId());
}
@ -1686,7 +1681,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6
int32 captionw = width - st::msgPadding.left() - st::msgPadding.right();
bool animating = (gif() && _gif->started());
bool animating = (_gif && _gif->started());
if (!animating || _parent->id < 0) {
if (displayLoading) {
@ -1730,7 +1725,7 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, uint6
App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, overlayCorners);
}
if (radial || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif())) || (_gif == Media::Clip::BadReader)) {
if (radial || _gif.isBad() || (!_gif && ((!loaded && !_data->loading()) || !cAutoPlayGif()))) {
float64 radialOpacity = (radial && loaded && _parent->id > 0) ? _animation->radial.opacity() : 1;
QRect inner(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
p.setPen(Qt::NoPen);
@ -1818,7 +1813,7 @@ HistoryTextState HistoryGif::getState(int x, int y, HistoryStateRequest request)
if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) {
if (_data->uploading()) {
result.link = _cancell;
} else if (!gif() || !cAutoPlayGif()) {
} else if (!_gif || !cAutoPlayGif()) {
result.link = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel);
}
if (_parent->getMedia() == this) {
@ -1891,36 +1886,34 @@ ImagePtr HistoryGif::replyPreview() {
}
bool HistoryGif::playInline(bool autoplay) {
if (gif()) {
if (_gif) {
stopInline();
} else if (_data->loaded(DocumentData::FilePathResolveChecked)) {
if (!cAutoPlayGif()) {
App::stopGifItems();
}
_gif = new Media::Clip::Reader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) {
_gif = Media::Clip::MakeReader(_data->location(), _data->data(), [this](Media::Clip::Notification notification) {
_parent->clipCallback(notification);
});
App::regGifItem(_gif, _parent);
if (gif()) _gif->setAutoplay();
App::regGifItem(_gif.get(), _parent);
if (_gif) _gif->setAutoplay();
}
return true;
}
void HistoryGif::stopInline() {
if (gif()) {
App::unregGifItem(_gif);
delete _gif;
_gif = 0;
if (_gif) {
App::unregGifItem(_gif.get());
}
_gif.reset();
_parent->setPendingInitDimensions();
Notify::historyItemLayoutChanged(_parent);
}
HistoryGif::~HistoryGif() {
if (gif()) {
App::unregGifItem(_gif);
deleteAndMark(_gif);
if (_gif) {
App::unregGifItem(_gif.get());
}
}
@ -3071,7 +3064,7 @@ void HistoryGame::draw(Painter &p, const QRect &r, TextSelection selection, uint
p.fillRect(bar, barfg);
if (_titleLines) {
p.setPen(st::black);
p.setPen(semibold);
int32 endskip = 0;
if (_title.hasSkipBlock()) {
endskip = _parent->skipBlockWidth();

View File

@ -446,7 +446,7 @@ public:
return _data;
}
Media::Clip::Reader *getClipReader() override {
return gif();
return _gif.get();
}
bool playInline(bool autoplay) override;
@ -491,16 +491,11 @@ protected:
private:
DocumentData *_data;
int32 _thumbw, _thumbh;
int32 _thumbw = 1;
int32 _thumbh = 1;
Text _caption;
Media::Clip::Reader *_gif;
Media::Clip::Reader *gif() {
return (_gif == Media::Clip::BadReader) ? nullptr : _gif;
}
const Media::Clip::Reader *gif() const {
return (_gif == Media::Clip::BadReader) ? nullptr : _gif;
}
Media::Clip::ReaderPointer _gif;
void setStatusSize(int32 newSize) const;
void updateStatusText() const;

View File

@ -112,8 +112,7 @@ void Gif::initDimensions() {
void Gif::setPosition(int32 position) {
ItemBase::setPosition(position);
if (_position < 0) {
if (gif()) delete _gif;
_gif = 0;
_gif.reset();
}
}
@ -133,15 +132,15 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
document->automaticLoad(nullptr);
bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
if (loaded && !gif() && _gif != Media::Clip::BadReader) {
if (loaded && !_gif && !_gif.isBad()) {
auto that = const_cast<Gif*>(this);
that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) {
that->_gif = Media::Clip::MakeReader(document->location(), document->data(), [that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
if (gif()) _gif->setAutoplay();
if (_gif) _gif->setAutoplay();
}
bool animating = (gif() && _gif->started());
bool animating = (_gif && _gif->started());
if (displayLoading) {
ensureAnimation();
if (!_animation->radial.animating()) {
@ -166,7 +165,7 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
}
}
if (radial || (!_gif && !loaded && !loading) || (_gif == Media::Clip::BadReader)) {
if (radial || _gif.isBad() || (!_gif && !loaded && !loading)) {
auto radialOpacity = (radial && loaded) ? _animation->radial.opacity() : 1.;
if (_animation && _animation->_a_over.animating(context->ms)) {
auto over = _animation->_a_over.current();
@ -248,7 +247,7 @@ void Gif::clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) {
}
QSize Gif::countFrameSize() const {
bool animating = (gif() && _gif->ready());
bool animating = (_gif && _gif->ready());
int32 framew = animating ? _gif->width() : content_width(), frameh = animating ? _gif->height() : content_height(), height = st::inlineMediaHeight;
if (framew * height > frameh * _width) {
if (framew < st::maxStickerSize || frameh > height) {
@ -274,10 +273,6 @@ QSize Gif::countFrameSize() const {
return QSize(framew, frameh);
}
Gif::~Gif() {
if (gif()) deleteAndMark(_gif);
}
void Gif::prepareThumb(int32 width, int32 height, const QSize &frame) const {
if (DocumentData *document = getShownDocument()) {
if (!document->thumb->isNull()) {
@ -332,18 +327,16 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
using namespace Media::Clip;
switch (notification) {
case NotificationReinit: {
if (gif()) {
if (_gif) {
if (_gif->state() == State::Error) {
delete _gif;
_gif = BadReader;
_gif.setBad();
getShownDocument()->forget();
} else if (_gif->ready() && !_gif->started()) {
int32 height = st::inlineMediaHeight;
QSize frame = countFrameSize();
_gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None);
} else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) {
delete _gif;
_gif = nullptr;
_gif.reset();
getShownDocument()->forget();
}
}
@ -352,7 +345,7 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
} break;
case NotificationRepaint: {
if (gif() && !_gif->currentDisplayed()) {
if (_gif && !_gif->currentDisplayed()) {
update();
}
} break;
@ -1193,8 +1186,7 @@ void Game::initDimensions() {
void Game::setPosition(int32 position) {
ItemBase::setPosition(position);
if (_position < 0) {
if (gif()) delete _gif;
_gif = 0;
_gif.reset();
}
}
@ -1212,15 +1204,15 @@ void Game::paint(Painter &p, const QRect &clip, const PaintContext *context) con
document->automaticLoad(nullptr);
bool loaded = document->loaded(), loading = document->loading(), displayLoading = document->displayLoading();
if (loaded && !gif() && _gif != Media::Clip::BadReader) {
if (loaded && !_gif && !_gif.isBad()) {
auto that = const_cast<Game*>(this);
that->_gif = new Media::Clip::Reader(document->location(), document->data(), [that](Media::Clip::Notification notification) {
that->_gif = Media::Clip::MakeReader(document->location(), document->data(), [that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
if (gif()) _gif->setAutoplay();
if (_gif) _gif->setAutoplay();
}
bool animating = (gif() && _gif->started());
bool animating = (_gif && _gif->started());
if (displayLoading) {
if (!_radial) {
_radial = std_::make_unique<Ui::RadialAnimation>(animation(const_cast<Game*>(this), &Game::step_radial));
@ -1342,16 +1334,14 @@ void Game::clipCallback(Media::Clip::Notification notification) {
using namespace Media::Clip;
switch (notification) {
case NotificationReinit: {
if (gif()) {
if (_gif) {
if (_gif->state() == State::Error) {
delete _gif;
_gif = BadReader;
_gif.setBad();
getResultDocument()->forget();
} else if (_gif->ready() && !_gif->started()) {
_gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None);
} else if (_gif->autoPausedGif() && !Ui::isInlineItemVisible(this)) {
delete _gif;
_gif = nullptr;
_gif.reset();
getResultDocument()->forget();
}
}
@ -1360,17 +1350,13 @@ void Game::clipCallback(Media::Clip::Notification notification) {
} break;
case NotificationRepaint: {
if (gif() && !_gif->currentDisplayed()) {
if (_gif && !_gif->currentDisplayed()) {
update();
}
} break;
}
}
Game::~Game() {
if (gif()) deleteAndMark(_gif);
}
} // namespace internal
} // namespace Layout
} // namespace InlineBots

View File

@ -77,10 +77,7 @@ public:
// ClickHandlerHost interface
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
~Gif();
private:
QSize countFrameSize() const;
enum class StateFlag {
@ -93,11 +90,8 @@ private:
return ~StateFlags(flag);
}
Media::Clip::Reader *_gif = nullptr;
Media::Clip::ReaderPointer _gif;
ClickHandlerPtr _delete;
bool gif() const {
return (!_gif || _gif == Media::Clip::BadReader) ? false : true;
}
mutable QPixmap _thumb;
void prepareThumb(int32 width, int32 height, const QSize &frame) const;
@ -349,14 +343,9 @@ public:
void paint(Painter &p, const QRect &clip, const PaintContext *context) const override;
void getState(ClickHandlerPtr &link, HistoryCursorState &cursor, int x, int y) const override;
~Game();
private:
void countFrameSize();
bool gif() const {
return (!_gif || _gif == Media::Clip::BadReader) ? false : true;
}
void prepareThumb(int32 width, int32 height) const;
bool isRadialAnimation(uint64 ms) const;
@ -364,7 +353,7 @@ private:
void clipCallback(Media::Clip::Notification notification);
Media::Clip::Reader *_gif = nullptr;
Media::Clip::ReaderPointer _gif;
mutable QPixmap _thumb;
mutable std_::unique_ptr<Ui::RadialAnimation> _radial;
Text _title, _description;

View File

@ -567,12 +567,7 @@ void MediaPreviewWidget::fillEmojiString() {
}
void MediaPreviewWidget::resetGifAndCache() {
if (_gif) {
if (gif()) {
delete _gif;
}
_gif = nullptr;
}
_gif.reset();
_cacheStatus = CacheNotLoaded;
_cachedSize = QSize();
}
@ -592,7 +587,7 @@ QSize MediaPreviewWidget::currentDimensions() const {
box = QSize(width() - 2 * st::boxVerticalMargin, height() - 2 * st::boxVerticalMargin);
} else {
result = _document->dimensions;
if (gif() && _gif->ready()) {
if (_gif && _gif->ready()) {
result = QSize(_gif->width(), _gif->height());
}
if (_document->sticker()) {
@ -636,15 +631,15 @@ QPixmap MediaPreviewWidget::currentImage() const {
} else {
_document->automaticLoad(nullptr);
if (_document->loaded()) {
if (!_gif && _gif != Media::Clip::BadReader) {
if (!_gif && !_gif.isBad()) {
auto that = const_cast<MediaPreviewWidget*>(this);
that->_gif = new Media::Clip::Reader(_document->location(), _document->data(), [this, that](Media::Clip::Notification notification) {
that->_gif = Media::Clip::MakeReader(_document->location(), _document->data(), [this, that](Media::Clip::Notification notification) {
that->clipCallback(notification);
});
if (gif()) _gif->setAutoplay();
if (_gif) _gif->setAutoplay();
}
}
if (gif() && _gif->started()) {
if (_gif && _gif->started()) {
QSize s = currentDimensions();
return _gif->current(s.width(), s.height(), s.width(), s.height(), getms());
}
@ -681,12 +676,11 @@ void MediaPreviewWidget::clipCallback(Media::Clip::Notification notification) {
using namespace Media::Clip;
switch (notification) {
case NotificationReinit: {
if (gif() && _gif->state() == State::Error) {
delete _gif;
_gif = BadReader;
if (_gif && _gif->state() == State::Error) {
_gif.setBad();
}
if (gif() && _gif->ready() && !_gif->started()) {
if (_gif && _gif->ready() && !_gif->started()) {
QSize s = currentDimensions();
_gif->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None);
}
@ -695,7 +689,7 @@ void MediaPreviewWidget::clipCallback(Media::Clip::Notification notification) {
} break;
case NotificationRepaint: {
if (gif() && !_gif->currentDisplayed()) {
if (_gif && !_gif->currentDisplayed()) {
update();
}
} break;

View File

@ -157,10 +157,7 @@ private:
Animation _a_shown;
DocumentData *_document = nullptr;
PhotoData *_photo = nullptr;
Media::Clip::Reader *_gif = nullptr;
bool gif() const {
return (!_gif || _gif == Media::Clip::BadReader) ? false : true;
}
Media::Clip::ReaderPointer _gif;
int _emojiSize;
QList<EmojiPtr> _emojiList;

View File

@ -23,6 +23,26 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
#include "media/media_clip_reader.h"
namespace Media {
namespace Clip {
Reader *const ReaderPointer::BadPointer = SharedMemoryLocation<Reader, 0>();
ReaderPointer::~ReaderPointer() {
if (valid()) {
delete _pointer;
}
_pointer = nullptr;
}
class Tmp;
void f(Tmp *t) {
delete t;
}
} // namespace Clip
} // namespace Media
namespace {
AnimationManager *_manager = nullptr;

View File

@ -29,7 +29,58 @@ namespace Media {
namespace Clip {
class Reader;
static Reader * const BadReader = SharedMemoryLocation<Reader, 0>();
class ReaderPointer {
public:
ReaderPointer(std::nullptr_t = nullptr) {
}
explicit ReaderPointer(Reader *pointer) : _pointer(pointer) {
}
ReaderPointer(const ReaderPointer &other) = delete;
ReaderPointer &operator=(const ReaderPointer &other) = delete;
ReaderPointer(ReaderPointer &&other) : _pointer(createAndSwap(other._pointer)) {
}
ReaderPointer &operator=(ReaderPointer &&other) {
swap(other);
return *this;
}
void swap(ReaderPointer &other) {
qSwap(_pointer, other._pointer);
}
Reader *get() const {
return valid() ? _pointer : nullptr;
}
Reader *operator->() const {
return get();
}
void setBad() {
reset();
_pointer = BadPointer;
}
void reset() {
ReaderPointer temp;
swap(temp);
}
bool isBad() const {
return (_pointer == BadPointer);
}
bool valid() const {
return _pointer && !isBad();
}
explicit operator bool() const {
return valid();
}
~ReaderPointer();
private:
Reader *_pointer = nullptr;
static Reader *const BadPointer;
};
template <typename ...Args>
inline ReaderPointer MakeReader(Args&&... args) {
return ReaderPointer(new Reader(std_::forward<Args>(args)...));
}
class Manager;