Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 0922302

Browse files
authored
[Skia] Only respect ui.Paint.dither when the colorSource is a gradient (#44730)
In the Impeller backend, we **only** support dithering of _gradients_. In addition, it will be the default (and only option). In the [process of enabling dithering by default](#44705), i.e. ```diff class Paint { - static bool enableDithering = false; + static bool enableDithering = true; } ``` ... we realized with internal Google testing this will now apply dithering on more than just gradients, i.e. images in the Skia backend. Since we won't support dithering of images in the Impeller backend, this PR gives a "hint" on whether the `colorSource` (if one is set) can be dithered by the contrived rules we've created.
1 parent 659cdfc commit 0922302

File tree

6 files changed

+109
-100
lines changed

6 files changed

+109
-100
lines changed

display_list/effects/dl_color_source.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,16 @@ class DlColorSource : public DlAttribute<DlColorSource, DlColorSourceType> {
119119
///
120120
virtual bool isUIThreadSafe() const = 0;
121121

122+
//----------------------------------------------------------------------------
123+
/// @brief If the underlying platform data represents a gradient.
124+
///
125+
/// TODO(matanl): Remove this flag when the Skia backend is
126+
/// removed, https://github.com/flutter/flutter/issues/112498.
127+
///
128+
/// @return True if the class represents the output of a gradient.
129+
///
130+
virtual bool isGradient() const { return false; }
131+
122132
// Return a DlColorColorSource pointer to this object iff it is an Color
123133
// type of ColorSource, otherwise return nullptr.
124134
virtual const DlColorColorSource* asColor() const { return nullptr; }
@@ -287,6 +297,8 @@ class DlGradientColorSourceBase : public DlMatrixColorSourceBase {
287297
return true;
288298
}
289299

300+
bool isGradient() const override { return true; }
301+
290302
DlTileMode tile_mode() const { return mode_; }
291303
int stop_count() const { return stop_count_; }
292304
const DlColor* colors() const {

display_list/skia/dl_sk_canvas.cc

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,47 +14,6 @@
1414

1515
namespace flutter {
1616

17-
// clang-format off
18-
constexpr float kInvertColorMatrix[20] = {
19-
-1.0, 0, 0, 1.0, 0,
20-
0, -1.0, 0, 1.0, 0,
21-
0, 0, -1.0, 1.0, 0,
22-
1.0, 1.0, 1.0, 1.0, 0
23-
};
24-
// clang-format on
25-
26-
static SkPaint ToSk(const DlPaint& paint, bool force_stroke = false) {
27-
SkPaint sk_paint;
28-
29-
sk_paint.setAntiAlias(paint.isAntiAlias());
30-
sk_paint.setDither(paint.isDither());
31-
32-
sk_paint.setColor(paint.getColor());
33-
sk_paint.setBlendMode(ToSk(paint.getBlendMode()));
34-
sk_paint.setStyle(force_stroke ? SkPaint::kStroke_Style
35-
: ToSk(paint.getDrawStyle()));
36-
sk_paint.setStrokeWidth(paint.getStrokeWidth());
37-
sk_paint.setStrokeMiter(paint.getStrokeMiter());
38-
sk_paint.setStrokeCap(ToSk(paint.getStrokeCap()));
39-
sk_paint.setStrokeJoin(ToSk(paint.getStrokeJoin()));
40-
41-
sk_paint.setShader(ToSk(paint.getColorSourcePtr()));
42-
sk_paint.setImageFilter(ToSk(paint.getImageFilterPtr()));
43-
auto color_filter = ToSk(paint.getColorFilterPtr());
44-
if (paint.isInvertColors()) {
45-
auto invert_filter = SkColorFilters::Matrix(kInvertColorMatrix);
46-
if (color_filter) {
47-
invert_filter = invert_filter->makeComposed(color_filter);
48-
}
49-
color_filter = invert_filter;
50-
}
51-
sk_paint.setColorFilter(color_filter);
52-
sk_paint.setMaskFilter(ToSk(paint.getMaskFilterPtr()));
53-
sk_paint.setPathEffect(ToSk(paint.getPathEffectPtr()));
54-
55-
return sk_paint;
56-
}
57-
5817
class SkOptionalPaint {
5918
public:
6019
explicit SkOptionalPaint(const DlPaint* dl_paint) {

display_list/skia/dl_sk_conversions.cc

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,61 @@
1010

1111
namespace flutter {
1212

13+
// clang-format off
14+
constexpr float kInvertColorMatrix[20] = {
15+
-1.0, 0, 0, 1.0, 0,
16+
0, -1.0, 0, 1.0, 0,
17+
0, 0, -1.0, 1.0, 0,
18+
1.0, 1.0, 1.0, 1.0, 0
19+
};
20+
// clang-format on
21+
22+
SkPaint ToSk(const DlPaint& paint, bool force_stroke) {
23+
SkPaint sk_paint;
24+
25+
sk_paint.setAntiAlias(paint.isAntiAlias());
26+
sk_paint.setColor(paint.getColor());
27+
sk_paint.setBlendMode(ToSk(paint.getBlendMode()));
28+
sk_paint.setStyle(force_stroke ? SkPaint::kStroke_Style
29+
: ToSk(paint.getDrawStyle()));
30+
sk_paint.setStrokeWidth(paint.getStrokeWidth());
31+
sk_paint.setStrokeMiter(paint.getStrokeMiter());
32+
sk_paint.setStrokeCap(ToSk(paint.getStrokeCap()));
33+
sk_paint.setStrokeJoin(ToSk(paint.getStrokeJoin()));
34+
sk_paint.setImageFilter(ToSk(paint.getImageFilterPtr()));
35+
auto color_filter = ToSk(paint.getColorFilterPtr());
36+
if (paint.isInvertColors()) {
37+
auto invert_filter = SkColorFilters::Matrix(kInvertColorMatrix);
38+
if (color_filter) {
39+
invert_filter = invert_filter->makeComposed(color_filter);
40+
}
41+
color_filter = invert_filter;
42+
}
43+
sk_paint.setColorFilter(color_filter);
44+
45+
auto color_source = paint.getColorSourcePtr();
46+
if (color_source) {
47+
// On the Impeller backend, we will only support dithering of *gradients*,
48+
// and it will be enabled by default (without the option to disable it).
49+
// Until Skia support is completely removed, we only want to respect the
50+
// dither flag for gradients (otherwise it will also apply to, for example,
51+
// images, which is not supported in Impeller).
52+
//
53+
// See https://github.com/flutter/flutter/issues/112498.
54+
if (color_source->isGradient()) {
55+
// Originates from `dart:ui#Paint.enableDithering`.
56+
auto user_specified_dither = paint.isDither();
57+
sk_paint.setDither(user_specified_dither);
58+
}
59+
sk_paint.setShader(ToSk(color_source));
60+
}
61+
62+
sk_paint.setMaskFilter(ToSk(paint.getMaskFilterPtr()));
63+
sk_paint.setPathEffect(ToSk(paint.getPathEffectPtr()));
64+
65+
return sk_paint;
66+
}
67+
1368
sk_sp<SkShader> ToSk(const DlColorSource* source) {
1469
if (!source) {
1570
return nullptr;

display_list/skia/dl_sk_conversions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
namespace flutter {
1212

13+
SkPaint ToSk(const DlPaint& paint, bool force_stroke = false);
14+
1315
inline SkBlendMode ToSk(DlBlendMode mode) {
1416
return static_cast<SkBlendMode>(mode);
1517
}

display_list/skia/dl_sk_conversions_unittests.cc

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
#include "flutter/display_list/skia/dl_sk_conversions.h"
6-
75
#include "flutter/display_list/dl_blend_mode.h"
86
#include "flutter/display_list/dl_paint.h"
97
#include "flutter/display_list/dl_sampling_options.h"
108
#include "flutter/display_list/dl_tile_mode.h"
119
#include "flutter/display_list/dl_vertices.h"
10+
#include "flutter/display_list/effects/dl_color_source.h"
11+
#include "flutter/display_list/skia/dl_sk_conversions.h"
1212
#include "gtest/gtest.h"
1313
#include "third_party/skia/include/core/SkSamplingOptions.h"
1414
#include "third_party/skia/include/core/SkTileMode.h"
@@ -270,5 +270,43 @@ TEST(DisplayListSkConversions, MatrixColorFilterModifiesTransparency) {
270270
}
271271
}
272272

273+
TEST(DisplayListSkConversions, ToSkDitheringDisabledForGradients) {
274+
// Test that when using the utility method "ToSk", the resulting SkPaint
275+
// does not have "isDither" set to true, even if it's requested by the
276+
// Flutter (dart:ui) paint, because it's not a supported feature in the
277+
// Impeller backend.
278+
279+
// Create a new DlPaint with isDither set to true.
280+
//
281+
// This mimics the behavior of ui.Paint.enableDithering = true.
282+
DlPaint dl_paint;
283+
dl_paint.setDither(true);
284+
285+
SkPaint sk_paint = ToSk(dl_paint);
286+
287+
EXPECT_FALSE(sk_paint.isDither());
288+
}
289+
290+
TEST(DisplayListSkConversions, ToSkDitheringEnabledForGradients) {
291+
// Test that when using the utility method "ToSk", the resulting SkPaint
292+
// has "isDither" set to true, if the paint is a gradient, because it's
293+
// a supported feature in the Impeller backend.
294+
295+
// Create a new DlPaint with isDither set to true.
296+
//
297+
// This mimics the behavior of ui.Paint.enableDithering = true.
298+
DlPaint dl_paint;
299+
dl_paint.setDither(true);
300+
301+
// Set the paint to be a gradient.
302+
dl_paint.setColorSource(DlColorSource::MakeLinear(SkPoint::Make(0, 0),
303+
SkPoint::Make(100, 100), 0,
304+
0, 0, DlTileMode::kClamp));
305+
306+
SkPaint sk_paint = ToSk(dl_paint);
307+
308+
EXPECT_TRUE(sk_paint.isDither());
309+
}
310+
273311
} // namespace testing
274312
} // namespace flutter

display_list/testing/dl_rendering_unittests.cc

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,63 +1247,6 @@ class CanvasCompareTester {
12471247
[=](DlCanvas* cv, DlPaint& p) { dl_aa_setup(cv, p, false); }));
12481248
}
12491249

1250-
{
1251-
// The CPU renderer does not always dither for solid colors and we
1252-
// need to use a non-default color (default is black) on an opaque
1253-
// surface, so we use a shader instead of a color. Also, thin stroked
1254-
// primitives (mainly drawLine and drawPoints) do not show much
1255-
// dithering so we use a non-trivial stroke width as well.
1256-
RenderEnvironment dither_env = RenderEnvironment::Make565(env.provider());
1257-
if (!dither_env.valid()) {
1258-
// Currently only happens on Metal backend
1259-
static std::set<std::string> warnings_sent;
1260-
std::string name = dither_env.backend_name();
1261-
if (warnings_sent.find(name) == warnings_sent.end()) {
1262-
warnings_sent.insert(name);
1263-
FML_LOG(INFO) << "Skipping Dithering tests on " << name;
1264-
}
1265-
} else {
1266-
DlColor dither_bg = DlColor::kBlack();
1267-
SkSetup sk_dither_setup = [=](SkCanvas*, SkPaint& p) {
1268-
p.setShader(kTestSkImageColorSource);
1269-
p.setAlpha(0xf0);
1270-
p.setStrokeWidth(5.0);
1271-
};
1272-
DlSetup dl_dither_setup = [=](DlCanvas*, DlPaint& p) {
1273-
p.setColorSource(&kTestDlImageColorSource);
1274-
p.setAlpha(0xf0);
1275-
p.setStrokeWidth(5.0);
1276-
};
1277-
dither_env.init_ref(sk_dither_setup, testP.sk_renderer(),
1278-
dl_dither_setup, testP.dl_renderer(), dither_bg);
1279-
quickCompareToReference(dither_env, "dither");
1280-
RenderWith(testP, dither_env, tolerance,
1281-
CaseParameters(
1282-
"Dither == True",
1283-
[=](SkCanvas* cv, SkPaint& p) {
1284-
sk_dither_setup(cv, p);
1285-
p.setDither(true);
1286-
},
1287-
[=](DlCanvas* cv, DlPaint& p) {
1288-
dl_dither_setup(cv, p);
1289-
p.setDither(true);
1290-
})
1291-
.with_bg(dither_bg));
1292-
RenderWith(testP, dither_env, tolerance,
1293-
CaseParameters(
1294-
"Dither = False",
1295-
[=](SkCanvas* cv, SkPaint& p) {
1296-
sk_dither_setup(cv, p);
1297-
p.setDither(false);
1298-
},
1299-
[=](DlCanvas* cv, DlPaint& p) {
1300-
dl_dither_setup(cv, p);
1301-
p.setDither(false);
1302-
})
1303-
.with_bg(dither_bg));
1304-
}
1305-
}
1306-
13071250
RenderWith(
13081251
testP, env, tolerance,
13091252
CaseParameters(

0 commit comments

Comments
 (0)