1515#include " include/core/SkPoint.h"
1616#include " include/core/SkRect.h"
1717#include " include/effects/SkDashPathEffect.h"
18+ #include " include/effects/SkGradientShader.h"
1819#include " include/effects/SkImageFilters.h"
1920
2021#include " src/core/SkImageFilterTypes.h"
2122#include " src/core/SkImageFilter_Base.h"
23+ #include " src/core/SkMatrixPriv.h"
2224
2325#include " tools/ToolUtils.h"
2426
@@ -58,6 +60,17 @@ static float print_info(SkCanvas* canvas,
5860 return y;
5961}
6062
63+ static void print_label (SkCanvas* canvas, float x, float y, float value) {
64+ SkFont font (nullptr , 12 );
65+ SkPaint text;
66+ text.setAntiAlias (true );
67+
68+ SkString label;
69+ label.printf (" %.3f" , value);
70+
71+ canvas->drawString (label, x, y + kLineHeight / 2 .f , font, text);
72+ }
73+
6174static SkPaint line_paint (SkColor color, bool dashed = false ) {
6275 SkPaint paint;
6376 paint.setColor (color);
@@ -84,6 +97,71 @@ static SkPath create_axis_path(const SkRect& rect, float axisSpace) {
8497 return localSpace;
8598}
8699
100+ static const SkColor4f kScaleGradientColors [] =
101+ { { 0 .05f , 0 .0f , 6 .f , 1 .f }, // Severe downscaling, s < 1/8, log(s) < -3
102+ { 0 .6f , 0 .6f , 0 .8f , 0 .6f }, // Okay downscaling, s < 1/2, log(s) < -1
103+ { 1 .f , 1 .f , 1 .f , 0 .2f }, // No scaling, s = 1, log(s) = 0
104+ { 0 .95f , 0 .6f , 0 .5f , 0 .6f }, // Okay upscaling, s > 2, log(s) > 1
105+ { 0 .8f , 0 .1f , 0 .f , 1 .f } }; // Severe upscaling, s > 8, log(s) > 3
106+ static const SkScalar kLogScaleFactors [] = { -3 .f , -1 .f , 0 .f , 1 .f , 3 .f };
107+ static const SkScalar kGradientStops [] = { 0 .f , 0 .33333f , 0 .5f , 0 .66667f , 1 .f };
108+ static const int kStopCount = (int ) SK_ARRAY_COUNT(kScaleGradientColors );
109+
110+ static void draw_scale_key (SkCanvas* canvas, float y) {
111+ SkRect key = SkRect::MakeXYWH (15 .f , y + 30 .f , 15 .f , 100 .f );
112+ SkPoint pts[] = {{key.centerX (), key.fTop }, {key.centerX (), key.fBottom }};
113+ sk_sp<SkShader> gradient = SkGradientShader::MakeLinear (
114+ pts, kScaleGradientColors , nullptr , kGradientStops , kStopCount , SkTileMode::kClamp ,
115+ SkGradientShader::kInterpolateColorsInPremul_Flag , nullptr );
116+ SkPaint keyPaint;
117+ keyPaint.setShader (gradient);
118+ canvas->drawRect (key, keyPaint);
119+ for (int i = 0 ; i < kStopCount ; ++i) {
120+ print_label (canvas, key.fRight + 5 .f , key.fTop + kGradientStops [i] * key.height (),
121+ SkScalarPow (2 .f , kLogScaleFactors [i]));
122+ }
123+ }
124+
125+ static void draw_scale_factors (SkCanvas* canvas, const skif::Mapping& mapping, const SkRect& rect) {
126+ SkPoint testPoints[5 ];
127+ testPoints[0 ] = {rect.centerX (), rect.centerY ()};
128+ rect.toQuad (testPoints + 1 );
129+ for (int i = 0 ; i < 5 ; ++i) {
130+ float scale = SkMatrixPriv::DifferentialScale (
131+ mapping.deviceMatrix (),
132+ SkPoint (mapping.paramToLayer (skif::ParameterSpace<SkPoint>(testPoints[i]))));
133+ SkColor4f color = {0 .f , 0 .f , 0 .f , 1 .f };
134+
135+ if (SkScalarIsFinite (scale)) {
136+ float logScale = SkScalarLog2 (scale);
137+ for (int j = 0 ; j <= kStopCount ; ++j) {
138+ if (j == kStopCount ) {
139+ color = kScaleGradientColors [j - 1 ];
140+ break ;
141+ } else if (kLogScaleFactors [j] >= logScale) {
142+ if (j == 0 ) {
143+ color = kScaleGradientColors [0 ];
144+ } else {
145+ SkScalar t = (logScale - kLogScaleFactors [j - 1 ]) /
146+ (kLogScaleFactors [j] - kLogScaleFactors [j - 1 ]);
147+
148+ SkColor4f a = kScaleGradientColors [j - 1 ] * (1 .f - t);
149+ SkColor4f b = kScaleGradientColors [j] * t;
150+ color = {a.fR + b.fR , a.fG + b.fG , a.fB + b.fB , a.fA + b.fA };
151+ }
152+ break ;
153+ }
154+ }
155+ }
156+
157+ SkPaint p;
158+ p.setAntiAlias (true );
159+ p.setColor4f (color, nullptr );
160+ canvas->drawRect (SkRect::MakeLTRB (testPoints[i].fX - 4 .f , testPoints[i].fY - 4 .f ,
161+ testPoints[i].fX + 4 .f , testPoints[i].fY + 4 .f ), p);
162+ }
163+ }
164+
87165class FilterBoundsSample : public Sample {
88166public:
89167 FilterBoundsSample () {}
@@ -114,6 +192,9 @@ class FilterBoundsSample : public Sample {
114192 // Add axis lines, to show perspective distortion
115193 canvas->drawPath (create_axis_path (localContentRect, 10 .f ), line_paint (SK_ColorGRAY));
116194
195+ // Visualize scale factors at the four corners and center of the local rect
196+ draw_scale_factors (canvas, mapping, localContentRect);
197+
117198 // The device content rect, e.g. the clip bounds if 'localContentRect' were used as a clip
118199 // before the draw or saveLayer, representing what the filter must cover if it affects
119200 // transparent black or doesn't have a local content hint.
@@ -146,10 +227,13 @@ class FilterBoundsSample : public Sample {
146227 canvas->drawRect (SkRect::Make (SkIRect (hintedOutputBounds)), line_paint (SK_ColorBLUE));
147228
148229 canvas->resetMatrix ();
149- print_info (canvas, SkIRect (mapping.paramToLayer (contentBounds).roundOut ()),
230+ float y = print_info (canvas, SkIRect (mapping.paramToLayer (contentBounds).roundOut ()),
150231 devContentRect.roundOut (),
151232 SkIRect (hintedOutputBounds),
152233 SkIRect (unhintedLayerBounds));
234+
235+ // Draw color key for layer visualization
236+ draw_scale_key (canvas, y);
153237 }
154238
155239 SkString name () override { return SkString (" FilterBounds" ); }
0 commit comments