|  |  | 
|  | /* | 
|  | * Copyright 2013 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "gm.h" | 
|  | #include "SkTArray.h" | 
|  | #include "SkRandom.h" | 
|  | #include "SkMatrix.h" | 
|  | #include "SkBlurMaskFilter.h" | 
|  | #include "SkGradientShader.h" | 
|  | #include "SkBlurDrawLooper.h" | 
|  | #include "SkRect.h" | 
|  | #include "SkRRect.h" | 
|  |  | 
|  | namespace skiagm { | 
|  |  | 
|  | class RoundRectGM : public GM { | 
|  | public: | 
|  | RoundRectGM() { | 
|  | this->setBGColor(0xFF000000); | 
|  | this->makePaints(); | 
|  | this->makeMatrices(); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | virtual uint32_t onGetFlags() const SK_OVERRIDE { | 
|  | return kSkipTiled_Flag; | 
|  | } | 
|  |  | 
|  | virtual SkString onShortName() SK_OVERRIDE { | 
|  | return SkString("roundrects"); | 
|  | } | 
|  |  | 
|  | virtual SkISize onISize() SK_OVERRIDE { | 
|  | return SkISize::Make(1200, 900); | 
|  | } | 
|  |  | 
|  | void makePaints() { | 
|  | { | 
|  | // no AA | 
|  | SkPaint p; | 
|  | fPaints.push_back(p); | 
|  | } | 
|  |  | 
|  | { | 
|  | // AA | 
|  | SkPaint p; | 
|  | p.setAntiAlias(true); | 
|  | fPaints.push_back(p); | 
|  | } | 
|  |  | 
|  | { | 
|  | // AA with stroke style | 
|  | SkPaint p; | 
|  | p.setAntiAlias(true); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  | p.setStrokeWidth(SkIntToScalar(5)); | 
|  | fPaints.push_back(p); | 
|  | } | 
|  |  | 
|  | { | 
|  | // AA with stroke style, width = 0 | 
|  | SkPaint p; | 
|  | p.setAntiAlias(true); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  | fPaints.push_back(p); | 
|  | } | 
|  |  | 
|  | { | 
|  | // AA with stroke and fill style | 
|  | SkPaint p; | 
|  | p.setAntiAlias(true); | 
|  | p.setStyle(SkPaint::kStrokeAndFill_Style); | 
|  | p.setStrokeWidth(SkIntToScalar(3)); | 
|  | fPaints.push_back(p); | 
|  | } | 
|  | } | 
|  |  | 
|  | void makeMatrices() { | 
|  | { | 
|  | SkMatrix m; | 
|  | m.setIdentity(); | 
|  | fMatrices.push_back(m); | 
|  | } | 
|  |  | 
|  | { | 
|  | SkMatrix m; | 
|  | m.setScale(SkIntToScalar(3), SkIntToScalar(2)); | 
|  | fMatrices.push_back(m); | 
|  | } | 
|  |  | 
|  | { | 
|  | SkMatrix m; | 
|  | m.setScale(SkIntToScalar(2), SkIntToScalar(2)); | 
|  | fMatrices.push_back(m); | 
|  | } | 
|  |  | 
|  | { | 
|  | SkMatrix m; | 
|  | m.setScale(SkIntToScalar(1), SkIntToScalar(2)); | 
|  | fMatrices.push_back(m); | 
|  | } | 
|  |  | 
|  | { | 
|  | SkMatrix m; | 
|  | m.setScale(SkIntToScalar(4), SkIntToScalar(1)); | 
|  | fMatrices.push_back(m); | 
|  | } | 
|  |  | 
|  | { | 
|  | SkMatrix m; | 
|  | m.setRotate(SkIntToScalar(90)); | 
|  | fMatrices.push_back(m); | 
|  | } | 
|  |  | 
|  | { | 
|  | SkMatrix m; | 
|  | m.setSkew(SkIntToScalar(2), SkIntToScalar(3)); | 
|  | fMatrices.push_back(m); | 
|  | } | 
|  |  | 
|  | { | 
|  | SkMatrix m; | 
|  | m.setRotate(SkIntToScalar(60)); | 
|  | fMatrices.push_back(m); | 
|  | } | 
|  | } | 
|  |  | 
|  | SkColor genColor(SkRandom* rand) { | 
|  | SkScalar hsv[3]; | 
|  | hsv[0] = rand->nextRangeF(0.0f, 360.0f); | 
|  | hsv[1] = rand->nextRangeF(0.75f, 1.0f); | 
|  | hsv[2] = rand->nextRangeF(0.75f, 1.0f); | 
|  |  | 
|  | return SkHSVToColor(hsv); | 
|  | } | 
|  |  | 
|  | virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE { | 
|  | SkRandom rand(1); | 
|  | canvas->translate(20 * SK_Scalar1, 20 * SK_Scalar1); | 
|  | SkRect rect = SkRect::MakeLTRB(-20, -30, 20, 30); | 
|  | SkRRect circleRect; | 
|  | circleRect.setRectXY(rect, 5, 5); | 
|  |  | 
|  | const SkScalar kXStart = 60.0f; | 
|  | const SkScalar kYStart = 80.0f; | 
|  | const int kXStep = 150; | 
|  | const int kYStep = 160; | 
|  | int maxX = fMatrices.count(); | 
|  |  | 
|  | SkPaint rectPaint; | 
|  | rectPaint.setAntiAlias(true); | 
|  | rectPaint.setStyle(SkPaint::kStroke_Style); | 
|  | rectPaint.setStrokeWidth(SkIntToScalar(0)); | 
|  | rectPaint.setColor(SK_ColorLTGRAY); | 
|  |  | 
|  | int testCount = 0; | 
|  | for (int i = 0; i < fPaints.count(); ++i) { | 
|  | for (int j = 0; j < fMatrices.count(); ++j) { | 
|  | canvas->save(); | 
|  | SkMatrix mat = fMatrices[j]; | 
|  | // position the roundrect, and make it at off-integer coords. | 
|  | mat.postTranslate(kXStart + SK_Scalar1 * kXStep * (testCount % maxX) + | 
|  | SK_Scalar1 / 4, | 
|  | kYStart + SK_Scalar1 * kYStep * (testCount / maxX) + | 
|  | 3 * SK_Scalar1 / 4); | 
|  | canvas->concat(mat); | 
|  |  | 
|  | SkColor color = genColor(&rand); | 
|  | fPaints[i].setColor(color); | 
|  |  | 
|  | canvas->drawRect(rect, rectPaint); | 
|  | canvas->drawRRect(circleRect, fPaints[i]); | 
|  |  | 
|  | canvas->restore(); | 
|  |  | 
|  | ++testCount; | 
|  | } | 
|  | } | 
|  |  | 
|  | // special cases | 
|  |  | 
|  | // non-scaled tall and skinny roundrect | 
|  | for (int i = 0; i < fPaints.count(); ++i) { | 
|  | SkRect rect = SkRect::MakeLTRB(-20, -60, 20, 60); | 
|  | SkRRect ellipseRect; | 
|  | ellipseRect.setRectXY(rect, 5, 10); | 
|  |  | 
|  | canvas->save(); | 
|  | // position the roundrect, and make it at off-integer coords. | 
|  | canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.55f + SK_Scalar1 / 4, | 
|  | kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4); | 
|  |  | 
|  | SkColor color = genColor(&rand); | 
|  | fPaints[i].setColor(color); | 
|  |  | 
|  | canvas->drawRect(rect, rectPaint); | 
|  | canvas->drawRRect(ellipseRect, fPaints[i]); | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | // non-scaled wide and short roundrect | 
|  | for (int i = 0; i < fPaints.count(); ++i) { | 
|  | SkRect rect = SkRect::MakeLTRB(-80, -30, 80, 30); | 
|  | SkRRect ellipseRect; | 
|  | ellipseRect.setRectXY(rect, 20, 5); | 
|  |  | 
|  | canvas->save(); | 
|  | // position the roundrect, and make it at off-integer coords. | 
|  | canvas->translate(kXStart + SK_Scalar1 * kXStep * 4 + SK_Scalar1 / 4, | 
|  | kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + | 
|  | SK_ScalarHalf * kYStep); | 
|  |  | 
|  | SkColor color = genColor(&rand); | 
|  | fPaints[i].setColor(color); | 
|  |  | 
|  | canvas->drawRect(rect, rectPaint); | 
|  | canvas->drawRRect(ellipseRect, fPaints[i]); | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | // super skinny roundrect | 
|  | for (int i = 0; i < fPaints.count(); ++i) { | 
|  | SkRect rect = SkRect::MakeLTRB(0, -60, 1, 60); | 
|  | SkRRect circleRect; | 
|  | circleRect.setRectXY(rect, 5, 5); | 
|  |  | 
|  | canvas->save(); | 
|  | // position the roundrect, and make it at off-integer coords. | 
|  | canvas->translate(kXStart + SK_Scalar1 * kXStep * 3.25f + SK_Scalar1 / 4, | 
|  | kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4); | 
|  |  | 
|  | SkColor color = genColor(&rand); | 
|  | fPaints[i].setColor(color); | 
|  |  | 
|  | canvas->drawRRect(circleRect, fPaints[i]); | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | // super short roundrect | 
|  | for (int i = 0; i < fPaints.count(); ++i) { | 
|  | SkRect rect = SkRect::MakeLTRB(-80, -1, 80, 0); | 
|  | SkRRect circleRect; | 
|  | circleRect.setRectXY(rect, 5, 5); | 
|  |  | 
|  | canvas->save(); | 
|  | // position the roundrect, and make it at off-integer coords. | 
|  | canvas->translate(kXStart + SK_Scalar1 * kXStep * 2.5f + SK_Scalar1 / 4, | 
|  | kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + | 
|  | SK_ScalarHalf * kYStep); | 
|  |  | 
|  | SkColor color = genColor(&rand); | 
|  | fPaints[i].setColor(color); | 
|  |  | 
|  | canvas->drawRRect(circleRect, fPaints[i]); | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | // radial gradient | 
|  | SkPoint center = SkPoint::Make(SkIntToScalar(0), SkIntToScalar(0)); | 
|  | SkColor colors[] = { SK_ColorBLUE, SK_ColorRED, SK_ColorGREEN }; | 
|  | SkScalar pos[] = { 0, SK_ScalarHalf, SK_Scalar1 }; | 
|  | SkAutoTUnref<SkShader> shader(SkGradientShader::CreateRadial(center, | 
|  | SkIntToScalar(20), | 
|  | colors, | 
|  | pos, | 
|  | SK_ARRAY_COUNT(colors), | 
|  | SkShader::kClamp_TileMode)); | 
|  |  | 
|  | for (int i = 0; i < fPaints.count(); ++i) { | 
|  | canvas->save(); | 
|  | // position the path, and make it at off-integer coords. | 
|  | canvas->translate(kXStart + SK_Scalar1 * kXStep * 0 + SK_Scalar1 / 4, | 
|  | kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + | 
|  | SK_ScalarHalf * kYStep); | 
|  |  | 
|  | SkColor color = genColor(&rand); | 
|  | fPaints[i].setColor(color); | 
|  | fPaints[i].setShader(shader); | 
|  |  | 
|  | canvas->drawRect(rect, rectPaint); | 
|  | canvas->drawRRect(circleRect, fPaints[i]); | 
|  |  | 
|  | fPaints[i].setShader(NULL); | 
|  |  | 
|  | canvas->restore(); | 
|  | } | 
|  |  | 
|  | // strokes and radii | 
|  | { | 
|  | SkScalar radii[][2] = { | 
|  | {10,10}, | 
|  | {5,15}, | 
|  | {5,15}, | 
|  | {5,15} | 
|  | }; | 
|  |  | 
|  | SkScalar strokeWidths[] = { | 
|  | 20, 10, 20, 40 | 
|  | }; | 
|  |  | 
|  | for (int i = 0; i < 4; ++i) { | 
|  | SkRRect circleRect; | 
|  | circleRect.setRectXY(rect, radii[i][0], radii[i][1]); | 
|  |  | 
|  | canvas->save(); | 
|  | // position the roundrect, and make it at off-integer coords. | 
|  | canvas->translate(kXStart + SK_Scalar1 * kXStep * 5 + SK_Scalar1 / 4, | 
|  | kYStart + SK_Scalar1 * kYStep * i + 3 * SK_Scalar1 / 4 + | 
|  | SK_ScalarHalf * kYStep); | 
|  |  | 
|  | SkColor color = genColor(&rand); | 
|  |  | 
|  | SkPaint p; | 
|  | p.setAntiAlias(true); | 
|  | p.setStyle(SkPaint::kStroke_Style); | 
|  | p.setStrokeWidth(strokeWidths[i]); | 
|  | p.setColor(color); | 
|  |  | 
|  | canvas->drawRRect(circleRect, p); | 
|  | canvas->restore(); | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | private: | 
|  | SkTArray<SkPaint> fPaints; | 
|  | SkTArray<SkMatrix> fMatrices; | 
|  |  | 
|  | typedef GM INHERITED; | 
|  | }; | 
|  |  | 
|  | ////////////////////////////////////////////////////////////////////////////// | 
|  |  | 
|  | static GM* MyFactory(void*) { return new RoundRectGM; } | 
|  | static GMRegistry reg(MyFactory); | 
|  |  | 
|  | } |