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