mirror of
https://github.com/aseprite/aseprite.git
synced 2025-02-21 12:40:34 +00:00
Fix issue #310 - crash on export sprite sheet
The timeline wasn't being added as a Document observer, so it wasn't getting notifications about layers modifications. In this way the timeline wasn't able to update its m_layers[] internal field and was accessing to removed layers/invalid memory.
This commit is contained in:
parent
03020d7bcf
commit
395be62b03
@ -632,7 +632,7 @@ void DocumentApi::removeLayer(Layer* layer)
|
|||||||
DocumentEvent ev(m_document);
|
DocumentEvent ev(m_document);
|
||||||
ev.sprite(layer->getSprite());
|
ev.sprite(layer->getSprite());
|
||||||
ev.layer(layer);
|
ev.layer(layer);
|
||||||
m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onRemoveLayer, ev);
|
m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onBeforeRemoveLayer, ev);
|
||||||
|
|
||||||
// Add undoers.
|
// Add undoers.
|
||||||
if (undoEnabled())
|
if (undoEnabled())
|
||||||
@ -640,6 +640,9 @@ void DocumentApi::removeLayer(Layer* layer)
|
|||||||
|
|
||||||
// Do the action.
|
// Do the action.
|
||||||
layer->getParent()->removeLayer(layer);
|
layer->getParent()->removeLayer(layer);
|
||||||
|
|
||||||
|
m_document->notifyObservers<DocumentEvent&>(&DocumentObserver::onAfterRemoveLayer, ev);
|
||||||
|
|
||||||
delete layer;
|
delete layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ namespace app {
|
|||||||
|
|
||||||
virtual void onRemoveSprite(DocumentEvent& ev) { }
|
virtual void onRemoveSprite(DocumentEvent& ev) { }
|
||||||
|
|
||||||
virtual void onRemoveLayer(DocumentEvent& ev) { }
|
virtual void onBeforeRemoveLayer(DocumentEvent& ev) { }
|
||||||
|
virtual void onAfterRemoveLayer(DocumentEvent& ev) { }
|
||||||
|
|
||||||
// Called when a frame is removed. It's called after the frame was
|
// Called when a frame is removed. It's called after the frame was
|
||||||
// removed, and the sprite's total number of frames is modified.
|
// removed, and the sprite's total number of frames is modified.
|
||||||
|
@ -218,7 +218,7 @@ void DocumentView::onAddLayer(DocumentEvent& ev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentView::onRemoveLayer(DocumentEvent& ev)
|
void DocumentView::onBeforeRemoveLayer(DocumentEvent& ev)
|
||||||
{
|
{
|
||||||
Sprite* sprite = ev.sprite();
|
Sprite* sprite = ev.sprite();
|
||||||
Layer* layer = ev.layer();
|
Layer* layer = ev.layer();
|
||||||
|
@ -64,7 +64,7 @@ namespace app {
|
|||||||
void onSpritePixelsModified(DocumentEvent& ev) OVERRIDE;
|
void onSpritePixelsModified(DocumentEvent& ev) OVERRIDE;
|
||||||
void onLayerMergedDown(DocumentEvent& ev) OVERRIDE;
|
void onLayerMergedDown(DocumentEvent& ev) OVERRIDE;
|
||||||
void onAddLayer(DocumentEvent& ev) OVERRIDE;
|
void onAddLayer(DocumentEvent& ev) OVERRIDE;
|
||||||
void onRemoveLayer(DocumentEvent& ev) OVERRIDE;
|
void onBeforeRemoveLayer(DocumentEvent& ev) OVERRIDE;
|
||||||
void onAddFrame(DocumentEvent& ev) OVERRIDE;
|
void onAddFrame(DocumentEvent& ev) OVERRIDE;
|
||||||
void onRemoveFrame(DocumentEvent& ev) OVERRIDE;
|
void onRemoveFrame(DocumentEvent& ev) OVERRIDE;
|
||||||
void onTotalFramesChanged(DocumentEvent& ev) OVERRIDE;
|
void onTotalFramesChanged(DocumentEvent& ev) OVERRIDE;
|
||||||
|
@ -180,6 +180,8 @@ void Timeline::updateUsingEditor(Editor* editor)
|
|||||||
DocumentView* view = m_editor->getDocumentView();
|
DocumentView* view = m_editor->getDocumentView();
|
||||||
view->getDocumentLocation(&location);
|
view->getDocumentLocation(&location);
|
||||||
|
|
||||||
|
location.document()->addObserver(this);
|
||||||
|
|
||||||
// If we are already in the same position as the "editor", we don't
|
// If we are already in the same position as the "editor", we don't
|
||||||
// need to update the at all timeline.
|
// need to update the at all timeline.
|
||||||
if (m_document == location.document() &&
|
if (m_document == location.document() &&
|
||||||
@ -859,11 +861,13 @@ void Timeline::onPreferredSize(PreferredSizeEvent& ev)
|
|||||||
void Timeline::onPaint(ui::PaintEvent& ev)
|
void Timeline::onPaint(ui::PaintEvent& ev)
|
||||||
{
|
{
|
||||||
Graphics* g = ev.getGraphics();
|
Graphics* g = ev.getGraphics();
|
||||||
|
bool noDoc = (m_document == NULL);
|
||||||
|
if (noDoc)
|
||||||
|
goto paintNoDoc;
|
||||||
|
|
||||||
if (!m_document) {
|
try {
|
||||||
drawPart(g, getClientBounds(), NULL, m_timelinePaddingStyle);
|
// Lock the sprite to read/render it.
|
||||||
return;
|
const DocumentReader documentReader(m_document);
|
||||||
}
|
|
||||||
|
|
||||||
int layer, first_layer, last_layer;
|
int layer, first_layer, last_layer;
|
||||||
FrameNumber frame, first_frame, last_frame;
|
FrameNumber frame, first_frame, last_frame;
|
||||||
@ -925,6 +929,14 @@ void Timeline::onPaint(ui::PaintEvent& ev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawPaddings(g);
|
drawPaddings(g);
|
||||||
|
}
|
||||||
|
catch (const LockedDocumentException&) {
|
||||||
|
noDoc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
paintNoDoc:;
|
||||||
|
if (noDoc)
|
||||||
|
drawPart(g, getClientBounds(), NULL, m_timelinePaddingStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::onCommandAfterExecution(Context* context)
|
void Timeline::onCommandAfterExecution(Context* context)
|
||||||
@ -954,7 +966,7 @@ void Timeline::onAddLayer(DocumentEvent& ev)
|
|||||||
invalidate();
|
invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timeline::onRemoveLayer(DocumentEvent& ev)
|
void Timeline::onAfterRemoveLayer(DocumentEvent& ev)
|
||||||
{
|
{
|
||||||
Sprite* sprite = ev.sprite();
|
Sprite* sprite = ev.sprite();
|
||||||
Layer* layer = ev.layer();
|
Layer* layer = ev.layer();
|
||||||
|
@ -114,7 +114,7 @@ namespace app {
|
|||||||
|
|
||||||
// DocumentObserver impl.
|
// DocumentObserver impl.
|
||||||
void onAddLayer(DocumentEvent& ev) OVERRIDE;
|
void onAddLayer(DocumentEvent& ev) OVERRIDE;
|
||||||
void onRemoveLayer(DocumentEvent& ev) OVERRIDE;
|
void onAfterRemoveLayer(DocumentEvent& ev) OVERRIDE;
|
||||||
void onAddFrame(DocumentEvent& ev) OVERRIDE;
|
void onAddFrame(DocumentEvent& ev) OVERRIDE;
|
||||||
void onRemoveFrame(DocumentEvent& ev) OVERRIDE;
|
void onRemoveFrame(DocumentEvent& ev) OVERRIDE;
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ public:
|
|||||||
// collection and will be destroyed calling the T::dispose() member
|
// collection and will be destroyed calling the T::dispose() member
|
||||||
// function.
|
// function.
|
||||||
void addObserver(observer_type* observer) {
|
void addObserver(observer_type* observer) {
|
||||||
|
ASSERT(std::find(m_observers.begin(), m_observers.end(), observer) == m_observers.end() && "You've tried to add an observer that already is in the collection");
|
||||||
m_observers.push_back(observer);
|
m_observers.push_back(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,6 +49,9 @@ public:
|
|||||||
iterator it = std::find(m_observers.begin(), m_observers.end(), observer);
|
iterator it = std::find(m_observers.begin(), m_observers.end(), observer);
|
||||||
if (it != end())
|
if (it != end())
|
||||||
m_observers.erase(it);
|
m_observers.erase(it);
|
||||||
|
else {
|
||||||
|
ASSERT(false && "You've tried to remove an observer that isn't in the collection");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void notifyObservers(void (observer_type::*method)()) {
|
void notifyObservers(void (observer_type::*method)()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user