Fix a crash selecting a tile or pasting clipboard when we are moving the selection boundaries

This is because the MovingSelectionState freeze the document mask, and
we should unfreeze it before we execute any other command.
This commit is contained in:
David Capello 2019-09-11 18:19:29 -03:00
parent 76681dc416
commit 26fbacc772
3 changed files with 49 additions and 15 deletions

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2017-2018 David Capello
//
// This program is distributed under the terms of
@ -17,6 +18,7 @@
#include "app/ui/skin/skin_theme.h"
#include "app/ui/status_bar.h"
#include "app/ui_context.h"
#include "app/ui_context.h"
#include "doc/mask.h"
#include "ui/message.h"
@ -25,14 +27,22 @@ namespace app {
using namespace ui;
MovingSelectionState::MovingSelectionState(Editor* editor, MouseMessage* msg)
: m_cursorStart(editor->screenToEditor(msg->position()))
: m_editor(editor)
, m_cursorStart(editor->screenToEditor(msg->position()))
, m_selOrigin(editor->document()->mask()->bounds().origin())
{
editor->captureMouse();
// Hook BeforeCommandExecution signal so we know if the user wants
// to execute other command, so we can unfreeze the document mask.
m_ctxConn = UIContext::instance()->BeforeCommandExecution.connect(
&MovingSelectionState::onBeforeCommandExecution, this);
}
MovingSelectionState::~MovingSelectionState()
void MovingSelectionState::onBeforeCommandExecution(CommandExecutionEvent& ev)
{
m_editor->backToPreviousState();
m_editor->releaseMouse();
}
void MovingSelectionState::onEnterState(Editor* editor)
@ -47,6 +57,8 @@ EditorState::LeaveAction MovingSelectionState::onLeaveState(Editor* editor, Edit
Mask* mask = doc->mask();
gfx::Point newOrigin = mask->bounds().origin();
ASSERT(mask->isFrozen());
// Restore the mask to the original state so we can transform it
// with the a undoable transaction.
mask->setOrigin(m_selOrigin.x,
@ -86,15 +98,21 @@ bool MovingSelectionState::onMouseMove(Editor* editor, MouseMessage* msg)
const gfx::Point newMaskOrigin = m_selOrigin + m_delta;
const gfx::Point oldMaskOrigin = editor->document()->mask()->bounds().origin();
ASSERT(editor->document()->mask()->isFrozen());
if (oldMaskOrigin != newMaskOrigin) {
editor->document()->mask()->setOrigin(newMaskOrigin.x,
newMaskOrigin.y);
MaskBoundaries* boundaries =
const_cast<MaskBoundaries*>(editor->document()->getMaskBoundaries());
const gfx::Point boundariesDelta = newMaskOrigin - oldMaskOrigin;
boundaries->offset(boundariesDelta.x,
boundariesDelta.y);
if (MaskBoundaries* boundaries =
const_cast<MaskBoundaries*>(editor->document()->getMaskBoundaries())) {
const gfx::Point boundariesDelta = newMaskOrigin - oldMaskOrigin;
boundaries->offset(boundariesDelta.x,
boundariesDelta.y);
}
else {
ASSERT(false);
}
editor->invalidate();
}

View File

@ -1,4 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2017 David Capello
//
// This program is distributed under the terms of
@ -8,13 +9,14 @@
#define APP_UI_EDITOR_MOVING_SELECTION_STATE_H_INCLUDED
#pragma once
#include "app/context.h"
#include "app/ui/editor/standby_state.h"
#include "obs/connection.h"
namespace app {
class MovingSelectionState : public StandbyState {
public:
MovingSelectionState(Editor* editor, ui::MouseMessage* msg);
virtual ~MovingSelectionState();
// EditorState
virtual void onEnterState(Editor* editor) override;
@ -27,9 +29,14 @@ namespace app {
virtual bool requireBrushPreview() override { return false; }
private:
// ContextObserver
void onBeforeCommandExecution(CommandExecutionEvent& ev);
Editor* m_editor;
gfx::Point m_cursorStart;
gfx::Point m_selOrigin;
gfx::Point m_delta;
obs::scoped_connection m_ctxConn;
};
} // namespace app

View File

@ -1,5 +1,6 @@
// Aseprite Document Library
// Copyright (c) 2001-2018 David Capello
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -113,6 +114,8 @@ bool Mask::isRectangular() const
void Mask::copyFrom(const Mask* sourceMask)
{
ASSERT(m_freeze_count == 0);
clear();
setName(sourceMask->name().c_str());
@ -120,8 +123,10 @@ void Mask::copyFrom(const Mask* sourceMask)
// Add all the area of "mask"
add(sourceMask->bounds());
// And copy the "mask" bitmap
copy_image(m_bitmap.get(), sourceMask->m_bitmap.get());
// And copy the "mask" bitmap (m_bitmap can be nullptr if this is
// frozen, so add() doesn't created the bitmap)
if (m_bitmap)
copy_image(m_bitmap.get(), sourceMask->m_bitmap.get());
}
}
@ -193,11 +198,15 @@ void Mask::add(const gfx::Rect& bounds)
if (m_freeze_count == 0)
reserve(bounds);
// m_bitmap can be nullptr if we have m_freeze_count > 0
if (!m_bitmap)
return;
fill_rect(m_bitmap.get(),
bounds.x-m_bounds.x,
bounds.y-m_bounds.y,
bounds.x-m_bounds.x+bounds.w-1,
bounds.y-m_bounds.y+bounds.h-1, 1);
bounds.x-m_bounds.x,
bounds.y-m_bounds.y,
bounds.x-m_bounds.x+bounds.w-1,
bounds.y-m_bounds.y+bounds.h-1, 1);
}
void Mask::subtract(const gfx::Rect& bounds)