| /* |
| * 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<SkPoint>* 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<SkPoint> 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 { |
| GrDrawContext* drawContext = canvas->internal_private_accessTopLayerDrawContext(); |
| if (!drawContext) { |
| 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;) |
| } |