12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067 |
- /*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "gm/gm.h"
- #include "include/core/SkBlendMode.h"
- #include "include/core/SkCanvas.h"
- #include "include/core/SkColor.h"
- #include "include/core/SkColorSpace.h"
- #include "include/core/SkMatrix.h"
- #include "include/core/SkPaint.h"
- #include "include/core/SkPicture.h"
- #include "include/core/SkPictureRecorder.h"
- #include "include/core/SkPoint.h"
- #include "include/core/SkRect.h"
- #include "include/core/SkRefCnt.h"
- #include "include/core/SkScalar.h"
- #include "include/core/SkShader.h"
- #include "include/core/SkSize.h"
- #include "include/core/SkString.h"
- #include "include/core/SkTileMode.h"
- #include "include/core/SkTypes.h"
- #include "include/effects/SkGradientShader.h"
- #include <math.h>
- namespace {
- struct GradData {
- int fCount;
- const SkColor* fColors;
- const SkColor4f* fColors4f;
- const SkScalar* fPos;
- };
- constexpr SkColor gColors[] = {
- SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
- };
- constexpr SkColor4f gColors4f[] ={
- { 1.0f, 0.0f, 0.0f, 1.0f }, // Red
- { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
- { 0.0f, 0.0f, 1.0f, 1.0f }, // Blue
- { 1.0f, 1.0f, 1.0f, 1.0f }, // White
- { 0.0f, 0.0f, 0.0f, 1.0f } // Black
- };
- constexpr SkScalar gPos0[] = { 0, SK_Scalar1 };
- constexpr SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
- constexpr SkScalar gPos2[] = {
- 0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
- };
- constexpr SkScalar gPosClamp[] = {0.0f, 0.0f, 1.0f, 1.0f};
- constexpr SkColor gColorClamp[] = {
- SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLUE
- };
- constexpr SkColor4f gColor4fClamp[] ={
- { 1.0f, 0.0f, 0.0f, 1.0f }, // Red
- { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
- { 0.0f, 1.0f, 0.0f, 1.0f }, // Green
- { 0.0f, 0.0f, 1.0f, 1.0f } // Blue
- };
- constexpr GradData gGradData[] = {
- { 2, gColors, gColors4f, nullptr },
- { 2, gColors, gColors4f, gPos0 },
- { 2, gColors, gColors4f, gPos1 },
- { 5, gColors, gColors4f, nullptr },
- { 5, gColors, gColors4f, gPos2 },
- { 4, gColorClamp, gColor4fClamp, gPosClamp }
- };
- static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix) {
- return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm, 0,
- &localMatrix);
- }
- static sk_sp<SkShader> MakeLinear4f(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix) {
- auto srgb = SkColorSpace::MakeSRGB();
- return SkGradientShader::MakeLinear(pts, data.fColors4f, srgb, data.fPos, data.fCount, tm, 0,
- &localMatrix);
- }
- static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix) {
- SkPoint center;
- center.set(SkScalarAve(pts[0].fX, pts[1].fX),
- SkScalarAve(pts[0].fY, pts[1].fY));
- return SkGradientShader::MakeRadial(center, center.fX, data.fColors, data.fPos, data.fCount,
- tm, 0, &localMatrix);
- }
- static sk_sp<SkShader> MakeRadial4f(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix) {
- SkPoint center;
- center.set(SkScalarAve(pts[0].fX, pts[1].fX),
- SkScalarAve(pts[0].fY, pts[1].fY));
- auto srgb = SkColorSpace::MakeSRGB();
- return SkGradientShader::MakeRadial(center, center.fX, data.fColors4f, srgb, data.fPos,
- data.fCount, tm, 0, &localMatrix);
- }
- static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data,
- SkTileMode, const SkMatrix& localMatrix) {
- SkPoint center;
- center.set(SkScalarAve(pts[0].fX, pts[1].fX),
- SkScalarAve(pts[0].fY, pts[1].fY));
- return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors, data.fPos, data.fCount,
- 0, &localMatrix);
- }
- static sk_sp<SkShader> MakeSweep4f(const SkPoint pts[2], const GradData& data,
- SkTileMode, const SkMatrix& localMatrix) {
- SkPoint center;
- center.set(SkScalarAve(pts[0].fX, pts[1].fX),
- SkScalarAve(pts[0].fY, pts[1].fY));
- auto srgb = SkColorSpace::MakeSRGB();
- return SkGradientShader::MakeSweep(center.fX, center.fY, data.fColors4f, srgb, data.fPos,
- data.fCount, 0, &localMatrix);
- }
- static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix) {
- SkPoint center0, center1;
- center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
- SkScalarAve(pts[0].fY, pts[1].fY));
- center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
- SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
- return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
- center0, (pts[1].fX - pts[0].fX) / 2,
- data.fColors, data.fPos, data.fCount, tm,
- 0, &localMatrix);
- }
- static sk_sp<SkShader> Make2Radial4f(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix) {
- SkPoint center0, center1;
- center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
- SkScalarAve(pts[0].fY, pts[1].fY));
- center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3) / 5),
- SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1) / 4));
- auto srgb = SkColorSpace::MakeSRGB();
- return SkGradientShader::MakeTwoPointConical(center1, (pts[1].fX - pts[0].fX) / 7,
- center0, (pts[1].fX - pts[0].fX) / 2,
- data.fColors4f, srgb, data.fPos, data.fCount, tm,
- 0, &localMatrix);
- }
- static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix) {
- SkPoint center0, center1;
- SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
- SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
- center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
- center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
- return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0,
- data.fColors, data.fPos,
- data.fCount, tm, 0, &localMatrix);
- }
- static sk_sp<SkShader> Make2Conical4f(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix) {
- SkPoint center0, center1;
- SkScalar radius0 = (pts[1].fX - pts[0].fX) / 10;
- SkScalar radius1 = (pts[1].fX - pts[0].fX) / 3;
- center0.set(pts[0].fX + radius0, pts[0].fY + radius0);
- center1.set(pts[1].fX - radius1, pts[1].fY - radius1);
- auto srgb = SkColorSpace::MakeSRGB();
- return SkGradientShader::MakeTwoPointConical(center1, radius1, center0, radius0,
- data.fColors4f, srgb, data.fPos,
- data.fCount, tm, 0, &localMatrix);
- }
- typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data,
- SkTileMode tm, const SkMatrix& localMatrix);
- constexpr GradMaker gGradMakers[] = {
- MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical
- };
- constexpr GradMaker gGradMakers4f[] ={
- MakeLinear4f, MakeRadial4f, MakeSweep4f, Make2Radial4f, Make2Conical4f
- };
- ///////////////////////////////////////////////////////////////////////////////
- class GradientsGM : public skiagm::GM {
- public:
- GradientsGM(bool dither) : fDither(dither) {}
- protected:
- const bool fDither;
- void onDraw(SkCanvas* canvas) override {
- SkPoint pts[2] = {
- { 0, 0 },
- { SkIntToScalar(100), SkIntToScalar(100) }
- };
- SkTileMode tm = SkTileMode::kClamp;
- SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setDither(fDither);
- canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
- for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
- canvas->save();
- for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
- SkMatrix scale = SkMatrix::I();
- if (i == 5) { // if the clamp case
- scale.setScale(0.5f, 0.5f);
- scale.postTranslate(25.f, 25.f);
- }
- paint.setShader(gGradMakers[j](pts, gGradData[i], tm, scale));
- canvas->drawRect(r, paint);
- canvas->translate(0, SkIntToScalar(120));
- }
- canvas->restore();
- canvas->translate(SkIntToScalar(120), 0);
- }
- }
- private:
- void onOnceBeforeDraw() override { this->setBGColor(0xFFDDDDDD); }
- SkString onShortName() override {
- return SkString(fDither ? "gradients" : "gradients_nodither");
- }
- SkISize onISize() override { return {840, 815}; }
- };
- DEF_GM( return new GradientsGM(true); )
- DEF_GM( return new GradientsGM(false); )
- // Like the original gradients GM, but using the SkColor4f shader factories. Should be identical.
- class Gradients4fGM : public skiagm::GM {
- public:
- Gradients4fGM(bool dither) : fDither(dither) {}
- private:
- void onOnceBeforeDraw() override { this->setBGColor(0xFFDDDDDD); }
- SkString onShortName() override {
- return SkString(fDither ? "gradients4f" : "gradients4f_nodither");
- }
- SkISize onISize() override { return {840, 815}; }
- void onDraw(SkCanvas* canvas) override {
- SkPoint pts[2] ={
- { 0, 0 },
- { SkIntToScalar(100), SkIntToScalar(100) }
- };
- SkTileMode tm = SkTileMode::kClamp;
- SkRect r ={ 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setDither(fDither);
- canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
- for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
- canvas->save();
- for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers4f); j++) {
- SkMatrix scale = SkMatrix::I();
- if (i == 5) { // if the clamp case
- scale.setScale(0.5f, 0.5f);
- scale.postTranslate(25.f, 25.f);
- }
- paint.setShader(gGradMakers4f[j](pts, gGradData[i], tm, scale));
- canvas->drawRect(r, paint);
- canvas->translate(0, SkIntToScalar(120));
- }
- canvas->restore();
- canvas->translate(SkIntToScalar(120), 0);
- }
- }
- bool fDither;
- };
- DEF_GM(return new Gradients4fGM(true); )
- DEF_GM(return new Gradients4fGM(false); )
- // Based on the original gradient slide, but with perspective applied to the
- // gradient shaders' local matrices
- class GradientsLocalPerspectiveGM : public skiagm::GM {
- public:
- GradientsLocalPerspectiveGM(bool dither) : fDither(dither) {
- this->setBGColor(0xFFDDDDDD);
- }
- private:
- SkString onShortName() override {
- return SkString(fDither ? "gradients_local_perspective" :
- "gradients_local_perspective_nodither");
- }
- SkISize onISize() override { return {840, 815}; }
- void onDraw(SkCanvas* canvas) override {
- SkPoint pts[2] = {
- { 0, 0 },
- { SkIntToScalar(100), SkIntToScalar(100) }
- };
- SkTileMode tm = SkTileMode::kClamp;
- SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setDither(fDither);
- canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
- for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
- canvas->save();
- for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
- // apply an increasing y perspective as we move to the right
- SkMatrix perspective;
- perspective.setIdentity();
- perspective.setPerspY(SkIntToScalar(i+1) / 500);
- perspective.setSkewX(SkIntToScalar(i+1) / 10);
- paint.setShader(gGradMakers[j](pts, gGradData[i], tm, perspective));
- canvas->drawRect(r, paint);
- canvas->translate(0, SkIntToScalar(120));
- }
- canvas->restore();
- canvas->translate(SkIntToScalar(120), 0);
- }
- }
- bool fDither;
- };
- DEF_GM( return new GradientsLocalPerspectiveGM(true); )
- DEF_GM( return new GradientsLocalPerspectiveGM(false); )
- // Based on the original gradient slide, but with perspective applied to
- // the view matrix
- class GradientsViewPerspectiveGM : public GradientsGM {
- public:
- GradientsViewPerspectiveGM(bool dither) : INHERITED(dither) { }
- private:
- SkString onShortName() override {
- return SkString(fDither ? "gradients_view_perspective" :
- "gradients_view_perspective_nodither");
- }
- SkISize onISize() override { return {840, 500}; }
- void onDraw(SkCanvas* canvas) override {
- SkMatrix perspective;
- perspective.setIdentity();
- perspective.setPerspY(0.001f);
- perspective.setSkewX(SkIntToScalar(8) / 25);
- canvas->concat(perspective);
- this->INHERITED::onDraw(canvas);
- }
- private:
- typedef GradientsGM INHERITED;
- };
- DEF_GM( return new GradientsViewPerspectiveGM(true); )
- DEF_GM( return new GradientsViewPerspectiveGM(false); )
- /*
- Inspired by this <canvas> javascript, where we need to detect that we are not
- solving a quadratic equation, but must instead solve a linear (since our X^2
- coefficient is 0)
- ctx.fillStyle = '#f00';
- ctx.fillRect(0, 0, 100, 50);
- var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
- g.addColorStop(0, '#f00');
- g.addColorStop(0.01, '#0f0');
- g.addColorStop(0.99, '#0f0');
- g.addColorStop(1, '#f00');
- ctx.fillStyle = g;
- ctx.fillRect(0, 0, 100, 50);
- */
- class GradientsDegenrate2PointGM : public skiagm::GM {
- public:
- GradientsDegenrate2PointGM(bool dither) : fDither(dither) {}
- private:
- SkString onShortName() override {
- return SkString(fDither ? "gradients_degenerate_2pt" : "gradients_degenerate_2pt_nodither");
- }
- SkISize onISize() override { return {320, 320}; }
- void onDraw(SkCanvas* canvas) override {
- canvas->drawColor(SK_ColorBLUE);
- SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
- SkScalar pos[] = { 0, 0.01f, 0.99f, SK_Scalar1 };
- SkPoint c0;
- c0.iset(-80, 25);
- SkScalar r0 = SkIntToScalar(70);
- SkPoint c1;
- c1.iset(0, 25);
- SkScalar r1 = SkIntToScalar(150);
- SkPaint paint;
- paint.setShader(SkGradientShader::MakeTwoPointConical(c0, r0, c1, r1, colors,
- pos, SK_ARRAY_COUNT(pos),
- SkTileMode::kClamp));
- paint.setDither(fDither);
- canvas->drawPaint(paint);
- }
- bool fDither;
- };
- DEF_GM( return new GradientsDegenrate2PointGM(true); )
- DEF_GM( return new GradientsDegenrate2PointGM(false); )
- /* bug.skia.org/517
- <canvas id="canvas"></canvas>
- <script>
- var c = document.getElementById("canvas");
- var ctx = c.getContext("2d");
- ctx.fillStyle = '#ff0';
- ctx.fillRect(0, 0, 100, 50);
- var g = ctx.createRadialGradient(200, 25, 20, 200, 25, 10);
- g.addColorStop(0, '#0f0');
- g.addColorStop(0.003, '#f00'); // 0.004 makes this work
- g.addColorStop(1, '#ff0');
- ctx.fillStyle = g;
- ctx.fillRect(0, 0, 100, 50);
- </script>
- */
- // should draw only green
- DEF_SIMPLE_GM(small_color_stop, canvas, 100, 150) {
- SkColor colors[] = { SK_ColorGREEN, SK_ColorRED, SK_ColorYELLOW };
- SkScalar pos[] = { 0, 0.003f, SK_Scalar1 }; // 0.004f makes this work
- SkPoint c0 = { 200, 25 };
- SkScalar r0 = 20;
- SkPoint c1 = { 200, 25 };
- SkScalar r1 = 10;
- SkPaint paint;
- paint.setColor(SK_ColorYELLOW);
- canvas->drawRect(SkRect::MakeWH(100, 150), paint);
- paint.setShader(SkGradientShader::MakeTwoPointConical(c0, r0, c1, r1, colors, pos,
- SK_ARRAY_COUNT(pos),
- SkTileMode::kClamp));
- canvas->drawRect(SkRect::MakeWH(100, 150), paint);
- }
- /// Tests correctness of *optimized* codepaths in gradients.
- class ClampedGradientsGM : public skiagm::GM {
- public:
- ClampedGradientsGM(bool dither) : fDither(dither) {}
- private:
- SkString onShortName() override {
- return SkString(fDither ? "clamped_gradients" : "clamped_gradients_nodither");
- }
- SkISize onISize() override { return {640, 510}; }
- void onDraw(SkCanvas* canvas) override {
- canvas->drawColor(0xFFDDDDDD);
- SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
- SkPaint paint;
- paint.setDither(fDither);
- paint.setAntiAlias(true);
- SkPoint center;
- center.iset(0, 300);
- canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
- paint.setShader(SkGradientShader::MakeRadial(
- SkPoint(center),
- SkIntToScalar(200), gColors, nullptr, 5,
- SkTileMode::kClamp));
- canvas->drawRect(r, paint);
- }
- bool fDither;
- };
- DEF_GM( return new ClampedGradientsGM(true); )
- DEF_GM( return new ClampedGradientsGM(false); )
- /// Checks quality of large radial gradients, which may display
- /// some banding.
- class RadialGradientGM : public skiagm::GM {
- SkString onShortName() override { return SkString("radial_gradient"); }
- SkISize onISize() override { return {1280, 1280}; }
- void onDraw(SkCanvas* canvas) override {
- const SkISize dim = this->getISize();
- canvas->drawColor(0xFF000000);
- SkPaint paint;
- paint.setDither(true);
- SkPoint center;
- center.set(SkIntToScalar(dim.width())/2, SkIntToScalar(dim.height())/2);
- SkScalar radius = SkIntToScalar(dim.width())/2;
- const SkColor colors[] = { 0x7f7f7f7f, 0x7f7f7f7f, 0xb2000000 };
- const SkScalar pos[] = { 0.0f,
- 0.35f,
- 1.0f };
- paint.setShader(SkGradientShader::MakeRadial(center, radius, colors, pos,
- SK_ARRAY_COUNT(pos),
- SkTileMode::kClamp));
- SkRect r = {
- 0, 0, SkIntToScalar(dim.width()), SkIntToScalar(dim.height())
- };
- canvas->drawRect(r, paint);
- }
- };
- DEF_GM( return new RadialGradientGM; )
- class RadialGradient2GM : public skiagm::GM {
- public:
- RadialGradient2GM(bool dither) : fDither(dither) {}
- private:
- SkString onShortName() override {
- return SkString(fDither ? "radial_gradient2" : "radial_gradient2_nodither");
- }
- SkISize onISize() override { return {800, 400}; }
- // Reproduces the example given in bug 7671058.
- void onDraw(SkCanvas* canvas) override {
- SkPaint paint1, paint2, paint3;
- paint1.setStyle(SkPaint::kFill_Style);
- paint2.setStyle(SkPaint::kFill_Style);
- paint3.setStyle(SkPaint::kFill_Style);
- const SkColor sweep_colors[] =
- { 0xFFFF0000, 0xFFFFFF00, 0xFF00FF00, 0xFF00FFFF, 0xFF0000FF, 0xFFFF00FF, 0xFFFF0000 };
- const SkColor colors1[] = { 0xFFFFFFFF, 0x00000000 };
- const SkColor colors2[] = { 0xFF000000, 0x00000000 };
- const SkScalar cx = 200, cy = 200, radius = 150;
- SkPoint center;
- center.set(cx, cy);
- // We can either interpolate endpoints and premultiply each point (default, more precision),
- // or premultiply the endpoints first, avoiding the need to premultiply each point (cheap).
- const uint32_t flags[] = { 0, SkGradientShader::kInterpolateColorsInPremul_Flag };
- for (size_t i = 0; i < SK_ARRAY_COUNT(flags); i++) {
- paint1.setShader(SkGradientShader::MakeSweep(cx, cy, sweep_colors,
- nullptr, SK_ARRAY_COUNT(sweep_colors),
- flags[i], nullptr));
- paint2.setShader(SkGradientShader::MakeRadial(center, radius, colors1,
- nullptr, SK_ARRAY_COUNT(colors1),
- SkTileMode::kClamp,
- flags[i], nullptr));
- paint3.setShader(SkGradientShader::MakeRadial(center, radius, colors2,
- nullptr, SK_ARRAY_COUNT(colors2),
- SkTileMode::kClamp,
- flags[i], nullptr));
- paint1.setDither(fDither);
- paint2.setDither(fDither);
- paint3.setDither(fDither);
- canvas->drawCircle(cx, cy, radius, paint1);
- canvas->drawCircle(cx, cy, radius, paint3);
- canvas->drawCircle(cx, cy, radius, paint2);
- canvas->translate(400, 0);
- }
- }
- private:
- bool fDither;
- typedef GM INHERITED;
- };
- DEF_GM( return new RadialGradient2GM(true); )
- DEF_GM( return new RadialGradient2GM(false); )
- // Shallow radial (shows banding on raster)
- class RadialGradient3GM : public skiagm::GM {
- public:
- RadialGradient3GM(bool dither) : fDither(dither) { }
- private:
- SkString onShortName() override {
- return SkString(fDither ? "radial_gradient3" : "radial_gradient3_nodither");
- }
- SkISize onISize() override { return {500, 500}; }
- bool runAsBench() const override { return true; }
- void onOnceBeforeDraw() override {
- const SkPoint center = { 0, 0 };
- const SkScalar kRadius = 3000;
- const SkColor gColors[] = { 0xFFFFFFFF, 0xFF000000 };
- fShader = SkGradientShader::MakeRadial(center, kRadius, gColors, nullptr, 2,
- SkTileMode::kClamp);
- }
- void onDraw(SkCanvas* canvas) override {
- SkPaint paint;
- paint.setShader(fShader);
- paint.setDither(fDither);
- canvas->drawRect(SkRect::MakeWH(500, 500), paint);
- }
- private:
- sk_sp<SkShader> fShader;
- bool fDither;
- typedef GM INHERITED;
- };
- DEF_GM( return new RadialGradient3GM(true); )
- DEF_GM( return new RadialGradient3GM(false); )
- class RadialGradient4GM : public skiagm::GM {
- public:
- RadialGradient4GM(bool dither) : fDither(dither) { }
- private:
- SkString onShortName() override {
- return SkString(fDither ? "radial_gradient4" : "radial_gradient4_nodither");
- }
- SkISize onISize() override { return {500, 500}; }
- void onOnceBeforeDraw() override {
- const SkPoint center = { 250, 250 };
- const SkScalar kRadius = 250;
- const SkColor colors[] = { SK_ColorRED, SK_ColorRED, SK_ColorWHITE, SK_ColorWHITE,
- SK_ColorRED };
- const SkScalar pos[] = { 0, .4f, .4f, .8f, .8f, 1 };
- fShader = SkGradientShader::MakeRadial(center, kRadius, colors, pos,
- SK_ARRAY_COUNT(gColors), SkTileMode::kClamp);
- }
- void onDraw(SkCanvas* canvas) override {
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setDither(fDither);
- paint.setShader(fShader);
- canvas->drawRect(SkRect::MakeWH(500, 500), paint);
- }
- private:
- sk_sp<SkShader> fShader;
- bool fDither;
- typedef GM INHERITED;
- };
- DEF_GM( return new RadialGradient4GM(true); )
- DEF_GM( return new RadialGradient4GM(false); )
- class LinearGradientGM : public skiagm::GM {
- public:
- LinearGradientGM(bool dither) : fDither(dither) { }
- private:
- SkString onShortName() override {
- return SkString(fDither ? "linear_gradient" : "linear_gradient_nodither");
- }
- const SkScalar kWidthBump = 30.f;
- const SkScalar kHeight = 5.f;
- const SkScalar kMinWidth = 540.f;
- SkISize onISize() override { return {500, 500}; }
- void onOnceBeforeDraw() override {
- SkPoint pts[2] = { {0, 0}, {0, 0} };
- const SkColor colors[] = { SK_ColorWHITE, SK_ColorWHITE, 0xFF008200, 0xFF008200,
- SK_ColorWHITE, SK_ColorWHITE };
- const SkScalar unitPos[] = { 0, 50, 70, 500, 540 };
- SkScalar pos[6];
- pos[5] = 1;
- for (int index = 0; index < (int) SK_ARRAY_COUNT(fShader); ++index) {
- pts[1].fX = 500.f + index * kWidthBump;
- for (int inner = 0; inner < (int) SK_ARRAY_COUNT(unitPos); ++inner) {
- pos[inner] = unitPos[inner] / (kMinWidth + index * kWidthBump);
- }
- fShader[index] = SkGradientShader::MakeLinear(pts, colors, pos,
- SK_ARRAY_COUNT(gColors), SkTileMode::kClamp);
- }
- }
- void onDraw(SkCanvas* canvas) override {
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setDither(fDither);
- for (int index = 0; index < (int) SK_ARRAY_COUNT(fShader); ++index) {
- paint.setShader(fShader[index]);
- canvas->drawRect(SkRect::MakeLTRB(0, index * kHeight, kMinWidth + index * kWidthBump,
- (index + 1) * kHeight), paint);
- }
- }
- private:
- sk_sp<SkShader> fShader[100];
- bool fDither;
- typedef GM INHERITED;
- };
- DEF_GM( return new LinearGradientGM(true); )
- DEF_GM( return new LinearGradientGM(false); )
- class LinearGradientTinyGM : public skiagm::GM {
- static constexpr uint32_t kFlags = 0;
- SkString onShortName() override { return SkString("linear_gradient_tiny"); }
- SkISize onISize() override { return {600, 500}; }
- void onDraw(SkCanvas* canvas) override {
- const SkScalar kRectSize = 100;
- const unsigned kStopCount = 3;
- const SkColor colors[kStopCount] = { SK_ColorGREEN, SK_ColorRED, SK_ColorGREEN };
- const struct {
- SkPoint pts[2];
- SkScalar pos[kStopCount];
- } configs[] = {
- { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.999999f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.000001f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.999999999f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(10, 0) }, { 0, 0.000000001f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.999999f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.000001f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.999999999f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(0, 10) }, { 0, 0.000000001f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(0.00001f, 0) }, { 0, 0.5f, 1 }},
- { { SkPoint::Make(9.99999f, 0), SkPoint::Make(10, 0) }, { 0, 0.5f, 1 }},
- { { SkPoint::Make(0, 0), SkPoint::Make(0, 0.00001f) }, { 0, 0.5f, 1 }},
- { { SkPoint::Make(0, 9.99999f), SkPoint::Make(0, 10) }, { 0, 0.5f, 1 }},
- };
- SkPaint paint;
- for (unsigned i = 0; i < SK_ARRAY_COUNT(configs); ++i) {
- SkAutoCanvasRestore acr(canvas, true);
- paint.setShader(SkGradientShader::MakeLinear(configs[i].pts, colors, configs[i].pos,
- kStopCount, SkTileMode::kClamp,
- kFlags, nullptr));
- canvas->translate(kRectSize * ((i % 4) * 1.5f + 0.25f),
- kRectSize * ((i / 4) * 1.5f + 0.25f));
- canvas->drawRect(SkRect::MakeWH(kRectSize, kRectSize), paint);
- }
- }
- };
- DEF_GM( return new LinearGradientTinyGM; )
- } // namespace
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- struct GradRun {
- SkColor fColors[4];
- SkScalar fPos[4];
- int fCount;
- };
- #define SIZE 121
- static sk_sp<SkShader> make_linear(const GradRun& run, SkTileMode mode) {
- const SkPoint pts[] { { 30, 30 }, { SIZE - 30, SIZE - 30 } };
- return SkGradientShader::MakeLinear(pts, run.fColors, run.fPos, run.fCount, mode);
- }
- static sk_sp<SkShader> make_radial(const GradRun& run, SkTileMode mode) {
- const SkScalar half = SIZE * 0.5f;
- return SkGradientShader::MakeRadial({half,half}, half - 10, run.fColors, run.fPos,
- run.fCount, mode);
- }
- static sk_sp<SkShader> make_conical(const GradRun& run, SkTileMode mode) {
- const SkScalar half = SIZE * 0.5f;
- const SkPoint center { half, half };
- return SkGradientShader::MakeTwoPointConical(center, 20, center, half - 10,
- run.fColors, run.fPos, run.fCount, mode);
- }
- static sk_sp<SkShader> make_sweep(const GradRun& run, SkTileMode) {
- const SkScalar half = SIZE * 0.5f;
- return SkGradientShader::MakeSweep(half, half, run.fColors, run.fPos, run.fCount);
- }
- /*
- * Exercise duplicate color-stops, at the ends, and in the middle
- *
- * At the time of this writing, only Linear correctly deals with duplicates at the ends,
- * and then only correctly on CPU backend.
- */
- DEF_SIMPLE_GM(gradients_dup_color_stops, canvas, 704, 564) {
- const SkColor preColor = 0xFFFF0000; // clamp color before start
- const SkColor postColor = 0xFF0000FF; // clamp color after end
- const SkColor color0 = 0xFF000000;
- const SkColor color1 = 0xFF00FF00;
- const SkColor badColor = 0xFF3388BB; // should never be seen, fills out fixed-size array
- const GradRun runs[] = {
- { { color0, color1, badColor, badColor },
- { 0, 1, -1, -1 },
- 2,
- },
- { { preColor, color0, color1, badColor },
- { 0, 0, 1, -1 },
- 3,
- },
- { { color0, color1, postColor, badColor },
- { 0, 1, 1, -1 },
- 3,
- },
- { { preColor, color0, color1, postColor },
- { 0, 0, 1, 1 },
- 4,
- },
- { { color0, color0, color1, color1 },
- { 0, 0.5f, 0.5f, 1 },
- 4,
- },
- };
- sk_sp<SkShader> (*factories[])(const GradRun&, SkTileMode) {
- make_linear, make_radial, make_conical, make_sweep
- };
- const SkRect rect = SkRect::MakeWH(SIZE, SIZE);
- const SkScalar dx = SIZE + 20;
- const SkScalar dy = SIZE + 20;
- const SkTileMode mode = SkTileMode::kClamp;
- SkPaint paint;
- canvas->translate(10, 10 - dy);
- for (auto factory : factories) {
- canvas->translate(0, dy);
- SkAutoCanvasRestore acr(canvas, true);
- for (const auto& run : runs) {
- paint.setShader(factory(run, mode));
- canvas->drawRect(rect, paint);
- canvas->translate(dx, 0);
- }
- }
- }
- static void draw_many_stops(SkCanvas* canvas) {
- const unsigned kStopCount = 200;
- const SkPoint pts[] = { {50, 50}, {450, 465}};
- SkColor colors[kStopCount];
- for (unsigned i = 0; i < kStopCount; i++) {
- switch (i % 5) {
- case 0: colors[i] = SK_ColorRED; break;
- case 1: colors[i] = SK_ColorGREEN; break;
- case 2: colors[i] = SK_ColorGREEN; break;
- case 3: colors[i] = SK_ColorBLUE; break;
- case 4: colors[i] = SK_ColorRED; break;
- }
- }
- SkPaint p;
- p.setShader(SkGradientShader::MakeLinear(
- pts, colors, nullptr, SK_ARRAY_COUNT(colors), SkTileMode::kClamp));
- canvas->drawRect(SkRect::MakeXYWH(0, 0, 500, 500), p);
- }
- DEF_SIMPLE_GM(gradient_many_stops, canvas, 500, 500) {
- draw_many_stops(canvas);
- }
- static void draw_circle_shader(SkCanvas* canvas, SkScalar cx, SkScalar cy, SkScalar r,
- sk_sp<SkShader> (*shaderFunc)()) {
- SkPaint p;
- p.setAntiAlias(true);
- p.setShader(shaderFunc());
- canvas->drawCircle(cx, cy, r, p);
- p.setShader(nullptr);
- p.setColor(SK_ColorGRAY);
- p.setStyle(SkPaint::kStroke_Style);
- p.setStrokeWidth(2);
- canvas->drawCircle(cx, cy, r, p);
- }
- DEF_SIMPLE_GM(fancy_gradients, canvas, 800, 300) {
- draw_circle_shader(canvas, 150, 150, 100, []() -> sk_sp<SkShader> {
- // Checkerboard using two linear gradients + picture shader.
- SkScalar kTileSize = 80 / sqrtf(2);
- SkColor colors1[] = { 0xff000000, 0xff000000,
- 0xffffffff, 0xffffffff,
- 0xff000000, 0xff000000 };
- SkColor colors2[] = { 0xff000000, 0xff000000,
- 0x00000000, 0x00000000,
- 0xff000000, 0xff000000 };
- SkScalar pos[] = { 0, .25f, .25f, .75f, .75f, 1 };
- static_assert(SK_ARRAY_COUNT(colors1) == SK_ARRAY_COUNT(pos), "color/pos size mismatch");
- static_assert(SK_ARRAY_COUNT(colors2) == SK_ARRAY_COUNT(pos), "color/pos size mismatch");
- SkPictureRecorder recorder;
- recorder.beginRecording(SkRect::MakeWH(kTileSize, kTileSize));
- SkPaint p;
- SkPoint pts1[] = { { 0, 0 }, { kTileSize, kTileSize }};
- p.setShader(SkGradientShader::MakeLinear(pts1, colors1, pos, SK_ARRAY_COUNT(colors1),
- SkTileMode::kClamp, 0, nullptr));
- recorder.getRecordingCanvas()->drawPaint(p);
- SkPoint pts2[] = { { 0, kTileSize }, { kTileSize, 0 }};
- p.setShader(SkGradientShader::MakeLinear(pts2, colors2, pos, SK_ARRAY_COUNT(colors2),
- SkTileMode::kClamp, 0, nullptr));
- recorder.getRecordingCanvas()->drawPaint(p);
- SkMatrix m = SkMatrix::I();
- m.preRotate(45);
- return recorder.finishRecordingAsPicture()->makeShader(
- SkTileMode::kRepeat,
- SkTileMode::kRepeat, &m, nullptr);
- });
- draw_circle_shader(canvas, 400, 150, 100, []() -> sk_sp<SkShader> {
- // Checkerboard using a sweep gradient + picture shader.
- SkScalar kTileSize = 80;
- SkColor colors[] = { 0xff000000, 0xff000000,
- 0xffffffff, 0xffffffff,
- 0xff000000, 0xff000000,
- 0xffffffff, 0xffffffff };
- SkScalar pos[] = { 0, .25f, .25f, .5f, .5f, .75f, .75f, 1 };
- static_assert(SK_ARRAY_COUNT(colors) == SK_ARRAY_COUNT(pos), "color/pos size mismatch");
- SkPaint p;
- p.setShader(SkGradientShader::MakeSweep(kTileSize / 2, kTileSize / 2,
- colors, pos, SK_ARRAY_COUNT(colors), 0, nullptr));
- SkPictureRecorder recorder;
- recorder.beginRecording(SkRect::MakeWH(kTileSize, kTileSize))->drawPaint(p);
- return recorder.finishRecordingAsPicture()->makeShader(
- SkTileMode::kRepeat,
- SkTileMode::kRepeat);
- });
- draw_circle_shader(canvas, 650, 150, 100, []() -> sk_sp<SkShader> {
- // Dartboard using sweep + radial.
- const SkColor a = 0xffffffff;
- const SkColor b = 0xff000000;
- SkColor colors[] = { a, a, b, b, a, a, b, b, a, a, b, b, a, a, b, b};
- SkScalar pos[] = { 0, .125f, .125f, .25f, .25f, .375f, .375f, .5f, .5f,
- .625f, .625f, .75f, .75f, .875f, .875f, 1};
- static_assert(SK_ARRAY_COUNT(colors) == SK_ARRAY_COUNT(pos), "color/pos size mismatch");
- SkPoint center = { 650, 150 };
- sk_sp<SkShader> sweep1 = SkGradientShader::MakeSweep(center.x(), center.y(), colors, pos,
- SK_ARRAY_COUNT(colors), 0, nullptr);
- SkMatrix m = SkMatrix::I();
- m.preRotate(22.5f, center.x(), center.y());
- sk_sp<SkShader> sweep2 = SkGradientShader::MakeSweep(center.x(), center.y(), colors, pos,
- SK_ARRAY_COUNT(colors), 0, &m);
- sk_sp<SkShader> sweep(SkShaders::Blend(SkBlendMode::kExclusion, sweep1, sweep2));
- SkScalar radialPos[] = { 0, .02f, .02f, .04f, .04f, .08f, .08f, .16f, .16f, .31f, .31f,
- .62f, .62f, 1, 1, 1 };
- static_assert(SK_ARRAY_COUNT(colors) == SK_ARRAY_COUNT(radialPos),
- "color/pos size mismatch");
- return SkShaders::Blend(SkBlendMode::kExclusion, sweep,
- SkGradientShader::MakeRadial(center, 100, colors,
- radialPos,
- SK_ARRAY_COUNT(radialPos),
- SkTileMode::kClamp));
- });
- }
- DEF_SIMPLE_GM(sweep_tiling, canvas, 690, 512) {
- static constexpr SkScalar size = 160;
- static constexpr SkColor colors[] = { SK_ColorBLUE, SK_ColorYELLOW, SK_ColorGREEN };
- static constexpr SkScalar pos[] = { 0, .25f, .50f };
- static_assert(SK_ARRAY_COUNT(colors) == SK_ARRAY_COUNT(pos), "size mismatch");
- static constexpr SkTileMode modes[] = { SkTileMode::kClamp,
- SkTileMode::kRepeat,
- SkTileMode::kMirror };
- static const struct {
- SkScalar start, end;
- } angles[] = {
- { -330, -270 },
- { 30, 90 },
- { 390, 450 },
- { -30, 800 },
- };
- SkPaint p;
- const SkRect r = SkRect::MakeWH(size, size);
- for (auto mode : modes) {
- {
- SkAutoCanvasRestore acr(canvas, true);
- for (auto angle : angles) {
- p.setShader(SkGradientShader::MakeSweep(size / 2, size / 2, colors, pos,
- SK_ARRAY_COUNT(colors), mode,
- angle.start, angle.end, 0, nullptr));
- canvas->drawRect(r, p);
- canvas->translate(size * 1.1f, 0);
- }
- }
- canvas->translate(0, size * 1.1f);
- }
- }
- // Exercises the special-case Ganesh gradient effects.
- DEF_SIMPLE_GM(gradients_interesting, canvas, 640, 1300) {
- static const SkColor colors2[] = { SK_ColorRED, SK_ColorBLUE };
- static const SkColor colors3[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorBLUE };
- static const SkColor colors4[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorYELLOW, SK_ColorBLUE };
- static const SkScalar softRight[] = { 0, .999f, 1 }; // Based on Android launcher "clipping"
- static const SkScalar hardLeft[] = { 0, 0, 1 };
- static const SkScalar hardRight[] = { 0, 1, 1 };
- static const SkScalar hardCenter[] = { 0, .5f, .5f, 1 };
- static const struct {
- const SkColor* colors;
- const SkScalar* pos;
- int count;
- } configs[] = {
- { colors2, nullptr, 2 }, // kTwo_ColorType
- { colors3, nullptr, 3 }, // kThree_ColorType (simple)
- { colors3, softRight, 3 }, // kThree_ColorType (tricky)
- { colors3, hardLeft, 3 }, // kHardStopLeftEdged_ColorType
- { colors3, hardRight, 3 }, // kHardStopRightEdged_ColorType
- { colors4, hardCenter, 4 }, // kSingleHardStop_ColorType
- };
- static const SkTileMode modes[] = {
- SkTileMode::kClamp,
- SkTileMode::kRepeat,
- SkTileMode::kMirror,
- };
- static constexpr SkScalar size = 200;
- static const SkPoint pts[] = { { size / 3, size / 3 }, { size * 2 / 3, size * 2 / 3} };
- SkPaint p;
- for (const auto& cfg : configs) {
- {
- SkAutoCanvasRestore acr(canvas, true);
- for (auto mode : modes) {
- p.setShader(SkGradientShader::MakeLinear(pts, cfg.colors, cfg.pos, cfg.count,
- mode));
- canvas->drawRect(SkRect::MakeWH(size, size), p);
- canvas->translate(size * 1.1f, 0);
- }
- }
- canvas->translate(0, size * 1.1f);
- }
- }
|