Update To 11.40.268.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), kGeometryProcessor_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 < kGrProcessorEdgeTypeCnt; ++edgeType) {
96                 SkAutoTUnref<GrGeometryProcessor> gp;
97                 {   // scope to contain GrTestTarget
98                     GrTestTarget tt;
99                     context->getTestTarget(&tt);
100                     if (NULL == tt.target()) {
101                         continue;
102                     }
103                     GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
104                     gp.reset(GrCubicEffect::Create(et, *tt.target()->caps()));
105                     if (!gp) {
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                     GrTestTarget tt;
158                     context->getTestTarget(&tt);
159                     SkASSERT(tt.target());
160
161                     GrDrawState* drawState = tt.target()->drawState();
162                     drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex));
163
164                     GrDrawTarget::AutoReleaseGeometry geo(tt.target(), 4, 0);
165                     Vertex* verts = reinterpret_cast<Vertex*>(geo.vertices());
166
167                     verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
168                                                   bounds.fRight, bounds.fBottom,
169                                                   sizeof(Vertex));
170                     for (int v = 0; v < 4; ++v) {
171                         verts[v].fKLM[0] = eval_line(verts[v].fPosition, klmEqs + 0, klmSigns[c]);
172                         verts[v].fKLM[1] = eval_line(verts[v].fPosition, klmEqs + 3, klmSigns[c]);
173                         verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
174                     }
175
176                     drawState->setGeometryProcessor(gp);
177                     drawState->setRenderTarget(rt);
178                     drawState->setColor(0xff000000);
179
180                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
181                     tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
182                 }
183                 ++col;
184                 if (numCols == col) {
185                     col = 0;
186                     ++row;
187                 }
188             }
189         }
190     }
191
192 private:
193     typedef GM INHERITED;
194 };
195
196 //////////////////////////////////////////////////////////////////////////////
197
198 /**
199  * This GM directly exercises effects that draw Bezier curves in the GPU backend.
200  */
201 class BezierConicEffects : public GM {
202 public:
203     BezierConicEffects() {
204         this->setBGColor(0xFFFFFFFF);
205     }
206
207 protected:
208     virtual SkString onShortName() SK_OVERRIDE {
209         return SkString("bezier_conic_effects");
210     }
211
212     virtual SkISize onISize() SK_OVERRIDE {
213         return SkISize::Make(800, 800);
214     }
215
216     virtual uint32_t onGetFlags() const SK_OVERRIDE {
217         // This is a GPU-specific GM.
218         return kGPUOnly_Flag;
219     }
220
221
222     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
223         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
224         if (NULL == rt) {
225             return;
226         }
227         GrContext* context = rt->getContext();
228         if (NULL == context) {
229             return;
230         }
231
232         struct Vertex {
233             SkPoint fPosition;
234             float   fKLM[4]; // The last value is ignored. The effect expects a vec4f.
235         };
236
237         static const int kNumConics = 10;
238         SkRandom rand;
239
240         // Mult by 3 for each edge effect type
241         int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumConics*3)));
242         int numRows = SkScalarCeilToInt(SkIntToScalar(kNumConics*3) / numCols);
243         SkScalar w = SkIntToScalar(rt->width()) / numCols;
244         SkScalar h = SkIntToScalar(rt->height()) / numRows;
245         int row = 0;
246         int col = 0;
247
248         for (int i = 0; i < kNumConics; ++i) {
249             SkPoint baseControlPts[] = {
250                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
251                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
252                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
253             };
254             SkScalar weight = rand.nextRangeF(0.f, 2.f);
255             for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
256                 SkAutoTUnref<GrGeometryProcessor> gp;
257                 {   // scope to contain GrTestTarget
258                     GrTestTarget tt;
259                     context->getTestTarget(&tt);
260                     if (NULL == tt.target()) {
261                         continue;
262                     }
263                     GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
264                     gp.reset(GrConicEffect::Create(et, *tt.target()->caps()));
265                     if (!gp) {
266                         continue;
267                     }
268                 }
269
270                 SkScalar x = SkScalarMul(col, w);
271                 SkScalar y = SkScalarMul(row, h);
272                 SkPoint controlPts[] = {
273                     {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
274                     {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
275                     {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
276                 };
277                 SkConic dst[4];
278                 SkScalar klmEqs[9];
279                 int cnt = chop_conic(controlPts, dst, weight);
280                 GrPathUtils::getConicKLM(controlPts, weight, klmEqs);
281
282                 SkPaint ctrlPtPaint;
283                 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
284                 for (int i = 0; i < 3; ++i) {
285                     canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
286                 }
287
288                 SkPaint polyPaint;
289                 polyPaint.setColor(0xffA0A0A0);
290                 polyPaint.setStrokeWidth(0);
291                 polyPaint.setStyle(SkPaint::kStroke_Style);
292                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
293
294                 SkPaint choppedPtPaint;
295                 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
296
297                 for (int c = 0; c < cnt; ++c) {
298                     SkPoint* pts = dst[c].fPts;
299                     for (int i = 0; i < 3; ++i) {
300                         canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
301                     }
302
303                     SkRect bounds;
304                     //SkPoint bPts[] = {{0.f, 0.f}, {800.f, 800.f}};
305                     //bounds.set(bPts, 2);
306                     bounds.set(pts, 3);
307
308                     SkPaint boundsPaint;
309                     boundsPaint.setColor(0xff808080);
310                     boundsPaint.setStrokeWidth(0);
311                     boundsPaint.setStyle(SkPaint::kStroke_Style);
312                     canvas->drawRect(bounds, boundsPaint);
313
314                     GrTestTarget tt;
315                     context->getTestTarget(&tt);
316                     SkASSERT(tt.target());
317
318                     GrDrawState* drawState = tt.target()->drawState();
319                     drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex));
320
321                     GrDrawTarget::AutoReleaseGeometry geo(tt.target(), 4, 0);
322                     Vertex* verts = reinterpret_cast<Vertex*>(geo.vertices());
323
324                     verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
325                                                   bounds.fRight, bounds.fBottom,
326                                                   sizeof(Vertex));
327                     for (int v = 0; v < 4; ++v) {
328                         verts[v].fKLM[0] = eval_line(verts[v].fPosition, klmEqs + 0, 1.f);
329                         verts[v].fKLM[1] = eval_line(verts[v].fPosition, klmEqs + 3, 1.f);
330                         verts[v].fKLM[2] = eval_line(verts[v].fPosition, klmEqs + 6, 1.f);
331                     }
332
333                     drawState->setGeometryProcessor(gp);
334                     drawState->setRenderTarget(rt);
335                     drawState->setColor(0xff000000);
336
337                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
338                     tt.target()->drawIndexed(kTriangleFan_GrPrimitiveType, 0, 0, 4, 6);
339                 }
340                 ++col;
341                 if (numCols == col) {
342                     col = 0;
343                     ++row;
344                 }
345             }
346         }
347     }
348
349 private:
350     // Uses the max curvature function for quads to estimate
351     // where to chop the conic. If the max curvature is not
352     // found along the curve segment it will return 1 and
353     // dst[0] is the original conic. If it returns 2 the dst[0]
354     // and dst[1] are the two new conics.
355     int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) {
356         SkScalar t = SkFindQuadMaxCurvature(src);
357         if (t == 0) {
358             if (dst) {
359                 dst[0].set(src, weight);
360             }
361             return 1;
362         } else {
363             if (dst) {
364                 SkConic conic;
365                 conic.set(src, weight);
366                 conic.chopAt(t, dst);
367             }
368             return 2;
369         }
370     }
371
372     // Calls split_conic on the entire conic and then once more on each subsection.
373     // Most cases will result in either 1 conic (chop point is not within t range)
374     // or 3 points (split once and then one subsection is split again).
375     int chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) {
376         SkConic dstTemp[2];
377         int conicCnt = split_conic(src, dstTemp, weight);
378         if (2 == conicCnt) {
379             int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW);
380             conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW);
381         } else {
382             dst[0] = dstTemp[0];
383         }
384         return conicCnt;
385     }
386
387     typedef GM INHERITED;
388 };
389
390 //////////////////////////////////////////////////////////////////////////////
391 /**
392  * This GM directly exercises effects that draw Bezier quad curves in the GPU backend.
393  */
394 class BezierQuadEffects : public GM {
395 public:
396     BezierQuadEffects() {
397         this->setBGColor(0xFFFFFFFF);
398     }
399
400 protected:
401     virtual SkString onShortName() SK_OVERRIDE {
402         return SkString("bezier_quad_effects");
403     }
404
405     virtual SkISize onISize() SK_OVERRIDE {
406         return SkISize::Make(800, 800);
407     }
408
409     virtual uint32_t onGetFlags() const SK_OVERRIDE {
410         // This is a GPU-specific GM.
411         return kGPUOnly_Flag;
412     }
413
414
415     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
416         GrRenderTarget* rt = canvas->internal_private_accessTopLayerRenderTarget();
417         if (NULL == rt) {
418             return;
419         }
420         GrContext* context = rt->getContext();
421         if (NULL == context) {
422             return;
423         }
424
425         struct Vertex {
426             SkPoint fPosition;
427             float   fUV[4]; // The last two values are ignored. The effect expects a vec4f.
428         };
429
430         static const int kNumQuads = 5;
431         SkRandom rand;
432
433         int numCols = SkScalarCeilToInt(SkScalarSqrt(SkIntToScalar(kNumQuads*3)));
434         int numRows = SkScalarCeilToInt(SkIntToScalar(kNumQuads*3) / numCols);
435         SkScalar w = SkIntToScalar(rt->width()) / numCols;
436         SkScalar h = SkIntToScalar(rt->height()) / numRows;
437         int row = 0;
438         int col = 0;
439
440         for (int i = 0; i < kNumQuads; ++i) {
441             SkPoint baseControlPts[] = {
442                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
443                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)},
444                 {rand.nextRangeF(0.f, w), rand.nextRangeF(0.f, h)}
445             };
446             for(int edgeType = 0; edgeType < kGrProcessorEdgeTypeCnt; ++edgeType) {
447                 SkAutoTUnref<GrGeometryProcessor> gp;
448                 {   // scope to contain GrTestTarget
449                     GrTestTarget tt;
450                     context->getTestTarget(&tt);
451                     if (NULL == tt.target()) {
452                         continue;
453                     }
454                     GrPrimitiveEdgeType et = (GrPrimitiveEdgeType)edgeType;
455                     gp.reset(GrQuadEffect::Create(et, *tt.target()->caps()));
456                     if (!gp) {
457                         continue;
458                     }
459                 }
460
461                 SkScalar x = SkScalarMul(col, w);
462                 SkScalar y = SkScalarMul(row, h);
463                 SkPoint controlPts[] = {
464                     {x + baseControlPts[0].fX, y + baseControlPts[0].fY},
465                     {x + baseControlPts[1].fX, y + baseControlPts[1].fY},
466                     {x + baseControlPts[2].fX, y + baseControlPts[2].fY}
467                 };
468                 SkPoint chopped[5];
469                 int cnt = SkChopQuadAtMaxCurvature(controlPts, chopped);
470
471                 SkPaint ctrlPtPaint;
472                 ctrlPtPaint.setColor(rand.nextU() | 0xFF000000);
473                 for (int i = 0; i < 3; ++i) {
474                     canvas->drawCircle(controlPts[i].fX, controlPts[i].fY, 6.f, ctrlPtPaint);
475                 }
476
477                 SkPaint polyPaint;
478                 polyPaint.setColor(0xffA0A0A0);
479                 polyPaint.setStrokeWidth(0);
480                 polyPaint.setStyle(SkPaint::kStroke_Style);
481                 canvas->drawPoints(SkCanvas::kPolygon_PointMode, 3, controlPts, polyPaint);
482
483                 SkPaint choppedPtPaint;
484                 choppedPtPaint.setColor(~ctrlPtPaint.getColor() | 0xFF000000);
485
486                 for (int c = 0; c < cnt; ++c) {
487                     SkPoint* pts = chopped + 2 * c;
488
489                     for (int i = 0; i < 3; ++i) {
490                         canvas->drawCircle(pts[i].fX, pts[i].fY, 3.f, choppedPtPaint);
491                     }
492
493                     SkRect bounds;
494                     bounds.set(pts, 3);
495
496                     SkPaint boundsPaint;
497                     boundsPaint.setColor(0xff808080);
498                     boundsPaint.setStrokeWidth(0);
499                     boundsPaint.setStyle(SkPaint::kStroke_Style);
500                     canvas->drawRect(bounds, boundsPaint);
501
502                     GrTestTarget tt;
503                     context->getTestTarget(&tt);
504                     SkASSERT(tt.target());
505
506                     GrDrawState* drawState = tt.target()->drawState();
507                     drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex));
508
509                     GrDrawTarget::AutoReleaseGeometry geo(tt.target(), 4, 0);
510                     Vertex* verts = reinterpret_cast<Vertex*>(geo.vertices());
511
512                     verts[0].fPosition.setRectFan(bounds.fLeft, bounds.fTop,
513                                                   bounds.fRight, bounds.fBottom,
514                                                   sizeof(Vertex));
515
516                     GrPathUtils::QuadUVMatrix DevToUV(pts);
517                     DevToUV.apply<4, sizeof(Vertex), sizeof(SkPoint)>(verts);
518
519                     drawState->setGeometryProcessor(gp);
520                     drawState->setRenderTarget(rt);
521                     drawState->setColor(0xff000000);
522
523                     tt.target()->setIndexSourceToBuffer(context->getQuadIndexBuffer());
524                     tt.target()->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 4, 6);
525                 }
526                 ++col;
527                 if (numCols == col) {
528                     col = 0;
529                     ++row;
530                 }
531             }
532         }
533     }
534
535 private:
536     typedef GM INHERITED;
537 };
538
539 DEF_GM( return SkNEW(BezierCubicEffects); )
540 DEF_GM( return SkNEW(BezierConicEffects); )
541 DEF_GM( return SkNEW(BezierQuadEffects); )
542
543 }
544
545 #endif