static void doDraw(SkCanvas* canvas, const SkPaint& paint, const char text[]) { canvas->drawColor(SK_ColorWHITE); SkPaint red; red.setColor(SK_ColorRED); canvas->drawCircle(150.0, 150.0, 100.0, red); SkRect bounds; canvas->getClipBounds(&bounds); canvas->drawText(text, strlen(text), bounds.centerX(), bounds.centerY(), paint); }
static void draw_center_letter(char c, SkPaint* p, SkColor color, SkScalar x, SkScalar y, SkCanvas* canvas) { SkRect bounds; p->setColor(color); p->measureText(&c, 1, &bounds); canvas->drawText(&c, 1, x - bounds.centerX(), y - bounds.centerY(), *p); }
static void draw_text(SkCanvas* canvas, const SkRect& r, SkImageFilter* imf) { SkPaint paint; paint.setImageFilter(imf); paint.setColor(SK_ColorGREEN); paint.setAntiAlias(true); paint.setTextSize(r.height()/2); paint.setTextAlign(SkPaint::kCenter_Align); canvas->save(); canvas->clipRect(r); canvas->drawText("Text", 4, r.centerX(), r.centerY(), paint); canvas->restore(); }
static void draw_text(SkCanvas* canvas, const SkRect& r, sk_sp<SkImageFilter> imf) { SkPaint paint; paint.setImageFilter(std::move(imf)); paint.setColor(SK_ColorGREEN); paint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&paint); paint.setTextSize(r.height()/2); paint.setTextAlign(SkPaint::kCenter_Align); canvas->save(); canvas->clipRect(r); canvas->drawText("Text", 4, r.centerX(), r.centerY(), paint); canvas->restore(); }
static void compute_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect* devInside, bool* isDegenerate, const SkMatrix& viewMatrix, const SkRect& rect, SkScalar strokeWidth, bool miterStroke) { SkRect devRect; viewMatrix.mapRect(&devRect, rect); SkVector devStrokeSize; if (strokeWidth > 0) { devStrokeSize.set(strokeWidth, strokeWidth); viewMatrix.mapVectors(&devStrokeSize, 1); devStrokeSize.setAbs(devStrokeSize); } else { devStrokeSize.set(SK_Scalar1, SK_Scalar1); } const SkScalar dx = devStrokeSize.fX; const SkScalar dy = devStrokeSize.fY; const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf); const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf); *devOutside = devRect; *devOutsideAssist = devRect; *devInside = devRect; devOutside->outset(rx, ry); devInside->inset(rx, ry); // If we have a degenerate stroking rect(ie the stroke is larger than inner rect) then we // make a degenerate inside rect to avoid double hitting. We will also jam all of the points // together when we render these rects. SkScalar spare; { SkScalar w = devRect.width() - dx; SkScalar h = devRect.height() - dy; spare = SkTMin(w, h); } *isDegenerate = spare <= 0; if (*isDegenerate) { devInside->fLeft = devInside->fRight = devRect.centerX(); devInside->fTop = devInside->fBottom = devRect.centerY(); } // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist) // to draw the outside of the octagon. Because there are 8 vertices on the outer // edge, while vertex number of inner edge is 4, the same as miter-stroke. if (!miterStroke) { devOutside->inset(0, ry); devOutsideAssist->outset(0, ry); } }
void drawTestBox(SkCanvas* cv, SkRect* r, float rot, SkPaint* paintIcon, std::string text, SkPaint* paintText) { cv->save(); cv->translate(r->centerX(),r->centerY()); cv->rotate(rot * 180 / M_PI); SkRect rs = SkRect::MakeLTRB(-r->width()/2, -r->height()/2, r->width()/2, r->height()/2); cv->drawRect(rs, *paintIcon); if (paintText != NULL) { cv->drawText(text.data(), text.length(), rs.centerX(), rs.centerY(), *paintText); } cv->restore(); }
static void draw_clipped_filter(SkCanvas* canvas, sk_sp<SkImageFilter> filter, size_t i, const SkRect& primBounds, const SkRect& clipBounds) { SkPaint paint; paint.setColor(SK_ColorWHITE); paint.setImageFilter(std::move(filter)); paint.setAntiAlias(true); canvas->save(); canvas->clipRect(clipBounds); if (5 == i) { canvas->translate(SkIntToScalar(16), SkIntToScalar(-32)); } else if (6 == i) { canvas->scale(SkScalarInvert(RESIZE_FACTOR_X), SkScalarInvert(RESIZE_FACTOR_Y)); } canvas->drawCircle(primBounds.centerX(), primBounds.centerY(), primBounds.width() * 2 / 5, paint); canvas->restore(); }
void onDraw(SkCanvas* canvas) override { SkPaint paint; paint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&paint); paint.setTextSize(1500); SkRect r; (void)paint.measureText("/", 1, &r); SkPoint pos = { this->width()/2 - r.centerX(), this->height()/2 - r.centerY() }; paint.setColor(SK_ColorRED); canvas->drawString("/", pos.fX, pos.fY, paint); paint.setColor(SK_ColorBLUE); canvas->drawPosText("\\", 1, &pos, paint); }
void onDrawContent(SkCanvas* canvas) override { const SkRect oval = fOval.makeOffset(fCenter.fX - fOval.centerX(), fCenter.fY - fOval.centerY()); SkPaint p; p.setAntiAlias(true); p.setStyle(SkPaint::kStroke_Style); canvas->drawOval(oval, p); const SkRect r = SkRect::MakeLTRB(200, 200, 300, 300); canvas->clipRect(r); p.setStyle(SkPaint::kFill_Style); p.setColor(SK_ColorRED); canvas->drawRect(r, p); p.setColor(0x800000FF); canvas->drawOval(oval, p); }
PathTexture* ArcShapeCache::getArc(float width, float height, float startAngle, float sweepAngle, bool useCenter, SkPaint* paint) { ArcShapeCacheEntry entry(width, height, startAngle, sweepAngle, useCenter, paint); PathTexture* texture = get(entry); if (!texture) { SkPath path; SkRect r; r.set(0.0f, 0.0f, width, height); if (useCenter) { path.moveTo(r.centerX(), r.centerY()); } path.arcTo(r, startAngle, sweepAngle, !useCenter); if (useCenter) { path.close(); } texture = addTexture(entry, &path, paint); } return texture; }
void onDrawContent(SkCanvas* canvas) override { SkRect oval = fOval; oval.offset(fCenter.fX - oval.centerX(), fCenter.fY - oval.centerY()); SkPaint p; p.setAntiAlias(true); p.setStyle(SkPaint::kStroke_Style); canvas->drawOval(oval, p); SkRect r; r.set(SkIntToScalar(200), SkIntToScalar(200), SkIntToScalar(300), SkIntToScalar(300)); canvas->clipRect(r); p.setStyle(SkPaint::kFill_Style); p.setColor(SK_ColorRED); canvas->drawRect(r, p); p.setColor(0x800000FF); r.set(SkIntToScalar(150), SkIntToScalar(10), SkIntToScalar(250), SkIntToScalar(400)); canvas->drawOval(oval, p); }
static void draw_oval(SkCanvas* canvas, bool showGL, int flags) { SkPaint paint; paint.setAntiAlias(true); SkRect r = SkRect::MakeLTRB(50, 70, 250, 370); setFade(&paint, showGL); canvas->drawOval(r, paint); if (showGL) { switch (flags) { case 0: { SkPath path; path.addOval(r); show_glframe(canvas, path); } break; case 1: case 3: { SkPath src, dst; src.addOval(r); tesselate(src, &dst); show_fan(canvas, dst, r.centerX(), r.centerY()); } break; case 2: { SkPaint p(paint); show_mesh(canvas, r); setGLFrame(&p); paint.setStyle(SkPaint::kFill_Style); canvas->drawCircle(r.centerX(), r.centerY(), 3, p); } break; } } canvas->translate(320, 0); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(25); canvas->drawOval(r, paint); if (showGL) { switch (flags) { case 0: { SkPath path; SkScalar rad = paint.getStrokeWidth() / 2; r.outset(rad, rad); path.addOval(r); r.inset(rad*2, rad*2); path.addOval(r); show_glframe(canvas, path); } break; case 1: { SkPath path0, path1; SkScalar rad = paint.getStrokeWidth() / 2; r.outset(rad, rad); path0.addOval(r); r.inset(rad*2, rad*2); path1.addOval(r); show_mesh_between(canvas, path0, path1); } break; case 2: { SkPath path; path.addOval(r); show_glframe(canvas, path); SkScalar rad = paint.getStrokeWidth() / 2; r.outset(rad, rad); show_mesh(canvas, r); } break; case 3: { SkScalar rad = paint.getStrokeWidth() / 2; r.outset(rad, rad); SkPaint paint; paint.setAlpha(0x33); canvas->drawRect(r, paint); show_mesh(canvas, r); } break; } } }
virtual void onDraw(SkCanvas* canvas) { this->drawBG(canvas); if (true) { SkRect r; r.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(220), SkIntToScalar(120)); SkPaint p; canvas->saveLayer(&r, &p); canvas->drawColor(0xFFFF0000); p.setAlpha(1); // or 0 p.setXfermodeMode(SkXfermode::kSrc_Mode); canvas->drawOval(r, p); canvas->restore(); return; } if (false) { SkRect r; r.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(220), SkIntToScalar(120)); SkPaint p; p.setAlpha(0x88); p.setAntiAlias(true); if (true) { canvas->saveLayer(&r, &p); p.setColor(0xFFFF0000); canvas->drawOval(r, p); canvas->restore(); } p.setColor(0xFF0000FF); r.offset(SkIntToScalar(20), SkIntToScalar(50)); canvas->drawOval(r, p); } if (false) { SkPaint p; p.setAlpha(0x88); p.setAntiAlias(true); canvas->translate(SkIntToScalar(300), 0); SkRect r; r.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(220), SkIntToScalar(60)); canvas->saveLayer(&r, &p, (SkCanvas::SaveFlags)(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag)); // canvas->clipRect(r, SkRegion::kDifference_Op); // canvas->clipRect(r, SkRegion::kIntersect_Op); r.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(220), SkIntToScalar(120)); p.setColor(SK_ColorBLUE); canvas->drawOval(r, p); canvas->restore(); return; } //canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); test_fade(canvas); return; // canvas->setDrawFilter(new RedFilter)->unref(); SkRect r; SkPaint p; canvas->translate(SkIntToScalar(220), SkIntToScalar(20)); p.setAntiAlias(true); r.set(SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(220), SkIntToScalar(120)); p.setColor(SK_ColorBLUE); // p.setMaskFilter(SkBlurMaskFilter::Create(SkIntToScalar(8), SkBlurMaskFilter::kNormal_BlurStyle))->unref(); canvas->drawRect(r, p); p.setMaskFilter(NULL); SkRect bounds = r; bounds.fBottom = bounds.centerY(); canvas->saveLayer(&bounds, NULL, SkCanvas::kARGB_NoClipLayer_SaveFlag); p.setColor(SK_ColorRED); canvas->drawOval(r, p); p.setAlpha(0x80); p.setXfermodeMode(SkXfermode::kDstIn_Mode); canvas->drawRect(bounds, p); canvas->restore(); }
virtual void onDraw(SkCanvas* canvas) { if (!fInitialized) { this->make_checkerboard(); this->make_gradient_circle(64, 64); fInitialized = true; } canvas->clear(0x00000000); SkAutoTUnref<SkImageFilter> gradient(SkBitmapSource::Create(fGradientCircle)); SkAutoTUnref<SkImageFilter> checkerboard(SkBitmapSource::Create(fCheckerboard)); SkAutoTUnref<SkShader> noise(SkPerlinNoiseShader::CreateFractalNoise( SkDoubleToScalar(0.1), SkDoubleToScalar(0.05), 1, 0)); SkMatrix resizeMatrix; resizeMatrix.setScale(RESIZE_FACTOR_X, RESIZE_FACTOR_Y); SkImageFilter* filters[] = { SkBlurImageFilter::Create(SkIntToScalar(12), SkIntToScalar(12)), SkDropShadowImageFilter::Create(SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(3), SK_ColorGREEN), SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType, SkDisplacementMapEffect::kR_ChannelSelectorType, SkIntToScalar(12), gradient.get(), checkerboard.get()), SkDilateImageFilter::Create(2, 2, checkerboard.get()), SkErodeImageFilter::Create(2, 2, checkerboard.get()), SkOffsetImageFilter::Create(SkIntToScalar(-16), SkIntToScalar(32)), SkMatrixImageFilter::Create(resizeMatrix, SkPaint::kNone_FilterLevel), SkRectShaderImageFilter::Create(noise), }; SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64)); SkScalar margin = SkIntToScalar(16); SkRect bounds = r; bounds.outset(margin, margin); for (int xOffset = 0; xOffset < 80; xOffset += 16) { canvas->save(); bounds.fLeft = SkIntToScalar(xOffset); for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { SkPaint paint; paint.setColor(SK_ColorWHITE); paint.setImageFilter(filters[i]); paint.setAntiAlias(true); canvas->save(); canvas->clipRect(bounds); if (5 == i) { canvas->translate(SkIntToScalar(16), SkIntToScalar(-32)); } else if (6 == i) { canvas->scale(SkScalarInvert(RESIZE_FACTOR_X), SkScalarInvert(RESIZE_FACTOR_Y)); } canvas->drawCircle(r.centerX(), r.centerY(), SkScalarDiv(r.width()*2, SkIntToScalar(5)), paint); canvas->restore(); canvas->translate(r.width() + margin, 0); } canvas->restore(); canvas->translate(0, r.height() + margin); } for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { SkSafeUnref(filters[i]); } }
bool GetSpotShadowTransform(const SkPoint3& lightPos, SkScalar lightRadius, const SkMatrix& ctm, const SkPoint3& zPlaneParams, const SkRect& pathBounds, SkMatrix* shadowTransform, SkScalar* radius) { auto heightFunc = [zPlaneParams] (SkScalar x, SkScalar y) { return zPlaneParams.fX*x + zPlaneParams.fY*y + zPlaneParams.fZ; }; SkScalar occluderHeight = heightFunc(pathBounds.centerX(), pathBounds.centerY()); if (!ctm.hasPerspective()) { SkScalar scale; SkVector translate; SkDrawShadowMetrics::GetSpotParams(occluderHeight, lightPos.fX, lightPos.fY, lightPos.fZ, lightRadius, radius, &scale, &translate); shadowTransform->setScaleTranslate(scale, scale, translate.fX, translate.fY); shadowTransform->preConcat(ctm); } else { if (SkScalarNearlyZero(pathBounds.width()) || SkScalarNearlyZero(pathBounds.height())) { return false; } // get rotated quad in 3D SkPoint pts[4]; ctm.mapRectToQuad(pts, pathBounds); // No shadows for bowties or other degenerate cases if (!SkIsConvexPolygon(pts, 4)) { return false; } SkPoint3 pts3D[4]; SkScalar z = heightFunc(pathBounds.fLeft, pathBounds.fTop); pts3D[0].set(pts[0].fX, pts[0].fY, z); z = heightFunc(pathBounds.fRight, pathBounds.fTop); pts3D[1].set(pts[1].fX, pts[1].fY, z); z = heightFunc(pathBounds.fRight, pathBounds.fBottom); pts3D[2].set(pts[2].fX, pts[2].fY, z); z = heightFunc(pathBounds.fLeft, pathBounds.fBottom); pts3D[3].set(pts[3].fX, pts[3].fY, z); // project from light through corners to z=0 plane for (int i = 0; i < 4; ++i) { SkScalar dz = lightPos.fZ - pts3D[i].fZ; // light shouldn't be below or at a corner's z-location if (dz <= SK_ScalarNearlyZero) { return false; } SkScalar zRatio = pts3D[i].fZ / dz; pts3D[i].fX -= (lightPos.fX - pts3D[i].fX)*zRatio; pts3D[i].fY -= (lightPos.fY - pts3D[i].fY)*zRatio; pts3D[i].fZ = SK_Scalar1; } // Generate matrix that projects from [-1,1]x[-1,1] square to projected quad SkPoint3 h0, h1, h2; // Compute homogenous crossing point between top and bottom edges (gives new x-axis). h0 = (pts3D[1].cross(pts3D[0])).cross(pts3D[2].cross(pts3D[3])); // Compute homogenous crossing point between left and right edges (gives new y-axis). h1 = (pts3D[0].cross(pts3D[3])).cross(pts3D[1].cross(pts3D[2])); // Compute homogenous crossing point between diagonals (gives new origin). h2 = (pts3D[0].cross(pts3D[2])).cross(pts3D[1].cross(pts3D[3])); // If h2 is a vector (z=0 in 2D homogeneous space), that means that at least // two of the quad corners are coincident and we don't have a realistic projection if (SkScalarNearlyZero(h2.fZ)) { return false; } // In some cases the crossing points are in the wrong direction // to map (-1,-1) to pts3D[0], so we need to correct for that. // Want h0 to be to the right of the left edge. SkVector3 v = pts3D[3] - pts3D[0]; SkVector3 w = h0 - pts3D[0]; SkScalar perpDot = v.fX*w.fY - v.fY*w.fX; if (perpDot > 0) { h0 = -h0; } // Want h1 to be above the bottom edge. v = pts3D[1] - pts3D[0]; perpDot = v.fX*w.fY - v.fY*w.fX; if (perpDot < 0) { h1 = -h1; } shadowTransform->setAll(h0.fX / h2.fZ, h1.fX / h2.fZ, h2.fX / h2.fZ, h0.fY / h2.fZ, h1.fY / h2.fZ, h2.fY / h2.fZ, h0.fZ / h2.fZ, h1.fZ / h2.fZ, 1); // generate matrix that transforms from bounds to [-1,1]x[-1,1] square SkMatrix toHomogeneous; SkScalar xScale = 2/(pathBounds.fRight - pathBounds.fLeft); SkScalar yScale = 2/(pathBounds.fBottom - pathBounds.fTop); toHomogeneous.setAll(xScale, 0, -xScale*pathBounds.fLeft - 1, 0, yScale, -yScale*pathBounds.fTop - 1, 0, 0, 1); shadowTransform->preConcat(toHomogeneous); *radius = SkDrawShadowMetrics::SpotBlurRadius(occluderHeight, lightPos.fZ, lightRadius); } return true; }
void onOnceBeforeDraw() override { const SkRect fieldBounds = kBounds.makeOutset(kBallSize / 2, kBallSize / 2); const SkRRect ball = SkRRect::MakeOval(SkRect::MakeWH(kBallSize, kBallSize)); const SkRRect paddle = SkRRect::MakeRectXY(SkRect::MakeWH(kPaddleSize.width(), kPaddleSize.height()), kPaddleSize.width() / 2, kPaddleSize.width() / 2); fBall.initialize(ball, SkPoint::Make(kBounds.centerX(), kBounds.centerY()), SkVector::Make(fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax), fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax))); fPaddle0.initialize(paddle, SkPoint::Make(fieldBounds.left() - kPaddleSize.width() / 2, fieldBounds.centerY()), SkVector::Make(0, 0)); fPaddle1.initialize(paddle, SkPoint::Make(fieldBounds.right() + kPaddleSize.width() / 2, fieldBounds.centerY()), SkVector::Make(0, 0)); // Background decoration. SkPath bgPath; bgPath.moveTo(kBounds.left() , fieldBounds.top()); bgPath.lineTo(kBounds.right(), fieldBounds.top()); bgPath.moveTo(kBounds.left() , fieldBounds.bottom()); bgPath.lineTo(kBounds.right(), fieldBounds.bottom()); // TODO: stroke-dash support would come in handy right about now. for (uint32_t i = 0; i < kBackgroundDashCount; ++i) { bgPath.moveTo(kBounds.centerX(), kBounds.top() + (i + 0.25f) * kBounds.height() / kBackgroundDashCount); bgPath.lineTo(kBounds.centerX(), kBounds.top() + (i + 0.75f) * kBounds.height() / kBackgroundDashCount); } auto bg_path = sksg::Path::Make(bgPath); auto bg_paint = sksg::Color::Make(SK_ColorBLACK); bg_paint->setStyle(SkPaint::kStroke_Style); bg_paint->setStrokeWidth(kBackgroundStroke); auto ball_paint = sksg::Color::Make(SK_ColorGREEN), paddle0_paint = sksg::Color::Make(SK_ColorBLUE), paddle1_paint = sksg::Color::Make(SK_ColorRED), shadow_paint = sksg::Color::Make(SK_ColorBLACK); ball_paint->setAntiAlias(true); paddle0_paint->setAntiAlias(true); paddle1_paint->setAntiAlias(true); shadow_paint->setAntiAlias(true); shadow_paint->setOpacity(kShadowOpacity); // Build the scene graph. auto group = sksg::Group::Make(); group->addChild(sksg::Draw::Make(std::move(bg_path), std::move(bg_paint))); group->addChild(sksg::Draw::Make(fPaddle0.shadowNode, shadow_paint)); group->addChild(sksg::Draw::Make(fPaddle1.shadowNode, shadow_paint)); group->addChild(sksg::Draw::Make(fBall.shadowNode, shadow_paint)); group->addChild(sksg::Draw::Make(fPaddle0.objectNode, paddle0_paint)); group->addChild(sksg::Draw::Make(fPaddle1.objectNode, paddle1_paint)); group->addChild(sksg::Draw::Make(fBall.objectNode, ball_paint)); // Handle everything in a normalized 1x1 space. fContentMatrix = sksg::Matrix<SkMatrix>::Make( SkMatrix::MakeRectToRect(SkRect::MakeWH(1, 1), SkRect::MakeIWH(this->width(), this->height()), SkMatrix::kFill_ScaleToFit)); auto root = sksg::TransformEffect::Make(std::move(group), fContentMatrix); fScene = sksg::Scene::Make(std::move(root), sksg::AnimatorList()); // Off we go. this->updatePaddleStrategy(); }
void onDraw(SkCanvas* canvas) override { canvas->drawColor(sk_tool_utils::color_to_565(SK_ColorGRAY)); SkPaint paint; paint.setTypeface(emojiFont.typeface); const char* text = emojiFont.text; // draw text at different point sizes const int textSize[] = { 10, 30, 50, }; const int textYOffset[] = { 10, 40, 100, }; SkASSERT(sizeof(textSize) == sizeof(textYOffset)); size_t y_offset = 0; for (size_t y = 0; y < sizeof(textSize) / sizeof(int); y++) { paint.setTextSize(SkIntToScalar(textSize[y])); canvas->drawText(text, strlen(text), 10, SkIntToScalar(textYOffset[y]), paint); y_offset += textYOffset[y]; } // draw with shaders and image filters for (int makeLinear = 0; makeLinear < 2; makeLinear++) { for (int makeBlur = 0; makeBlur < 2; makeBlur++) { for (int makeGray = 0; makeGray < 2; makeGray++) { SkPaint shaderPaint; shaderPaint.setTypeface(paint.getTypeface()); if (SkToBool(makeLinear)) { shaderPaint.setShader(MakeLinear())->unref(); } if (SkToBool(makeBlur) && SkToBool(makeGray)) { SkAutoTUnref<SkImageFilter> grayScale(make_grayscale(nullptr)); SkAutoTUnref<SkImageFilter> blur(make_blur(3.0f, grayScale)); shaderPaint.setImageFilter(blur); } else if (SkToBool(makeBlur)) { SkAutoTUnref<SkImageFilter> blur(make_blur(3.0f, nullptr)); shaderPaint.setImageFilter(blur); } else if (SkToBool(makeGray)) { SkAutoTUnref<SkImageFilter> grayScale(make_grayscale(nullptr)); shaderPaint.setImageFilter(grayScale); } shaderPaint.setTextSize(30); canvas->drawText(text, strlen(text), 380, SkIntToScalar(y_offset), shaderPaint); y_offset += 32; } } } // setup work needed to draw text with different clips canvas->translate(10, 160); paint.setTextSize(40); // compute the bounds of the text SkRect bounds; paint.measureText(text, strlen(text), &bounds); const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf; const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf; const SkScalar boundsQuarterWidth = boundsHalfWidth * SK_ScalarHalf; const SkScalar boundsQuarterHeight = boundsHalfHeight * SK_ScalarHalf; SkRect upperLeftClip = SkRect::MakeXYWH(bounds.left(), bounds.top(), boundsHalfWidth, boundsHalfHeight); SkRect lowerRightClip = SkRect::MakeXYWH(bounds.centerX(), bounds.centerY(), boundsHalfWidth, boundsHalfHeight); SkRect interiorClip = bounds; interiorClip.inset(boundsQuarterWidth, boundsQuarterHeight); const SkRect clipRects[] = { bounds, upperLeftClip, lowerRightClip, interiorClip }; SkPaint clipHairline; clipHairline.setColor(SK_ColorWHITE); clipHairline.setStyle(SkPaint::kStroke_Style); for (size_t x = 0; x < sizeof(clipRects) / sizeof(SkRect); ++x) { canvas->save(); canvas->drawRect(clipRects[x], clipHairline); paint.setAlpha(0x20); canvas->drawText(text, strlen(text), 0, 0, paint); canvas->clipRect(clipRects[x]); paint.setAlpha(0xFF); canvas->drawText(text, strlen(text), 0, 0, paint); canvas->restore(); canvas->translate(0, bounds.height() + SkIntToScalar(25)); } }
// Draw stroked rects (both AA and nonAA) with all the types of joins: // bevel, miter, miter-limited-to-bevel, round // and as a hairline. DEF_SIMPLE_GM(stroke_rect_shader, canvas, 690, 300) { constexpr SkRect kRect {0, 0, 100, 100}; constexpr SkPoint kPts[] {{kRect.fLeft, kRect.fTop}, {kRect.fRight, kRect.fBottom}}; constexpr SkColor kColors[] {SK_ColorRED, SK_ColorBLUE}; SkPaint paint; sk_sp<SkShader> shader = SkGradientShader::MakeLinear(kPts, kColors, nullptr, 2, SkShader::kClamp_TileMode); paint.setShader(std::move(shader)); paint.setStyle(SkPaint::kStroke_Style); // Do a large initial translate so that local coords disagree with device coords significantly // for the first rect drawn. canvas->translate(kRect.centerX(), kRect.centerY()); constexpr SkScalar kPad = 20; for (auto aa : {false, true}) { paint.setAntiAlias(aa); canvas->save(); constexpr SkScalar kStrokeWidth = 10; paint.setStrokeWidth(kStrokeWidth); paint.setStrokeJoin(SkPaint::kBevel_Join); canvas->drawRect(kRect, paint); canvas->translate(kRect.width() + kPad, 0); paint.setStrokeJoin(SkPaint::kMiter_Join); canvas->drawRect(kRect, paint); canvas->translate(kRect.width() + kPad, 0);
virtual void onDraw(SkCanvas* canvas) { if (!fInitialized) { fCheckerboard.allocN32Pixels(64, 64); SkCanvas checkerboardCanvas(fCheckerboard); sk_tool_utils::draw_checkerboard(&checkerboardCanvas, 0xFFA0A0A0, 0xFF404040, 8); this->make_gradient_circle(64, 64); fInitialized = true; } canvas->clear(SK_ColorBLACK); SkAutoTUnref<SkImageFilter> gradient(SkBitmapSource::Create(fGradientCircle)); SkAutoTUnref<SkImageFilter> checkerboard(SkBitmapSource::Create(fCheckerboard)); SkAutoTUnref<SkShader> noise(SkPerlinNoiseShader::CreateFractalNoise( SkDoubleToScalar(0.1), SkDoubleToScalar(0.05), 1, 0)); SkPoint3 pointLocation(0, 0, SkIntToScalar(10)); SkPoint3 spotLocation(SkIntToScalar(-10), SkIntToScalar(-10), SkIntToScalar(20)); SkPoint3 spotTarget(SkIntToScalar(40), SkIntToScalar(40), 0); SkScalar spotExponent = SK_Scalar1; SkScalar cutoffAngle = SkIntToScalar(15); SkScalar kd = SkIntToScalar(2); SkScalar surfaceScale = SkIntToScalar(1); SkColor white(0xFFFFFFFF); SkMatrix resizeMatrix; resizeMatrix.setScale(RESIZE_FACTOR, RESIZE_FACTOR); SkImageFilter* filters[] = { SkBlurImageFilter::Create(SkIntToScalar(4), SkIntToScalar(4)), SkDropShadowImageFilter::Create(SkIntToScalar(5), SkIntToScalar(10), SkIntToScalar(3), SkIntToScalar(3), SK_ColorYELLOW, SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode), SkDisplacementMapEffect::Create(SkDisplacementMapEffect::kR_ChannelSelectorType, SkDisplacementMapEffect::kR_ChannelSelectorType, SkIntToScalar(12), gradient.get(), checkerboard.get()), SkDilateImageFilter::Create(1, 1, checkerboard.get()), SkErodeImageFilter::Create(1, 1, checkerboard.get()), SkOffsetImageFilter::Create(SkIntToScalar(32), 0), SkImageFilter::CreateMatrixFilter(resizeMatrix, kNone_SkFilterQuality), SkRectShaderImageFilter::Create(noise), SkLightingImageFilter::CreatePointLitDiffuse(pointLocation, white, surfaceScale, kd), SkLightingImageFilter::CreateSpotLitDiffuse(spotLocation, spotTarget, spotExponent, cutoffAngle, white, surfaceScale, kd), }; SkVector scales[] = { SkVector::Make(SkScalarInvert(2), SkScalarInvert(2)), SkVector::Make(SkIntToScalar(1), SkIntToScalar(1)), SkVector::Make(SkIntToScalar(1), SkIntToScalar(2)), SkVector::Make(SkIntToScalar(2), SkIntToScalar(1)), SkVector::Make(SkIntToScalar(2), SkIntToScalar(2)), }; SkRect r = SkRect::MakeWH(SkIntToScalar(64), SkIntToScalar(64)); SkScalar margin = SkIntToScalar(16); SkRect bounds = r; bounds.outset(margin, margin); for (size_t j = 0; j < SK_ARRAY_COUNT(scales); ++j) { canvas->save(); for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { SkPaint paint; paint.setColor(SK_ColorBLUE); paint.setImageFilter(filters[i]); paint.setAntiAlias(true); canvas->save(); canvas->scale(scales[j].fX, scales[j].fY); if (5 == i) { canvas->translate(SkIntToScalar(-32), 0); } else if (6 == i) { canvas->scale(SkScalarInvert(RESIZE_FACTOR), SkScalarInvert(RESIZE_FACTOR)); } canvas->drawCircle(r.centerX(), r.centerY(), SkScalarDiv(r.width()*2, SkIntToScalar(5)), paint); canvas->restore(); canvas->translate(r.width() * scales[j].fX + margin, 0); } canvas->restore(); canvas->translate(0, r.height() * scales[j].fY + margin); } for (size_t i = 0; i < SK_ARRAY_COUNT(filters); ++i) { filters[i]->unref(); } }
void onOnceBeforeDraw() override { const SkRect fieldBounds = kBounds.makeOutset(kBallSize / 2, kBallSize / 2); const SkRRect ball = SkRRect::MakeOval(SkRect::MakeWH(kBallSize, kBallSize)); const SkRRect paddle = SkRRect::MakeRectXY(SkRect::MakeWH(kPaddleSize.width(), kPaddleSize.height()), kPaddleSize.width() / 2, kPaddleSize.width() / 2); fBall.initialize(ball, SK_ColorGREEN, SkPoint::Make(kBounds.centerX(), kBounds.centerY()), SkVector::Make(fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax), fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax))); fPaddle0.initialize(paddle, SK_ColorBLUE, SkPoint::Make(fieldBounds.left() - kPaddleSize.width() / 2, fieldBounds.centerY()), SkVector::Make(0, 0)); fPaddle1.initialize(paddle, SK_ColorRED, SkPoint::Make(fieldBounds.right() + kPaddleSize.width() / 2, fieldBounds.centerY()), SkVector::Make(0, 0)); // Background decoration. SkPath bgPath; bgPath.moveTo(kBounds.left() , fieldBounds.top()); bgPath.lineTo(kBounds.right(), fieldBounds.top()); bgPath.moveTo(kBounds.left() , fieldBounds.bottom()); bgPath.lineTo(kBounds.right(), fieldBounds.bottom()); // TODO: stroke-dash support would come in handy right about now. for (uint32_t i = 0; i < kBackgroundDashCount; ++i) { bgPath.moveTo(kBounds.centerX(), kBounds.top() + (i + 0.25f) * kBounds.height() / kBackgroundDashCount); bgPath.lineTo(kBounds.centerX(), kBounds.top() + (i + 0.75f) * kBounds.height() / kBackgroundDashCount); } sk_sp<SkSVGPath> bg = SkSVGPath::Make(); bg->setPath(bgPath); bg->setFill(SkSVGPaint(SkSVGPaint::Type::kNone)); bg->setStroke(SkSVGPaint(SkSVGColorType(SK_ColorBLACK))); bg->setStrokeWidth(SkSVGLength(kBackgroundStroke)); // Build the SVG DOM tree. sk_sp<SkSVGSVG> root = SkSVGSVG::Make(); root->appendChild(std::move(bg)); root->appendChild(fPaddle0.shadowNode); root->appendChild(fPaddle1.shadowNode); root->appendChild(fBall.shadowNode); root->appendChild(fPaddle0.objectNode); root->appendChild(fPaddle1.objectNode); root->appendChild(fBall.objectNode); // Handle everything in a normalized 1x1 space. root->setViewBox(SkSVGViewBoxType(SkRect::MakeWH(1, 1))); fDom = sk_sp<SkSVGDOM>(new SkSVGDOM()); fDom->setContainerSize(SkSize::Make(this->width(), this->height())); fDom->setRoot(std::move(root)); // Off we go. this->updatePaddleStrategy(); }