blob: 97b4e8e3404c51063f609bb19af925a84974073e [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001#include "SampleCode.h"
2#include "SkView.h"
3#include "SkCanvas.h"
4#include "SkGradientShader.h"
5#include "SkGraphics.h"
6#include "SkImageDecoder.h"
7#include "SkPackBits.h"
8#include "SkPath.h"
9#include "SkPathMeasure.h"
10#include "SkRandom.h"
11#include "SkRegion.h"
12#include "SkShader.h"
13#include "SkUtils.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkColorPriv.h"
15#include "SkColorFilter.h"
16#include "SkTypeface.h"
17#include "SkAvoidXfermode.h"
18
19#define REPEAT_COUNT 1
20
21static const char gText[] = "Hamburgefons";
22
23static bool gDevKern;
24
25static void rand_text(char text[], SkRandom& rand, size_t count) {
26 for (size_t i = 0; i < count; i++) {
27 text[i] = rand.nextU() & 0x7F;
28 }
29}
30
31static SkScalar sum_widths(const SkScalar widths[], int count) {
32 SkScalar w = 0;
33 for (int i = 0; i < count; i++) {
34 w += widths[i];
35 }
36 return w;
37}
38
39static void test_measure(const SkPaint& paint) {
40 char text[256];
41 SkScalar widths[256];
42 SkRect rects[256];
43 SkRect bounds;
44 int count = 256;
45
46 SkRandom rand;
47
48 for (int i = 0; i < 100; i++) {
49 rand_text(text, rand, 256);
50 paint.getTextWidths(text, count, widths, NULL);
51 SkScalar tw0 = sum_widths(widths, count);
52 paint.getTextWidths(text, count, widths, rects);
53 SkScalar tw1 = sum_widths(widths, count);
54 SkASSERT(tw0 == tw1);
55
56 SkScalar w0 = paint.measureText(text, count, NULL);
57 SkScalar w1 = paint.measureText(text, count, &bounds);
58 SkASSERT(w0 == w1);
59 SkASSERT(w0 == tw0);
60
61 SkRect r = rects[0];
62 SkScalar x = 0;
63 for (int j = 1; j < count; j++) {
64 x += widths[j-1];
65 rects[j].offset(x, 0);
66 r.join(rects[j]);
67 }
68 SkASSERT(r == bounds);
69
70 if (r != bounds) {
71 printf("flags=%x i=%d [%g %g %g %g] [%g %g %g %g]\n",
72 paint.getFlags(), i,
73 SkScalarToFloat(r.fLeft),
74 SkScalarToFloat(r.fTop),
75 SkScalarToFloat(r.fRight),
76 SkScalarToFloat(r.fBottom),
77 SkScalarToFloat(bounds.fLeft),
78 SkScalarToFloat(bounds.fTop),
79 SkScalarToFloat(bounds.fRight),
80 SkScalarToFloat(bounds.fBottom));
81 }
82 }
83}
84
85static void test_measure() {
86 SkPaint paint;
87
88 for (int i = 0; i <= SkPaint::kAllFlags; i++) {
89 paint.setFlags(i);
90 test_measure(paint);
91 }
92}
93
94//////////////////////////////////////////////////////////////////////////////
95
96static void test_textBounds(SkCanvas* canvas) {
97// canvas->scale(SK_Scalar1/2, SK_Scalar1/2);
98
99// canvas->rotate(SkIntToScalar(30));
100
101 gDevKern = !gDevKern;
102
103 SkScalar x = SkIntToScalar(50);
104 SkScalar y = SkIntToScalar(150);
105 SkScalar w[100];
106 SkRect r[100], bounds;
107
108 SkPaint paint;
109 paint.setTextSize(SkIntToScalar(64));
110 paint.setAntiAlias(true);
111 paint.setDevKernText(gDevKern);
112
113 (void)paint.measureText(gText, strlen(gText), &bounds, NULL);
114 paint.setColor(SK_ColorGREEN);
115 bounds.offset(x, y);
116 canvas->drawRect(bounds, paint);
117
118 int count = paint.getTextWidths(gText, strlen(gText), w, r);
119
120 paint.setColor(SK_ColorRED);
121 for (int i = 0; i < count; i++) {
122 r[i].offset(x, y);
123 canvas->drawRect(r[i], paint);
124 x += w[i];
125 }
126 x = SkIntToScalar(50);
127 paint.setColor(gDevKern ? SK_ColorDKGRAY : SK_ColorBLACK);
128 canvas->drawText(gText, strlen(gText), x, y, paint);
129}
130
131static void create_src(SkBitmap* bitmap, SkBitmap::Config config) {
132 bitmap->setConfig(config, 100, 100);
133 bitmap->allocPixels();
134 bitmap->eraseColor(0);
135
136 SkCanvas canvas(*bitmap);
137 SkPaint paint;
138
139 paint.setAntiAlias(true);
140 canvas.drawCircle(SkIntToScalar(50), SkIntToScalar(50),
141 SkIntToScalar(50), paint);
142}
143
144static void blur(SkBitmap* dst, const SkBitmap& src, SkScalar radius) {
145 *dst = src;
146}
147
148static void test_bitmap_blur(SkCanvas* canvas) {
149 SkBitmap src, dst;
150
151 create_src(&src, SkBitmap::kARGB_8888_Config);
152 blur(&dst, src, SkIntToScalar(4));
153
154 SkPaint paint;
155
156 paint.setColor(SK_ColorRED);
157
158 canvas->drawBitmap(dst, SkIntToScalar(30), SkIntToScalar(60), &paint);
159}
160
161static SkScalar getpathlen(const SkPath& path) {
162 SkPathMeasure meas(path, false);
163 return meas.getLength();
164}
165
166static void test_textpathmatrix(SkCanvas* canvas) {
167 SkPaint paint;
168 SkPath path;
169 SkMatrix matrix;
170
171 path.moveTo(SkIntToScalar(200), SkIntToScalar(300));
172 path.quadTo(SkIntToScalar(400), SkIntToScalar(100),
173 SkIntToScalar(600), SkIntToScalar(300));
174
175 paint.setAntiAlias(true);
176
177 paint.setStyle(SkPaint::kStroke_Style);
178 canvas->drawPath(path, paint);
179 paint.setStyle(SkPaint::kFill_Style);
180 paint.setTextSize(SkIntToScalar(48));
181 paint.setTextAlign(SkPaint::kRight_Align);
182
183 const char* text = "Android";
184 size_t len = strlen(text);
185 SkScalar pathLen = getpathlen(path);
186
187 canvas->drawTextOnPath(text, len, path, NULL, paint);
188
189 paint.setColor(SK_ColorRED);
190 matrix.setScale(-SK_Scalar1, SK_Scalar1);
191 matrix.postTranslate(pathLen, 0);
192 canvas->drawTextOnPath(text, len, path, &matrix, paint);
193
194 paint.setColor(SK_ColorBLUE);
195 matrix.setScale(SK_Scalar1, -SK_Scalar1);
196 canvas->drawTextOnPath(text, len, path, &matrix, paint);
197
198 paint.setColor(SK_ColorGREEN);
199 matrix.setScale(-SK_Scalar1, -SK_Scalar1);
200 matrix.postTranslate(pathLen, 0);
201 canvas->drawTextOnPath(text, len, path, &matrix, paint);
202}
203
204class TextOnPathView : public SkView {
205public:
206 SkPath fPath;
207 SkScalar fHOffset;
208
209 TextOnPathView() {
210 SkRect r;
211 r.set(SkIntToScalar(100), SkIntToScalar(100),
212 SkIntToScalar(300), SkIntToScalar(300));
213 fPath.addOval(r);
214
215 fHOffset = SkIntToScalar(50);
216 }
217
218protected:
219 // overrides from SkEventSink
220 virtual bool onQuery(SkEvent* evt) {
221 if (SampleCode::TitleQ(*evt)) {
222 SampleCode::TitleR(evt, "Text On Path");
223 return true;
224 }
225 return this->INHERITED::onQuery(evt);
226 }
227
228 void drawBG(SkCanvas* canvas) {
229 canvas->drawColor(SK_ColorWHITE);
230#if 0
231 SkRect r;
232 SkPaint p;
233 SkRandom rand;
234 p.setAntiAlias(true);
235
236 for (int i = 0; i < 100; i++) {
237 SkScalar x = rand.nextUScalar1() * 300 + SkIntToScalar(50);
238 SkScalar y = rand.nextUScalar1() * 200 + SkIntToScalar(50);
239 SkScalar w = rand.nextUScalar1() * 10;
240 SkScalar h = rand.nextUScalar1() * 10;
241 r.set(x, y, x + w, y + h);
242 canvas->drawRect(r, p);
243 }
244
245 test_textBounds(canvas);
246// return;
247
248 SkBitmap bm;
249 if (SkImageDecoder::DecodeFile("/loading_tile.png",
250 &bm, SkBitmap::kRGB_565_Config, true))
251 canvas->drawBitmap(bm, 0, 0);
252#endif
253 }
254
255 virtual void onDraw(SkCanvas* canvas) {
256 this->drawBG(canvas);
257
258 SkPaint paint;
259
260 paint.setAntiAlias(true);
261 paint.setTextSize(SkIntToScalar(50));
262
263 for (int j = 0; j < REPEAT_COUNT; j++) {
264 SkScalar x = fHOffset;
265
266 paint.setColor(SK_ColorBLACK);
267 canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
268 x, paint.getTextSize()/2, paint);
269
270 paint.setColor(SK_ColorRED);
271 canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
272 x + SkIntToScalar(50), 0, paint);
273
274 paint.setColor(SK_ColorBLUE);
275 canvas->drawTextOnPathHV(gText, sizeof(gText)-1, fPath,
276 x + SkIntToScalar(100), -paint.getTextSize()/2, paint);
277 }
278
279 paint.setColor(SK_ColorGREEN);
280 paint.setStyle(SkPaint::kStroke_Style);
281 canvas->drawPath(fPath, paint);
282
283 canvas->translate(SkIntToScalar(200), 0);
284 test_textpathmatrix(canvas);
285
286 test_bitmap_blur(canvas);
287
288 if (REPEAT_COUNT > 1)
289 this->inval(NULL);
290 }
291
292 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) {
293 fHints += 1;
294 this->inval(NULL);
295 return this->INHERITED::onFindClickHandler(x, y);
296 }
297
298 virtual bool onClick(Click* click) {
299 return this->INHERITED::onClick(click);
300 }
301
302private:
303 int fHints;
304 typedef SkView INHERITED;
305};
306
307static const uint16_t gTest0[] = { 0, 0, 1, 1 };
308static const uint16_t gTest1[] = { 1, 2, 3, 4, 5, 6 };
309static const uint16_t gTest2[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
310static const uint16_t gTest3[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
311
312#include "SkRandom.h"
313static SkRandom gRand;
314static void rand_fill(uint16_t buffer[], int count) {
315 for (int i = 0; i < count; i++)
316 buffer[i] = (uint16_t)gRand.nextU();
317}
318
319static void test_pack16() {
320 static const struct {
321 const uint16_t* fSrc;
322 int fCount;
323 } gTests[] = {
324 { gTest0, SK_ARRAY_COUNT(gTest0) },
325 { gTest1, SK_ARRAY_COUNT(gTest1) },
326 { gTest2, SK_ARRAY_COUNT(gTest2) },
327 { gTest3, SK_ARRAY_COUNT(gTest3) }
328 };
329
330 for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); i++) {
331 uint8_t dst[100];
332 size_t dstSize = SkPackBits::Pack16(gTests[i].fSrc,
333 gTests[i].fCount, dst);
334 printf("Test[%d] orig size = %d, dst size = %d",
335 i, gTests[i].fCount, (int)dstSize);
336 uint16_t src[100];
337 int srcCount = SkPackBits::Unpack16(dst, dstSize, src);
338 printf(", src size = %d", srcCount);
339 bool match = gTests[i].fCount == srcCount && memcmp(gTests[i].fSrc, src,
340 gTests[i].fCount * sizeof(uint16_t)) == 0;
341 printf(", match = %d\n", match);
342 }
343
344 for (int n = 1000; n; n--) {
345 size_t size = 50;
346 uint16_t src[100], src2[100];
347 uint8_t dst[200];
348 rand_fill(src, size);
349
350 size_t dstSize = SkPackBits::Pack16(src, size, dst);
351 size_t maxSize = SkPackBits::ComputeMaxSize16(size);
352 SkASSERT(maxSize >= dstSize);
353
354 int srcCount = SkPackBits::Unpack16(dst, dstSize, src2);
355 SkASSERT(size == srcCount);
356 bool match = memcmp(src, src2, size * sizeof(uint16_t)) == 0;
357 SkASSERT(match);
358 }
359}
360
361static const uint8_t gTest80[] = { 0, 0, 1, 1 };
362static const uint8_t gTest81[] = { 1, 2, 3, 4, 5, 6 };
363static const uint8_t gTest82[] = { 0, 0, 0, 1, 2, 3, 3, 3 };
364static const uint8_t gTest83[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 0, 0, 1 };
365static const uint8_t gTest84[] = { 1, 0, 3, 0, 0, 0, 2, 1, 1, 2 };
366
367static void rand_fill(uint8_t buffer[], int count) {
368 for (int i = 0; i < count; i++)
369 buffer[i] = (uint8_t)((gRand.nextU() >> 8) & 0x3);
370}
371
372static void test_pack8() {
373 static const struct {
374 const uint8_t* fSrc;
375 int fCount;
376 } gTests[] = {
377 { gTest80, SK_ARRAY_COUNT(gTest80) },
378 { gTest81, SK_ARRAY_COUNT(gTest81) },
379 { gTest82, SK_ARRAY_COUNT(gTest82) },
380 { gTest83, SK_ARRAY_COUNT(gTest83) },
381 { gTest84, SK_ARRAY_COUNT(gTest84) }
382 };
383
384 for (size_t i = 4; i < SK_ARRAY_COUNT(gTests); i++) {
385 uint8_t dst[100];
386 size_t maxSize = SkPackBits::ComputeMaxSize8(gTests[i].fCount);
387 size_t dstSize = SkPackBits::Pack8(gTests[i].fSrc,
388 gTests[i].fCount, dst);
389 SkASSERT(dstSize <= maxSize);
390 printf("Test[%d] orig size = %d, dst size = %d", i,
391 gTests[i].fCount, (int)dstSize);
392 uint8_t src[100];
393 int srcCount = SkPackBits::Unpack8(dst, dstSize, src);
394 printf(", src size = %d", srcCount);
395 bool match = gTests[i].fCount == srcCount &&
396 memcmp(gTests[i].fSrc, src,
397 gTests[i].fCount * sizeof(uint8_t)) == 0;
398 printf(", match = %d\n", match);
399 }
400
401 for (size_t size = 1; size <= 512; size += 1) {
402 for (int n = 200; n; n--) {
403 uint8_t src[600], src2[600];
404 uint8_t dst[600];
405 rand_fill(src, size);
406
407 size_t dstSize = SkPackBits::Pack8(src, size, dst);
408 size_t maxSize = SkPackBits::ComputeMaxSize8(size);
409 SkASSERT(maxSize >= dstSize);
410
411 int srcCount = SkPackBits::Unpack8(dst, dstSize, src2);
412 SkASSERT(size == srcCount);
413 bool match = memcmp(src, src2, size * sizeof(uint8_t)) == 0;
414 SkASSERT(match);
415
416 for (int j = 0; j < 200; j++) {
417 size_t skip = gRand.nextU() % size;
418 size_t write = gRand.nextU() % size;
419 if (skip + write > size) {
420 write = size - skip;
421 }
422 SkPackBits::Unpack8(src, skip, write, dst);
423 bool match = memcmp(src, src2 + skip, write) == 0;
424 SkASSERT(match);
425 }
426 }
427 }
428}
429
430//////////////////////////////////////////////////////////////////////////////
431
432static SkView* MyFactory() {
433 static bool gOnce;
434 if (!gOnce) {
435// test_pack8();
436 gOnce = true;
437 }
438 return new TextOnPathView;
439}
440
441static SkViewRegister reg(MyFactory);
442