1 /* 2 * Copyright 2011 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 #include "Resources.h" 10 #include "SkPath.h" 11 #include "SkTypeface.h" 12 13 class SkJSCanvas { 14 public: 15 SkJSCanvas(SkCanvas* target); 16 ~SkJSCanvas(); 17 18 void save(); 19 void restore(); 20 21 double lineWidth; 22 void setLineWidth(double); 23 24 void beginPath(); 25 void moveTo(double x, double y); 26 void lineTo(double x, double y); 27 void closePath(); 28 29 void fill(); 30 void stroke(); 31 32 void fillText(const char text[], double x, double y); 33 34 private: 35 SkCanvas* fTarget; 36 SkPaint fFillPaint; 37 SkPaint fStrokePaint; 38 SkPath fPath; 39 }; 40 41 SkJSCanvas::SkJSCanvas(SkCanvas* target) : fTarget(target) { 42 fFillPaint.setAntiAlias(true); 43 sk_tool_utils::set_portable_typeface(&fFillPaint); 44 fStrokePaint.setAntiAlias(true); 45 fStrokePaint.setStyle(SkPaint::kStroke_Style); 46 fStrokePaint.setStrokeWidth(SK_Scalar1); 47 } 48 49 SkJSCanvas::~SkJSCanvas() {} 50 51 void SkJSCanvas::save() { fTarget->save(); } 52 void SkJSCanvas::restore() { fTarget->restore(); } 53 54 void SkJSCanvas::beginPath() { fPath.reset(); } 55 void SkJSCanvas::moveTo(double x, double y) { 56 fPath.moveTo(SkDoubleToScalar(x), SkDoubleToScalar(y)); 57 } 58 59 void SkJSCanvas::lineTo(double x, double y) { 60 fPath.lineTo(SkDoubleToScalar(x), SkDoubleToScalar(y)); 61 } 62 63 void SkJSCanvas::closePath() { fPath.close(); } 64 65 void SkJSCanvas::fill() { 66 fTarget->drawPath(fPath, fFillPaint); 67 } 68 69 void SkJSCanvas::stroke() { 70 fStrokePaint.setStrokeWidth(SkDoubleToScalar(lineWidth)); 71 fTarget->drawPath(fPath, fStrokePaint); 72 } 73 74 void SkJSCanvas::fillText(const char text[], double x, double y) { 75 fTarget->drawText(text, strlen(text), 76 SkDoubleToScalar(x), SkDoubleToScalar(y), fFillPaint); 77 } 78 79 /////////////////////////////////////////////////////////////////////////////// 80 81 static void dump(const SkPath& path) { 82 const SkRect& r = path.getBounds(); 83 SkDebugf("isEmpty %d, bounds [%g %g %g %g]\n", path.isEmpty(), 84 r.fLeft, r.fTop, r.fRight, r.fBottom); 85 } 86 87 static void test_stroke(SkCanvas* canvas) { 88 if (true) { 89 SkPath path; 90 dump(path); 91 path.reset(); path.moveTo(0, 0); 92 dump(path); 93 path.reset(); path.moveTo(100, 100); 94 dump(path); 95 path.reset(); path.moveTo(0, 0); path.moveTo(100, 100); 96 dump(path); 97 path.reset(); path.moveTo(0, 0); path.lineTo(100, 100); 98 dump(path); 99 path.reset(); path.moveTo(0, 0); path.lineTo(100, 100); path.moveTo(200, 200); 100 dump(path); 101 } 102 103 #if 0 104 // TEST 1 - The rectangle as it's expected to look 105 var canvas = document.createElement('canvas'); 106 document.body.appendChild(canvas); 107 var ctx = canvas.getContext("2d"); 108 #else 109 SkJSCanvas ctx(canvas); 110 #endif 111 112 ctx.save(); 113 ctx.lineWidth = 2; 114 ctx.beginPath(); 115 ctx.moveTo(10, 100); 116 ctx.lineTo(150, 100); 117 ctx.lineTo(150, 15); 118 ctx.lineTo(10, 15); 119 ctx.closePath(); 120 121 // no extra moveTo here 122 // ctx.moveTo(175, 125); 123 124 ctx.stroke(); 125 ctx.restore(); 126 127 ctx.fillText("As Expected", 10, 10); 128 129 #if 0 130 // TEST 2 - Includes an extra moveTo call before stroke; the rectangle appears larger 131 canvas = document.createElement('canvas'); 132 document.body.appendChild(canvas); 133 ctx = canvas.getContext("2d"); 134 #else 135 canvas->translate(200, 0); 136 #endif 137 138 ctx.save(); 139 ctx.lineWidth = 2; 140 ctx.beginPath(); 141 ctx.moveTo(10, 100); 142 ctx.lineTo(150, 100); 143 ctx.lineTo(150, 15); 144 ctx.lineTo(10, 15); 145 ctx.closePath(); 146 147 ctx.moveTo(175, 125); 148 149 ctx.stroke(); 150 ctx.restore(); 151 152 ctx.fillText("Larger Rectangle", 10, 10); 153 154 #if 0 155 // TEST 3 - Identical to test 2 except the line width is 1 156 canvas = document.createElement('canvas'); 157 document.body.appendChild(canvas); 158 ctx = canvas.getContext("2d"); 159 #else 160 canvas->translate(200, 0); 161 #endif 162 163 ctx.save(); 164 ctx.lineWidth = 1; 165 ctx.beginPath(); 166 ctx.moveTo(10, 100); 167 ctx.lineTo(150, 100); 168 ctx.lineTo(150, 15); 169 ctx.lineTo(10, 15); 170 ctx.closePath(); 171 172 ctx.moveTo(175, 125); 173 174 ctx.stroke(); 175 ctx.restore(); 176 177 ctx.fillText("As Expected - line width 1", 10, 10); 178 } 179 180 class Poly2PolyGM : public skiagm::GM { 181 public: 182 Poly2PolyGM() {} 183 184 protected: 185 186 SkString onShortName() override { 187 return SkString("poly2poly"); 188 } 189 190 SkISize onISize() override { 191 return SkISize::Make(835, 840); 192 } 193 194 static void doDraw(SkCanvas* canvas, SkPaint* paint, const int isrc[], 195 const int idst[], int count) { 196 SkMatrix matrix; 197 SkPoint src[4], dst[4]; 198 199 for (int i = 0; i < count; i++) { 200 src[i].set(SkIntToScalar(isrc[2*i+0]), SkIntToScalar(isrc[2*i+1])); 201 dst[i].set(SkIntToScalar(idst[2*i+0]), SkIntToScalar(idst[2*i+1])); 202 } 203 204 canvas->save(); 205 matrix.setPolyToPoly(src, dst, count); 206 canvas->concat(matrix); 207 208 paint->setColor(sk_tool_utils::color_to_565(SK_ColorGRAY)); 209 paint->setStyle(SkPaint::kStroke_Style); 210 const SkScalar D = SkIntToScalar(64); 211 canvas->drawRectCoords(0, 0, D, D, *paint); 212 canvas->drawLine(0, 0, D, D, *paint); 213 canvas->drawLine(0, D, D, 0, *paint); 214 215 SkPaint::FontMetrics fm; 216 paint->getFontMetrics(&fm); 217 paint->setColor(SK_ColorRED); 218 paint->setStyle(SkPaint::kFill_Style); 219 SkScalar x = D/2; 220 SkScalar y = D/2 - (fm.fAscent + fm.fDescent)/2; 221 uint16_t glyphID = 3; // X 222 canvas->drawText((void*) &glyphID, sizeof(glyphID), x, y, *paint); 223 canvas->restore(); 224 } 225 226 void onOnceBeforeDraw() override { 227 fEmFace.reset(GetResourceAsTypeface("/fonts/Em.ttf")); 228 } 229 230 void onDraw(SkCanvas* canvas) override { 231 if (false) { test_stroke(canvas); return; } 232 233 SkPaint paint; 234 paint.setAntiAlias(true); 235 paint.setTypeface(fEmFace); 236 paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 237 paint.setStrokeWidth(SkIntToScalar(4)); 238 paint.setTextSize(SkIntToScalar(40)); 239 paint.setTextAlign(SkPaint::kCenter_Align); 240 241 canvas->save(); 242 canvas->translate(SkIntToScalar(10), SkIntToScalar(10)); 243 // translate (1 point) 244 const int src1[] = { 0, 0 }; 245 const int dst1[] = { 5, 5 }; 246 doDraw(canvas, &paint, src1, dst1, 1); 247 canvas->restore(); 248 249 canvas->save(); 250 canvas->translate(SkIntToScalar(160), SkIntToScalar(10)); 251 // rotate/uniform-scale (2 points) 252 const int src2[] = { 32, 32, 64, 32 }; 253 const int dst2[] = { 32, 32, 64, 48 }; 254 doDraw(canvas, &paint, src2, dst2, 2); 255 canvas->restore(); 256 257 canvas->save(); 258 canvas->translate(SkIntToScalar(10), SkIntToScalar(110)); 259 // rotate/skew (3 points) 260 const int src3[] = { 0, 0, 64, 0, 0, 64 }; 261 const int dst3[] = { 0, 0, 96, 0, 24, 64 }; 262 doDraw(canvas, &paint, src3, dst3, 3); 263 canvas->restore(); 264 265 canvas->save(); 266 canvas->translate(SkIntToScalar(160), SkIntToScalar(110)); 267 // perspective (4 points) 268 const int src4[] = { 0, 0, 64, 0, 64, 64, 0, 64 }; 269 const int dst4[] = { 0, 0, 96, 0, 64, 96, 0, 64 }; 270 doDraw(canvas, &paint, src4, dst4, 4); 271 canvas->restore(); 272 } 273 274 private: 275 typedef skiagm::GM INHERITED; 276 SkAutoTUnref<SkTypeface> fEmFace; 277 }; 278 279 ////////////////////////////////////////////////////////////////////////////// 280 281 DEF_GM( return new Poly2PolyGM; ) 282