299 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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/gm.h"
 | |
| #include "include/core/SkCanvas.h"
 | |
| #include "include/core/SkColor.h"
 | |
| #include "include/core/SkPaint.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 <string.h>
 | |
| 
 | |
| using namespace skiagm;
 | |
| 
 | |
| struct GradData {
 | |
|     int             fCount;
 | |
|     const SkColor*  fColors;
 | |
|     const SkScalar* fPos;
 | |
| };
 | |
| 
 | |
| constexpr SkColor gColors[] = {
 | |
|     SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE,
 | |
| };
 | |
| 
 | |
| constexpr GradData gGradData[] = {
 | |
|     { 1, gColors, nullptr },
 | |
|     { 2, gColors, nullptr },
 | |
|     { 3, gColors, nullptr },
 | |
|     { 4, gColors, nullptr },
 | |
| };
 | |
| 
 | |
| static sk_sp<SkShader> MakeLinear(const SkPoint pts[2], const GradData& data, SkTileMode tm) {
 | |
|     return SkGradientShader::MakeLinear(pts, data.fColors, data.fPos, data.fCount, tm);
 | |
| }
 | |
| 
 | |
| static sk_sp<SkShader> MakeRadial(const SkPoint pts[2], const GradData& data, SkTileMode tm) {
 | |
|     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);
 | |
| }
 | |
| 
 | |
| static sk_sp<SkShader> MakeSweep(const SkPoint pts[2], const GradData& data, SkTileMode) {
 | |
|     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);
 | |
| }
 | |
| 
 | |
| static sk_sp<SkShader> Make2Radial(const SkPoint pts[2], const GradData& data, SkTileMode tm) {
 | |
|     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);
 | |
| }
 | |
| 
 | |
| static sk_sp<SkShader> Make2Conical(const SkPoint pts[2], const GradData& data, SkTileMode tm) {
 | |
|     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);
 | |
| }
 | |
| 
 | |
| 
 | |
| typedef sk_sp<SkShader> (*GradMaker)(const SkPoint pts[2], const GradData& data, SkTileMode tm);
 | |
| 
 | |
| constexpr GradMaker gGradMakers[] = {
 | |
|     MakeLinear, MakeRadial, MakeSweep, Make2Radial, Make2Conical,
 | |
| };
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| class GradientsNoTextureGM : public GM {
 | |
| public:
 | |
|     GradientsNoTextureGM(bool dither) : fDither(dither) {
 | |
|         this->setBGColor(0xFFDDDDDD);
 | |
|     }
 | |
| 
 | |
| protected:
 | |
| 
 | |
|     SkString onShortName() override {
 | |
|         return SkString(fDither ? "gradients_no_texture" : "gradients_no_texture_nodither");
 | |
|     }
 | |
| 
 | |
|     SkISize onISize() override { return SkISize::Make(640, 615); }
 | |
| 
 | |
|     void onDraw(SkCanvas* canvas) override {
 | |
|         constexpr SkPoint kPts[2] = { { 0, 0 },
 | |
|                                          { SkIntToScalar(50), SkIntToScalar(50) } };
 | |
|         constexpr SkTileMode kTM = SkTileMode::kClamp;
 | |
|         SkRect kRect = { 0, 0, SkIntToScalar(50), SkIntToScalar(50) };
 | |
|         SkPaint paint;
 | |
|         paint.setAntiAlias(true);
 | |
|         paint.setDither(fDither);
 | |
| 
 | |
|         canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
 | |
|         constexpr uint8_t kAlphas[] = { 0xff, 0x40 };
 | |
|         for (size_t a = 0; a < SK_ARRAY_COUNT(kAlphas); ++a) {
 | |
|             for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); ++i) {
 | |
|                 canvas->save();
 | |
|                 for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); ++j) {
 | |
|                     paint.setShader(gGradMakers[j](kPts, gGradData[i], kTM));
 | |
|                     paint.setAlpha(kAlphas[a]);
 | |
|                     canvas->drawRect(kRect, paint);
 | |
|                     canvas->translate(0, SkIntToScalar(kRect.height() + 20));
 | |
|                 }
 | |
|                 canvas->restore();
 | |
|                 canvas->translate(SkIntToScalar(kRect.width() + 20), 0);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     bool fDither;
 | |
| 
 | |
|     using INHERITED = GM;
 | |
| };
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| struct ColorPos {
 | |
|     SkColor*    fColors;
 | |
|     SkScalar*   fPos;
 | |
|     int         fCount;
 | |
| 
 | |
|     ColorPos() : fColors(nullptr), fPos(nullptr), fCount(0) {}
 | |
|     ~ColorPos() {
 | |
|         delete[] fColors;
 | |
|         delete[] fPos;
 | |
|     }
 | |
| 
 | |
|     void construct(const SkColor colors[], const SkScalar pos[], int count) {
 | |
|         fColors = new SkColor[count];
 | |
|         memcpy(fColors, colors, count * sizeof(SkColor));
 | |
|         if (pos) {
 | |
|             fPos = new SkScalar[count];
 | |
|             memcpy(fPos, pos, count * sizeof(SkScalar));
 | |
|             fPos[0] = 0;
 | |
|             fPos[count - 1] = 1;
 | |
|         }
 | |
|         fCount = count;
 | |
|     }
 | |
| };
 | |
| 
 | |
| static void make0(ColorPos* rec) {
 | |
| #if 0
 | |
|     From http://jsfiddle.net/3fe2a/
 | |
| 
 | |
| background-image: -webkit-linear-gradient(left, #22d1cd 1%, #22d1cd 0.9510157507590116%, #df4b37 2.9510157507590113%, #df4b37 23.695886056604927%, #22d1cd 25.695886056604927%, #22d1cd 25.39321881940624%, #e6de36 27.39321881940624%, #e6de36 31.849399922570655%, #3267ff 33.849399922570655%, #3267ff 44.57735802921938%, #9d47d1 46.57735802921938%, #9d47d1 53.27185850805876%, #3267ff 55.27185850805876%, #3267ff 61.95718972227316%, #5cdd9d 63.95718972227316%, #5cdd9d 69.89166004442%, #3267ff 71.89166004442%, #3267ff 74.45795382765857%, #9d47d1 76.45795382765857%, #9d47d1 82.78364610713776%, #3267ff 84.78364610713776%, #3267ff 94.52743647737229%, #e3d082 96.52743647737229%, #e3d082 96.03934633331295%);
 | |
| height: 30px;
 | |
| #endif
 | |
| 
 | |
|     const SkColor colors[] = {
 | |
|         0xFF22d1cd, 0xFF22d1cd, 0xFFdf4b37, 0xFFdf4b37, 0xFF22d1cd, 0xFF22d1cd, 0xFFe6de36, 0xFFe6de36,
 | |
|         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFF5cdd9d, 0xFF5cdd9d,
 | |
|         0xFF3267ff, 0xFF3267ff, 0xFF9d47d1, 0xFF9d47d1, 0xFF3267ff, 0xFF3267ff, 0xFFe3d082, 0xFFe3d082
 | |
|     };
 | |
|     const double percent[] = {
 | |
|         1, 0.9510157507590116, 2.9510157507590113, 23.695886056604927,
 | |
|         25.695886056604927, 25.39321881940624, 27.39321881940624, 31.849399922570655,
 | |
|         33.849399922570655, 44.57735802921938, 46.57735802921938, 53.27185850805876,
 | |
|         55.27185850805876, 61.95718972227316, 63.95718972227316, 69.89166004442,
 | |
|         71.89166004442, 74.45795382765857, 76.45795382765857, 82.78364610713776,
 | |
|         84.78364610713776, 94.52743647737229, 96.52743647737229, 96.03934633331295,
 | |
|     };
 | |
|     const int N = SK_ARRAY_COUNT(percent);
 | |
|     SkScalar pos[N];
 | |
|     for (int i = 0; i < N; ++i) {
 | |
|         pos[i] = SkDoubleToScalar(percent[i] / 100);
 | |
|     }
 | |
|     rec->construct(colors, pos, N);
 | |
| }
 | |
| 
 | |
| static void make1(ColorPos* rec) {
 | |
|     const SkColor colors[] = {
 | |
|         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
 | |
|         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
 | |
|         SK_ColorBLACK,
 | |
|     };
 | |
|     rec->construct(colors, nullptr, SK_ARRAY_COUNT(colors));
 | |
| }
 | |
| 
 | |
| static void make2(ColorPos* rec) {
 | |
|     const SkColor colors[] = {
 | |
|         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
 | |
|         SK_ColorBLACK, SK_ColorWHITE, SK_ColorBLACK, SK_ColorWHITE,
 | |
|         SK_ColorBLACK,
 | |
|     };
 | |
|     const int N = SK_ARRAY_COUNT(colors);
 | |
|     SkScalar pos[N];
 | |
|     for (int i = 0; i < N; ++i) {
 | |
|         pos[i] = SK_Scalar1 * i / (N - 1);
 | |
|     }
 | |
|     rec->construct(colors, pos, N);
 | |
| }
 | |
| 
 | |
| static void make3(ColorPos* rec) {
 | |
|     const SkColor colors[] = {
 | |
|         SK_ColorRED, SK_ColorBLUE, SK_ColorBLUE, SK_ColorGREEN, SK_ColorGREEN, SK_ColorBLACK,
 | |
|     };
 | |
|     const SkScalar pos[] = {
 | |
|         0, 0, 0.5f, 0.5, 1, 1,
 | |
|     };
 | |
|     rec->construct(colors, pos, SK_ARRAY_COUNT(colors));
 | |
| }
 | |
| 
 | |
| class GradientsManyColorsGM : public GM {
 | |
|     enum {
 | |
|         W = 800,
 | |
|     };
 | |
|     sk_sp<SkShader> fShader;
 | |
| 
 | |
|     typedef void (*Proc)(ColorPos*);
 | |
| public:
 | |
|     GradientsManyColorsGM(bool dither) : fDither(dither) {}
 | |
| 
 | |
| protected:
 | |
| 
 | |
|     SkString onShortName() override {
 | |
|         return SkString(fDither ? "gradients_many" : "gradients_many_nodither");
 | |
|     }
 | |
| 
 | |
|     SkISize onISize() override { return SkISize::Make(880, 400); }
 | |
| 
 | |
|     void onDraw(SkCanvas* canvas) override {
 | |
|         const Proc procs[] = {
 | |
|             make0, make1, make2, make3,
 | |
|         };
 | |
|         const SkPoint pts[] = {
 | |
|             { 0, 0 },
 | |
|             { SkIntToScalar(W), 0 },
 | |
|         };
 | |
|         const SkRect r = SkRect::MakeWH(SkIntToScalar(W), 30);
 | |
| 
 | |
|         SkPaint paint;
 | |
|         paint.setDither(fDither);
 | |
| 
 | |
|         canvas->translate(40, 20);
 | |
| 
 | |
|         for (int i = 0; i <= 8; ++i) {
 | |
|             SkScalar x = r.width() * i / 8;
 | |
|             canvas->drawLine(x, 0, x, 10000, paint);
 | |
|         }
 | |
| 
 | |
|         // expand the drawing rect so we exercise clampping in the gradients
 | |
|         const SkRect drawR = r.makeOutset(20, 0);
 | |
|         for (size_t i = 0; i < SK_ARRAY_COUNT(procs); ++i) {
 | |
|             ColorPos rec;
 | |
|             procs[i](&rec);
 | |
|             paint.setShader(SkGradientShader::MakeLinear(pts, rec.fColors, rec.fPos, rec.fCount,
 | |
|                                                          SkTileMode::kClamp));
 | |
|             canvas->drawRect(drawR, paint);
 | |
| 
 | |
|             canvas->save();
 | |
|             canvas->translate(r.centerX(), r.height() + 4);
 | |
|             canvas->scale(-1, 1);
 | |
|             canvas->translate(-r.centerX(), 0);
 | |
|             canvas->drawRect(drawR, paint);
 | |
|             canvas->restore();
 | |
| 
 | |
|             canvas->translate(0, r.height() + 2*r.height() + 8);
 | |
|         }
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     bool fDither;
 | |
| 
 | |
|     using INHERITED = GM;
 | |
| };
 | |
| 
 | |
| ///////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| DEF_GM(return new GradientsNoTextureGM(true);)
 | |
| DEF_GM(return new GradientsNoTextureGM(false);)
 | |
| DEF_GM(return new GradientsManyColorsGM(true);)
 | |
| DEF_GM(return new GradientsManyColorsGM(false);)
 |