0

Use float for alpha everywhere in cc/paint

Bug: 1308932
Change-Id: I8a05dedbbf9cbca5e44683bfd8b3af7e91312596
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4177774
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: Vladimir Levin <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1094061}
This commit is contained in:
Xianzhu Wang
2023-01-18 21:06:01 +00:00
committed by Chromium LUCI CQ
parent aa3616dd4d
commit 34d2164afd
16 changed files with 70 additions and 72 deletions

@ -1028,7 +1028,7 @@ bool TurbulencePaintFilter::EqualsForTesting(
}
ShaderPaintFilter::ShaderPaintFilter(sk_sp<PaintShader> shader,
uint8_t alpha,
float alpha,
PaintFlags::FilterQuality filter_quality,
SkImageFilters::Dither dither,
const CropRect* crop_rect)
@ -1039,10 +1039,10 @@ ShaderPaintFilter::ShaderPaintFilter(sk_sp<PaintShader> shader,
dither_(dither) {
sk_sp<SkShader> sk_shader = shader_->GetSkShader(filter_quality_);
// Combine the alpha multiply into the SkShader if it's not opaque
if (alpha < 255) {
if (alpha < 1.0f) {
// The blend effectively produces (shader * alpha), the rgb of the secondary
// color are ignored.
SkColor4f color{1.0f, 1.0f, 1.0f, alpha / 255.0f};
SkColor4f color{1.0f, 1.0f, 1.0f, alpha};
// TODO(crbug/1308932): Remove toSkColor and make all SkColor4f.
sk_shader = SkShaders::Blend(SkBlendMode::kDstIn, std::move(sk_shader),
SkShaders::Color(color.toSkColor()));
@ -1067,7 +1067,7 @@ sk_sp<PaintFilter> ShaderPaintFilter::SnapshotWithImagesInternal(
ImageProvider* image_provider) const {
PaintFlags orig_flags;
orig_flags.setShader(shader_);
orig_flags.setAlphaf(alpha_ / 255.0f);
orig_flags.setAlphaf(alpha_);
orig_flags.setFilterQuality(filter_quality_);
orig_flags.setDither(dither_ == SkImageFilters::Dither::kYes);
@ -1077,7 +1077,7 @@ sk_sp<PaintFilter> ShaderPaintFilter::SnapshotWithImagesInternal(
if (snapshot) {
// Ref the updated paint shader so that it can outlive ScopedRasterFlags
return sk_make_sp<ShaderPaintFilter>(
sk_ref_sp(snapshot->getShader()), snapshot->getAlpha(),
sk_ref_sp(snapshot->getShader()), snapshot->getAlphaf(),
snapshot->getFilterQuality(),
snapshot->isDither() ? Dither::kYes : Dither::kNo, GetCropRect());
} else {

@ -693,15 +693,21 @@ class CC_PAINT_EXPORT ShaderPaintFilter final : public PaintFilter {
using Dither = SkImageFilters::Dither;
ShaderPaintFilter(sk_sp<PaintShader> shader,
uint8_t alpha,
float alpha,
PaintFlags::FilterQuality filter_quality,
SkImageFilters::Dither dither,
const CropRect* crop_rect = nullptr);
// This declaration prevents int alpha from being passed.
ShaderPaintFilter(sk_sp<PaintShader>,
unsigned alpha,
PaintFlags::FilterQuality,
SkImageFilters::Dither,
const CropRect* = nullptr) = delete;
~ShaderPaintFilter() override;
const PaintShader& shader() const { return *shader_; }
uint8_t alpha() const { return alpha_; }
float alpha() const { return alpha_; }
PaintFlags::FilterQuality filter_quality() const { return filter_quality_; }
SkImageFilters::Dither dither() const { return dither_; }
@ -714,7 +720,7 @@ class CC_PAINT_EXPORT ShaderPaintFilter final : public PaintFilter {
private:
sk_sp<PaintShader> shader_;
uint8_t alpha_;
float alpha_;
PaintFlags::FilterQuality filter_quality_;
SkImageFilters::Dither dither_;
};

@ -115,7 +115,7 @@ sk_sp<PaintFilter> CreateTestFilter(PaintFilter::Type filter_type,
return sk_make_sp<ShaderPaintFilter>(
PaintShader::MakeImage(image, SkTileMode::kClamp, SkTileMode::kClamp,
nullptr),
/*alpha=*/255, PaintFlags::FilterQuality::kNone,
/*alpha=*/1.0f, PaintFlags::FilterQuality::kNone,
SkImageFilters::Dither::kNo, &crop_rect);
}
case PaintFilter::Type::kMatrix:

@ -1418,7 +1418,7 @@ void SaveLayerAlphaOp::Raster(const SaveLayerAlphaOp* op,
absl::optional<SkPaint> paint;
if (op->alpha != 1.0f) {
paint.emplace();
paint->setAlpha(op->alpha * 255.0f);
paint->setAlphaf(op->alpha);
}
SkCanvas::SaveLayerRec rec(unset ? nullptr : &op->bounds,
base::OptionalToPtr(paint));

@ -241,11 +241,11 @@ void PaintOpBuffer::Playback(SkCanvas* canvas,
auto* context = canvas->recordingContext();
const ScopedRasterFlags scoped_flags(
&flags_op.flags, new_params.image_provider, canvas->getTotalMatrix(),
context ? context->maxTextureSize() : 0, iter.alphaf());
context ? context->maxTextureSize() : 0, iter.alpha());
if (const auto* raster_flags = scoped_flags.flags())
flags_op.RasterWithFlags(canvas, raster_flags, new_params);
} else {
DCHECK_EQ(iter.alpha(), 255);
DCHECK_EQ(iter.alpha(), 1.0f);
op->Raster(canvas, new_params);
}

@ -226,12 +226,8 @@ class CC_PAINT_EXPORT PaintOpBuffer::PlaybackFoldingIterator
explicit operator bool() const { return !!current_op_; }
// Guaranteed to be 255 for all ops without flags.
uint8_t alpha() const {
return static_cast<uint8_t>(current_alpha_ * 255.0f);
}
float alphaf() const { return current_alpha_; }
// Guaranteed to be 1.0f for all ops without flags.
float alpha() const { return current_alpha_; }
private:
void FindNextOp();

@ -186,7 +186,7 @@ void PaintOpBufferSerializer::SerializePreamble(SkCanvas* canvas,
bool PaintOpBufferSerializer::WillSerializeNextOp(const PaintOp& op,
SkCanvas* canvas,
const PlaybackParams& params,
uint8_t alpha) {
float alpha) {
// Skip ops outside the current clip if they have images. This saves
// performing an unnecessary expensive decode.
bool skip_op = PaintOp::OpHasDiscardableImages(op) &&
@ -273,12 +273,12 @@ bool PaintOpBufferSerializer::SerializeOpWithFlags(
SkCanvas* canvas,
const PaintOpWithFlags& flags_op,
const PlaybackParams& params,
uint8_t alpha) {
float alpha) {
// We use a null |image_provider| here because images are decoded during
// serialization.
const ScopedRasterFlags scoped_flags(
&flags_op.flags, nullptr, canvas->getTotalMatrix(),
options_.max_texture_size, alpha / 255.0f);
const ScopedRasterFlags scoped_flags(&flags_op.flags, nullptr,
canvas->getTotalMatrix(),
options_.max_texture_size, alpha);
const PaintFlags* flags_to_serialize = scoped_flags.flags();
if (!flags_to_serialize)
return true;

@ -86,11 +86,11 @@ class CC_PAINT_EXPORT PaintOpBufferSerializer {
bool WillSerializeNextOp(const PaintOp& op,
SkCanvas* canvas,
const PlaybackParams& params,
uint8_t alpha);
float alpha);
bool SerializeOpWithFlags(SkCanvas* canvas,
const PaintOpWithFlags& flags_op,
const PlaybackParams& params,
uint8_t alpha);
float alpha);
bool SerializeOp(SkCanvas* canvas,
const PaintOp& op,
const PaintFlags* flags_to_serialize,

@ -54,6 +54,7 @@ using ::testing::Contains;
using ::testing::Each;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::FloatEq;
using ::testing::Key;
using ::testing::Le;
using ::testing::Matcher;
@ -136,7 +137,7 @@ class PaintOpAppendTest : public ::testing::Test {
PaintOpAppendTest() {
rect_ = SkRect::MakeXYWH(2, 3, 4, 5);
flags_.setColor(SK_ColorMAGENTA);
flags_.setAlphaf(100.0f / 255.0f);
flags_.setAlphaf(0.25f);
}
void PushOps(PaintOpBuffer* buffer) {
@ -242,10 +243,10 @@ TEST(PaintOpBufferTest, SaveDrawRestore) {
float alpha = 0.4f;
buffer.push<SaveLayerAlphaOp>(alpha);
int paint_flags_alpha = 50;
float paint_flags_alpha = 0.25f;
PaintFlags draw_flags;
draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlphaf(paint_flags_alpha / 255.0f);
draw_flags.setAlphaf(paint_flags_alpha);
EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
buffer.push<DrawRectOp>(rect, draw_flags);
@ -260,8 +261,8 @@ TEST(PaintOpBufferTest, SaveDrawRestore) {
// Expect the alpha from the draw and the save layer to be folded together.
// Since alpha is stored in a uint8_t and gets rounded, so use tolerance.
float expected_alpha = alpha * paint_flags_alpha / 255.0f;
EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlphaf()), 0.01f);
float expected_alpha = alpha * paint_flags_alpha;
EXPECT_NEAR(expected_alpha, canvas.paint_.getAlphaf(), 0.01f);
}
// Verify that we don't optimize SaveLayerAlpha / DrawTextBlob / Restore.
@ -295,7 +296,7 @@ TEST(PaintOpBufferTest, SaveDrawRestoreFail_BadFlags) {
PaintFlags draw_flags;
draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlphaf(50.0f / 255.0f);
draw_flags.setAlphaf(0.25f);
draw_flags.setBlendMode(SkBlendMode::kSrc);
EXPECT_FALSE(draw_flags.SupportsFoldingAlpha());
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
@ -322,7 +323,7 @@ TEST(PaintOpBufferTest, SaveDrawRestore_BadFlags255Alpha) {
PaintFlags draw_flags;
draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlphaf(50.0f / 255.0f);
draw_flags.setAlphaf(0.25f);
draw_flags.setBlendMode(SkBlendMode::kColorBurn);
EXPECT_FALSE(draw_flags.SupportsFoldingAlpha());
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
@ -347,7 +348,7 @@ TEST(PaintOpBufferTest, SaveDrawRestoreFail_TooManyOps) {
PaintFlags draw_flags;
draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlphaf(50.0f / 255.0f);
draw_flags.setAlphaf(0.25f);
draw_flags.setBlendMode(SkBlendMode::kSrcOver);
EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
@ -387,10 +388,10 @@ TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpNotADrawOp) {
TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleOp) {
PaintOpBuffer sub_buffer;
int paint_flags_alpha = 50;
float paint_flags_alpha = 0.25f;
PaintFlags draw_flags;
draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlphaf(paint_flags_alpha / 255.0f);
draw_flags.setAlphaf(paint_flags_alpha);
EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
sub_buffer.push<DrawRectOp>(rect, draw_flags);
@ -410,7 +411,7 @@ TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleOp) {
EXPECT_EQ(0, canvas.restore_count_);
EXPECT_EQ(rect, canvas.draw_rect_);
float expected_alpha = alpha * paint_flags_alpha / 255.f;
float expected_alpha = alpha * paint_flags_alpha;
EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlphaf()), 0.01f);
}
@ -1143,7 +1144,7 @@ std::vector<PaintFlags> test_flags = {
[] {
PaintFlags flags;
flags.setColor(SK_ColorCYAN);
flags.setAlphaf(103.0f / 255.0f);
flags.setAlphaf(0.25f);
flags.setStrokeWidth(0.32f);
flags.setStrokeMiter(7.98f);
flags.setBlendMode(SkBlendMode::kSrcOut);
@ -2113,7 +2114,7 @@ TEST_P(PaintOpSerializationTest, UsesOverridenFlags) {
written = nullptr;
PaintFlags override_flags = static_cast<const PaintOpWithFlags&>(op).flags;
override_flags.setAlphaf(override_flags.getAlpha() * 0.5f / 255.0f);
override_flags.setAlphaf(override_flags.getAlphaf() * 0.5f);
bytes_written = op.Serialize(output_.get(), output_size_,
options_provider.serialize_options(),
&override_flags, SkM44(), SkM44());
@ -2292,8 +2293,9 @@ TEST(PaintOpBufferSerializationTest, AlphaFoldingDuringSerialization) {
buffer.push<SaveLayerAlphaOp>(alpha);
PaintFlags draw_flags;
float draw_rect_alpha = 0.25f;
draw_flags.setColor(SkColors::kMagenta);
draw_flags.setAlphaf(50.0f / 255.0f);
draw_flags.setAlphaf(draw_rect_alpha);
SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
buffer.push<DrawRectOp>(rect, draw_flags);
buffer.push<RestoreOp>();
@ -2317,21 +2319,17 @@ TEST(PaintOpBufferSerializationTest, AlphaFoldingDuringSerialization) {
EXPECT_THAT(
deserialized_buffer,
Pointee(ElementsAre(
PaintOpIs<SaveOp>(), PaintOpIs<ClipRectOp>(),
AllOf(PaintOpIs<DrawRectOp>(),
// Expect the alpha from the draw and the save layer to be
// folded together. Since alpha is stored in a uint8_t and
// gets rounded, so use tolerance.
ResultOf(
[alpha](const PaintOp& op) {
float expected_alpha = alpha * 50;
return std::abs(
expected_alpha -
static_cast<const DrawRectOp&>(op).flags.getAlpha());
},
Le(1.f))),
PaintOpIs<RestoreOp>())));
Pointee(ElementsAre(PaintOpIs<SaveOp>(), PaintOpIs<ClipRectOp>(),
AllOf(PaintOpIs<DrawRectOp>(),
// Expect the alpha from the draw and the save
// layer to be folded together.
ResultOf(
[](const PaintOp& op) {
return static_cast<const DrawRectOp&>(op)
.flags.getAlphaf();
},
FloatEq(alpha * draw_rect_alpha))),
PaintOpIs<RestoreOp>())));
}
// Test generic PaintOp deserializing failure cases.

@ -294,7 +294,7 @@ TEST(PaintOpHelper, SaveLayerAlphaToString) {
SaveLayerAlphaOp op(SkRect::MakeXYWH(1, 2, 3, 4), 1.0f);
std::string str = PaintOpHelper::ToString(op);
EXPECT_EQ(str,
"SaveLayerAlphaOp(bounds=[1.000,2.000 3.000x4.000], alpha=255)");
"SaveLayerAlphaOp(bounds=[1.000,2.000 3.000x4.000], alpha=1.000)");
}
TEST(PaintOpHelper, ScaleToString) {
@ -523,7 +523,7 @@ TEST(PaintOpHelperFilters, ShaderPaintFilter) {
/*tx=*/SkTileMode::kClamp,
/*ty=*/SkTileMode::kRepeat,
/*local_matrix=*/nullptr),
/*alpha=*/255, PaintFlags::FilterQuality::kMedium,
/*alpha=*/1.0f, PaintFlags::FilterQuality::kMedium,
SkImageFilters::Dither::kYes, &crop_rect);
EXPECT_EQ(
PaintOpHelper::ToString(filter),
@ -534,7 +534,7 @@ TEST(PaintOpHelperFilters, ShaderPaintFilter) {
"0.000x0.000], start_point=[0.000,0.000], end_point=[0.000,0.000], "
"start_degrees=0, end_degrees=0, image=<paint image>, record=(nil), "
"id=4294967295, tile_scale=(nil), colors=(nil), positions=(nil)], "
"alpha=255, filter_quality=kMedium_SkFilterQuality, dither=kYes, "
"alpha=1.000, filter_quality=kMedium_SkFilterQuality, dither=kYes, "
"crop_rect=[0.000,0.000 100.000x100.000])");
}

@ -1252,7 +1252,7 @@ void PaintOpReader::ReadShaderPaintFilter(
using Dither = SkImageFilters::Dither;
sk_sp<PaintShader> shader;
uint8_t alpha = 255;
float alpha = 1.0f;
PaintFlags::FilterQuality quality = PaintFlags::FilterQuality::kNone;
Dither dither = Dither::kNo;

@ -119,10 +119,8 @@ void ScopedRasterFlags::AdjustStrokeIfNeeded(const SkMatrix& ctm) {
// Use modulated hairline when possible, as it is faster and produces
// results closer to the original intent.
MutableFlags()->setStrokeWidth(0);
MutableFlags()->setAlphaf(
std::round(flags()->getAlpha() *
std::sqrt(stroke_vec.x() * stroke_vec.y())) /
255.0f);
MutableFlags()->setAlphaf(flags()->getAlphaf() *
std::sqrt(stroke_vec.x() * stroke_vec.y()));
return;
}

@ -567,10 +567,10 @@ TEST(RasterSourceTest, RasterPartialClear) {
recording_source->SetRequiresClear(true);
// First record everything as white.
const unsigned alpha_dark = 10u;
const float alpha_dark = 0.04f;
PaintFlags white_flags;
white_flags.setColor(SK_ColorWHITE);
white_flags.setAlphaf(alpha_dark / 255.0f);
white_flags.setAlphaf(alpha_dark);
recording_source->add_draw_rect_with_flags(gfx::Rect(layer_bounds),
white_flags);
recording_source->Rerecord();
@ -593,7 +593,7 @@ TEST(RasterSourceTest, RasterPartialClear) {
gfx::AxisTransform2d(contents_scale, gfx::Vector2dF()),
RasterSource::PlaybackSettings());
SkColor pixel_dark = SkColorSetARGB(alpha_dark, 255, 255, 255);
SkColor pixel_dark = SkColor4f{1, 1, 1, alpha_dark}.toSkColor();
for (int i = 0; i < bitmap.width(); ++i) {
for (int j = 0; j < bitmap.height(); ++j)
EXPECT_COLOR_EQ(pixel_dark, bitmap.getColor(i, j)) << i << "," << j;
@ -605,8 +605,8 @@ TEST(RasterSourceTest, RasterPartialClear) {
recording_source_light->SetRequiresClear(true);
// Record everything as a slightly lighter white.
const unsigned alpha_light = 18u;
white_flags.setAlphaf(alpha_light / 255.0f);
const float alpha_light = 0.1f;
white_flags.setAlphaf(alpha_light);
recording_source_light->add_draw_rect_with_flags(gfx::Rect(layer_bounds),
white_flags);
recording_source_light->Rerecord();
@ -625,7 +625,7 @@ TEST(RasterSourceTest, RasterPartialClear) {
RasterSource::PlaybackSettings());
// Test that the whole playback_rect was cleared and repainted with new alpha.
SkColor pixel_light = SkColorSetARGB(alpha_light, 255, 255, 255);
SkColor pixel_light = SkColor4f{1, 1, 1, alpha_light}.toSkColor();
for (int i = 0; i < playback_rect.width(); ++i) {
for (int j = 0; j < playback_rect.height(); ++j)
EXPECT_COLOR_EQ(pixel_light, bitmap.getColor(i, j)) << i << "," << j;

@ -40,7 +40,7 @@ scoped_refptr<FakeRasterSource> FakeRasterSource::CreateFilled(
PaintFlags salmon_pink_flags;
salmon_pink_flags.setColor(SK_ColorRED);
salmon_pink_flags.setBlendMode(SkBlendMode::kMultiply);
salmon_pink_flags.setAlphaf(128.0f / 255.0f);
salmon_pink_flags.setAlphaf(0.5f);
recording_source->add_draw_rect_with_flags(gfx::Rect(size),
salmon_pink_flags);

@ -197,7 +197,7 @@ class PaintOpHelper {
case PaintOpType::SaveLayerAlpha: {
const auto& op = static_cast<const SaveLayerAlphaOp&>(base_op);
str << "SaveLayerAlphaOp(bounds=" << ToString(op.bounds)
<< ", alpha=" << static_cast<uint32_t>(op.alpha * 255) << ")";
<< ", alpha=" << ToString(op.alpha) << ")";
break;
}
case PaintOpType::Scale: {

@ -26,12 +26,12 @@ sk_sp<PaintFilter> PaintFilterEffect::CreateImageFilter() {
: SkImageFilters::Dither::kNo;
if (shader) {
// Include the paint's alpha modulation
return sk_make_sp<ShaderPaintFilter>(sk_ref_sp(shader), flags_.getAlpha(),
return sk_make_sp<ShaderPaintFilter>(sk_ref_sp(shader), flags_.getAlphaf(),
flags_.getFilterQuality(), dither);
} else {
// ShaderPaintFilter requires shader to be non-null
return sk_make_sp<ShaderPaintFilter>(
cc::PaintShader::MakeColor(flags_.getColor4f()), 255,
cc::PaintShader::MakeColor(flags_.getColor4f()), 1.0f,
flags_.getFilterQuality(), dither);
}
}