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 23 Canvas::Canvas(BRect frame) 24 : BList(10), 25 fBounds(frame) 26 { 27 } 28 29 // destructor 30 Canvas::~Canvas() 31 { 32 MakeEmpty(); 33 } 34 35 // IsValid 36 bool 37 Canvas::IsValid() const 38 { 39 return fBounds.IsValid(); 40 } 41 42 // MakeEmpty 43 void 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 54 Canvas::AddLayer(Layer* layer) 55 { 56 return AddLayer(layer, CountLayers()); 57 } 58 59 // AddLayer 60 bool 61 Canvas::AddLayer(Layer* layer, int32 index) 62 { 63 return layer && AddItem((void*)layer, index); 64 } 65 66 // RemoveLayer 67 Layer* 68 Canvas::RemoveLayer(int32 index) 69 { 70 return (Layer*)RemoveItem(index); 71 } 72 73 // RemoveLayer 74 bool 75 Canvas::RemoveLayer(Layer* layer) 76 { 77 return RemoveItem((void*)layer); 78 } 79 80 // LayerAt 81 Layer* 82 Canvas::LayerAt(int32 index) const 83 { 84 return (Layer*)ItemAt(index); 85 } 86 87 // LayerAtFast 88 Layer* 89 Canvas::LayerAtFast(int32 index) const 90 { 91 return (Layer*)ItemAtFast(index); 92 } 93 94 // IndexOf 95 int32 96 Canvas::IndexOf(Layer* layer) const 97 { 98 return BList::IndexOf((void*)layer); 99 } 100 101 // CountLayers 102 int32 103 Canvas::CountLayers() const 104 { 105 return CountItems(); 106 } 107 108 // HasLayer 109 bool 110 Canvas::HasLayer(Layer* layer) const 111 { 112 return HasItem((void*)layer); 113 } 114 115 // SetBounds 116 void 117 Canvas::SetBounds(BRect bounds) 118 { 119 if (bounds.IsValid()) 120 fBounds = bounds; 121 } 122 123 // Bounds 124 BRect 125 Canvas::Bounds() const 126 { 127 return fBounds; 128 } 129 130 // Compose 131 void 132 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* 146 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 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