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