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 "PictureTestCases.h"
10
11#include <GradientLinear.h>
12#include <GradientRadial.h>
13#include <GradientRadialFocus.h>
14#include <GradientDiamond.h>
15#include <GradientConic.h>
16
17#include <stdio.h>
18
19static const rgb_color kBlack = {0, 0, 0};
20static const rgb_color kWhite = {255, 255, 255};
21static const rgb_color kRed = {255, 0, 0};
22static const rgb_color kGreen = {0, 255, 0};
23static const rgb_color kBlue = {0, 0, 255};
24
25static BPoint centerPoint(BRect rect)
26{
27	int x = (int)(rect.left + rect.IntegerWidth() / 2);
28	int y = (int)(rect.top + rect.IntegerHeight() / 2);
29	return BPoint(x, y);
30}
31
32static void testNoOp(BView *view, BRect frame)
33{
34	// no op
35}
36
37static void testDrawChar(BView *view, BRect frame)
38{
39	view->MovePenTo(frame.left, frame.bottom - 5);
40	view->DrawChar('A');
41
42	view->DrawChar('B', BPoint(frame.left + 20, frame.bottom - 5));
43}
44
45static void testDrawString(BView *view, BRect frame)
46{
47	BFont font;
48	view->GetFont(&font);
49	font_height height;
50	font.GetHeight(&height);
51	float baseline = frame.bottom - height.descent;
52	// draw base line
53	view->SetHighColor(kGreen);
54	view->StrokeLine(BPoint(frame.left, baseline - 1), BPoint(frame.right, baseline -1));
55
56	view->SetHighColor(kBlack);
57	view->DrawString("Haiku [������������]", BPoint(frame.left, baseline));
58}
59
60static void testDrawStringWithLength(BView *view, BRect frame)
61{
62	BFont font;
63	view->GetFont(&font);
64	font_height height;
65	font.GetHeight(&height);
66	float baseline = frame.bottom - height.descent;
67	// draw base line
68	view->SetHighColor(kGreen);
69	view->StrokeLine(BPoint(frame.left, baseline - 1), BPoint(frame.right, baseline -1));
70
71	view->SetHighColor(kBlack);
72	view->DrawString("Haiku [������������]", 13, BPoint(frame.left, baseline));
73}
74
75
76static void testDrawStringWithOffsets(BView* view, BRect frame)
77{
78	BFont font;
79	view->GetFont(&font);
80	font_height height;
81	font.GetHeight(&height);
82	float baseline = frame.bottom - height.descent;
83	// draw base line
84	view->SetHighColor(kGreen);
85	view->StrokeLine(BPoint(frame.left, baseline - 1), BPoint(frame.right, baseline -1));
86
87	view->SetHighColor(kBlack);
88	BPoint point(frame.left, baseline);
89	BPoint pointArray[] = {
90		point,
91		point,
92		point,
93		point,
94		point
95	};
96
97	for (size_t i = 1; i < (sizeof(pointArray) / sizeof(pointArray[0])); i++)
98		pointArray[i] = pointArray[i - 1] + BPoint(10, 0);
99
100	view->DrawString("Haiku", pointArray, sizeof(pointArray) / sizeof(pointArray[0]));
101}
102
103
104static void testDrawStringWithoutPosition(BView* view, BRect frame)
105{
106	BFont font;
107	view->GetFont(&font);
108	font_height height;
109	font.GetHeight(&height);
110	float baseline = frame.bottom - height.descent;
111	// draw base line
112	view->SetHighColor(kGreen);
113	view->StrokeLine(BPoint(frame.left, baseline - 1), BPoint(frame.right, baseline -1));
114
115	view->SetHighColor(kBlack);
116	view->MovePenTo(BPoint(frame.left, baseline));
117	view->DrawString("H");
118	view->DrawString("a");
119	view->DrawString("i");
120	view->DrawString("k");
121	view->DrawString("u");
122}
123
124
125static void testFillArc(BView *view, BRect frame)
126{
127	frame.InsetBy(2, 2);
128	view->FillArc(frame, 45, 180);
129}
130
131static void testStrokeArc(BView *view, BRect frame)
132{
133	frame.InsetBy(2, 2);
134	view->StrokeArc(frame, 45, 180);
135}
136
137static void testFillBezier(BView *view, BRect frame)
138{
139	frame.InsetBy(2, 2);
140	BPoint points[4];
141	points[0] = BPoint(frame.left, frame.bottom);
142	points[1] = BPoint(frame.left, frame.top);
143	points[1] = BPoint(frame.left, frame.top);
144	points[3] = BPoint(frame.right, frame.top);
145	view->FillBezier(points);
146}
147
148static void testStrokeBezier(BView *view, BRect frame)
149{
150	frame.InsetBy(2, 2);
151	BPoint points[4];
152	points[0] = BPoint(frame.left, frame.bottom);
153	points[1] = BPoint(frame.left, frame.top);
154	points[1] = BPoint(frame.left, frame.top);
155	points[3] = BPoint(frame.right, frame.top);
156	view->StrokeBezier(points);
157}
158
159static void testFillEllipse(BView *view, BRect frame)
160{
161	frame.InsetBy(2, 2);
162	view->FillEllipse(frame);
163
164	view->SetHighColor(kRed);
165	float r = frame.Width() / 3;
166	float s = frame.Height() / 4;
167	view->FillEllipse(centerPoint(frame), r, s);
168}
169
170static void testStrokeEllipse(BView *view, BRect frame)
171{
172	frame.InsetBy(2, 2);
173	view->StrokeEllipse(frame);
174
175	view->SetHighColor(kRed);
176	float r = frame.Width() / 3;
177	float s = frame.Height() / 4;
178	view->StrokeEllipse(centerPoint(frame), r, s);
179}
180
181static void testFillPolygon(BView *view, BRect frame)
182{
183	frame.InsetBy(2, 2);
184
185	BPoint points[4];
186	points[0] = BPoint(frame.left, frame.top);
187	points[1] = BPoint(frame.right, frame.bottom);
188	points[2] = BPoint(frame.right, frame.top);
189	points[3] = BPoint(frame.left, frame.bottom);
190
191	view->FillPolygon(points, 4);
192}
193
194static void testStrokePolygon(BView *view, BRect frame)
195{
196	frame.InsetBy(2, 2);
197
198	BPoint points[4];
199	points[0] = BPoint(frame.left, frame.top);
200	points[1] = BPoint(frame.right, frame.bottom);
201	points[2] = BPoint(frame.right, frame.top);
202	points[3] = BPoint(frame.left, frame.bottom);
203
204	view->StrokePolygon(points, 4);
205}
206
207static void testFillRect(BView *view, BRect frame)
208{
209	frame.InsetBy(2, 2);
210	view->FillRect(frame);
211}
212
213static void testFillRectGradientLinear(BView* view, BRect frame)
214{
215	BGradientLinear gradient(0, 0, frame.right, frame.bottom);
216	gradient.AddColor(kRed, 0);
217	gradient.AddColor(kBlue, 255);
218	frame.InsetBy(2, 2);
219	view->FillRect(frame, gradient);
220}
221
222static void testFillRectGradientRadial(BView* view, BRect frame)
223{
224	BGradientRadial gradient(10, 10, 10);
225	gradient.AddColor(kRed, 0);
226	gradient.AddColor(kBlue, 255);
227	frame.InsetBy(2, 2);
228	view->FillRect(frame, gradient);
229}
230
231static void testFillRectGradientRadialFocus(BView* view, BRect frame)
232{
233	BGradientRadialFocus gradient(0, 0, 10, 10, 5);
234	gradient.AddColor(kRed, 0);
235	gradient.AddColor(kBlue, 255);
236	frame.InsetBy(2, 2);
237	view->FillRect(frame, gradient);
238}
239
240static void testFillRectGradientDiamond(BView* view, BRect frame)
241{
242	BGradientDiamond gradient(0, 10);
243	gradient.AddColor(kRed, 0);
244	gradient.AddColor(kBlue, 255);
245	frame.InsetBy(2, 2);
246	view->FillRect(frame, gradient);
247}
248
249static void testFillRectGradientConic(BView* view, BRect frame)
250{
251	BGradientConic gradient(0, 0, 10);
252	gradient.AddColor(kRed, 0);
253	gradient.AddColor(kBlue, 255);
254	frame.InsetBy(2, 2);
255	view->FillRect(frame, gradient);
256}
257
258static void testStrokeRect(BView *view, BRect frame)
259{
260	frame.InsetBy(2, 2);
261	view->StrokeRect(frame);
262}
263
264static void testFillRegion(BView *view, BRect frame)
265{
266	frame.InsetBy(2, 2);
267	BRegion region(frame);
268	frame.InsetBy(10, 10);
269	region.Exclude(frame);
270	view->FillRegion(&region);
271}
272
273static void testFillRegionGradientLinear(BView* view, BRect frame)
274{
275	BGradientLinear gradient(0, 0, frame.right, frame.bottom);
276	gradient.AddColor(kRed, 0);
277	gradient.AddColor(kBlue, 255);
278	frame.InsetBy(2, 2);
279	BRegion region(frame);
280	frame.InsetBy(10, 10);
281	region.Exclude(frame);
282	view->FillRegion(&region, gradient);
283}
284
285static void testFillRegionGradientRadial(BView* view, BRect frame)
286{
287	BGradientRadial gradient(10, 10, 10);
288	gradient.AddColor(kRed, 0);
289	gradient.AddColor(kBlue, 255);
290	frame.InsetBy(2, 2);
291	BRegion region(frame);
292	frame.InsetBy(10, 10);
293	region.Exclude(frame);
294	view->FillRegion(&region, gradient);
295}
296
297static void testFillRegionGradientRadialFocus(BView* view, BRect frame)
298{
299	BGradientRadialFocus gradient(0, 0, 10, 10, 5);
300	gradient.AddColor(kRed, 0);
301	gradient.AddColor(kBlue, 255);
302	frame.InsetBy(2, 2);
303	BRegion region(frame);
304	frame.InsetBy(10, 10);
305	region.Exclude(frame);
306	view->FillRegion(&region, gradient);
307}
308
309static void testFillRegionGradientDiamond(BView* view, BRect frame)
310{
311	BGradientDiamond gradient(0, 10);
312	gradient.AddColor(kRed, 0);
313	gradient.AddColor(kBlue, 255);
314	frame.InsetBy(2, 2);
315	BRegion region(frame);
316	frame.InsetBy(10, 10);
317	region.Exclude(frame);
318	view->FillRegion(&region, gradient);
319}
320
321static void testFillRegionGradientConic(BView* view, BRect frame)
322{
323	BGradientConic gradient(0, 0, 10);
324	gradient.AddColor(kRed, 0);
325	gradient.AddColor(kBlue, 255);
326	frame.InsetBy(2, 2);
327	BRegion region(frame);
328	frame.InsetBy(10, 10);
329	region.Exclude(frame);
330	view->FillRegion(&region, gradient);
331}
332
333static void testFillRoundRect(BView *view, BRect frame)
334{
335	frame.InsetBy(2, 2);
336	view->FillRoundRect(frame, 5, 3);
337}
338
339static void testFillRoundRectGradientLinear(BView* view, BRect frame)
340{
341	BGradientLinear gradient(0, 0, frame.right, frame.bottom);
342	gradient.AddColor(kRed, 0);
343	gradient.AddColor(kBlue, 255);
344	frame.InsetBy(2, 2);
345	view->FillRoundRect(frame, 5, 3, gradient);
346}
347
348static void testFillRoundRectGradientRadial(BView* view, BRect frame)
349{
350	BGradientRadial gradient(10, 10, 10);
351	gradient.AddColor(kRed, 0);
352	gradient.AddColor(kBlue, 255);
353	frame.InsetBy(2, 2);
354	view->FillRoundRect(frame, 5, 3, gradient);
355}
356
357static void testFillRoundRectGradientRadialFocus(BView* view, BRect frame)
358{
359	BGradientRadialFocus gradient(0, 0, 10, 10, 5);
360	gradient.AddColor(kRed, 0);
361	gradient.AddColor(kBlue, 255);
362	view->FillRoundRect(frame, 5, 3, gradient);
363}
364
365static void testFillRoundRectGradientDiamond(BView* view, BRect frame)
366{
367	BGradientDiamond gradient(0, 10);
368	gradient.AddColor(kRed, 0);
369	gradient.AddColor(kBlue, 255);
370	frame.InsetBy(2, 2);
371	view->FillRoundRect(frame, 5, 3, gradient);
372}
373
374static void testFillRoundRectGradientConic(BView* view, BRect frame)
375{
376	BGradientConic gradient(0, 0, 10);
377	gradient.AddColor(kRed, 0);
378	gradient.AddColor(kBlue, 255);
379	frame.InsetBy(2, 2);
380	view->FillRoundRect(frame, 5, 3, gradient);
381}
382
383static void testStrokeRoundRect(BView *view, BRect frame)
384{
385	frame.InsetBy(2, 2);
386	view->StrokeRoundRect(frame, 5, 3);
387}
388
389static void testFillTriangle(BView *view, BRect frame)
390{
391	frame.InsetBy(2, 2);
392	BPoint points[3];
393	points[0] = BPoint(frame.left, frame.bottom);
394	points[1] = BPoint(centerPoint(frame).x, frame.top);
395	points[2] = BPoint(frame.right, frame.bottom);
396	view->FillTriangle(points[0], points[1], points[2]);
397}
398
399static void testFillTriangleGradientLinear(BView* view, BRect frame)
400{
401	BGradientLinear gradient(0, 0, frame.right, frame.bottom);
402	gradient.AddColor(kRed, 0);
403	gradient.AddColor(kBlue, 255);
404	frame.InsetBy(2, 2);
405	BPoint points[3];
406	points[0] = BPoint(frame.left, frame.bottom);
407	points[1] = BPoint(centerPoint(frame).x, frame.top);
408	points[2] = BPoint(frame.right, frame.bottom);
409	view->FillTriangle(points[0], points[1], points[2], gradient);
410}
411
412static void testFillTriangleGradientRadial(BView* view, BRect frame)
413{
414	BGradientRadial gradient(10, 10, 10);
415	gradient.AddColor(kRed, 0);
416	gradient.AddColor(kBlue, 255);
417	frame.InsetBy(2, 2);
418	BPoint points[3];
419	points[0] = BPoint(frame.left, frame.bottom);
420	points[1] = BPoint(centerPoint(frame).x, frame.top);
421	points[2] = BPoint(frame.right, frame.bottom);
422	view->FillTriangle(points[0], points[1], points[2], gradient);
423}
424
425static void testFillTriangleGradientRadialFocus(BView* view, BRect frame)
426{
427	BGradientRadialFocus gradient(0, 0, 10, 10, 5);
428	gradient.AddColor(kRed, 0);
429	gradient.AddColor(kBlue, 255);
430	frame.InsetBy(2, 2);
431	BPoint points[3];
432	points[0] = BPoint(frame.left, frame.bottom);
433	points[1] = BPoint(centerPoint(frame).x, frame.top);
434	points[2] = BPoint(frame.right, frame.bottom);
435	view->FillTriangle(points[0], points[1], points[2], gradient);
436}
437
438static void testFillTriangleGradientDiamond(BView* view, BRect frame)
439{
440	BGradientDiamond gradient(0, 10);
441	gradient.AddColor(kRed, 0);
442	gradient.AddColor(kBlue, 255);
443	frame.InsetBy(2, 2);
444	BPoint points[3];
445	points[0] = BPoint(frame.left, frame.bottom);
446	points[1] = BPoint(centerPoint(frame).x, frame.top);
447	points[2] = BPoint(frame.right, frame.bottom);
448	view->FillTriangle(points[0], points[1], points[2], gradient);
449}
450
451static void testFillTriangleGradientConic(BView* view, BRect frame)
452{
453	BGradientConic gradient(0, 0, 10);
454	gradient.AddColor(kRed, 0);
455	gradient.AddColor(kBlue, 255);
456	frame.InsetBy(2, 2);
457	BPoint points[3];
458	points[0] = BPoint(frame.left, frame.bottom);
459	points[1] = BPoint(centerPoint(frame).x, frame.top);
460	points[2] = BPoint(frame.right, frame.bottom);
461	view->FillTriangle(points[0], points[1], points[2], gradient);
462}
463
464static void testStrokeTriangle(BView *view, BRect frame)
465{
466	frame.InsetBy(2, 2);
467	BPoint points[3];
468	points[0] = BPoint(frame.left, frame.bottom);
469	points[1] = BPoint(centerPoint(frame).x, frame.top);
470	points[2] = BPoint(frame.right, frame.bottom);
471	view->StrokeTriangle(points[0], points[1], points[2]);
472}
473
474static void testStrokeLine(BView *view, BRect frame)
475{
476	frame.InsetBy(2, 2);
477	view->StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.top));
478
479	frame.top += 2;
480	frame.bottom -= 2;
481	view->StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.bottom));
482
483	frame.bottom += 2;;
484	frame.top = frame.bottom;
485	view->StrokeLine(BPoint(frame.right, frame.top), BPoint(frame.left, frame.top));
486}
487
488static void testFillShape(BView *view, BRect frame)
489{
490	frame.InsetBy(2, 2);
491	BShape shape;
492	shape.MoveTo(BPoint(frame.left, frame.bottom));
493	shape.LineTo(BPoint(frame.right, frame.top));
494	shape.LineTo(BPoint(frame.left, frame.top));
495	shape.LineTo(BPoint(frame.right, frame.bottom));
496	view->FillShape(&shape);
497}
498
499static void testStrokeShape(BView *view, BRect frame)
500{
501	frame.InsetBy(2, 2);
502	BShape shape;
503	shape.MoveTo(BPoint(frame.left, frame.bottom));
504	shape.LineTo(BPoint(frame.right, frame.top));
505	shape.LineTo(BPoint(frame.left, frame.top));
506	shape.LineTo(BPoint(frame.right, frame.bottom));
507	view->StrokeShape(&shape);
508}
509
510static void testRecordPicture(BView *view, BRect frame)
511{
512	BPicture *picture = new BPicture();
513	view->BeginPicture(picture);
514	view->FillRect(frame);
515	view->EndPicture();
516	delete picture;
517}
518
519static void testRecordAndPlayPicture(BView *view, BRect frame)
520{
521	BPicture *picture = new BPicture();
522	view->BeginPicture(picture);
523	frame.InsetBy(2, 2);
524	view->FillRect(frame);
525	view->EndPicture();
526	view->DrawPicture(picture);
527	delete picture;
528}
529
530static void testRecordAndPlayPictureWithOffset(BView *view, BRect frame)
531{
532	BPicture *picture = new BPicture();
533	view->BeginPicture(picture);
534	frame.InsetBy(frame.Width() / 4, frame.Height() / 4);
535	frame.OffsetTo(0, 0);
536	view->FillRect(frame);
537	view->EndPicture();
538
539	view->DrawPicture(picture, BPoint(10, 10));
540	// color of picture should not change
541	view->SetLowColor(kGreen);
542	view->SetLowColor(kRed);
543	view->DrawPicture(picture, BPoint(0, 0));
544	delete picture;
545}
546
547static void testAppendToPicture(BView *view, BRect frame)
548{
549	frame.InsetBy(2, 2);
550	view->BeginPicture(new BPicture());
551	view->FillRect(frame);
552	BPicture* picture = view->EndPicture();
553	if (picture == NULL)
554		return;
555
556	frame.InsetBy(2, 2);
557	view->AppendToPicture(picture);
558	view->SetHighColor(kRed);
559	view->FillRect(frame);
560	if (view->EndPicture() != picture)
561		return;
562
563	view->DrawPicture(picture);
564	delete picture;
565}
566
567static void testDrawScaledPicture(BView* view, BRect frame)
568{
569	view->BeginPicture(new BPicture());
570	view->FillRect(BRect(0, 0, 15, 15));
571	BPicture* picture = view->EndPicture();
572
573	// first unscaled at left, top
574	view->DrawPicture(picture, BPoint(2, 2));
575
576	// draw scaled at middle top
577	view->SetScale(0.5);
578	// the drawing offset must be scaled too!
579	view->DrawPicture(picture, BPoint(frame.Width(), 4));
580
581	delete picture;
582}
583
584static void testLineArray(BView *view, BRect frame)
585{
586	frame.InsetBy(2, 2);
587	view->BeginLineArray(3);
588	view->AddLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.top), kBlack);
589
590	frame.top += 2;
591	frame.bottom -= 2;
592	view->AddLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.bottom), kRed);
593
594	frame.bottom += 2;;
595	frame.top = frame.bottom;
596	view->AddLine(BPoint(frame.right, frame.top), BPoint(frame.left, frame.top), kGreen);
597
598	view->EndLineArray();
599}
600
601static void testInvertRect(BView *view, BRect frame)
602{
603	frame.InsetBy(2, 2);
604	view->InvertRect(frame);
605}
606
607static void testInvertRectSetDrawingMode(BView *view, BRect frame)
608{
609	view->SetDrawingMode(B_OP_ALPHA);
610	view->SetHighColor(128, 128, 128, 128);
611	frame.InsetBy(2, 2);
612	view->InvertRect(frame);
613	frame.InsetBy(10, 10);
614	view->FillRect(frame, B_SOLID_HIGH);
615}
616
617static bool isBorder(int32 x, int32 y, int32 width, int32 height) {
618	return x == 0 || y == 0 || x == width - 1 || y == height - 1;
619}
620
621static void fillBitmap(BBitmap &bitmap) {
622	int32 height = bitmap.Bounds().IntegerHeight()+1;
623	int32 width = bitmap.Bounds().IntegerWidth()+1;
624	for (int32 y = 0; y < height; y ++) {
625		for (int32 x = 0; x < width; x ++) {
626			char *pixel = (char*)bitmap.Bits();
627			pixel += bitmap.BytesPerRow() * y + 4 * x;
628			if (isBorder(x, y, width, height)) {
629				// fill with green
630				pixel[0] = 255;
631				pixel[1] = 0;
632				pixel[2] = 255;
633				pixel[3] = 0;
634			} else  {
635				// fill with blue
636				pixel[0] = 255;
637				pixel[1] = 0;
638				pixel[2] = 0;
639				pixel[3] = 255;
640			}
641		}
642	}
643}
644
645static void testDrawBitmap(BView *view, BRect frame) {
646	BBitmap bitmap(frame, B_RGBA32);
647	fillBitmap(bitmap);
648	view->DrawBitmap(&bitmap, BPoint(0, 0));
649}
650
651static void testDrawBitmapAtPoint(BView *view, BRect frame) {
652	frame.InsetBy(2, 2);
653
654	BRect bounds(frame);
655	bounds.OffsetTo(0, 0);
656	bounds.right /= 2;
657	bounds.bottom /= 2;
658
659	BBitmap bitmap(bounds, B_RGBA32);
660	fillBitmap(bitmap);
661	view->DrawBitmap(&bitmap, centerPoint(frame));
662}
663
664static void testDrawBitmapAtRect(BView *view, BRect frame) {
665	BRect bounds(frame);
666	BBitmap bitmap(bounds, B_RGBA32);
667	fillBitmap(bitmap);
668	frame.InsetBy(2, 2);
669	view->DrawBitmap(&bitmap, frame);
670}
671
672static void testDrawLargeBitmap(BView *view, BRect frame) {
673	BRect bounds(frame);
674	bounds.OffsetTo(0, 0);
675	bounds.right *= 4;
676	bounds.bottom *= 4;
677	BBitmap bitmap(bounds, B_RGBA32);
678	fillBitmap(bitmap);
679	frame.InsetBy(2, 2);
680	view->DrawBitmap(&bitmap, frame);
681}
682
683static void testConstrainClippingRegion(BView *view, BRect frame)
684{
685	frame.InsetBy(2, 2);
686	// draw background
687	view->SetHighColor(kRed);
688	view->FillRect(frame);
689
690	frame.InsetBy(1, 1);
691	BRegion region(frame);
692	BRect r(frame);
693	r.InsetBy(r.IntegerWidth() / 4, r.IntegerHeight() / 4);
694	region.Exclude(r);
695	view->ConstrainClippingRegion(&region);
696
697	frame.InsetBy(-1, -1);
698	view->SetHighColor(kBlack);
699	view->FillRect(frame);
700	// a filled black rectangle with a red one pixel border
701	// and inside a red rectangle should be drawn.
702}
703
704static void testClipToPicture(BView *view, BRect frame)
705{
706	frame.InsetBy(2, 2);
707	view->BeginPicture(new BPicture());
708	view->FillEllipse(frame);
709	BPicture *picture = view->EndPicture();
710	if (picture == NULL)
711		return;
712
713	view->ClipToPicture(picture);
714	delete picture;
715
716	view->FillRect(frame);
717	// black ellipse should be drawn
718}
719
720static void testClipToInversePicture(BView *view, BRect frame)
721{
722	frame.InsetBy(2, 2);
723
724	view->BeginPicture(new BPicture());
725	view->FillEllipse(frame);
726	BPicture *picture = view->EndPicture();
727	if (picture == NULL)
728		return;
729
730	view->ClipToInversePicture(picture);
731	delete picture;
732
733	view->FillRect(frame);
734	// white ellipse inside a black rectangle
735}
736
737static void testSetPenSize(BView *view, BRect frame)
738{
739	frame.InsetBy(8, 2);
740	float x = centerPoint(frame).x;
741
742	view->StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.top));
743
744	frame.OffsetBy(0, 5);
745	view->SetPenSize(1);
746	view->StrokeLine(BPoint(frame.left, frame.top), BPoint(x, frame.top));
747	view->SetPenSize(0);
748	view->StrokeLine(BPoint(x+1, frame.top), BPoint(frame.right, frame.top));
749
750	frame.OffsetBy(0, 5);
751	view->SetPenSize(1);
752	view->StrokeLine(BPoint(frame.left, frame.top), BPoint(x, frame.top));
753	view->SetPenSize(2);
754	view->StrokeLine(BPoint(x+1, frame.top), BPoint(frame.right, frame.top));
755
756	frame.OffsetBy(0, 5);
757	view->SetPenSize(1);
758	view->StrokeLine(BPoint(frame.left, frame.top), BPoint(x, frame.top));
759	view->SetPenSize(3);
760	view->StrokeLine(BPoint(x+1, frame.top), BPoint(frame.right, frame.top));
761
762	frame.OffsetBy(0, 5);
763	view->SetPenSize(1);
764	view->StrokeLine(BPoint(frame.left, frame.top), BPoint(x, frame.top));
765	view->SetPenSize(4);
766	view->StrokeLine(BPoint(x+1, frame.top), BPoint(frame.right, frame.top));
767}
768
769static void testSetPenSize2(BView *view, BRect frame)
770{
771	// test if pen size is scaled too
772	frame.InsetBy(2, 2);
773	frame.OffsetBy(0, 5);
774	view->SetPenSize(4);
775	view->StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.top));
776	view->SetScale(0.5);
777	view->StrokeLine(BPoint(frame.left + 2, frame.bottom), BPoint(frame.right + 2, frame.bottom));
778
779	// black line from left to right, 4 pixel size
780	// below black line with half the length of the first one
781	// and 2 pixel size
782}
783
784static void testPattern(BView *view, BRect frame)
785{
786	frame.InsetBy(2, 2);
787	int x = frame.IntegerWidth() / 3;
788	frame.right = frame.left + x - 2;
789		// -2 for an empty pixel row between
790		// filled rectangles
791
792	view->SetLowColor(kGreen);
793	view->SetHighColor(kRed);
794
795	view->FillRect(frame, B_SOLID_HIGH);
796
797	frame.OffsetBy(x, 0);
798	view->FillRect(frame, B_MIXED_COLORS);
799
800	frame.OffsetBy(x, 0);
801	view->FillRect(frame, B_SOLID_LOW);
802}
803
804static void testSetOrigin(BView *view, BRect frame)
805{
806	BPoint origin = view->Origin();
807	BPoint center = centerPoint(frame);
808	view->SetOrigin(center);
809
810	BRect r(0, 0, center.x, center.y);
811	view->SetHighColor(kBlue);
812	view->FillRect(r);
813
814	view->SetOrigin(origin);
815	view->SetHighColor(kRed);
816	view->FillRect(r);
817
818	// red rectangle in left, top corner
819	// blue rectangle in right, bottom corner
820	// the red rectangle overwrites the
821	// top, left pixel of the blue rectangle
822}
823
824static void testSetOrigin2(BView *view, BRect frame)
825{
826	BPoint center = centerPoint(frame);
827	BRect r(0, 0, center.x, center.y);
828	view->SetOrigin(center);
829	view->PushState();
830		view->SetOrigin(BPoint(-center.x, 0));
831		view->FillRect(r);
832	view->PopState();
833	// black rectangle in left, bottom corner
834}
835
836static void testSetScale(BView *view, BRect frame)
837{
838	view->SetScale(0.5);
839	view->FillRect(frame);
840	// black rectangle in left, top corner
841}
842
843static void testSetScale2(BView *view, BRect frame)
844{
845	view->SetScale(0.5);
846	view->PushState();
847		view->SetScale(0.5);
848		view->FillRect(frame);
849	view->PopState();
850	// black rectangle in left, top corner
851	// with half the size of the rectangle
852	// from test testSetScaling
853}
854
855static void testSetScale3(BView *view, BRect frame)
856{
857	view->SetScale(0.5);
858	view->PushState();
859		// if the second scale value differs slightly
860		// the bug under BeOS R5 in testSetScale2
861		// does not occur
862		view->SetScale(0.5000001);
863		view->FillRect(frame);
864	view->PopState();
865	// black rectangle in left, top corner
866	// with half the size of the rectangle
867	// from test testSetScaling
868}
869
870static void testSetOriginAndScale(BView *view, BRect frame)
871{
872	frame.InsetBy(2, 2);
873	BPoint center = centerPoint(frame);
874
875	BRect r(0, 0, frame.IntegerWidth() / 2, frame.IntegerHeight() / 2);
876	view->SetOrigin(center);
877	view->FillRect(r);
878
879	view->SetScale(0.5);
880	view->SetHighColor(kRed);
881	view->FillRect(r);
882}
883
884static void testSetOriginAndScale2(BView *view, BRect frame)
885{
886	frame.InsetBy(2, 2);
887	BPoint center = centerPoint(frame);
888
889	BRect r(0, 0, frame.IntegerWidth() / 2, frame.IntegerHeight() / 2);
890	view->SetOrigin(center);
891	view->FillRect(r);
892
893	view->SetScale(0.5);
894	view->SetHighColor(kRed);
895	view->FillRect(r);
896
897	view->SetOrigin(0, 0);
898	view->SetHighColor(kGreen);
899	view->FillRect(r);
900}
901
902static void testSetOriginAndScale3(BView *view, BRect frame)
903{
904	frame.InsetBy(2, 2);
905	BPoint center = centerPoint(frame);
906
907	BRect r(0, 0, frame.IntegerWidth() / 2, frame.IntegerHeight() / 2);
908	view->SetOrigin(center);
909	view->FillRect(r);
910
911	view->SetScale(0.5);
912	view->SetHighColor(kRed);
913	view->FillRect(r);
914
915	view->SetScale(0.25);
916	view->SetHighColor(kGreen);
917	view->FillRect(r);
918}
919
920static void testSetOriginAndScale4(BView *view, BRect frame)
921{
922	frame.InsetBy(2, 2);
923	BPoint center = centerPoint(frame);
924
925	BRect r(0, 0, frame.IntegerWidth() / 2, frame.IntegerHeight() / 2);
926	view->SetOrigin(center);
927	view->FillRect(r);
928
929	view->SetScale(0.5);
930	view->SetHighColor(kRed);
931	view->FillRect(r);
932
933	view->PushState();
934		//
935		view->SetOrigin(center.x+1, center.y);
936			// +1 to work around BeOS bug
937			// where setting the origin has no
938			// effect if it is the same as
939			// the previous value althou
940			// it is from the "outer" coordinate
941			// system
942		view->SetHighColor(kGreen);
943		view->FillRect(r);
944	view->PopState();
945}
946
947static void testSetOriginAndScale5(BView *view, BRect frame)
948{
949	frame.InsetBy(2, 2);
950	BPoint center = centerPoint(frame);
951
952	BRect r(0, 0, frame.IntegerWidth() / 2, frame.IntegerHeight() / 2);
953	view->SetOrigin(center);
954	view->FillRect(r);
955
956	view->SetScale(0.5);
957	view->SetHighColor(kRed);
958	view->FillRect(r);
959
960	view->PushState();
961	view->SetScale(0.75);
962	view->SetHighColor(kGreen);
963	view->FillRect(r);
964	view->PopState();
965}
966
967static void testSetFontSize(BView *view, BRect frame)
968{
969	frame.InsetBy(2, 2);
970	int size = frame.IntegerHeight() / 3;
971
972	frame.OffsetBy(0, size);
973	view->MovePenTo(BPoint(frame.left, frame.top));
974	view->SetFontSize(size);
975	view->DrawString("Haiku");
976
977	size *= 2;
978	frame.OffsetBy(0, size);
979	view->MovePenTo(BPoint(frame.left, frame.top));
980	view->SetFontSize(size);
981	view->DrawString("Haiku");
982}
983
984static void testSetFontFamilyAndStyle(BView *view, BRect frame)
985{
986	view->DrawString("This is a test", BPoint(2, 6));
987
988	BFont font;
989	view->GetFont(&font);
990
991	int32 families = count_font_families();
992	font_family familyName;
993	get_font_family(families - 1, &familyName);
994
995	int32 styles = count_font_styles(familyName);
996	font_style styleName;
997	get_font_style(familyName, styles - 1, &styleName);
998	font.SetFamilyAndStyle(familyName, styleName);
999	view->SetFont(&font);
1000	view->DrawString( "This is a test", BPoint(2, 19));
1001}
1002
1003static void testSetDrawingMode(BView *view, BRect frame)
1004{
1005	frame.InsetBy(2, 2);
1006	view->StrokeLine(frame.LeftTop(), frame.RightBottom());
1007	view->StrokeLine(frame.LeftBottom(), frame.RightTop());
1008	view->SetDrawingMode(B_OP_ALPHA);
1009	rgb_color color = kRed;
1010	color.alpha = 127;
1011	view->SetHighColor(color);
1012	view->FillRect(frame, B_SOLID_HIGH);
1013}
1014
1015static void testPushPopState(BView *view, BRect frame)
1016{
1017	frame.InsetBy(2, 2);
1018	view->SetHighColor(kGreen);
1019	view->PushState();
1020	view->SetHighColor(kRed);
1021	view->PopState();
1022
1023	view->FillRect(frame, B_SOLID_HIGH);
1024}
1025
1026static void testFontRotation(BView* view, BRect frame)
1027{
1028	BFont font;
1029	view->GetFont(&font);
1030
1031	font.SetRotation(90);
1032	view->SetFont(&font, B_FONT_ROTATION);
1033	view->DrawString("This is a test!", BPoint(frame.Width() / 2, frame.bottom - 3));
1034
1035	view->GetFont(&font);
1036	if (font.Rotation() != 90.0)
1037		fprintf(stderr, "Error: Rotation is %f but should be 90.0\n", font.Rotation());
1038}
1039
1040
1041static void testClipToRect(BView* view, BRect frame)
1042{
1043	BRect clipped = frame;
1044	clipped.InsetBy(5, 5);
1045
1046	view->ClipToRect(clipped);
1047
1048	view->FillRect(frame);
1049}
1050
1051
1052static void testClipToInverseRect(BView* view, BRect frame)
1053{
1054	BRect clipped = frame;
1055	clipped.InsetBy(5, 5);
1056
1057	view->ClipToInverseRect(clipped);
1058
1059	view->FillRect(frame);
1060}
1061
1062
1063static void testClipToShape(BView* view, BRect frame)
1064{
1065	frame.InsetBy(2, 2);
1066	BShape shape;
1067	shape.MoveTo(BPoint(frame.left, frame.bottom));
1068	shape.LineTo(BPoint(frame.right, frame.top));
1069	shape.LineTo(BPoint(frame.left, frame.top));
1070	shape.LineTo(BPoint(frame.right, frame.bottom));
1071	view->ClipToShape(&shape);
1072
1073	view->FillRect(frame);
1074}
1075
1076
1077static void testClipToInverseShape(BView* view, BRect frame)
1078{
1079	frame.InsetBy(2, 2);
1080	BShape shape;
1081	shape.MoveTo(BPoint(frame.left, frame.bottom));
1082	shape.LineTo(BPoint(frame.right, frame.top));
1083	shape.LineTo(BPoint(frame.left, frame.top));
1084	shape.LineTo(BPoint(frame.right, frame.bottom));
1085	view->ClipToInverseShape(&shape);
1086
1087	view->FillRect(frame);
1088}
1089
1090
1091// TODO
1092// - blending mode
1093// - line mode
1094// - push/pop state
1095// - move pen
1096// - set font
1097
1098
1099TestCase gTestCases[] = {
1100	{ "Test No Operation", testNoOp },
1101	{ "Test DrawChar", testDrawChar },
1102	{ "Test Draw String", testDrawString },
1103	{ "Test Draw String With Length", testDrawStringWithLength },
1104	{ "Test Draw String With Offsets", testDrawStringWithOffsets },
1105	{ "Test Draw String Without Position", testDrawStringWithoutPosition },
1106	{ "Test FillArc", testFillArc },
1107	{ "Test StrokeArc", testStrokeArc },
1108	// testFillBezier fails under BeOS because the
1109	// direct draw version is not correct
1110	{ "Test FillBezier", testFillBezier },
1111	{ "Test StrokeBezier", testStrokeBezier },
1112	{ "Test FillEllipse", testFillEllipse },
1113	{ "Test StrokeEllipse", testStrokeEllipse },
1114	{ "Test FillPolygon", testFillPolygon },
1115	{ "Test StrokePolygon", testStrokePolygon },
1116	{ "Test FillRect", testFillRect },
1117	{ "Test FillRectGradientLinear", testFillRectGradientLinear },
1118	{ "Test FillRectGradientRadial", testFillRectGradientRadial },
1119	{ "Test FillRectGradientRadialFocus", testFillRectGradientRadialFocus },
1120	{ "Test FillRectGradientDiamond", testFillRectGradientDiamond },
1121	{ "Test FillRectGradientConic", testFillRectGradientConic },
1122	{ "Test StrokeRect", testStrokeRect },
1123	{ "Test FillRegion", testFillRegion },
1124	{ "Test FillRegionGradientLinear", testFillRegionGradientLinear },
1125	{ "Test FillRegionGradientRadial", testFillRegionGradientRadial },
1126	{ "Test FillRegionGradientRadialFocus", testFillRegionGradientRadialFocus },
1127	{ "Test FillRegionGradientDiamond", testFillRegionGradientDiamond },
1128	{ "Test FillRegionGradientConic", testFillRegionGradientConic },
1129	{ "Test FillRoundRect", testFillRoundRect },
1130	{ "Test FillRoundRectGradientLinear", testFillRoundRectGradientLinear },
1131	{ "Test FillRoundRectGradientRadial", testFillRoundRectGradientRadial },
1132	{ "Test FillRoundRectGradientRadialFocus", testFillRoundRectGradientRadialFocus },
1133	{ "Test FillRoundRectGradientDiamond", testFillRoundRectGradientDiamond },
1134	{ "Test FillRoundRectGradientConic", testFillRoundRectGradientConic },
1135	{ "Test StrokeRoundRect", testStrokeRoundRect },
1136	{ "Test FillTriangle", testFillTriangle },
1137	{ "Test FillTriangleGradientLinear", testFillTriangleGradientLinear },
1138	{ "Test FillTriangleGradientRadial", testFillTriangleGradientRadial },
1139	{ "Test FillTriangleGradientRadialFocus", testFillTriangleGradientRadialFocus },
1140	{ "Test FillTriangleGradientDiamond", testFillTriangleGradientDiamond },
1141	{ "Test FillTriangleGradientConic", testFillTriangleGradientConic },
1142	{ "Test StrokeTriangle", testStrokeTriangle },
1143	{ "Test StrokeLine", testStrokeLine },
1144	{ "Test FillShape", testFillShape },
1145	{ "Test StrokeShape", testStrokeShape },
1146	{ "Test Record Picture", testRecordPicture },
1147	{ "Test Record And Play Picture", testRecordAndPlayPicture },
1148	{ "Test Record And Play Picture With Offset", testRecordAndPlayPictureWithOffset },
1149	{ "Test AppendToPicture", testAppendToPicture },
1150	{ "Test Draw Scaled Picture", testDrawScaledPicture },
1151	{ "Test LineArray", testLineArray },
1152	{ "Test InvertRect", testInvertRect },
1153	{ "Test InvertRectSetDrawingMode", testInvertRectSetDrawingMode },
1154	{ "Test DrawBitmap", testDrawBitmap },
1155	{ "Test DrawBitmapAtPoint", testDrawBitmapAtPoint },
1156	{ "Test DrawBitmapAtRect", testDrawBitmapAtRect },
1157	{ "Test DrawLargeBitmap", testDrawLargeBitmap },
1158	{ "Test ConstrainClippingRegion", testConstrainClippingRegion },
1159	{ "Test ClipToPicture", testClipToPicture },
1160	{ "Test ClipToInversePicture", testClipToInversePicture },
1161	{ "Test ClipToRect", testClipToRect },
1162	{ "Test ClipToInverseRect", testClipToInverseRect },
1163	{ "Test ClipToShape", testClipToShape },
1164	{ "Test ClipToInverseShape", testClipToInverseShape },
1165	{ "Test SetPenSize", testSetPenSize },
1166	{ "Test SetPenSize2", testSetPenSize2 },
1167	{ "Test Pattern", testPattern },
1168	{ "Test SetOrigin", testSetOrigin },
1169	{ "Test SetOrigin2", testSetOrigin2 },
1170	{ "Test SetScale", testSetScale },
1171	// testSetScale2 fails under BeOS. The picture versions of the
1172	// rectangle are twice as large as the direct draw version
1173	{ "Test SetScale2", testSetScale2 },
1174	{ "Test SetScale3", testSetScale3 },
1175	{ "Test SetOriginAndScale", testSetOriginAndScale },
1176	{ "Test SetOriginAndScale2", testSetOriginAndScale2 },
1177	{ "Test SetOriginAndScale3", testSetOriginAndScale3 },
1178	{ "Test SetOriginAndScale4", testSetOriginAndScale4 },
1179	{ "Test SetOriginAndScale5", testSetOriginAndScale5 },
1180	{ "Test SetFontSize", testSetFontSize },
1181	{ "Test SetFontFamilyAndStyle", testSetFontFamilyAndStyle },
1182	{ "Test SetDrawingMode", testSetDrawingMode },
1183	{ "Test PushPopState", testPushPopState },
1184	{ "Test FontRotation", testFontRotation },
1185	{ NULL, NULL }
1186};
1187
1188
1189