1 /* 2 * Copyright 2007, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Pfeiffer 7 */ 8 9 #include <InterfaceKit.h> 10 #include <String.h> 11 12 #include <stdio.h> 13 14 #include "PictureTest.h" 15 16 #define TEST_AND_RETURN(condition, message, result) \ 17 { \ 18 if (condition) { \ 19 SetErrorMessage(message); \ 20 return result; \ 21 } \ 22 } 23 24 template <class T> 25 class AutoDelete 26 { 27 public: 28 AutoDelete(T *object) : fObject(object) { } 29 ~AutoDelete() { delete fObject; fObject = NULL; } 30 31 T* Release() { T* object = fObject; fObject = NULL; return object; } 32 33 private: 34 T *fObject; 35 }; 36 37 class OffscreenBitmap { 38 public: 39 OffscreenBitmap(BRect frame, color_space colorSpace); 40 virtual ~OffscreenBitmap(); 41 status_t InitCheck() const { return fStatus; } 42 43 BView *View(); 44 BBitmap *Copy(); 45 46 private: 47 BRect fFrame; 48 color_space fColorSpace; 49 status_t fStatus; 50 51 BBitmap *fBitmap; 52 BView *fView; 53 }; 54 55 OffscreenBitmap::OffscreenBitmap(BRect frame, color_space colorSpace) 56 : fFrame(frame) 57 , fColorSpace(colorSpace) 58 , fStatus(B_ERROR) 59 , fBitmap(NULL) 60 , fView(NULL) 61 { 62 BBitmap *bitmap = new BBitmap(frame, fColorSpace, true); 63 AutoDelete<BBitmap> _bitmap(bitmap); 64 if (bitmap == NULL || bitmap->IsValid() == false || bitmap->InitCheck() != B_OK) 65 return; 66 67 BView *view = new BView(frame, "offscreen", B_FOLLOW_ALL, B_WILL_DRAW); 68 AutoDelete<BView> _view(view); 69 if (view == NULL) 70 return; 71 72 bitmap->Lock(); 73 bitmap->AddChild(view); 74 // bitmap is locked during the life time of this object 75 76 fBitmap = _bitmap.Release(); 77 fView = _view.Release(); 78 fStatus = B_OK; 79 } 80 81 OffscreenBitmap::~OffscreenBitmap() 82 { 83 if (fStatus != B_OK) 84 return; 85 86 fView->RemoveSelf(); 87 fBitmap->Unlock(); 88 delete fView; 89 fView = NULL; 90 91 delete fBitmap; 92 fBitmap = NULL; 93 94 fStatus = B_ERROR; 95 } 96 97 BView * 98 OffscreenBitmap::View() 99 { 100 return fView; 101 } 102 103 BBitmap* 104 OffscreenBitmap::Copy() 105 { 106 // the result bitmap that does not accept views 107 // to save resources in the application server 108 BBitmap *copy = new BBitmap(fFrame, fColorSpace, false); 109 AutoDelete<BBitmap> _copy(copy); 110 if (copy == NULL || copy->IsValid() == false || copy->InitCheck() != B_OK) 111 return NULL; 112 113 fView->Sync(); 114 fBitmap->Unlock(); 115 116 memcpy(copy->Bits(), fBitmap->Bits(), fBitmap->BitsLength()); 117 118 fBitmap->Lock(); 119 120 return _copy.Release(); 121 } 122 123 PictureTest::PictureTest() 124 : fColorSpace(B_RGBA32) 125 , fDirectBitmap(NULL) 126 , fBitmapFromPicture(NULL) 127 , fBitmapFromRestoredPicture(NULL) 128 { 129 } 130 131 132 BBitmap* 133 PictureTest::DirectBitmap(bool detach) 134 { 135 BBitmap* bitmap = fDirectBitmap; 136 if (detach) 137 fDirectBitmap = NULL; 138 return bitmap; 139 } 140 141 BBitmap* 142 PictureTest::BitmapFromPicture(bool detach) 143 { 144 BBitmap* bitmap = fBitmapFromPicture; 145 if (detach) 146 fBitmapFromPicture = NULL; 147 return bitmap; 148 } 149 150 151 BBitmap* 152 PictureTest::BitmapFromRestoredPicture(bool detach) 153 { 154 BBitmap* bitmap = fBitmapFromRestoredPicture; 155 if (detach) 156 fBitmapFromRestoredPicture = NULL; 157 return bitmap; 158 } 159 160 161 PictureTest::~PictureTest() 162 { 163 CleanUp(); 164 } 165 166 void 167 PictureTest::CleanUp() 168 { 169 delete fBitmapFromPicture; 170 fBitmapFromPicture = NULL; 171 delete fBitmapFromRestoredPicture; 172 fBitmapFromRestoredPicture = NULL; 173 fErrorMessage = ""; 174 } 175 176 void 177 PictureTest::SetErrorMessage(const char *message) 178 { 179 if (fErrorMessage.Length() == 0) 180 fErrorMessage = message; 181 } 182 183 bool 184 PictureTest::Test(draw_func* func, BRect frame) 185 { 186 CleanUp(); 187 188 fDirectBitmap = CreateBitmap(func, frame); 189 TEST_AND_RETURN(fDirectBitmap == NULL, "Could not create direct draw bitmap!", false); 190 191 BPicture *picture = RecordPicture(func, frame); 192 AutoDelete<BPicture> _picture(picture); 193 TEST_AND_RETURN(picture == NULL, "Picture could not be recorded!", false); 194 195 BPicture *archivedPicture = SaveAndRestore(picture); 196 AutoDelete<BPicture> _archivedPicture(archivedPicture); 197 TEST_AND_RETURN(picture == NULL, "Picture could not be flattened and unflattened!", false); 198 199 fBitmapFromPicture = CreateBitmap(picture, frame); 200 TEST_AND_RETURN(fBitmapFromPicture == NULL, "Could not create bitmap from original picture!", false); 201 202 fBitmapFromRestoredPicture = CreateBitmap(archivedPicture, frame); 203 TEST_AND_RETURN(fBitmapFromRestoredPicture == NULL, "Could not create bitmap from archived picture!", false); 204 205 TEST_AND_RETURN(!IsSame(fDirectBitmap, fBitmapFromPicture), "Bitmap from picture differs from direct drawing bitmap", false); 206 TEST_AND_RETURN(!IsSame(fDirectBitmap, fBitmapFromRestoredPicture), "Bitmap from picture differs from direct drawing bitmap", false); 207 return true; 208 } 209 210 211 BBitmap * 212 PictureTest::CreateBitmap(draw_func* func, BRect frame) 213 { 214 OffscreenBitmap bitmap(frame, fColorSpace); 215 TEST_AND_RETURN(bitmap.InitCheck() != B_OK, "Offscreen bitmap for direct drawing could not be created!" , NULL); 216 func(bitmap.View(), frame); 217 return bitmap.Copy(); 218 } 219 220 BPicture * 221 PictureTest::RecordPicture(draw_func* func, BRect frame) 222 { 223 OffscreenBitmap bitmap(frame, fColorSpace); 224 TEST_AND_RETURN(bitmap.InitCheck() != B_OK, "Offscreen bitmap for picture recording could not be created!" , NULL); 225 226 BView *view = bitmap.View(); 227 // record 228 BPicture *picture = new BPicture(); 229 view->BeginPicture(picture); 230 func(view, frame); 231 picture = view->EndPicture(); 232 233 return picture; 234 } 235 236 BBitmap * 237 PictureTest::CreateBitmap(BPicture *picture, BRect frame) 238 { 239 OffscreenBitmap bitmap(frame, fColorSpace); 240 TEST_AND_RETURN(bitmap.InitCheck() != B_OK, "Offscreen bitmap for picture drawing could not be created!" , NULL); 241 242 BView *view = bitmap.View(); 243 view->DrawPicture(picture); 244 view->Sync(); 245 246 return bitmap.Copy(); 247 } 248 249 250 bool 251 PictureTest::IsSame(BBitmap *bitmap1, BBitmap *bitmap2) 252 { 253 if (bitmap1->ColorSpace() != bitmap2->ColorSpace()) 254 return false; 255 256 if (bitmap1->BitsLength() != bitmap2->BitsLength()) 257 return false; 258 259 return memcmp(bitmap1->Bits(), bitmap2->Bits(), bitmap1->BitsLength()) == 0; 260 } 261 262 263 FlattenPictureTest::FlattenPictureTest() 264 { 265 } 266 267 BPicture * 268 FlattenPictureTest::SaveAndRestore(BPicture *picture) 269 { 270 BMallocIO *data = new BMallocIO(); 271 AutoDelete<BMallocIO> _data(data); 272 TEST_AND_RETURN(data == NULL, "BMallocIO could not be allocated for flattening the picture!" , NULL); 273 274 picture->Flatten(data); 275 276 data->Seek(0, SEEK_SET); 277 BPicture *archivedPicture = new BPicture(); 278 TEST_AND_RETURN(archivedPicture == NULL, "BPicture could not be allocated for unflattening the picture!" , NULL); 279 archivedPicture->Unflatten(data); 280 281 return archivedPicture; 282 } 283 284 ArchivePictureTest::ArchivePictureTest() 285 { 286 } 287 288 BPicture * 289 ArchivePictureTest::SaveAndRestore(BPicture *picture) 290 { 291 BMessage archive; 292 TEST_AND_RETURN(picture->Archive(&archive) != B_OK, "Picture could not be archived to BMessage", NULL); 293 294 BArchivable *archivable = BPicture::Instantiate(&archive); 295 AutoDelete<BArchivable> _archivable(archivable); 296 TEST_AND_RETURN(archivable == NULL, "Picture could not be instantiated from BMessage", NULL); 297 298 BPicture *archivedPicture = dynamic_cast<BPicture*>(archivable); 299 TEST_AND_RETURN(archivedPicture == NULL, "Picture could not be restored from BMessage", NULL); 300 301 _archivable.Release(); 302 return archivedPicture; 303 } 304 305