1/*
2 * Copyright 2006, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan A��mus <superstippi@gmx.de>
7 */
8
9#include "Canvas.h"
10
11#include <new>
12#include <stdio.h>
13
14#include <Bitmap.h>
15#include <Entry.h>
16#include <Message.h>
17
18#include "Layer.h"
19
20using std::nothrow;
21
22// constructor
23Canvas::Canvas(BRect frame)
24	: BList(10),
25	  fBounds(frame)
26{
27}
28
29// destructor
30Canvas::~Canvas()
31{
32	MakeEmpty();
33}
34
35// IsValid
36bool
37Canvas::IsValid() const
38{
39	return fBounds.IsValid();
40}
41
42// MakeEmpty
43void
44Canvas::MakeEmpty()
45{
46	int32 count = CountLayers();
47	for (int32 i = 0; i < count; i++)
48		delete LayerAtFast(i);
49	BList::MakeEmpty();
50}
51
52// AddLayer
53bool
54Canvas::AddLayer(Layer* layer)
55{
56	return AddLayer(layer, CountLayers());
57}
58
59// AddLayer
60bool
61Canvas::AddLayer(Layer* layer, int32 index)
62{
63	return layer && AddItem((void*)layer, index);
64}
65
66// RemoveLayer
67Layer*
68Canvas::RemoveLayer(int32 index)
69{
70	return (Layer*)RemoveItem(index);
71}
72
73// RemoveLayer
74bool
75Canvas::RemoveLayer(Layer* layer)
76{
77	return RemoveItem((void*)layer);
78}
79
80// LayerAt
81Layer*
82Canvas::LayerAt(int32 index) const
83{
84	return (Layer*)ItemAt(index);
85}
86
87// LayerAtFast
88Layer*
89Canvas::LayerAtFast(int32 index) const
90{
91	return (Layer*)ItemAtFast(index);
92}
93
94// IndexOf
95int32
96Canvas::IndexOf(Layer* layer) const
97{
98	return BList::IndexOf((void*)layer);
99}
100
101// CountLayers
102int32
103Canvas::CountLayers() const
104{
105	return CountItems();
106}
107
108// HasLayer
109bool
110Canvas::HasLayer(Layer* layer) const
111{
112	return HasItem((void*)layer);
113}
114
115// SetBounds
116void
117Canvas::SetBounds(BRect bounds)
118{
119	if (bounds.IsValid())
120		fBounds = bounds;
121}
122
123// Bounds
124BRect
125Canvas::Bounds() const
126{
127	return fBounds;
128}
129
130// Compose
131void
132Canvas::Compose(BBitmap* into, BRect area) const
133{
134	if (into && into->IsValid()
135		&& area.IsValid() && area.Intersects(into->Bounds())) {
136		area = area & into->Bounds();
137		int32 count = CountLayers();
138		for (int32 i = count - 1; Layer* layer = LayerAt(i); i--) {
139			layer->Compose(into, area);
140		}
141	}
142}
143
144// Bitmap
145BBitmap*
146Canvas::Bitmap() const
147{
148	BBitmap* bitmap = new BBitmap(fBounds, 0, B_RGBA32);
149	if (!bitmap->IsValid()) {
150		delete bitmap;
151		return NULL;
152	}
153
154	// this bitmap is uninitialized, clear to black/fully transparent
155	memset(bitmap->Bits(), 0, bitmap->BitsLength());
156	Compose(bitmap, fBounds);
157	// remove image data where alpha = 0 to improve compression later on
158	uint8* bits = (uint8*)bitmap->Bits();
159	uint32 bpr = bitmap->BytesPerRow();
160	uint32 width = bitmap->Bounds().IntegerWidth() + 1;
161	uint32 height = bitmap->Bounds().IntegerHeight() + 1;
162	while (height > 0) {
163		uint8* bitsHandle = bits;
164		for (uint32 x = 0; x < width; x++) {
165			if (!bitsHandle[3]) {
166				bitsHandle[0] = 0;
167				bitsHandle[1] = 0;
168				bitsHandle[2] = 0;
169			}
170			bitsHandle += 4;
171		}
172		bits += bpr;
173		height--;
174	}
175
176	return bitmap;
177}
178
179
180
181static const char*	LAYER_KEY			= "layer";
182static const char*	BOUNDS_KEY			= "bounds";
183
184// Unarchive
185status_t
186Canvas::Unarchive(const BMessage* archive)
187{
188	if (!archive)
189		return B_BAD_VALUE;
190
191	// restore bounds
192	BRect bounds;
193	if (archive->FindRect(BOUNDS_KEY, &bounds) < B_OK)
194		return B_ERROR;
195
196	fBounds = bounds;
197	// restore each layer
198	BMessage layerMessage;
199	for (int32 i = 0;
200		 archive->FindMessage(LAYER_KEY, i, &layerMessage) == B_OK;
201		 i++) {
202
203		Layer* layer = new (nothrow) Layer();
204		if (!layer || layer->Unarchive(&layerMessage) < B_OK
205			|| !AddLayer(layer)) {
206			delete layer;
207			return B_NO_MEMORY;
208		}
209	}
210
211	return B_OK;
212}
213
214