xref: /haiku/src/tests/servers/app/transformation/main.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2014 Stephan Aßmus <superstippi@gmx.de>
3  * All rights reserved. Distributed under the terms of the MIT license.
4  */
5 
6 
7 #include <algorithm>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <Application.h>
12 #include <Bitmap.h>
13 #include <GradientLinear.h>
14 #include <Picture.h>
15 #include <Region.h>
16 #include <Resources.h>
17 #include <Roster.h>
18 #include <String.h>
19 #include <StringView.h>
20 
21 #include "harness.h"
22 
23 static const char* kAppSignature = "application/x-vnd.Haiku-Transformation";
24 
25 
26 class BitmapTest : public Test {
27 public:
28 	BitmapTest(const char* name)
29 		:
30 		Test(name),
31 		fBitmap(_LoadBitmap(555))
32 	{
33 	}
34 
35 private:
36 	status_t
37 	_GetAppResources(BResources& resources) const
38 	{
39 		app_info info;
40 		status_t status = be_app->GetAppInfo(&info);
41 		if (status != B_OK)
42 			return status;
43 
44 		return resources.SetTo(&info.ref);
45 	}
46 
47 
48 	BBitmap* _LoadBitmap(int resourceID) const
49 	{
50 		BResources resources;
51 		status_t status = _GetAppResources(resources);
52 		if (status != B_OK)
53 			return NULL;
54 
55 		size_t dataSize;
56 		const void* data = resources.LoadResource(B_MESSAGE_TYPE, resourceID,
57 			&dataSize);
58 		if (data == NULL)
59 			return NULL;
60 
61 		BMemoryIO stream(data, dataSize);
62 
63 		// Try to read as an archived bitmap.
64 		BMessage archive;
65 		status = archive.Unflatten(&stream);
66 		if (status != B_OK)
67 			return NULL;
68 
69 		BBitmap* bitmap = new BBitmap(&archive);
70 
71 		status = bitmap->InitCheck();
72 		if (status != B_OK) {
73 			delete bitmap;
74 			bitmap = NULL;
75 		}
76 
77 		return bitmap;
78 	}
79 
80 protected:
81 	BBitmap*	fBitmap;
82 };
83 
84 
85 // #pragma mark - Test1
86 
87 
88 class RectsTest : public Test {
89 public:
90 	RectsTest()
91 		:
92 		Test("Rects")
93 	{
94 	}
95 
96 	virtual void Draw(BView* view, BRect updateRect)
97 	{
98 		view->DrawString("Rects", BPoint(20, 30));
99 
100 		view->SetDrawingMode(B_OP_ALPHA);
101 		view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
102 
103 		BRect rect(view->Bounds());
104 		rect.OffsetTo(B_ORIGIN);
105 
106 		rect.InsetBy(rect.Width() / 3, rect.Height() / 3);
107 		BPoint center(
108 			rect.left + rect.Width() / 2,
109 			rect.top + rect.Height() / 2);
110 
111 		for (int32 i = 0; i < 360; i += 40) {
112 			BAffineTransform transform;
113 			transform.RotateBy(center, i * M_PI / 180.0);
114 			view->SetTransform(transform);
115 
116 			view->SetHighColor(51, 151, 255, 20);
117 			view->FillRect(rect);
118 
119 			view->SetHighColor(51, 255, 151, 180);
120 			view->DrawString("Rect", center);
121 		}
122 	}
123 };
124 
125 
126 // #pragma mark - AlphaMaskBitmapTest
127 
128 
129 class AlphaMaskBitmapTest : public BitmapTest {
130 public:
131 	AlphaMaskBitmapTest()
132 		:
133 		BitmapTest("Alpha Masked Bitmap")
134 	{
135 	}
136 
137 	virtual void Draw(BView* view, BRect updateRect)
138 	{
139 		BRect rect(view->Bounds());
140 
141 		if (fBitmap == NULL) {
142 			view->SetHighColor(255, 0, 0);
143 			view->FillRect(rect);
144 			view->SetHighColor(0, 0, 0);
145 			view->DrawString("Failed to load the bitmap.", BPoint(20, 20));
146 			return;
147 		}
148 
149 		rect.left = (rect.Width() - fBitmap->Bounds().Width()) / 2;
150 		rect.top = (rect.Height() - fBitmap->Bounds().Height()) / 2;
151 		rect.right = rect.left + fBitmap->Bounds().Width();
152 		rect.bottom = rect.top + fBitmap->Bounds().Height();
153 
154 		BPoint center(
155 			rect.left + rect.Width() / 2,
156 			rect.top + rect.Height() / 2);
157 
158 		BPicture picture;
159 		view->BeginPicture(&picture);
160 		view->SetDrawingMode(B_OP_ALPHA);
161 		view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
162 		BFont font;
163 		view->GetFont(&font);
164 		font.SetSize(70);
165 		view->SetFont(&font);
166 		view->SetHighColor(0, 0, 0, 80);
167 		view->FillRect(view->Bounds());
168 		view->SetHighColor(0, 0, 0, 255);
169 		view->DrawString("CLIPPING", BPoint(0, center.y + 35));
170 		view->EndPicture();
171 
172 		view->ClipToPicture(&picture);
173 
174 		BAffineTransform transform;
175 			transform.RotateBy(center, 30 * M_PI / 180.0);
176 			view->SetTransform(transform);
177 
178 		view->DrawBitmap(fBitmap, fBitmap->Bounds(), rect);
179 	}
180 };
181 
182 
183 // #pragma mark - Gradient
184 
185 
186 class GradientTest : public Test {
187 public:
188 	GradientTest()
189 		:
190 		Test("Gradient")
191 	{
192 	}
193 
194 	virtual void Draw(BView* view, BRect updateRect)
195 	{
196 		BRect rect(view->Bounds());
197 		rect.InsetBy(rect.Width() / 3, rect.Height() / 3);
198 		BPoint center(
199 			rect.left + rect.Width() / 2,
200 			rect.top + rect.Height() / 2);
201 
202 		BAffineTransform transform;
203 		transform.RotateBy(center, 30.0 * M_PI / 180.0);
204 		view->SetTransform(transform);
205 
206 		rgb_color top = (rgb_color){ 255, 255, 0, 255 };
207 		rgb_color bottom = (rgb_color){ 0, 255, 255, 255 };
208 
209 		BGradientLinear gradient;
210 		gradient.AddColor(top, 0.0f);
211 		gradient.AddColor(bottom, 255.0f);
212 		gradient.SetStart(rect.LeftTop());
213 		gradient.SetEnd(rect.LeftBottom());
214 
215 		float radius = std::min(rect.Width() / 5, rect.Height() / 5);
216 
217 		view->FillRoundRect(rect, radius, radius, gradient);
218 	}
219 };
220 
221 
222 // #pragma mark - NestedStates
223 
224 
225 class NestedStatesTest : public Test {
226 public:
227 	NestedStatesTest()
228 		:
229 		Test("Nested view states")
230 	{
231 	}
232 
233 	virtual void Draw(BView* view, BRect updateRect)
234 	{
235 		BAffineTransform transform;
236 		transform.RotateBy(BPoint(100, 100), 30.0 * M_PI / 180.0);
237 		view->SetTransform(transform);
238 
239 		rgb_color top = (rgb_color){ 255, 0, 0, 255 };
240 		rgb_color bottom = (rgb_color){ 255, 255, 0, 255 };
241 
242 		BRect rect(20, 20, 120, 120);
243 
244 		BGradientLinear gradient;
245 		gradient.AddColor(top, 0.0f);
246 		gradient.AddColor(bottom, 255.0f);
247 		gradient.SetStart(rect.LeftTop());
248 		gradient.SetEnd(rect.LeftBottom());
249 
250 		view->FillRoundRect(rect, 20, 20, gradient);
251 
252 		view->PushState();
253 		// Should be in the same place!
254 		view->StrokeRoundRect(rect, 20, 20);
255 
256 		// Now rotated by another 30 degree
257 		view->SetTransform(transform);
258 
259 		view->SetDrawingMode(B_OP_ALPHA);
260 		view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
261 		view->SetHighColor(0, 0, 255, 120);
262 		view->FillRoundRect(rect, 20, 20);
263 
264 		view->PopState();
265 	}
266 };
267 
268 
269 // #pragma mark - Clipping
270 
271 
272 class ClippingTest : public Test {
273 public:
274 	ClippingTest()
275 		:
276 		Test("View bounds clipping")
277 	{
278 	}
279 
280 	virtual void Draw(BView* view, BRect updateRect)
281 	{
282 		BRect r (20, 20, 50, 50);
283 		view->SetHighColor(ui_color(B_FAILURE_COLOR));
284 		view->FillRect(r);
285 
286 		BAffineTransform transform;
287 		transform.TranslateBy(400, 400);
288 		view->SetTransform(transform);
289 
290 		// Make sure this rectangle is drawn, even when the original one is out
291 		// of the view bounds (for example because of scrolling).
292 		view->SetHighColor(ui_color(B_SUCCESS_COLOR));
293 		view->FillRect(r);
294 	}
295 };
296 
297 
298 // #pragma mark - Clipping
299 
300 
301 class TextClippingTest : public Test {
302 public:
303 	TextClippingTest()
304 		:
305 		Test("Text clipping")
306 	{
307 	}
308 
309 	virtual void Draw(BView* view, BRect updateRect)
310 	{
311 		BFont font;
312 		view->GetFont(&font);
313 		font.SetSize(70);
314 		view->SetFont(&font);
315 
316 		float width = view->Bounds().Width();
317 
318 		// The translation make the text, which has negative coordinates, be
319 		// visible inside the viewport.
320 		BAffineTransform transform;
321 		transform.TranslateBy(width, 0);
322 		view->SetTransform(transform);
323 
324 		const char* str = "CLIPPING";
325 
326 		// Test the standard DrawString method
327 
328 		// Draw the text bounds
329 		float size = view->StringWidth(str);
330 		BRect r(-width, 0, size - width, 70);
331 		view->SetHighColor(ui_color(B_SUCCESS_COLOR));
332 		view->FillRect(r);
333 
334 		// Draw the text (which should fit inside the bounds rectangle)
335 		view->SetHighColor(0, 0, 0, 255);
336 		view->DrawString(str, BPoint(-width, 70));
337 
338 		// Test with offset-based DrawString
339 		BPoint offsets[strlen(str)];
340 		for(unsigned int i = 0; i < strlen(str); i++)
341 		{
342 			offsets[i].x = i * 35 - width;
343 			offsets[i].y = 145;
344 		}
345 
346 		// Draw the text bounds
347 		view->SetHighColor(ui_color(B_SUCCESS_COLOR));
348 		r = BRect(offsets[0], offsets[strlen(str) - 1]);
349 		r.top = 75;
350 		view->FillRect(r);
351 
352 		// Draw the text (which should fit inside the bounds rectangle)
353 		view->SetHighColor(0, 0, 0, 255);
354 		view->DrawString(str, offsets, strlen(str));
355 
356 	}
357 };
358 
359 
360 // #pragma mark - BitmapClipTest
361 
362 
363 class BitmapClipTest : public BitmapTest {
364 public:
365 	BitmapClipTest()
366 		:
367 		BitmapTest("Bitmap clipping")
368 	{
369 	}
370 
371 	virtual void Draw(BView* view, BRect updateRect)
372 	{
373 		BRect rect(view->Bounds());
374 
375 		if (fBitmap == NULL) {
376 			view->SetHighColor(255, 0, 0);
377 			view->FillRect(rect);
378 			view->SetHighColor(0, 0, 0);
379 			view->DrawString("Failed to load the bitmap.", BPoint(20, 20));
380 			return;
381 		}
382 
383 		rect = fBitmap->Bounds();
384 
385 		view->SetHighColor(ui_color(B_FAILURE_COLOR));
386 		view->FillRect(rect);
387 
388 		// The rect offset should compensate the transform translation, so the
389 		// bitmap should be drawn at the view origin. It will then exactly
390 		// cover the red rectangle, which should not be visible anymore.
391 		rect.OffsetBy(0, 40);
392 
393 		BAffineTransform transform;
394 			transform.TranslateBy(0, -40);
395 		view->SetTransform(transform);
396 
397 		view->DrawBitmap(fBitmap, fBitmap->Bounds(), rect);
398 	}
399 };
400 
401 
402 // #pragma mark - PixelAlignTest
403 
404 
405 class PixelAlignTest : public Test {
406 public:
407 	PixelAlignTest()
408 		:
409 		Test("Pixel alignment")
410 	{
411 	}
412 
413 	virtual void Draw(BView* view, BRect updateRect)
414 	{
415 		BRect rect(20, 20, 120, 120);
416 		view->SetHighColor(ui_color(B_SUCCESS_COLOR));
417 		view->StrokeRect(rect);
418 
419 		BAffineTransform transform;
420 			transform.TranslateBy(140, 0);
421 		view->SetTransform(transform);
422 
423 		// Translating a pixel-aligned rectangle by an integer number of
424 		// pixels should result in a pixel-aligned rectangle.
425 		view->SetHighColor(ui_color(B_FAILURE_COLOR));
426 		view->StrokeRect(rect);
427 	}
428 };
429 
430 
431 // #pragma mark -
432 
433 
434 int
435 main(int argc, char** argv)
436 {
437 	BApplication app(kAppSignature);
438 
439 	TestWindow* window = new TestWindow("Transformation tests");
440 
441 	window->AddTest(new RectsTest());
442 	window->AddTest(new BitmapClipTest());
443 	window->AddTest(new TextClippingTest());
444 	window->AddTest(new AlphaMaskBitmapTest());
445 	window->AddTest(new GradientTest());
446 	window->AddTest(new NestedStatesTest());
447 	window->AddTest(new ClippingTest());
448 	window->AddTest(new PixelAlignTest());
449 
450 	window->SetToTest(2);
451 	window->Show();
452 
453 	app.Run();
454 	return 0;
455 }
456