Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: athena/content/content_proxy.cc

Issue 591693002: Creating PNG images from web content to be used by OverviewMode navigation (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "athena/content/content_proxy.h" 5 #include "athena/content/content_proxy.h"
6 6
7 #include "athena/activity/public/activity.h" 7 #include "athena/activity/public/activity.h"
8 #include "athena/activity/public/activity_view_model.h" 8 #include "athena/activity/public/activity_view_model.h"
9 #include "base/bind.h"
10 #include "base/threading/worker_pool.h"
11 #include "content/public/browser/render_view_host.h"
12 #include "content/public/browser/render_widget_host_view.h"
9 #include "content/public/browser/web_contents.h" 13 #include "content/public/browser/web_contents.h"
10 #include "ui/aura/window.h" 14 #include "ui/aura/window.h"
11 #include "ui/views/background.h" 15 #include "ui/gfx/codec/png_codec.h"
16 #include "ui/gfx/geometry/rect.h"
17 #include "ui/gfx/image/image_png_rep.h"
12 #include "ui/views/controls/webview/webview.h" 18 #include "ui/views/controls/webview/webview.h"
13 #include "ui/views/widget/widget.h" 19 #include "ui/views/widget/widget.h"
14 20
15 namespace athena { 21 namespace athena {
16 22
23 // Encodes an A8 SkBitmap to grayscale PNG in a worker thread.
24 class ProxyImageData : public base::RefCountedThreadSafe<ProxyImageData> {
25 public:
26 ProxyImageData() {
27 }
28
29 void EncodeImage(const SkBitmap& bitmap, base::Closure callback) {
30 if (!base::WorkerPool::PostTaskAndReply(FROM_HERE,
31 base::Bind(&ProxyImageData::EncodeOnWorker,
32 this,
33 bitmap),
34 callback,
35 true)) {
36 // When coming here, the resulting image will be empty.
37 DCHECK(false) << "Cannot start bitmap encode task.";
38 callback.Run();
39 }
40 }
41
42 scoped_refptr<base::RefCountedBytes> data() const { return data_; }
43
44 private:
45 friend class base::RefCountedThreadSafe<ProxyImageData>;
46 virtual ~ProxyImageData() {
47 }
48
49 void EncodeOnWorker(const SkBitmap& bitmap) {
50 DCHECK_EQ(bitmap.colorType(), kAlpha_8_SkColorType);
51 // Encode the A8 bitmap to grayscale PNG treating alpha as color intensity.
52 std::vector<unsigned char> data;
53 if (gfx::PNGCodec::EncodeA8SkBitmap(bitmap, &data))
54 data_ = new base::RefCountedBytes(data);
55 }
56
57 scoped_refptr<base::RefCountedBytes> data_;
58
59 DISALLOW_COPY_AND_ASSIGN(ProxyImageData);
60 };
61
17 ContentProxy::ContentProxy(views::WebView* web_view, Activity* activity) 62 ContentProxy::ContentProxy(views::WebView* web_view, Activity* activity)
18 : web_view_(web_view), 63 : web_view_(web_view),
19 window_(activity->GetWindow()), 64 content_visible_(true),
20 background_color_( 65 content_loaded_(true),
21 activity->GetActivityViewModel()->GetRepresentativeColor()), 66 content_creation_called_(false),
22 content_loaded_(true) { 67 proxy_content_to_image_factory_(this) {
68 // Note: The content will be hidden once the image got created.
23 CreateProxyContent(); 69 CreateProxyContent();
24 HideOriginalContent();
25 } 70 }
26 71
27 ContentProxy::~ContentProxy() { 72 ContentProxy::~ContentProxy() {
28 // If we still have a connection to the original Activity, we make it visible 73 // If we still have a connection to the original Activity, we make it visible
29 // again. 74 // again.
30 ShowOriginalContent(); 75 ShowOriginalContent();
31 // At this point we should either have no view - or the view should not be
32 // shown by its parent anymore.
33 DCHECK(!proxy_content_.get() || !proxy_content_->parent());
34 proxy_content_.reset();
35 } 76 }
36 77
37 void ContentProxy::ContentWillUnload() { 78 void ContentProxy::ContentWillUnload() {
38 content_loaded_ = false; 79 content_loaded_ = false;
39 } 80 }
40 81
41 gfx::ImageSkia ContentProxy::GetContentImage() { 82 gfx::Image ContentProxy::GetContentImage() {
42 // For the time being we keep this here and return an empty image. 83 // While we compress to PNG, we use the original read back.
43 return image_; 84 if (!raw_image_.IsEmpty() || !png_data_.get())
85 return gfx::Image(raw_image_);
86
87 // Otherwise we convert the PNG.
88 std::vector<gfx::ImagePNGRep> image_reps;
89 image_reps.push_back(gfx::ImagePNGRep(png_data_, 1.0f));
90 return gfx::Image(image_reps);
44 } 91 }
45 92
46 void ContentProxy::EvictContent() { 93 void ContentProxy::EvictContent() {
47 HideProxyContent(); 94 raw_image_ = gfx::Image();
48 CreateSolidProxyContent(); 95 png_data_->Release();
49 ShowProxyContent();
50 } 96 }
51 97
52 void ContentProxy::Reparent(aura::Window* new_parent_window) { 98 void ContentProxy::OnPreContentDestroyed() {
53 if (new_parent_window == window_)
54 return;
55
56 // Since we are breaking now the connection to the old content, we make the 99 // Since we are breaking now the connection to the old content, we make the
57 // content visible again before we continue. 100 // content visible again before we continue.
58 // Note: Since the owning window is invisible, it does not matter that we 101 // Note: Since the owning window is invisible, it does not matter that we
59 // make the web content visible if the window gets destroyed shortly after. 102 // make the web content visible if the window gets destroyed shortly after.
60 ShowOriginalContent(); 103 ShowOriginalContent();
61 104
62 // Transfer the |proxy_content_| to the passed window.
63 window_ = new_parent_window;
64 web_view_ = NULL; 105 web_view_ = NULL;
65
66 // Move the view to the new window and show it there.
67 HideOriginalContent();
68 } 106 }
69 107
70 void ContentProxy::ShowOriginalContent() { 108 void ContentProxy::ShowOriginalContent() {
71 // Hide our content. 109 if (web_view_ && !content_visible_) {
72 HideProxyContent();
73
74 if (web_view_) {
75 // Show the original |web_view_| again. 110 // Show the original |web_view_| again.
76 web_view_->SetFastResize(false); 111 web_view_->SetFastResize(false);
77 // If the content is loaded, we ask it to relayout itself since the 112 // If the content is loaded, we ask it to relayout itself since the
78 // dimensions might have changed. If not, we will reload new content and no 113 // dimensions might have changed. If not, we will reload new content and no
79 // layout is required for the old content. 114 // layout is required for the old content.
80 if (content_loaded_) 115 if (content_loaded_)
81 web_view_->Layout(); 116 web_view_->Layout();
82 web_view_->GetWebContents()->GetNativeView()->Show(); 117 web_view_->GetWebContents()->GetNativeView()->Show();
83 web_view_->SetVisible(true); 118 web_view_->SetVisible(true);
119 content_visible_ = true;
84 } 120 }
85 } 121 }
86 122
87 void ContentProxy::HideOriginalContent() { 123 void ContentProxy::HideOriginalContent() {
88 if (web_view_) { 124 if (web_view_ && content_visible_) {
89 // Hide the |web_view_|. 125 // Hide the |web_view_|.
90 // TODO(skuhne): We might consider removing the view from the window while 126 // TODO(skuhne): We might consider removing the view from the window while
91 // it's hidden - it should work the same way as show/hide and does not have 127 // it's hidden - it should work the same way as show/hide and does not have
92 // any window re-ordering effect. 128 // any window re-ordering effect. Furthermore we want possibly to suppress
129 // any resizing of content (not only fast resize) here to avoid jank on
130 // rotation.
93 web_view_->GetWebContents()->GetNativeView()->Hide(); 131 web_view_->GetWebContents()->GetNativeView()->Hide();
94 web_view_->SetVisible(false); 132 web_view_->SetVisible(false);
95 // Don't allow the content to get resized with window size changes. 133 // Don't allow the content to get resized with window size changes.
96 web_view_->SetFastResize(true); 134 web_view_->SetFastResize(true);
135 content_visible_ = false;
97 } 136 }
98
99 // Show our replacement content.
100 ShowProxyContent();
101 } 137 }
102 138
103 void ContentProxy::CreateProxyContent() { 139 void ContentProxy::CreateProxyContent() {
104 // For the time being we create only a solid color here. 140 DCHECK(!content_creation_called_);
105 // TODO(skuhne): Replace with copying the drawn content into |proxy_content_| 141 content_creation_called_ = true;
106 // instead. 142 // Unit tests might not have a |web_view_|.
107 CreateSolidProxyContent(); 143 if (!web_view_)
144 return;
145
146 content::RenderViewHost* host =
147 web_view_->GetWebContents()->GetRenderViewHost();
148 DCHECK(host && host->GetView());
149 gfx::Size source = host->GetView()->GetViewBounds().size();
150 gfx::Size target = gfx::Size(source.width() / 2, source.height() / 2);
151 host->CopyFromBackingStore(
152 gfx::Rect(),
153 target,
154 base::Bind(&ContentProxy::OnContentImageRead,
155 proxy_content_to_image_factory_.GetWeakPtr()),
156 kAlpha_8_SkColorType);
108 } 157 }
109 158
110 void ContentProxy::CreateSolidProxyContent() { 159 void ContentProxy::OnContentImageRead(bool success, const SkBitmap& bitmap) {
111 proxy_content_.reset(new views::View()); 160 // Now we can hide the content. Note that after hiding we are freeing memory
112 proxy_content_->set_owned_by_client(); 161 // and if something goes wrong we will end up with an empty page.
113 proxy_content_->set_background( 162 HideOriginalContent();
114 views::Background::CreateSolidBackground(background_color_)); 163
164 if (!success || bitmap.empty() || bitmap.isNull())
165 return;
166
167 // While we are encoding the image, we keep the current image as reference
168 // to have something for the overview mode to grab. Once we have the encoded
169 // PNG, we will get rid of this.
170 raw_image_ = gfx::Image::CreateFrom1xBitmap(bitmap);
171
172 scoped_refptr<ProxyImageData> png_image = new ProxyImageData();
173 png_image->EncodeImage(
174 bitmap,
175 base::Bind(&ContentProxy::OnContentImageEncodeComplete,
176 proxy_content_to_image_factory_.GetWeakPtr(),
177 png_image));
115 } 178 }
116 179
117 void ContentProxy::ShowProxyContent() { 180 void ContentProxy::OnContentImageEncodeComplete(
118 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window_); 181 scoped_refptr<ProxyImageData> image) {
119 DCHECK(widget); 182 png_data_ = image->data();
120 views::View* client_view = widget->client_view();
121 // Place the view in front of all others.
122 client_view->AddChildView(proxy_content_.get());
123 proxy_content_->SetSize(client_view->bounds().size());
124 }
125 183
126 void ContentProxy::HideProxyContent() { 184 // From now on we decode the image as needed to save memory.
127 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window_); 185 raw_image_ = gfx::Image();
128 views::View* client_view = widget->client_view();
129 client_view->RemoveChildView(proxy_content_.get());
130 } 186 }
131 187
132 } // namespace athena 188 } // namespace athena
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698