1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "gm.h"
9
10 #include "SkAutoMalloc.h"
11 #include "SkCanvas.h"
12 #include "SkRSXform.h"
13 #include "SkSurface.h"
14
15 class DrawAtlasGM : public skiagm::GM {
MakeAtlas(SkCanvas * caller,const SkRect & target)16 static sk_sp<SkImage> MakeAtlas(SkCanvas* caller, const SkRect& target) {
17 SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
18 auto surface(caller->makeSurface(info));
19 if (nullptr == surface) {
20 surface = SkSurface::MakeRaster(info);
21 }
22 SkCanvas* canvas = surface->getCanvas();
23 // draw red everywhere, but we don't expect to see it in the draw, testing the notion
24 // that drawAtlas draws a subset-region of the atlas.
25 canvas->clear(SK_ColorRED);
26
27 SkPaint paint;
28 paint.setBlendMode(SkBlendMode::kClear);
29 SkRect r(target);
30 r.inset(-1, -1);
31 // zero out a place (with a 1-pixel border) to land our drawing.
32 canvas->drawRect(r, paint);
33 paint.setBlendMode(SkBlendMode::kSrcOver);
34 paint.setColor(SK_ColorBLUE);
35 paint.setAntiAlias(true);
36 canvas->drawOval(target, paint);
37 return surface->makeImageSnapshot();
38 }
39
40 public:
DrawAtlasGM()41 DrawAtlasGM() {}
42
43 protected:
44
onShortName()45 SkString onShortName() override {
46 return SkString("draw-atlas");
47 }
48
onISize()49 SkISize onISize() override {
50 return SkISize::Make(640, 480);
51 }
52
onDraw(SkCanvas * canvas)53 void onDraw(SkCanvas* canvas) override {
54 const SkRect target = { 50, 50, 80, 90 };
55 auto atlas = MakeAtlas(canvas, target);
56
57 const struct {
58 SkScalar fScale;
59 SkScalar fDegrees;
60 SkScalar fTx;
61 SkScalar fTy;
62
63 void apply(SkRSXform* xform) const {
64 const SkScalar rad = SkDegreesToRadians(fDegrees);
65 xform->fSCos = fScale * SkScalarCos(rad);
66 xform->fSSin = fScale * SkScalarSin(rad);
67 xform->fTx = fTx;
68 xform->fTy = fTy;
69 }
70 } rec[] = {
71 { 1, 0, 10, 10 }, // just translate
72 { 2, 0, 110, 10 }, // scale + translate
73 { 1, 30, 210, 10 }, // rotate + translate
74 { 2, -30, 310, 30 }, // scale + rotate + translate
75 };
76
77 const int N = SK_ARRAY_COUNT(rec);
78 SkRSXform xform[N];
79 SkRect tex[N];
80 SkColor colors[N];
81
82 for (int i = 0; i < N; ++i) {
83 rec[i].apply(&xform[i]);
84 tex[i] = target;
85 colors[i] = 0x80FF0000 + (i * 40 * 256);
86 }
87
88 SkPaint paint;
89 paint.setFilterQuality(kLow_SkFilterQuality);
90 paint.setAntiAlias(true);
91
92 canvas->drawAtlas(atlas.get(), xform, tex, N, nullptr, &paint);
93 canvas->translate(0, 100);
94 canvas->drawAtlas(atlas.get(), xform, tex, colors, N, SkBlendMode::kSrcIn, nullptr, &paint);
95 }
96
97 private:
98 typedef GM INHERITED;
99 };
DEF_GM(return new DrawAtlasGM;)100 DEF_GM( return new DrawAtlasGM; )
101
102 ///////////////////////////////////////////////////////////////////////////////////////////////////
103 #include "SkPath.h"
104 #include "SkPathMeasure.h"
105
106 static void draw_text_on_path_rigid(SkCanvas* canvas, const void* text, size_t length,
107 const SkPoint xy[], const SkPath& path, const SkPaint& paint) {
108 SkPathMeasure meas(path, false);
109
110 int count = paint.countText(text, length);
111 size_t size = count * (sizeof(SkRSXform) + sizeof(SkScalar));
112 SkAutoSMalloc<512> storage(size);
113 SkRSXform* xform = (SkRSXform*)storage.get();
114 SkScalar* widths = (SkScalar*)(xform + count);
115
116 paint.getTextWidths(text, length, widths);
117
118 for (int i = 0; i < count; ++i) {
119 // we want to position each character on the center of its advance
120 const SkScalar offset = SkScalarHalf(widths[i]);
121 SkPoint pos;
122 SkVector tan;
123 if (!meas.getPosTan(xy[i].x() + offset, &pos, &tan)) {
124 pos = xy[i];
125 tan.set(1, 0);
126 }
127 xform[i].fSCos = tan.x();
128 xform[i].fSSin = tan.y();
129 xform[i].fTx = pos.x() - tan.y() * xy[i].y() - tan.x() * offset;
130 xform[i].fTy = pos.y() + tan.x() * xy[i].y() - tan.y() * offset;
131 }
132
133 // Compute a conservative bounds so we can cull the draw
134 const SkRect font = paint.getFontBounds();
135 const SkScalar max = SkTMax(SkTMax(SkScalarAbs(font.fLeft), SkScalarAbs(font.fRight)),
136 SkTMax(SkScalarAbs(font.fTop), SkScalarAbs(font.fBottom)));
137 const SkRect bounds = path.getBounds().makeOutset(max, max);
138
139 canvas->drawTextRSXform(text, length, &xform[0], &bounds, paint);
140
141 if (true) {
142 SkPaint p;
143 p.setStyle(SkPaint::kStroke_Style);
144 canvas->drawRect(bounds, p);
145 }
146 }
147
148 DEF_SIMPLE_GM(drawTextRSXform, canvas, 860, 860) {
149 const char text0[] = "ABCDFGHJKLMNOPQRSTUVWXYZ";
150 const int N = sizeof(text0) - 1;
151 SkPoint pos[N];
152
153 SkPaint paint;
154 paint.setAntiAlias(true);
155 paint.setTextSize(100);
156
157 SkScalar x = 0;
158 for (int i = 0; i < N; ++i) {
159 pos[i].set(x, 0);
160 x += paint.measureText(&text0[i], 1);
161 }
162
163 SkPath path;
164 path.addOval(SkRect::MakeXYWH(160, 160, 540, 540));
165
166 draw_text_on_path_rigid(canvas, text0, N, pos, path, paint);
167
168 paint.setStyle(SkPaint::kStroke_Style);
169 canvas->drawPath(path, paint);
170 }
171
172
173