/* * Copyright 2016 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 "SkRRect.h" #include "SkGaussianEdgeShader.h" //#define VIZ 1 #ifdef VIZ #include "SkStroke.h" static void draw_stroke(SkCanvas* canvas, const SkRRect& rr, const SkPaint& p, SkColor color) { SkPath output; if (SkPaint::kFill_Style == p.getStyle()) { output.addRRect(rr); } else { SkPath input; input.addRRect(rr); SkStroke stroke(p); stroke.strokePath(input, &output); } SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setColor(color); canvas->drawPath(output, paint); } static void extract_pts(const SkBitmap& bm, SkTDArray* pts, int xOff, int width) { pts->rewind(); for (int x = 0; x < width; ++x) { SkColor color = bm.getColor(xOff+x, 0); pts->append()->set(SkIntToScalar(x), 255.0f-SkColorGetB(color)); if (x > 0 && x < width-1) { pts->append()->set(SkIntToScalar(x), 255.0f-SkColorGetB(color)); } } } static void draw_row(SkCanvas* canvas, int row, int width) { SkPaint paint; paint.setAntiAlias(true); SkBitmap readback; if (!canvas->readPixels(SkIRect::MakeXYWH(0, row, width, 1), &readback)) { return; } SkTDArray pts; pts.setReserve(width/3); extract_pts(readback, &pts, 0, width/3); paint.setColor(SK_ColorRED); canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint); extract_pts(readback, &pts, width/3, width/3); paint.setColor(SK_ColorGREEN); canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint); extract_pts(readback, &pts, 2*width/3, width/3); paint.setColor(SK_ColorBLUE); canvas->drawPoints(SkCanvas::kLines_PointMode, pts.count(), pts.begin(), paint); } #endif namespace skiagm { // This GM exercises the SkGaussianEdgeShader. // It draws three columns showing filled, stroked, and stroke and filled rendering. // It draws three rows showing a blur radius smaller than, equal to // and, finally, double the RRect's corner radius // In VIZ mode an extra column is drawn showing the blur ramps (they should all line up). class GaussianEdgeGM : public GM { public: GaussianEdgeGM() { this->setBGColor(SK_ColorWHITE); } protected: SkString onShortName() override { return SkString("gaussianedge"); } SkISize onISize() override { int numCols = kNumBaseCols; #ifdef VIZ numCols++; #endif return SkISize::Make(kPad + numCols*(kCellWidth+kPad), kPad + kNumRows*(kCellWidth+kPad)); } static void DrawRow(SkCanvas* canvas, int blurRad, int midLine) { SkAutoCanvasRestore acr(canvas, true); SkRRect rrects[kNumBaseCols]; SkPaint paints[kNumBaseCols]; { const SkRect r = SkRect::MakeIWH(kRRSize, kRRSize); const SkRRect baseRR = SkRRect::MakeRectXY(r, SkIntToScalar(kRRRad), SkIntToScalar(kRRRad)); SkPaint basePaint; basePaint.setAntiAlias(true); basePaint.setShader(SkGaussianEdgeShader::Make()); basePaint.setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff, 0)); //---- paints[0] = basePaint; rrects[0] = baseRR; //---- paints[1] = basePaint; paints[1].setStyle(SkPaint::kStroke_Style); rrects[1] = baseRR; if (blurRad/2.0f < kRRRad) { rrects[1].inset(blurRad/2.0f, blurRad/2.0f); paints[1].setStrokeWidth(SkIntToScalar(blurRad)); } else { SkScalar inset = kRRRad - 0.5f; rrects[1].inset(inset, inset); SkScalar pad = blurRad/2.0f - inset; paints[1].setStrokeWidth(blurRad + 2.0f * pad); paints[1].setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff, (int)(4.0f*pad))); } //---- paints[2] = basePaint; paints[2].setStyle(SkPaint::kStrokeAndFill_Style); rrects[2] = baseRR; if (blurRad/2.0f < kRRRad) { rrects[2].inset(blurRad/2.0f, blurRad/2.0f); paints[2].setStrokeWidth(SkIntToScalar(blurRad)); } else { SkScalar inset = kRRRad - 0.5f; rrects[2].inset(inset, inset); SkScalar pad = blurRad/2.0f - inset; paints[2].setStrokeWidth(blurRad + 2.0f * pad); paints[2].setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff, (int)(4.0f*pad))); } } //---- canvas->save(); // draw the shadows for (int i = 0; i < kNumBaseCols; ++i) { canvas->drawRRect(rrects[i], paints[i]); canvas->translate(SkIntToScalar(kCellWidth+kPad), 0.0f); } #ifdef VIZ // draw the visualization of the shadow ramps draw_row(canvas, midLine, 3*(kRRSize+kPad)); #endif canvas->restore(); #ifdef VIZ const SkColor colors[kNumBaseCols] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE }; // circle back and draw the stroked geometry (they would mess up the viz otherwise) for (int i = 0; i < kNumBaseCols; ++i) { draw_stroke(canvas, rrects[i], paints[i], colors[i]); canvas->translate(SkIntToScalar(kCellWidth+kPad), 0.0f); } #endif } void onDraw(SkCanvas* canvas) override { GrRenderTargetContext* renderTargetContext = canvas->internal_private_accessTopLayerRenderTargetContext(); if (!renderTargetContext) { skiagm::GM::DrawGpuOnlyMessage(canvas); return; } const int blurRadii[kNumRows] = { kRRRad/2, kRRRad, 2*kRRRad }; canvas->translate(SkIntToScalar(kPad), SkIntToScalar(kPad)); for (int i = 0; i < kNumRows; ++i) { DrawRow(canvas, blurRadii[i], kPad+(i*kRRSize)+kRRSize/2); canvas->translate(0.0f, SkIntToScalar(kCellWidth+kPad)); } } private: static const int kNumRows = 3; static const int kNumBaseCols = 3; static const int kPad = 5; static const int kRRSize = 256; static const int kRRRad = 64; static const int kCellWidth = kRRSize; typedef GM INHERITED; }; ////////////////////////////////////////////////////////////////////////////// DEF_GM(return new GaussianEdgeGM;) }