| // Copyright 2015 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 "third_party/blink/renderer/core/frame/frame_overlay.h" |
| |
| #include <memory> |
| |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/widget/device_emulation_params.h" |
| #include "third_party/blink/renderer/core/exported/web_view_impl.h" |
| #include "third_party/blink/renderer/core/frame/frame_test_helpers.h" |
| #include "third_party/blink/renderer/core/frame/local_frame_view.h" |
| #include "third_party/blink/renderer/core/frame/visual_viewport.h" |
| #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" |
| #include "third_party/blink/renderer/core/layout/layout_view.h" |
| #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h" |
| #include "third_party/blink/renderer/platform/graphics/color.h" |
| #include "third_party/blink/renderer/platform/graphics/graphics_context.h" |
| #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" |
| #include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h" |
| #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h" |
| #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h" |
| #include "third_party/blink/renderer/platform/graphics/paint/paint_controller_test.h" |
| #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h" |
| #include "third_party/blink/renderer/platform/testing/paint_test_configurations.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| |
| using testing::ElementsAre; |
| using testing::Property; |
| |
| namespace blink { |
| namespace { |
| |
| // FrameOverlay that paints a solid color. |
| class SolidColorOverlay : public FrameOverlay::Delegate { |
| public: |
| SolidColorOverlay(Color color) : color_(color) {} |
| |
| void PaintFrameOverlay(const FrameOverlay& frame_overlay, |
| GraphicsContext& graphics_context, |
| const IntSize& size) const override { |
| if (DrawingRecorder::UseCachedDrawingIfPossible( |
| graphics_context, frame_overlay, DisplayItem::kFrameOverlay)) |
| return; |
| FloatRect rect(0, 0, size.Width(), size.Height()); |
| DrawingRecorder recorder(graphics_context, frame_overlay, |
| DisplayItem::kFrameOverlay, |
| IntRect(IntPoint(), size)); |
| graphics_context.FillRect(rect, color_); |
| } |
| |
| private: |
| Color color_; |
| }; |
| |
| class FrameOverlayTest : public testing::Test, public PaintTestConfigurations { |
| protected: |
| static constexpr int kViewportWidth = 800; |
| static constexpr int kViewportHeight = 600; |
| |
| FrameOverlayTest() { |
| helper_.Initialize(nullptr, nullptr, nullptr); |
| GetWebView()->MainFrameViewWidget()->Resize( |
| gfx::Size(kViewportWidth, kViewportHeight)); |
| GetWebView()->MainFrameViewWidget()->UpdateAllLifecyclePhases( |
| DocumentUpdateReason::kTest); |
| } |
| |
| WebViewImpl* GetWebView() const { return helper_.GetWebView(); } |
| |
| std::unique_ptr<FrameOverlay> CreateSolidYellowOverlay() { |
| return std::make_unique<FrameOverlay>( |
| GetWebView()->MainFrameImpl()->GetFrame(), |
| std::make_unique<SolidColorOverlay>(SK_ColorYELLOW)); |
| } |
| |
| template <typename OverlayType> |
| void RunFrameOverlayTestWithAcceleratedCompositing(); |
| |
| private: |
| frame_test_helpers::WebViewHelper helper_; |
| }; |
| |
| class MockFrameOverlayCanvas : public SkCanvas { |
| public: |
| MOCK_METHOD2(onDrawRect, void(const SkRect&, const SkPaint&)); |
| }; |
| |
| INSTANTIATE_PAINT_TEST_SUITE_P(FrameOverlayTest); |
| |
| TEST_P(FrameOverlayTest, AcceleratedCompositing) { |
| std::unique_ptr<FrameOverlay> frame_overlay = CreateSolidYellowOverlay(); |
| frame_overlay->UpdatePrePaint(); |
| EXPECT_EQ(PropertyTreeState::Root(), |
| frame_overlay->DefaultPropertyTreeState()); |
| |
| // Ideally, we would get results from the compositor that showed that this |
| // page overlay actually winds up getting drawn on top of the rest. |
| // For now, we just check that the GraphicsLayer will draw the right thing. |
| MockFrameOverlayCanvas canvas; |
| EXPECT_CALL(canvas, |
| onDrawRect(SkRect::MakeWH(kViewportWidth, kViewportHeight), |
| Property(&SkPaint::getColor, SK_ColorYELLOW))); |
| |
| PaintRecordBuilder builder; |
| if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { |
| frame_overlay->Paint(builder.Context()); |
| builder.EndRecording()->Playback(&canvas); |
| } else { |
| auto* graphics_layer = frame_overlay->GetGraphicsLayer(); |
| EXPECT_FALSE(graphics_layer->IsHitTestable()); |
| EXPECT_EQ(PropertyTreeState::Root(), |
| graphics_layer->GetPropertyTreeState()); |
| Vector<PreCompositedLayerInfo> pre_composited_layers; |
| graphics_layer->PaintRecursively(builder.Context(), pre_composited_layers); |
| ASSERT_EQ(1u, pre_composited_layers.size()); |
| graphics_layer->GetPaintController().FinishCycle(); |
| SkiaPaintCanvas(&canvas).drawPicture( |
| graphics_layer->GetPaintController().GetPaintArtifact().GetPaintRecord( |
| PropertyTreeState::Root())); |
| } |
| } |
| |
| TEST_P(FrameOverlayTest, DeviceEmulationScale) { |
| DeviceEmulationParams params; |
| params.scale = 1.5; |
| params.view_size = gfx::Size(800, 600); |
| GetWebView()->EnableDeviceEmulation(params); |
| GetWebView()->MainFrameViewWidget()->UpdateAllLifecyclePhases( |
| DocumentUpdateReason::kTest); |
| |
| std::unique_ptr<FrameOverlay> frame_overlay = CreateSolidYellowOverlay(); |
| frame_overlay->UpdatePrePaint(); |
| auto* transform = GetWebView() |
| ->MainFrameImpl() |
| ->GetFrame() |
| ->GetPage() |
| ->GetVisualViewport() |
| .GetDeviceEmulationTransformNode(); |
| EXPECT_EQ(TransformationMatrix().Scale(1.5), transform->Matrix()); |
| const auto& state = frame_overlay->DefaultPropertyTreeState(); |
| EXPECT_EQ(transform, &state.Transform()); |
| EXPECT_EQ(&ClipPaintPropertyNode::Root(), &state.Clip()); |
| EXPECT_EQ(&EffectPaintPropertyNode::Root(), &state.Effect()); |
| |
| auto check_paint_results = [&frame_overlay, |
| &state](PaintController& paint_controller) { |
| EXPECT_THAT( |
| paint_controller.GetDisplayItemList(), |
| ElementsAre(IsSameId(frame_overlay.get(), DisplayItem::kFrameOverlay))); |
| EXPECT_EQ(IntRect(0, 0, 800, 600), |
| paint_controller.GetDisplayItemList()[0].VisualRect()); |
| EXPECT_THAT( |
| paint_controller.PaintChunks(), |
| ElementsAre(IsPaintChunk( |
| 0, 1, PaintChunk::Id(*frame_overlay, DisplayItem::kFrameOverlay), |
| state, nullptr, IntRect(0, 0, 800, 600)))); |
| }; |
| |
| PaintController paint_controller(PaintController::kTransient); |
| GraphicsContext context(paint_controller); |
| if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { |
| frame_overlay->Paint(context); |
| paint_controller.CommitNewDisplayItems(); |
| check_paint_results(paint_controller); |
| } else { |
| auto* graphics_layer = frame_overlay->GetGraphicsLayer(); |
| EXPECT_FALSE(graphics_layer->IsHitTestable()); |
| EXPECT_EQ(state, graphics_layer->GetPropertyTreeState()); |
| Vector<PreCompositedLayerInfo> pre_composited_layers; |
| graphics_layer->PaintRecursively(context, pre_composited_layers); |
| check_paint_results(graphics_layer->GetPaintController()); |
| graphics_layer->GetPaintController().FinishCycle(); |
| } |
| } |
| |
| TEST_P(FrameOverlayTest, LayerOrder) { |
| // This test doesn't apply in CompositeAfterPaint. |
| if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) |
| return; |
| |
| auto frame_overlay1 = CreateSolidYellowOverlay(); |
| auto frame_overlay2 = CreateSolidYellowOverlay(); |
| frame_overlay1->UpdatePrePaint(); |
| frame_overlay2->UpdatePrePaint(); |
| |
| auto* parent_layer = GetWebView() |
| ->MainFrameImpl() |
| ->GetFrameView() |
| ->GetLayoutView() |
| ->Compositor() |
| ->PaintRootGraphicsLayer(); |
| ASSERT_EQ(3u, parent_layer->Children().size()); |
| EXPECT_EQ(parent_layer, frame_overlay1->GetGraphicsLayer()->Parent()); |
| EXPECT_EQ(parent_layer->Children()[1], frame_overlay1->GetGraphicsLayer()); |
| EXPECT_EQ(parent_layer, frame_overlay2->GetGraphicsLayer()->Parent()); |
| EXPECT_EQ(parent_layer->Children()[2], frame_overlay2->GetGraphicsLayer()); |
| |
| auto extra_layer = std::make_unique<GraphicsLayer>(parent_layer->Client()); |
| parent_layer->AddChild(extra_layer.get()); |
| |
| frame_overlay1->UpdatePrePaint(); |
| frame_overlay2->UpdatePrePaint(); |
| ASSERT_EQ(4u, parent_layer->Children().size()); |
| EXPECT_EQ(parent_layer, frame_overlay1->GetGraphicsLayer()->Parent()); |
| EXPECT_EQ(parent_layer->Children()[2], frame_overlay1->GetGraphicsLayer()); |
| EXPECT_EQ(parent_layer, frame_overlay2->GetGraphicsLayer()->Parent()); |
| EXPECT_EQ(parent_layer->Children()[3], frame_overlay2->GetGraphicsLayer()); |
| } |
| |
| } // namespace |
| } // namespace blink |