xref: /haiku/src/add-ons/translators/wonderbrush/Canvas.cpp (revision 7fc7e14b312d60b930ae76b002dd842aeb882a35)
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 
20 using std::nothrow;
21 
22 // constructor
Canvas(BRect frame)23 Canvas::Canvas(BRect frame)
24 	: BList(10),
25 	  fBounds(frame)
26 {
27 }
28 
29 // destructor
~Canvas()30 Canvas::~Canvas()
31 {
32 	MakeEmpty();
33 }
34 
35 // IsValid
36 bool
IsValid() const37 Canvas::IsValid() const
38 {
39 	return fBounds.IsValid();
40 }
41 
42 // MakeEmpty
43 void
MakeEmpty()44 Canvas::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
53 bool
AddLayer(Layer * layer)54 Canvas::AddLayer(Layer* layer)
55 {
56 	return AddLayer(layer, CountLayers());
57 }
58 
59 // AddLayer
60 bool
AddLayer(Layer * layer,int32 index)61 Canvas::AddLayer(Layer* layer, int32 index)
62 {
63 	return layer && AddItem((void*)layer, index);
64 }
65 
66 // RemoveLayer
67 Layer*
RemoveLayer(int32 index)68 Canvas::RemoveLayer(int32 index)
69 {
70 	return (Layer*)RemoveItem(index);
71 }
72 
73 // RemoveLayer
74 bool
RemoveLayer(Layer * layer)75 Canvas::RemoveLayer(Layer* layer)
76 {
77 	return RemoveItem((void*)layer);
78 }
79 
80 // LayerAt
81 Layer*
LayerAt(int32 index) const82 Canvas::LayerAt(int32 index) const
83 {
84 	return (Layer*)ItemAt(index);
85 }
86 
87 // LayerAtFast
88 Layer*
LayerAtFast(int32 index) const89 Canvas::LayerAtFast(int32 index) const
90 {
91 	return (Layer*)ItemAtFast(index);
92 }
93 
94 // IndexOf
95 int32
IndexOf(Layer * layer) const96 Canvas::IndexOf(Layer* layer) const
97 {
98 	return BList::IndexOf((void*)layer);
99 }
100 
101 // CountLayers
102 int32
CountLayers() const103 Canvas::CountLayers() const
104 {
105 	return CountItems();
106 }
107 
108 // HasLayer
109 bool
HasLayer(Layer * layer) const110 Canvas::HasLayer(Layer* layer) const
111 {
112 	return HasItem((void*)layer);
113 }
114 
115 // SetBounds
116 void
SetBounds(BRect bounds)117 Canvas::SetBounds(BRect bounds)
118 {
119 	if (bounds.IsValid())
120 		fBounds = bounds;
121 }
122 
123 // Bounds
124 BRect
Bounds() const125 Canvas::Bounds() const
126 {
127 	return fBounds;
128 }
129 
130 // Compose
131 void
Compose(BBitmap * into,BRect area) const132 Canvas::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
145 BBitmap*
Bitmap() const146 Canvas::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 
181 static const char*	LAYER_KEY			= "layer";
182 static const char*	BOUNDS_KEY			= "bounds";
183 
184 // Unarchive
185 status_t
Unarchive(const BMessage * archive)186 Canvas::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