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.
5 #include "athena/content/content_proxy.h"
8 #include "base/threading/worker_pool.h"
9 #include "content/public/browser/render_view_host.h"
10 #include "content/public/browser/render_widget_host_view.h"
11 #include "content/public/browser/web_contents.h"
12 #include "ui/aura/window.h"
13 #include "ui/gfx/codec/png_codec.h"
14 #include "ui/gfx/geometry/rect.h"
15 #include "ui/gfx/image/image.h"
16 #include "ui/gfx/image/image_png_rep.h"
17 #include "ui/views/controls/webview/webview.h"
18 #include "ui/views/widget/widget.h"
22 // Encodes an A8 SkBitmap to grayscale PNG in a worker thread.
23 class ProxyImageData
: public base::RefCountedThreadSafe
<ProxyImageData
> {
28 void EncodeImage(const SkBitmap
& bitmap
, base::Closure callback
) {
29 if (!base::WorkerPool::PostTaskAndReply(FROM_HERE
,
30 base::Bind(&ProxyImageData::EncodeOnWorker
,
35 // When coming here, the resulting image will be empty.
36 DCHECK(false) << "Cannot start bitmap encode task.";
41 scoped_refptr
<base::RefCountedBytes
> data() const { return data_
; }
44 friend class base::RefCountedThreadSafe
<ProxyImageData
>;
47 void EncodeOnWorker(const SkBitmap
& bitmap
) {
48 DCHECK_EQ(bitmap
.colorType(), kAlpha_8_SkColorType
);
49 // Encode the A8 bitmap to grayscale PNG treating alpha as color intensity.
50 std::vector
<unsigned char> data
;
51 if (gfx::PNGCodec::EncodeA8SkBitmap(bitmap
, &data
))
52 data_
= new base::RefCountedBytes(data
);
55 scoped_refptr
<base::RefCountedBytes
> data_
;
57 DISALLOW_COPY_AND_ASSIGN(ProxyImageData
);
60 ContentProxy::ContentProxy(views::WebView
* web_view
)
61 : web_view_(web_view
),
62 content_visible_(true),
63 content_loaded_(true),
64 content_creation_called_(false),
65 proxy_content_to_image_factory_(this) {
66 // Note: The content will be hidden once the image got created.
70 ContentProxy::~ContentProxy() {
71 // If we still have a connection to the original web contents, we make it
73 ShowOriginalContent();
76 void ContentProxy::ContentWillUnload() {
77 content_loaded_
= false;
80 gfx::ImageSkia
ContentProxy::GetContentImage() {
81 // While we compress to PNG, we use the original read back.
85 // Otherwise we convert the PNG.
86 std::vector
<gfx::ImagePNGRep
> image_reps
;
87 image_reps
.push_back(gfx::ImagePNGRep(png_data_
, 1.0f
));
88 return *(gfx::Image(image_reps
).ToImageSkia());
91 void ContentProxy::EvictContent() {
92 raw_image_
= gfx::ImageSkia();
96 void ContentProxy::OnPreContentDestroyed() {
97 // Since we are breaking now the connection to the old content, we make the
98 // content visible again before we continue.
99 // Note: Since the owning window is invisible, it does not matter that we
100 // make the web content visible if the window gets destroyed shortly after.
101 ShowOriginalContent();
106 void ContentProxy::ShowOriginalContent() {
107 if (web_view_
&& !content_visible_
) {
108 // Show the original |web_view_| again.
109 web_view_
->SetFastResize(false);
110 // If the content is loaded, we ask it to relayout itself since the
111 // dimensions might have changed. If not, we will reload new content and no
112 // layout is required for the old content.
115 web_view_
->GetWebContents()->GetNativeView()->Show();
116 web_view_
->SetVisible(true);
117 content_visible_
= true;
121 void ContentProxy::HideOriginalContent() {
122 if (web_view_
&& content_visible_
) {
123 // Hide the |web_view_|.
124 // TODO(skuhne): We might consider removing the view from the window while
125 // it's hidden - it should work the same way as show/hide and does not have
126 // any window re-ordering effect. Furthermore we want possibly to suppress
127 // any resizing of content (not only fast resize) here to avoid jank on
129 web_view_
->GetWebContents()->GetNativeView()->Hide();
130 web_view_
->SetVisible(false);
131 // Don't allow the content to get resized with window size changes.
132 web_view_
->SetFastResize(true);
133 content_visible_
= false;
137 void ContentProxy::CreateProxyContent() {
138 DCHECK(!content_creation_called_
);
139 content_creation_called_
= true;
140 // Unit tests might not have a |web_view_|.
144 content::RenderViewHost
* host
=
145 web_view_
->GetWebContents()->GetRenderViewHost();
147 // A never fully initialized content can come here with no view.
148 if (!host
->GetView())
150 gfx::Size source
= host
->GetView()->GetViewBounds().size();
151 gfx::Size target
= gfx::Size(source
.width() / 2, source
.height() / 2);
152 host
->CopyFromBackingStore(
155 base::Bind(&ContentProxy::OnContentImageRead
,
156 proxy_content_to_image_factory_
.GetWeakPtr()),
157 kAlpha_8_SkColorType
);
160 void ContentProxy::OnContentImageRead(const SkBitmap
& bitmap
,
161 content::ReadbackResponse response
) {
162 // Now we can hide the content. Note that after hiding we are freeing memory
163 // and if something goes wrong we will end up with an empty page.
164 HideOriginalContent();
166 if (response
!= content::READBACK_SUCCESS
|| bitmap
.empty() ||
170 // While we are encoding the image, we keep the current image as reference
171 // to have something for the overview mode to grab. Once we have the encoded
172 // PNG, we will get rid of this.
173 raw_image_
= gfx::ImageSkia::CreateFrom1xBitmap(bitmap
);
175 scoped_refptr
<ProxyImageData
> png_image
= new ProxyImageData();
176 png_image
->EncodeImage(
178 base::Bind(&ContentProxy::OnContentImageEncodeComplete
,
179 proxy_content_to_image_factory_
.GetWeakPtr(),
183 void ContentProxy::OnContentImageEncodeComplete(
184 scoped_refptr
<ProxyImageData
> image
) {
185 png_data_
= image
->data();
187 // From now on we decode the image as needed to save memory.
188 raw_image_
= gfx::ImageSkia();
191 } // namespace athena