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