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