1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/renderer/child_frame_compositing_helper.h"
6 
7 #include <utility>
8 
9 #include "build/build_config.h"
10 #include "cc/layers/picture_layer.h"
11 #include "cc/layers/surface_layer.h"
12 #include "cc/paint/paint_image.h"
13 #include "cc/paint/paint_image_builder.h"
14 #include "content/renderer/child_frame_compositor.h"
15 #include "skia/ext/image_operations.h"
16 #include "third_party/skia/include/core/SkBitmap.h"
17 #include "third_party/skia/include/core/SkImage.h"
18 #include "ui/gfx/geometry/point_f.h"
19 #include "ui/gfx/geometry/size.h"
20 #include "ui/gfx/skia_util.h"
21 
22 namespace content {
23 
ChildFrameCompositingHelper(ChildFrameCompositor * child_frame_compositor)24 ChildFrameCompositingHelper::ChildFrameCompositingHelper(
25     ChildFrameCompositor* child_frame_compositor)
26     : child_frame_compositor_(child_frame_compositor) {
27   DCHECK(child_frame_compositor_);
28 }
29 
~ChildFrameCompositingHelper()30 ChildFrameCompositingHelper::~ChildFrameCompositingHelper() {
31   if (crash_ui_layer_)
32     crash_ui_layer_->ClearClient();
33 }
34 
ChildFrameGone(const gfx::Size & frame_size_in_dip,float device_scale_factor)35 void ChildFrameCompositingHelper::ChildFrameGone(
36     const gfx::Size& frame_size_in_dip,
37     float device_scale_factor) {
38   surface_id_ = viz::SurfaceId();
39   device_scale_factor_ = device_scale_factor;
40 
41   crash_ui_layer_ = cc::PictureLayer::Create(this);
42   crash_ui_layer_->SetMasksToBounds(true);
43   crash_ui_layer_->SetIsDrawable(true);
44 
45   bool prevent_contents_opaque_changes = false;
46   bool is_surface_layer = false;
47   child_frame_compositor_->SetLayer(
48       crash_ui_layer_, prevent_contents_opaque_changes, is_surface_layer);
49 }
50 
SetSurfaceId(const viz::SurfaceId & surface_id,const gfx::Size & frame_size_in_dip,const cc::DeadlinePolicy & deadline)51 void ChildFrameCompositingHelper::SetSurfaceId(
52     const viz::SurfaceId& surface_id,
53     const gfx::Size& frame_size_in_dip,
54     const cc::DeadlinePolicy& deadline) {
55   if (surface_id_ == surface_id)
56     return;
57 
58   surface_id_ = surface_id;
59 
60   surface_layer_ = cc::SurfaceLayer::Create();
61   surface_layer_->SetMasksToBounds(true);
62   surface_layer_->SetSurfaceHitTestable(true);
63   surface_layer_->SetBackgroundColor(SK_ColorTRANSPARENT);
64 
65   surface_layer_->SetSurfaceId(surface_id, deadline);
66 
67   // TODO(lfg): Investigate if it's possible to propagate the information
68   // about the child surface's opacity. https://crbug.com/629851.
69   bool prevent_contents_opaque_changes = true;
70   child_frame_compositor_->SetLayer(surface_layer_,
71                                     prevent_contents_opaque_changes,
72                                     true /* is_surface_layer */);
73 
74   UpdateVisibility(true);
75 
76   surface_layer_->SetBounds(frame_size_in_dip);
77 }
78 
UpdateVisibility(bool visible)79 void ChildFrameCompositingHelper::UpdateVisibility(bool visible) {
80   cc::Layer* layer = child_frame_compositor_->GetLayer();
81   if (layer) {
82     layer->SetIsDrawable(visible);
83     layer->SetHitTestable(visible);
84   }
85 }
86 
PaintableRegion()87 gfx::Rect ChildFrameCompositingHelper::PaintableRegion() {
88   DCHECK(crash_ui_layer_);
89   return gfx::Rect(crash_ui_layer_->bounds());
90 }
91 
92 scoped_refptr<cc::DisplayItemList>
PaintContentsToDisplayList(PaintingControlSetting)93 ChildFrameCompositingHelper::PaintContentsToDisplayList(
94     PaintingControlSetting) {
95   DCHECK(crash_ui_layer_);
96   auto layer_size = crash_ui_layer_->bounds();
97   auto display_list = base::MakeRefCounted<cc::DisplayItemList>();
98   display_list->StartPaint();
99   display_list->push<cc::DrawColorOp>(SK_ColorGRAY, SkBlendMode::kSrc);
100 
101   SkBitmap* sad_bitmap = child_frame_compositor_->GetSadPageBitmap();
102   if (sad_bitmap) {
103     int paint_width = sad_bitmap->width() * device_scale_factor_;
104     int paint_height = sad_bitmap->height() * device_scale_factor_;
105     if (layer_size.width() >= paint_width &&
106         layer_size.height() >= paint_height) {
107       int x = (layer_size.width() - paint_width) / 2;
108       int y = (layer_size.height() - paint_height) / 2;
109       if (device_scale_factor_ != 1.f) {
110         display_list->push<cc::SaveOp>();
111         display_list->push<cc::TranslateOp>(x, y);
112         display_list->push<cc::ScaleOp>(device_scale_factor_,
113                                         device_scale_factor_);
114         x = 0;
115         y = 0;
116       }
117 
118       auto image = cc::PaintImageBuilder::WithDefault()
119                        .set_id(cc::PaintImage::GetNextId())
120                        .set_image(SkImage::MakeFromBitmap(*sad_bitmap),
121                                   cc::PaintImage::GetNextContentId())
122                        .TakePaintImage();
123       display_list->push<cc::DrawImageOp>(image, x, y, nullptr);
124 
125       if (device_scale_factor_ != 1.f)
126         display_list->push<cc::RestoreOp>();
127     }
128   }
129   display_list->EndPaintOfUnpaired(gfx::Rect(layer_size));
130   display_list->Finalize();
131   return display_list;
132 }
133 
FillsBoundsCompletely() const134 bool ChildFrameCompositingHelper::FillsBoundsCompletely() const {
135   // Because we paint a full opaque gray background.
136   return true;
137 }
138 
GetApproximateUnsharedMemoryUsage() const139 size_t ChildFrameCompositingHelper::GetApproximateUnsharedMemoryUsage() const {
140   return sizeof(*this);
141 }
142 
143 }  // namespace content
144