* fixed memory leaks and display bugs

* VectorPath objects were released one two many times
  by the Shape PathContainers (they don't acquire when
  a path is added, the Shape does that for them) the
  PathContainer of the Icon needs to release though, as
  it "owns" the paths
* put the Selection class used by PathManipulator into
  the PathManipulator namespace, since the compiler seemed
  to use the wrong destructor (the one from the generic
  Selection class)
* uses a better mechanism to track and render
  changed parts of icon


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17903 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2006-06-22 00:22:23 +00:00
parent 63a9a8f72a
commit ce181bb0cd
15 changed files with 231 additions and 30 deletions
+34 -3
View File
@@ -21,7 +21,9 @@ CanvasView::CanvasView(BRect frame)
: StateView(frame, "canvas view", B_FOLLOW_ALL, : StateView(frame, "canvas view", B_FOLLOW_ALL,
B_WILL_DRAW | B_FRAME_EVENTS), B_WILL_DRAW | B_FRAME_EVENTS),
fBitmap(new BBitmap(BRect(0, 0, 63, 63), 0, B_RGB32)), fBitmap(new BBitmap(BRect(0, 0, 63, 63), 0, B_RGB32)),
fIcon(NULL),
fRenderer(new IconRenderer(fBitmap)), fRenderer(new IconRenderer(fBitmap)),
fDirtyIconArea(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN),
fCanvasOrigin(50.0, 50.0), fCanvasOrigin(50.0, 50.0),
fZoomLevel(8.0), fZoomLevel(8.0),
@@ -37,6 +39,7 @@ CanvasView::CanvasView(BRect frame)
// destructor // destructor
CanvasView::~CanvasView() CanvasView::~CanvasView()
{ {
SetIcon(NULL);
delete fRenderer; delete fRenderer;
delete fBitmap; delete fBitmap;
@@ -101,13 +104,40 @@ CanvasView::Draw(BRect updateRect)
} }
} }
// #pragma mark -
// AreaInvalidated
void
CanvasView::AreaInvalidated(const BRect& area)
{
if (fDirtyIconArea.Contains(area))
return;
fDirtyIconArea = fDirtyIconArea | area;
BRect viewArea(area);
ConvertFromCanvas(&viewArea);
Invalidate(viewArea);
}
// #pragma mark - // #pragma mark -
// SetIcon // SetIcon
void void
CanvasView::SetIcon(Icon* icon) CanvasView::SetIcon(Icon* icon)
{ {
if (fIcon == icon)
return;
if (fIcon)
fIcon->RemoveListener(this);
fIcon = icon;
fRenderer->SetIcon(icon); fRenderer->SetIcon(icon);
if (fIcon)
fIcon->AddListener(this);
} }
// ConvertFromCanvas // ConvertFromCanvas
@@ -234,9 +264,10 @@ CanvasView::_FreeBackBitmap()
void void
CanvasView::_DrawInto(BView* view, BRect updateRect) CanvasView::_DrawInto(BView* view, BRect updateRect)
{ {
// TODO: don't render here, use some if (fDirtyIconArea.IsValid()) {
// listener technique on the shapes instead... fRenderer->Render(fDirtyIconArea);
fRenderer->Render(); fDirtyIconArea.Set(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN);
}
// icon // icon
BRect canvas(_CanvasRect()); BRect canvas(_CanvasRect());
+8 -2
View File
@@ -9,13 +9,14 @@
#ifndef CANVAS_VIEW_H #ifndef CANVAS_VIEW_H
#define CANVAS_VIEW_H #define CANVAS_VIEW_H
#include "Icon.h"
#include "StateView.h" #include "StateView.h"
class BBitmap; class BBitmap;
class Icon;
class IconRenderer; class IconRenderer;
class CanvasView : public StateView { class CanvasView : public StateView,
public IconListener {
public: public:
CanvasView(BRect frame); CanvasView(BRect frame);
virtual ~CanvasView(); virtual ~CanvasView();
@@ -25,6 +26,9 @@ class CanvasView : public StateView {
virtual void FrameResized(float width, float height); virtual void FrameResized(float width, float height);
virtual void Draw(BRect updateRect); virtual void Draw(BRect updateRect);
// IconListener interface
virtual void AreaInvalidated(const BRect& area);
// CanvasView // CanvasView
void SetIcon(Icon* icon); void SetIcon(Icon* icon);
@@ -52,7 +56,9 @@ class CanvasView : public StateView {
private: private:
BBitmap* fBitmap; BBitmap* fBitmap;
Icon* fIcon;
IconRenderer* fRenderer; IconRenderer* fRenderer;
BRect fDirtyIconArea;
BPoint fCanvasOrigin; BPoint fCanvasOrigin;
float fZoomLevel; float fZoomLevel;
+4
View File
@@ -28,6 +28,10 @@ IconEditorApp::IconEditorApp()
// destructor // destructor
IconEditorApp::~IconEditorApp() IconEditorApp::~IconEditorApp()
{ {
// NOTE: it is important that the GUI has been deleted
// at this point, so that all the listener/observer
// stuff is properly detached
delete fDocument;
} }
// #pragma mark - // #pragma mark -
+2
View File
@@ -44,6 +44,7 @@ MainWindow::MainWindow(IconEditorApp* app, Document* document)
// destructor // destructor
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete fState;
} }
// #pragma mark - // #pragma mark -
@@ -139,6 +140,7 @@ MainWindow::_Init()
PathManipulator* pathManipulator = new PathManipulator(path); PathManipulator* pathManipulator = new PathManipulator(path);
state->AddManipulator(pathManipulator); state->AddManipulator(pathManipulator);
fState = state;
// ---- // ----
} }
+3
View File
@@ -14,6 +14,7 @@
class CanvasView; class CanvasView;
class Document; class Document;
class IconEditorApp; class IconEditorApp;
class ViewState;
class MainWindow : public BWindow { class MainWindow : public BWindow {
public: public:
@@ -33,6 +34,8 @@ class MainWindow : public BWindow {
Document* fDocument; Document* fDocument;
CanvasView* fCanvasView; CanvasView* fCanvasView;
// TODO: for testing only...
ViewState* fState;
}; };
#endif // MAIN_WINDOW_H #endif // MAIN_WINDOW_H
@@ -33,6 +33,7 @@ Document::Document(const char* name)
// destructor // destructor
Document::~Document() Document::~Document()
{ {
delete fIcon;
delete fCommandStack; delete fCommandStack;
delete fSelection; delete fSelection;
delete fRef; delete fRef;
+85 -5
View File
@@ -11,21 +11,101 @@
#include <new> #include <new>
#include "PathContainer.h" #include "PathContainer.h"
#include "ShapeContainer.h" #include "Shape.h"
using std::nothrow; using std::nothrow;
// constructor // constructor
Icon::Icon() IconListener::IconListener()
: fPaths(new (nothrow) PathContainer()),
fShapes(new (nothrow) ShapeContainer())
{ {
} }
// destructor
IconListener::~IconListener()
{
}
// #pragma mark -
// constructor
Icon::Icon()
: fPaths(new (nothrow) PathContainer(true)),
fShapes(new (nothrow) ShapeContainer()),
fListeners(2)
{
if (fShapes)
fShapes->AddListener(this);
}
// destructor // destructor
Icon::~Icon() Icon::~Icon()
{ {
delete fShapes; if (fShapes) {
fShapes->MakeEmpty();
fShapes->RemoveListener(this);
delete fShapes;
}
delete fPaths; delete fPaths;
} }
// ShapeAdded
void
Icon::ShapeAdded(Shape* shape)
{
shape->AddObserver(this);
_NotifyAreaInvalidated(shape->Bounds());
}
// ShapeRemoved
void
Icon::ShapeRemoved(Shape* shape)
{
shape->RemoveObserver(this);
_NotifyAreaInvalidated(shape->Bounds());
}
// ObjectChanged
void
Icon::ObjectChanged(const Observable* object)
{
const Shape* shape = dynamic_cast<const Shape*>(object);
if (shape) {
BRect area = shape->LastBounds();
area = area | shape->Bounds(true);
area.InsetBy(-1, -1);
_NotifyAreaInvalidated(area);
}
}
// AddListener
bool
Icon::AddListener(IconListener* listener)
{
if (listener && !fListeners.HasItem((void*)listener))
return fListeners.AddItem((void*)listener);
return false;
}
// RemoveListener
bool
Icon::RemoveListener(IconListener* listener)
{
return fListeners.RemoveItem((void*)listener);
}
// #pragma mark -
// _NotifyShapeRemoved
void
Icon::_NotifyAreaInvalidated(const BRect& area) const
{
BList listeners(fListeners);
int32 count = listeners.CountItems();
for (int32 i = 0; i < count; i++) {
IconListener* listener
= (IconListener*)listeners.ItemAtFast(i);
listener->AreaInvalidated(area);
}
}
+32 -3
View File
@@ -9,22 +9,51 @@
#ifndef ICON_H #ifndef ICON_H
#define ICON_H #define ICON_H
class PathContainer; #include <List.h>
class ShapeContainer;
class Icon { #include "Observer.h"
#include "ShapeContainer.h"
class PathContainer;
class IconListener {
public:
IconListener();
virtual ~IconListener();
virtual void AreaInvalidated(const BRect& area) = 0;
};
class Icon : public ShapeContainerListener,
public Observer {
public: public:
Icon(); Icon();
virtual ~Icon(); virtual ~Icon();
// ShapeContainerListener interface
virtual void ShapeAdded(Shape* shape);
virtual void ShapeRemoved(Shape* shape);
// Observer interface
virtual void ObjectChanged(const Observable* object);
// Icon
PathContainer* Paths() const PathContainer* Paths() const
{ return fPaths; } { return fPaths; }
ShapeContainer* Shapes() const ShapeContainer* Shapes() const
{ return fShapes; } { return fShapes; }
bool AddListener(IconListener* listener);
bool RemoveListener(IconListener* listener);
private: private:
void _NotifyAreaInvalidated(
const BRect& area) const;
PathContainer* fPaths; PathContainer* fPaths;
ShapeContainer* fShapes; ShapeContainer* fShapes;
BList fListeners;
}; };
#endif // ICON_H #endif // ICON_H
@@ -28,9 +28,10 @@ PathContainerListener::~PathContainerListener()
// constructor // constructor
PathContainer::PathContainer() PathContainer::PathContainer(bool ownsPaths)
: fPaths(16), : fPaths(16),
fListeners(2) fListeners(2),
fOwnsPaths(ownsPaths)
{ {
} }
@@ -156,7 +157,8 @@ PathContainer::_MakeEmpty()
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
VectorPath* path = PathAtFast(i); VectorPath* path = PathAtFast(i);
_NotifyPathRemoved(path); _NotifyPathRemoved(path);
path->Release(); if (fOwnsPaths)
path->Release();
} }
fPaths.MakeEmpty(); fPaths.MakeEmpty();
} }
+2 -1
View File
@@ -24,7 +24,7 @@ class PathContainerListener {
class PathContainer { class PathContainer {
public: public:
PathContainer(); PathContainer(bool ownsPaths);
virtual ~PathContainer(); virtual ~PathContainer();
bool AddPath(VectorPath* path); bool AddPath(VectorPath* path);
@@ -50,6 +50,7 @@ class PathContainer {
BList fPaths; BList fPaths;
BList fListeners; BList fListeners;
bool fOwnsPaths;
}; };
#endif // PATH_CONTAINER_H #endif // PATH_CONTAINER_H
@@ -109,7 +109,7 @@ string_for_mode(uint32 mode)
return "<unknown mode>"; return "<unknown mode>";
} }
class Selection : protected BList class PathManipulator::Selection : protected BList
{ {
public: public:
inline Selection(int32 count = 20) inline Selection(int32 count = 20)
@@ -16,7 +16,6 @@ class CanvasView;
class ChangePointCommand; class ChangePointCommand;
class UndoStack; class UndoStack;
class InsertPointCommand; class InsertPointCommand;
class Selection;
class VectorPath; class VectorPath;
//class PathSelection { //class PathSelection {
@@ -146,6 +145,7 @@ class PathManipulator : public Manipulator {
InsertPointCommand* fInsertPointCommand; InsertPointCommand* fInsertPointCommand;
AddPointCommand* fAddPointCommand; AddPointCommand* fAddPointCommand;
class Selection;
Selection* fSelection; Selection* fSelection;
Selection* fOldSelection; Selection* fOldSelection;
+41 -8
View File
@@ -2,6 +2,9 @@
#include <new> #include <new>
#include <limits.h> #include <limits.h>
#include <stdio.h>
#include "agg_bounding_rect.h"
#include "Style.h" #include "Style.h"
#include "VectorPath.h" #include "VectorPath.h"
@@ -13,10 +16,14 @@ Shape::Shape(::Style* style)
: Observable(), : Observable(),
Referenceable(), Referenceable(),
PathContainerListener(), PathContainerListener(),
fPaths(new (nothrow) PathContainer()),
fPaths(new (nothrow) PathContainer(false)),
fStyle(style), fStyle(style),
fPathSource(fPaths), fPathSource(fPaths),
fTransformers(4) fTransformers(4),
fLastBounds(0, 0, -1, -1)
{ {
if (fPaths) if (fPaths)
fPaths->AddListener(this); fPaths->AddListener(this);
@@ -45,17 +52,31 @@ void
Shape::PathAdded(VectorPath* path) Shape::PathAdded(VectorPath* path)
{ {
path->Acquire(); path->Acquire();
path->AddObserver(this);
Notify();
} }
// PathRemoved // PathRemoved
void void
Shape::PathRemoved(VectorPath* path) Shape::PathRemoved(VectorPath* path)
{ {
path->RemoveObserver(this);
Notify();
path->Release(); path->Release();
} }
// #pragma mark - // #pragma mark -
// ObjectChanged
void
Shape::ObjectChanged(const Observable* object)
{
// simply pass on the event for now
Notify();
}
// #pragma mark -
// InitCheck // InitCheck
status_t status_t
Shape::InitCheck() const Shape::InitCheck() const
@@ -83,14 +104,26 @@ Shape::SetStyle(::Style* style)
// Bounds // Bounds
BRect BRect
Shape::Bounds() const Shape::Bounds(bool updateLast) const
{ {
// TODO: incorrect - use VertexSource instead!! // TODO: what about sub-paths?!?
BRect bounds(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN); // the problem is that the path ids are
// nowhere stored while converting VectorPath
// to agg::path_storage, but it is also unclear
// if those would mean anything later on in
// the Transformer pipeline
uint32 pathID[1];
pathID[0] = 0;
double left, top, right, bottom;
int32 count = fPaths->CountPaths(); ::VertexSource& source = const_cast<Shape*>(this)->VertexSource();
for (int32 i = 0; i < count; i++) agg::bounding_rect(source, pathID, 0, 1,
bounds = bounds | fPaths->PathAtFast(i)->Bounds(); &left, &top, &right, &bottom);
BRect bounds(left, top, right, bottom);
if (updateLast)
fLastBounds = bounds;
return bounds; return bounds;
} }
+10 -1
View File
@@ -5,6 +5,7 @@
#include <Rect.h> #include <Rect.h>
#include "Observable.h" #include "Observable.h"
#include "Observer.h"
#include "PathContainer.h" #include "PathContainer.h"
#include "PathSource.h" #include "PathSource.h"
#include "Referenceable.h" #include "Referenceable.h"
@@ -12,6 +13,7 @@
class Style; class Style;
class Shape : public Observable, class Shape : public Observable,
public Observer, // observing all the paths
public Referenceable, public Referenceable,
public PathContainerListener { public PathContainerListener {
public: public:
@@ -22,6 +24,9 @@ class Shape : public Observable,
virtual void PathAdded(VectorPath* path); virtual void PathAdded(VectorPath* path);
virtual void PathRemoved(VectorPath* path); virtual void PathRemoved(VectorPath* path);
// Observer interface
virtual void ObjectChanged(const Observable* object);
// Shape // Shape
status_t InitCheck() const; status_t InitCheck() const;
@@ -32,7 +37,9 @@ class Shape : public Observable,
inline ::Style* Style() const inline ::Style* Style() const
{ return fStyle; } { return fStyle; }
BRect Bounds() const; inline BRect LastBounds() const
{ return fLastBounds; }
BRect Bounds(bool updateLast = false) const;
::VertexSource& VertexSource(); ::VertexSource& VertexSource();
bool AppendTransformer( bool AppendTransformer(
@@ -44,6 +51,8 @@ class Shape : public Observable,
PathSource fPathSource; PathSource fPathSource;
BList fTransformers; BList fTransformers;
mutable BRect fLastBounds;
}; };
#endif // SHAPE_H #endif // SHAPE_H
@@ -135,7 +135,7 @@ bool
ShapeContainer::AddListener(ShapeContainerListener* listener) ShapeContainer::AddListener(ShapeContainerListener* listener)
{ {
if (listener && !fListeners.HasItem((void*)listener)) if (listener && !fListeners.HasItem((void*)listener))
return fListeners.AddItem(listener); return fListeners.AddItem((void*)listener);
return false; return false;
} }
@@ -143,7 +143,7 @@ ShapeContainer::AddListener(ShapeContainerListener* listener)
bool bool
ShapeContainer::RemoveListener(ShapeContainerListener* listener) ShapeContainer::RemoveListener(ShapeContainerListener* listener)
{ {
return fListeners.RemoveItem(listener); return fListeners.RemoveItem((void*)listener);
} }
// #pragma mark - // #pragma mark -