xref: /haiku/src/tests/kits/interface/flatten_picture/PictureTest.cpp (revision 1b8f7f13a3dc70e0e903cb94248220b40b732204)
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