blob: 5d920c13e92c72a73e6c3696febfdc9a95352ac6 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/blink/web_display_item_list_impl.h"
#include "base/strings/stringprintf.h"
#include "cc/paint/display_item_list.h"
#include "cc/paint/paint_op_buffer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebFloatPoint.h"
namespace cc_blink {
namespace {
// SkCanvas::saveLayer(Alpha) allows for an optional bounds which is a hint
// for the backing size to use for the indirect buffer. It is not really
// a clip though, as Skia is allowed to use any size buffer it wants.
// Additionally, PaintOpBuffer can drop the bounds when folding
// save/draw/restore into a single draw-with-alpha. However, in some cases
// calling code (SVGMask) is drawing unclipped items which really need
// a clip to not pollute the rest of the painted content with their draw
// commands. Therefore, this tests that when providing bounds to
// AppendCompositingItem that a clip is inserted.
TEST(WebDisplayItemListImpl, ClipWhenCompositing) {
// Test with two different blend modes to differentiate the saveLayer vs
// saveLayerAlpha logic inside of AppendCompositingItem;
SkBlendMode blend_modes[] = {SkBlendMode::kSrc, SkBlendMode::kSrcOver};
for (size_t i = 0; i < arraysize(blend_modes); ++i) {
static constexpr int size = 20;
static constexpr SkColor background_color = SK_ColorMAGENTA;
static constexpr SkColor clip_color = SK_ColorYELLOW;
blink::WebRect full_bounds(0, 0, size, size);
blink::WebRect clip_bounds(5, 3, 13, 9);
SkRect sk_clip_bounds = SkRect::MakeXYWH(
clip_bounds.x, clip_bounds.y, clip_bounds.width, clip_bounds.height);
SkIRect clip_irect = sk_clip_bounds.roundOut();
auto cc_list = base::MakeRefCounted<cc::DisplayItemList>();
cc_blink::WebDisplayItemListImpl web_list(cc_list.get());
// drawColor(background color)
// saveLayer(should clip)
// drawColor(clip color)
// end
auto background_record = sk_make_sp<cc::PaintRecord>();
background_record->push<cc::DrawColorOp>(background_color,
SkBlendMode::kSrcOver);
web_list.AppendDrawingItem(full_bounds, background_record);
web_list.AppendCompositingItem(1.f, blend_modes[i], &sk_clip_bounds,
nullptr);
auto clip_record = sk_make_sp<cc::PaintRecord>();
clip_record->push<cc::DrawColorOp>(clip_color, SkBlendMode::kSrcOver);
web_list.AppendDrawingItem(full_bounds, clip_record);
web_list.AppendEndCompositingItem();
cc_list->Finalize();
SkBitmap bitmap;
bitmap.allocPixels(SkImageInfo::MakeN32Premul(size, size));
SkCanvas canvas(bitmap);
canvas.drawColor(SK_ColorGRAY);
cc_list->Raster(&canvas);
uint8_t* pixels = static_cast<uint8_t*>(bitmap.getPixels());
size_t row_bytes = size * 4;
for (size_t y = 0; y < size; ++y) {
size_t y_offset = y * row_bytes;
for (size_t x = 0; x < size; ++x) {
size_t x_offset = x * 4;
uint8_t* pixel = &pixels[y_offset + x_offset];
SCOPED_TRACE(
base::StringPrintf("x(%zd) y(%zd) mode(%d)", x, y, blend_modes[i]));
if (clip_irect.contains(x, y)) {
EXPECT_EQ(SkColorGetR(clip_color), pixel[SK_R32_SHIFT / 8]);
EXPECT_EQ(SkColorGetG(clip_color), pixel[SK_G32_SHIFT / 8]);
EXPECT_EQ(SkColorGetB(clip_color), pixel[SK_B32_SHIFT / 8]);
EXPECT_EQ(SkColorGetA(clip_color), pixel[SK_A32_SHIFT / 8]);
} else {
EXPECT_EQ(SkColorGetR(background_color), pixel[SK_R32_SHIFT / 8]);
EXPECT_EQ(SkColorGetG(background_color), pixel[SK_G32_SHIFT / 8]);
EXPECT_EQ(SkColorGetB(background_color), pixel[SK_B32_SHIFT / 8]);
EXPECT_EQ(SkColorGetA(background_color), pixel[SK_A32_SHIFT / 8]);
}
}
}
}
}
} // namespace
} // namespace cc_blink