Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / athena / content / content_proxy.cc
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 "athena/content/content_proxy.h"
6
7 #include "base/bind.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"
19
20 namespace athena {
21
22 // Encodes an A8 SkBitmap to grayscale PNG in a worker thread.
23 class ProxyImageData : public base::RefCountedThreadSafe<ProxyImageData> {
24  public:
25   ProxyImageData() {
26   }
27
28   void EncodeImage(const SkBitmap& bitmap, base::Closure callback) {
29     if (!base::WorkerPool::PostTaskAndReply(FROM_HERE,
30             base::Bind(&ProxyImageData::EncodeOnWorker,
31                        this,
32                        bitmap),
33             callback,
34             true)) {
35       // When coming here, the resulting image will be empty.
36       DCHECK(false) << "Cannot start bitmap encode task.";
37       callback.Run();
38     }
39   }
40
41   scoped_refptr<base::RefCountedBytes> data() const { return data_; }
42
43  private:
44   friend class base::RefCountedThreadSafe<ProxyImageData>;
45   ~ProxyImageData() {}
46
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);
53   }
54
55   scoped_refptr<base::RefCountedBytes> data_;
56
57   DISALLOW_COPY_AND_ASSIGN(ProxyImageData);
58 };
59
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.
67   CreateProxyContent();
68 }
69
70 ContentProxy::~ContentProxy() {
71   // If we still have a connection to the original web contents, we make it
72   // visible again.
73   ShowOriginalContent();
74 }
75
76 void ContentProxy::ContentWillUnload() {
77   content_loaded_ = false;
78 }
79
80 gfx::ImageSkia ContentProxy::GetContentImage() {
81   // While we compress to PNG, we use the original read back.
82   if (!png_data_.get())
83     return raw_image_;
84
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());
89 }
90
91 void ContentProxy::EvictContent() {
92   raw_image_ = gfx::ImageSkia();
93   png_data_->Release();
94 }
95
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();
102
103   web_view_ = nullptr;
104 }
105
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.
113     if (content_loaded_)
114       web_view_->Layout();
115     web_view_->GetWebContents()->GetNativeView()->Show();
116     web_view_->SetVisible(true);
117     content_visible_ = true;
118   }
119 }
120
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
128     // rotation.
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;
134   }
135 }
136
137 void ContentProxy::CreateProxyContent() {
138   DCHECK(!content_creation_called_);
139   content_creation_called_ = true;
140   // Unit tests might not have a |web_view_|.
141   if (!web_view_)
142     return;
143
144   content::RenderViewHost* host =
145       web_view_->GetWebContents()->GetRenderViewHost();
146   DCHECK(host);
147   // A never fully initialized content can come here with no view.
148   if (!host->GetView())
149     return;
150   gfx::Size source = host->GetView()->GetViewBounds().size();
151   gfx::Size target = gfx::Size(source.width() / 2, source.height() / 2);
152   host->CopyFromBackingStore(
153       gfx::Rect(),
154       target,
155       base::Bind(&ContentProxy::OnContentImageRead,
156                  proxy_content_to_image_factory_.GetWeakPtr()),
157       kAlpha_8_SkColorType);
158 }
159
160 void ContentProxy::OnContentImageRead(bool success, const SkBitmap& bitmap) {
161   // Now we can hide the content. Note that after hiding we are freeing memory
162   // and if something goes wrong we will end up with an empty page.
163   HideOriginalContent();
164
165   if (!success || bitmap.empty() || bitmap.isNull())
166     return;
167
168   // While we are encoding the image, we keep the current image as reference
169   // to have something for the overview mode to grab. Once we have the encoded
170   // PNG, we will get rid of this.
171   raw_image_ = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
172
173   scoped_refptr<ProxyImageData> png_image = new ProxyImageData();
174   png_image->EncodeImage(
175       bitmap,
176       base::Bind(&ContentProxy::OnContentImageEncodeComplete,
177                  proxy_content_to_image_factory_.GetWeakPtr(),
178                  png_image));
179 }
180
181 void ContentProxy::OnContentImageEncodeComplete(
182     scoped_refptr<ProxyImageData> image) {
183   png_data_ = image->data();
184
185   // From now on we decode the image as needed to save memory.
186   raw_image_ = gfx::ImageSkia();
187 }
188
189 }  // namespace athena