Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / gm / beziereffects.cpp
1
2 /*
3  * Copyright 2013 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8
9 // This test only works with the GPU backend.
10
11 #include "gm.h"
12
13 #if SK_SUPPORT_GPU
14
15 #include "GrContext.h"
16 #include "GrPathUtils.h"
17 #include "GrTest.h"
18 #include "SkColorPriv.h"
19 #include "SkDevice.h"
20 #include "SkGeometry.h"
21
22 #include "effects/GrBezierEffect.h"
23
24 // Position & KLM line eq values. These are the vertex attributes for Bezier curves. The last value
25 // of the Vec4f is ignored.
26 namespace {
27 extern const GrVertexAttrib kAttribs[] = {
28     {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
29     {kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
30 };
31 }
32
33 static inline SkScalar eval_line(const SkPoint& p, const SkScalar lineEq[3], SkScalar sign) {
34     return sign * (lineEq[0] * p.fX + lineEq[1] * p.fY + lineEq[2]);
35 }
36
37 namespace skiagm {
38 /**
39  * This GM directly exercises effects that draw Bezier curves in the GPU backend.
40  */
41 class BezierCubicEffects : public GM {
42 public:
43     BezierCubicEffects() {
44         this->setBGColor(0xFFFFFFFF);
45     }
46
47 protected:
48     virtual SkString onShortName() SK_OVERRIDE {
49         return SkString("bezier_cubic_effects");
50     }
51
52     virtual SkISize onISize() SK_OVERRIDE {
53         return SkISize::Make(800, 800);
54     }
55
56     virtual uint32_t onGetFlags() const SK_OVERRIDE {
57         // This is a GPU-specific GM.
58         return kGPUOnly_Flag;
59     }
60
61
62     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
63         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
64         if (NULL == rt) {
65             return;
66         }
67         GrContext* context = rt->getContext();
68         if (NULL == context) {
69             return;
70         }
71
72         struct Vertex {
73             SkPoint fPosition;
74             float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
75         };
76
77         static const int kNumCubics = 15;
78         SkRandom rand;
79
80         // Mult by 3 for each edge effect type
81         int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumCubics*3)));
82         int numRows = SkScalarCeilToInt(SkIntToScalar(kNumCubics*3) / numCols);
83         SkScalar w = SkIntToScalar(rt->width()) / numCols;
84         SkScalar h = SkIntToScalar(rt->height()) / numRows;
85         int row = 0;
86         int col = 0;
87
88         for (int i = 0; i < kNumCubics; ++i) {
89             SkPoint baseControlPts[] = {
90                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
91                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
92                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
93                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
94             };
95             for(int edgeType = 0; edgeType < kGrEffectEdgeTypeCnt; ++edgeType) {
96                 SkAutoTUnref<GrEffect> effect;
97                 {   // scope to contain GrTestTarget
98                     GrTestTarget tt;
99                     context->getTestTarget(&tt);
100                     if (NULL == tt.target()) {
101                         continue;
102                     }
103                     GrEffectEdgeType et = (GrEffectEdgeType)edgeType;
104                     effect.reset(GrCubicEffect::Create(et, *tt.target()->caps()));
105                     if (!effect) {
106                         continue;
107                     }
108                 }
109
110                 SkScalar x = SkScalarMul(col, w);
111                 SkScalar y = SkScalarMul(row, h);
112                 SkPoint controlPts[] = {
113                     {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
114                     {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
115                     {x + baseControlPts[2].fX, y + baseControlPts[2].fY},
116                     {x + baseControlPts[3].fX, y + baseControlPts[3].fY}
117                 };
118                 SkPoint chopped[10];
119                 SkScalar klmEqs[9];
120                 SkScalar klmSigns[3];
121                 int cnt = GrPathUtils::chopCubicAtLoopIntersection(controlPts,
122                                                                    chopped,
123                                                                    klmEqs,
124                                                                    klmSigns);
125
126                 SkPaint ctrlPtPaint;
127                 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
128                 for (int i = 0; i < 4; ++i) {
129                     canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
130                 }
131
132                 SkPaint polyPaint;
133                 polyPaint.setColor(0xffA0A0A0);
134                 polyPaint.setStrokeWidth(0);
135                 polyPaint.setStyle(SkPaint::kStroke_Style);
136                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 4, controlPts, polyPaint);
137
138                 SkPaint choppedPtPaint;
139                 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
140
141                 for (int c = 0; c < cnt; ++c) {
142                     SkPoint* pts = chopped + 3 * c;
143
144                     for (int i = 0; i < 4; ++i) {
145                         canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
146                     }
147
148                     SkRect bounds;
149                     bounds.set(pts, 4);
150
151                     SkPaint boundsPaint;
152                     boundsPaint.setColor(0xff808080);
153                     boundsPaint.setStrokeWidth(0);
154                     boundsPaint.setStyle(SkPaint::kStroke_Style);
155                     canvas->drawRect(bounds, boundsPaint);
156
157                     Vertex verts[4];
158                     verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
159                                                   bounds.fRight, bounds.fBottom,
160                                                   sizeof(Vertex));
161                     for (int v = 0; v < 4; ++v) {
162                         verts[v].fKLM[0] = eval_line(verts[v].fPosition, klmEqs + 0, klmSigns[c]);
163                         verts[v].fKLM[1] = eval_line(verts[v].fPosition, klmEqs + 3, klmSigns[c]);
164                         verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
165                     }
166
167                     GrTestTarget tt;
168                     context->getTestTarget(&tt);
169                     SkASSERT(NULL != tt.target());
170                     GrDrawState* drawState = tt.target()->drawState();
171                     drawState->setVertexAttribs<kAttribs>(2);
172
173                     drawState->addCoverageEffect(effect, 1);
174                     drawState->setRenderTarget(rt);
175                     drawState->setColor(0xff000000);
176
177                     tt.target()->setVertexSourceToArray(verts, 4);
178                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
179                     tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
180                 }
181                 ++col;
182                 if (numCols == col) {
183                     col = 0;
184                     ++row;
185                 }
186             }
187         }
188     }
189
190 private:
191     typedef GM INHERITED;
192 };
193
194 //////////////////////////////////////////////////////////////////////////////
195
196 /**
197  * This GM directly exercises effects that draw Bezier curves in the GPU backend.
198  */
199 class BezierConicEffects : public GM {
200 public:
201     BezierConicEffects() {
202         this->setBGColor(0xFFFFFFFF);
203     }
204
205 protected:
206     virtual SkString onShortName() SK_OVERRIDE {
207         return SkString("bezier_conic_effects");
208     }
209
210     virtual SkISize onISize() SK_OVERRIDE {
211         return SkISize::Make(800, 800);
212     }
213
214     virtual uint32_t onGetFlags() const SK_OVERRIDE {
215         // This is a GPU-specific GM.
216         return kGPUOnly_Flag;
217     }
218
219
220     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
221         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
222         if (NULL == rt) {
223             return;
224         }
225         GrContext* context = rt->getContext();
226         if (NULL == context) {
227             return;
228         }
229
230         struct Vertex {
231             SkPoint fPosition;
232             float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
233         };
234
235         static const int kNumConics = 10;
236         SkRandom rand;
237
238         // Mult by 3 for each edge effect type
239         int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
240         int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
241         SkScalar w = SkIntToScalar(rt->width()) / numCols;
242         SkScalar h = SkIntToScalar(rt->height()) / numRows;
243         int row = 0;
244         int col = 0;
245
246         for (int i = 0; i < kNumConics; ++i) {
247             SkPoint baseControlPts[] = {
248                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
249                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
250                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
251             };
252             SkScalar weight = rand.nextRangeF(0.f, 2.f);
253             for(int edgeType = 0; edgeType < kGrEffectEdgeTypeCnt; ++edgeType) {
254                 SkAutoTUnref<GrEffect> effect;
255                 {   // scope to contain GrTestTarget
256                     GrTestTarget tt;
257                     context->getTestTarget(&tt);
258                     if (NULL == tt.target()) {
259                         continue;
260                     }
261                     GrEffectEdgeType et = (GrEffectEdgeType)edgeType;
262                     effect.reset(GrConicEffect::Create(et, *tt.target()->caps()));
263                     if (!effect) {
264                         continue;
265                     }
266                 }
267
268                 SkScalar x = SkScalarMul(col, w);
269                 SkScalar y = SkScalarMul(row, h);
270                 SkPoint controlPts[] = {
271                     {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
272                     {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
273                     {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
274                 };
275                 SkConic dst[4];
276                 SkScalar klmEqs[9];
277                 int cnt = chop_conic(controlPts, dst, weight);
278                 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
279
280                 SkPaint ctrlPtPaint;
281                 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
282                 for (int i = 0; i < 3; ++i) {
283                     canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
284                 }
285
286                 SkPaint polyPaint;
287                 polyPaint.setColor(0xffA0A0A0);
288                 polyPaint.setStrokeWidth(0);
289                 polyPaint.setStyle(SkPaint::kStroke_Style);
290                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
291
292                 SkPaint choppedPtPaint;
293                 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
294
295                 for (int c = 0; c < cnt; ++c) {
296                     SkPoint* pts = dst[c].fPts;
297                     for (int i = 0; i < 3; ++i) {
298                         canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
299                     }
300
301                     SkRect bounds;
302                     //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
303                     //bounds.set(bPts, 2);
304                     bounds.set(pts, 3);
305
306                     SkPaint boundsPaint;
307                     boundsPaint.setColor(0xff808080);
308                     boundsPaint.setStrokeWidth(0);
309                     boundsPaint.setStyle(SkPaint::kStroke_Style);
310                     canvas->drawRect(bounds, boundsPaint);
311
312                     Vertex verts[4];
313                     verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
314                                                   bounds.fRight, bounds.fBottom,
315                                                   sizeof(Vertex));
316                     for (int v = 0; v < 4; ++v) {
317                         verts[v].fKLM[0] = eval_line(verts[v].fPosition, klmEqs + 0, 1.f);
318                         verts[v].fKLM[1] = eval_line(verts[v].fPosition, klmEqs + 3, 1.f);
319                         verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
320                     }
321
322                     GrTestTarget tt;
323                     context->getTestTarget(&tt);
324                     SkASSERT(NULL != tt.target());
325                     GrDrawState* drawState = tt.target()->drawState();
326                     drawState->setVertexAttribs<kAttribs>(2);
327
328                     drawState->addCoverageEffect(effect, 1);
329                     drawState->setRenderTarget(rt);
330                     drawState->setColor(0xff000000);
331
332                     tt.target()->setVertexSourceToArray(verts, 4);
333                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
334                     tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
335                 }
336                 ++col;
337                 if (numCols == col) {
338                     col = 0;
339                     ++row;
340                 }
341             }
342         }
343     }
344
345 private:
346     // Uses the max curvature function for quads to estimate
347     // where to chop the conic. If the max curvature is not
348     // found along the curve segment it will return 1 and
349     // dst[0] is the original conic. If it returns 2 the dst[0]
350     // and dst[1] are the two new conics.
351     int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
352         SkScalar t = SkFindQuadMaxCurvature(src);
353         if (t == 0) {
354             if (dst) {
355                 dst[0].set(src, weight);
356             }
357             return 1;
358         } else {
359             if (dst) {
360                 SkConic conic;
361                 conic.set(src, weight);
362                 conic.chopAt(t, dst);
363             }
364             return 2;
365         }
366     }
367
368     // Calls split_conic on the entire conic and then once more on each subsection.
369     // Most cases will result in either 1 conic (chop point is not within t range)
370     // or 3 points (split once and then one subsection is split again).
371     int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
372         SkConic dstTemp[2];
373         int conicCnt = split_conic(src, dstTemp, weight);
374         if (2 == conicCnt) {
375             int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
376             conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
377         } else {
378             dst[0] = dstTemp[0];
379         }
380         return conicCnt;
381     }
382
383     typedef GM INHERITED;
384 };
385
386 //////////////////////////////////////////////////////////////////////////////
387 /**
388  * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
389  */
390 class BezierQuadEffects : public GM {
391 public:
392     BezierQuadEffects() {
393         this->setBGColor(0xFFFFFFFF);
394     }
395
396 protected:
397     virtual SkString onShortName() SK_OVERRIDE {
398         return SkString("bezier_quad_effects");
399     }
400
401     virtual SkISize onISize() SK_OVERRIDE {
402         return SkISize::Make(800, 800);
403     }
404
405     virtual uint32_t onGetFlags() const SK_OVERRIDE {
406         // This is a GPU-specific GM.
407         return kGPUOnly_Flag;
408     }
409
410
411     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
412         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
413         if (NULL == rt) {
414             return;
415         }
416         GrContext* context = rt->getContext();
417         if (NULL == context) {
418             return;
419         }
420
421         struct Vertex {
422             SkPoint fPosition;
423             float   fUV[4]; // The last two values are ignored. The effect expects a vec4f.
424         };
425
426         static const int kNumQuads = 5;
427         SkRandom rand;
428
429         int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
430         int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
431         SkScalar w = SkIntToScalar(rt->width()) / numCols;
432         SkScalar h = SkIntToScalar(rt->height()) / numRows;
433         int row = 0;
434         int col = 0;
435
436         for (int i = 0; i < kNumQuads; ++i) {
437             SkPoint baseControlPts[] = {
438                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
439                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
440                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
441             };
442             for(int edgeType = 0; edgeType < kGrEffectEdgeTypeCnt; ++edgeType) {
443                 SkAutoTUnref<GrEffect> effect;
444                 {   // scope to contain GrTestTarget
445                     GrTestTarget tt;
446                     context->getTestTarget(&tt);
447                     if (NULL == tt.target()) {
448                         continue;
449                     }
450                     GrEffectEdgeType et = (GrEffectEdgeType)edgeType;
451                     effect.reset(GrQuadEffect::Create(et, *tt.target()->caps()));
452                     if (!effect) {
453                         continue;
454                     }
455                 }
456
457                 SkScalar x = SkScalarMul(col, w);
458                 SkScalar y = SkScalarMul(row, h);
459                 SkPoint controlPts[] = {
460                     {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
461                     {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
462                     {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
463                 };
464                 SkPoint chopped[5];
465                 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
466
467                 SkPaint ctrlPtPaint;
468                 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
469                 for (int i = 0; i < 3; ++i) {
470                     canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
471                 }
472
473                 SkPaint polyPaint;
474                 polyPaint.setColor(0xffA0A0A0);
475                 polyPaint.setStrokeWidth(0);
476                 polyPaint.setStyle(SkPaint::kStroke_Style);
477                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
478
479                 SkPaint choppedPtPaint;
480                 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
481
482                 for (int c = 0; c < cnt; ++c) {
483                     SkPoint* pts = chopped + 2 * c;
484
485                     for (int i = 0; i < 3; ++i) {
486                         canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
487                     }
488
489                     SkRect bounds;
490                     bounds.set(pts, 3);
491
492                     SkPaint boundsPaint;
493                     boundsPaint.setColor(0xff808080);
494                     boundsPaint.setStrokeWidth(0);
495                     boundsPaint.setStyle(SkPaint::kStroke_Style);
496                     canvas->drawRect(bounds, boundsPaint);
497
498                     Vertex verts[4];
499                     verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
500                                                   bounds.fRight, bounds.fBottom,
501                                                   sizeof(Vertex));
502
503                     GrPathUtils::QuadUVMatrix DevToUV(pts);
504                     DevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
505
506                     GrTestTarget tt;
507                     context->getTestTarget(&tt);
508                     SkASSERT(NULL != tt.target());
509                     GrDrawState* drawState = tt.target()->drawState();
510                     drawState->setVertexAttribs<kAttribs>(2);
511
512                     drawState->addCoverageEffect(effect, 1);
513                     drawState->setRenderTarget(rt);
514                     drawState->setColor(0xff000000);
515
516                     tt.target()->setVertexSourceToArray(verts, 4);
517                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
518                     tt.target()->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 4, 6);
519                 }
520                 ++col;
521                 if (numCols == col) {
522                     col = 0;
523                     ++row;
524                 }
525             }
526         }
527     }
528
529 private:
530     typedef GM INHERITED;
531 };
532
533 DEF_GM( return SkNEW(BezierCubicEffects); )
534 DEF_GM( return SkNEW(BezierConicEffects); )
535 DEF_GM( return SkNEW(BezierQuadEffects); )
536
537 }
538
539 #endif