1 2/* 3 * Copyright 2014 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#include "gm.h" 10 11#include "SkBitmap.h" 12#include "SkGradientShader.h" 13#include "SkPath.h" 14#include "SkTLList.h" 15 16static SkBitmap make_bmp(int w, int h) { 17 SkBitmap bmp; 18 bmp.allocN32Pixels(w, h, true); 19 20 SkCanvas canvas(bmp); 21 SkScalar wScalar = SkIntToScalar(w); 22 SkScalar hScalar = SkIntToScalar(h); 23 24 SkPoint pt = { wScalar / 2, hScalar / 2 }; 25 26 SkScalar radius = 3 * SkMaxScalar(wScalar, hScalar); 27 28 SkColor colors[] = { sk_tool_utils::color_to_565(SK_ColorDKGRAY), 29 sk_tool_utils::color_to_565(0xFF222255), 30 sk_tool_utils::color_to_565(0xFF331133), 31 sk_tool_utils::color_to_565(0xFF884422), 32 sk_tool_utils::color_to_565(0xFF000022), SK_ColorWHITE, 33 sk_tool_utils::color_to_565(0xFFAABBCC) }; 34 35 SkScalar pos[] = {0, 36 SK_Scalar1 / 6, 37 2 * SK_Scalar1 / 6, 38 3 * SK_Scalar1 / 6, 39 4 * SK_Scalar1 / 6, 40 5 * SK_Scalar1 / 6, 41 SK_Scalar1}; 42 43 SkPaint paint; 44 SkRect rect = SkRect::MakeWH(wScalar, hScalar); 45 SkMatrix mat = SkMatrix::I(); 46 for (int i = 0; i < 4; ++i) { 47 paint.setShader(SkGradientShader::CreateRadial( 48 pt, radius, 49 colors, pos, 50 SK_ARRAY_COUNT(colors), 51 SkShader::kRepeat_TileMode, 52 0, &mat))->unref(); 53 canvas.drawRect(rect, paint); 54 rect.inset(wScalar / 8, hScalar / 8); 55 mat.preTranslate(6 * wScalar, 6 * hScalar); 56 mat.postScale(SK_Scalar1 / 3, SK_Scalar1 / 3); 57 } 58 59 paint.setAntiAlias(true); 60 sk_tool_utils::set_portable_typeface(&paint); 61 paint.setTextSize(wScalar / 2.2f); 62 paint.setShader(0); 63 paint.setColor(sk_tool_utils::color_to_565(SK_ColorLTGRAY)); 64 static const char kTxt[] = "Skia"; 65 SkPoint texPos = { wScalar / 17, hScalar / 2 + paint.getTextSize() / 2.5f }; 66 canvas.drawText(kTxt, SK_ARRAY_COUNT(kTxt)-1, texPos.fX, texPos.fY, paint); 67 paint.setColor(SK_ColorBLACK); 68 paint.setStyle(SkPaint::kStroke_Style); 69 paint.setStrokeWidth(SK_Scalar1); 70 canvas.drawText(kTxt, SK_ARRAY_COUNT(kTxt)-1, texPos.fX, texPos.fY, paint); 71 return bmp; 72} 73 74namespace skiagm { 75/** 76 * This GM tests convex polygon clips. 77 */ 78class ConvexPolyClip : public GM { 79public: 80 ConvexPolyClip() { 81 this->setBGColor(0xFFFFFFFF); 82 } 83 84protected: 85 SkString onShortName() override { 86 return SkString("convex_poly_clip"); 87 } 88 89 SkISize onISize() override { 90 // When benchmarking the saveLayer set of draws is skipped. 91 int w = 435; 92 if (kBench_Mode != this->getMode()) { 93 w *= 2; 94 } 95 return SkISize::Make(w, 540); 96 } 97 98 void onOnceBeforeDraw() override { 99 SkPath tri; 100 tri.moveTo(5.f, 5.f); 101 tri.lineTo(100.f, 20.f); 102 tri.lineTo(15.f, 100.f); 103 104 fClips.addToTail()->setPath(tri); 105 106 SkPath hexagon; 107 static const SkScalar kRadius = 45.f; 108 const SkPoint center = { kRadius, kRadius }; 109 for (int i = 0; i < 6; ++i) { 110 SkScalar angle = 2 * SK_ScalarPI * i / 6; 111 SkPoint point; 112 point.fY = SkScalarSinCos(angle, &point.fX); 113 point.scale(kRadius); 114 point = center + point; 115 if (0 == i) { 116 hexagon.moveTo(point); 117 } else { 118 hexagon.lineTo(point); 119 } 120 } 121 fClips.addToTail()->setPath(hexagon); 122 123 SkMatrix scaleM; 124 scaleM.setScale(1.1f, 0.4f, kRadius, kRadius); 125 hexagon.transform(scaleM); 126 fClips.addToTail()->setPath(hexagon); 127 128 fClips.addToTail()->setRect(SkRect::MakeXYWH(8.3f, 11.6f, 78.2f, 72.6f)); 129 130 SkPath rotRect; 131 SkRect rect = SkRect::MakeLTRB(10.f, 12.f, 80.f, 86.f); 132 rotRect.addRect(rect); 133 SkMatrix rotM; 134 rotM.setRotate(23.f, rect.centerX(), rect.centerY()); 135 rotRect.transform(rotM); 136 fClips.addToTail()->setPath(rotRect); 137 138 fBmp = make_bmp(100, 100); 139 } 140 141 void onDraw(SkCanvas* canvas) override { 142 SkScalar y = 0; 143 static const SkScalar kMargin = 10.f; 144 145 SkPaint bgPaint; 146 bgPaint.setAlpha(0x15); 147 SkISize size = canvas->getDeviceSize(); 148 canvas->drawBitmapRect(fBmp, SkRect::MakeIWH(size.fWidth, size.fHeight), &bgPaint); 149 150 static const char kTxt[] = "Clip Me!"; 151 SkPaint txtPaint; 152 txtPaint.setTextSize(23.f); 153 txtPaint.setAntiAlias(true); 154 sk_tool_utils::set_portable_typeface(&txtPaint); 155 txtPaint.setColor(sk_tool_utils::color_to_565(SK_ColorDKGRAY)); 156 SkScalar textW = txtPaint.measureText(kTxt, SK_ARRAY_COUNT(kTxt)-1); 157 158 SkScalar startX = 0; 159 int testLayers = kBench_Mode != this->getMode(); 160 for (int doLayer = 0; doLayer <= testLayers; ++doLayer) { 161 for (ClipList::Iter iter(fClips, ClipList::Iter::kHead_IterStart); 162 iter.get(); 163 iter.next()) { 164 const Clip* clip = iter.get(); 165 SkScalar x = startX; 166 for (int aa = 0; aa < 2; ++aa) { 167 if (doLayer) { 168 SkRect bounds; 169 clip->getBounds(&bounds); 170 bounds.outset(2, 2); 171 bounds.offset(x, y); 172 canvas->saveLayer(&bounds, nullptr); 173 } else { 174 canvas->save(); 175 } 176 canvas->translate(x, y); 177 clip->setOnCanvas(canvas, SkRegion::kIntersect_Op, SkToBool(aa)); 178 canvas->drawBitmap(fBmp, 0, 0); 179 canvas->restore(); 180 x += fBmp.width() + kMargin; 181 } 182 for (int aa = 0; aa < 2; ++aa) { 183 184 SkPaint clipOutlinePaint; 185 clipOutlinePaint.setAntiAlias(true); 186 clipOutlinePaint.setColor(0x50505050); 187 clipOutlinePaint.setStyle(SkPaint::kStroke_Style); 188 clipOutlinePaint.setStrokeWidth(0); 189 190 if (doLayer) { 191 SkRect bounds; 192 clip->getBounds(&bounds); 193 bounds.outset(2, 2); 194 bounds.offset(x, y); 195 canvas->saveLayer(&bounds, nullptr); 196 } else { 197 canvas->save(); 198 } 199 canvas->translate(x, y); 200 SkPath closedClipPath; 201 clip->asClosedPath(&closedClipPath); 202 canvas->drawPath(closedClipPath, clipOutlinePaint); 203 clip->setOnCanvas(canvas, SkRegion::kIntersect_Op, SkToBool(aa)); 204 canvas->scale(1.f, 1.8f); 205 canvas->drawText(kTxt, SK_ARRAY_COUNT(kTxt)-1, 206 0, 1.5f * txtPaint.getTextSize(), 207 txtPaint); 208 canvas->restore(); 209 x += textW + 2 * kMargin; 210 } 211 y += fBmp.height() + kMargin; 212 } 213 y = 0; 214 startX += 2 * fBmp.width() + SkScalarCeilToInt(2 * textW) + 6 * kMargin; 215 } 216 } 217 218 bool runAsBench() const override { return true; } 219 220private: 221 class Clip { 222 public: 223 enum ClipType { 224 kNone_ClipType, 225 kPath_ClipType, 226 kRect_ClipType 227 }; 228 229 Clip () : fClipType(kNone_ClipType) {} 230 231 void setOnCanvas(SkCanvas* canvas, SkRegion::Op op, bool aa) const { 232 switch (fClipType) { 233 case kPath_ClipType: 234 canvas->clipPath(fPath, op, aa); 235 break; 236 case kRect_ClipType: 237 canvas->clipRect(fRect, op, aa); 238 break; 239 case kNone_ClipType: 240 SkDEBUGFAIL("Uninitialized Clip."); 241 break; 242 } 243 } 244 245 void asClosedPath(SkPath* path) const { 246 switch (fClipType) { 247 case kPath_ClipType: 248 *path = fPath; 249 path->close(); 250 break; 251 case kRect_ClipType: 252 path->reset(); 253 path->addRect(fRect); 254 break; 255 case kNone_ClipType: 256 SkDEBUGFAIL("Uninitialized Clip."); 257 break; 258 } 259 } 260 261 void setPath(const SkPath& path) { 262 fClipType = kPath_ClipType; 263 fPath = path; 264 } 265 266 void setRect(const SkRect& rect) { 267 fClipType = kRect_ClipType; 268 fRect = rect; 269 fPath.reset(); 270 } 271 272 ClipType getType() const { return fClipType; } 273 274 void getBounds(SkRect* bounds) const { 275 switch (fClipType) { 276 case kPath_ClipType: 277 *bounds = fPath.getBounds(); 278 break; 279 case kRect_ClipType: 280 *bounds = fRect; 281 break; 282 case kNone_ClipType: 283 SkDEBUGFAIL("Uninitialized Clip."); 284 break; 285 } 286 } 287 288 private: 289 ClipType fClipType; 290 SkPath fPath; 291 SkRect fRect; 292 }; 293 294 typedef SkTLList<Clip, 1> ClipList; 295 ClipList fClips; 296 SkBitmap fBmp; 297 298 typedef GM INHERITED; 299}; 300 301DEF_GM(return new ConvexPolyClip;) 302} 303