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

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: 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> {
oshima 2014/09/22 16:10:28 If this is to be used by overview mode, it will be
Mr4D (OOO till 08-26) 2014/09/23 19:07:34 No. The problem is that every activity will have t
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 callback.Run();
oshima 2014/09/22 16:10:28 should this be DCHECK? Does it make sense to run c
Mr4D (OOO till 08-26) 2014/09/23 19:07:33 Adding a DCHECK is possibly a good idea to see a f
oshima 2014/09/24 00:40:00 Acknowledged.
37 }
38 }
39
40 scoped_refptr<base::RefCountedBytes> data() const { return data_; }
41
42 private:
43 friend class base::RefCountedThreadSafe<ProxyImageData>;
44 virtual ~ProxyImageData() {
45 }
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 };
sadrul 2014/09/22 16:13:32 Any chance this can be consolidated with Navigatio
Mr4D (OOO till 08-26) 2014/09/23 19:07:34 I looked into that at the beginning, but there are
59
17 ContentProxy::ContentProxy(views::WebView* web_view, Activity* activity) 60 ContentProxy::ContentProxy(views::WebView* web_view, Activity* activity)
18 : web_view_(web_view), 61 : web_view_(web_view),
19 window_(activity->GetWindow()), 62 content_visible_(true),
20 background_color_( 63 content_loaded_(true),
21 activity->GetActivityViewModel()->GetRepresentativeColor()), 64 proxy_content_to_image_factory_(this) {
22 content_loaded_(true) { 65 // Note: The content will be hidden once the image got created.
23 CreateProxyContent(); 66 CreateProxyContent();
24 HideOriginalContent();
25 } 67 }
26 68
27 ContentProxy::~ContentProxy() { 69 ContentProxy::~ContentProxy() {
28 // If we still have a connection to the original Activity, we make it visible 70 // If we still have a connection to the original Activity, we make it visible
29 // again. 71 // again.
30 ShowOriginalContent(); 72 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 } 73 }
36 74
37 void ContentProxy::ContentWillUnload() { 75 void ContentProxy::ContentWillUnload() {
38 content_loaded_ = false; 76 content_loaded_ = false;
39 } 77 }
40 78
41 gfx::ImageSkia ContentProxy::GetContentImage() { 79 scoped_ptr<gfx::Image> ContentProxy::GetContentImage() {
42 // For the time being we keep this here and return an empty image. 80 // While we compress to PNG, we use the original read back.
43 return image_; 81 if (image_.IsEmpty())
oshima 2014/09/22 16:10:28 shouldn't this be !image_.IsEmpty(), or maybe chec
Mr4D (OOO till 08-26) 2014/09/23 19:07:34 Done.
82 return scoped_ptr<gfx::Image>(new gfx::Image(image_));
83
84 // Otherwise we convert the PNG.
85 std::vector<gfx::ImagePNGRep> image_reps;
86 image_reps.push_back(gfx::ImagePNGRep(png_data_, 2.0f));
oshima 2014/09/22 16:10:28 why this is using 2x scale factor?
Mr4D (OOO till 08-26) 2014/09/23 19:07:33 I wasn't able to test this yet, but according to t
oshima 2014/09/24 00:40:00 The thumbnail should be "unscaled" image (that is,
Mr4D (OOO till 08-26) 2014/09/24 16:18:25 Done. I tested and the result seems to work. Note
87 return scoped_ptr<gfx::Image>(new gfx::Image(image_reps));
44 } 88 }
45 89
46 void ContentProxy::EvictContent() { 90 void ContentProxy::EvictContent() {
47 HideProxyContent(); 91 image_ = gfx::Image();
48 CreateSolidProxyContent(); 92 png_data_->Release();
49 ShowProxyContent();
50 } 93 }
51 94
52 void ContentProxy::Reparent(aura::Window* new_parent_window) { 95 void ContentProxy::ContentGetsDestroyed() {
53 if (new_parent_window == window_)
54 return;
55
56 // Since we are breaking now the connection to the old content, we make the 96 // Since we are breaking now the connection to the old content, we make the
57 // content visible again before we continue. 97 // content visible again before we continue.
58 // Note: Since the owning window is invisible, it does not matter that we 98 // 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. 99 // make the web content visible if the window gets destroyed shortly after.
60 ShowOriginalContent(); 100 ShowOriginalContent();
61 101
62 // Transfer the |proxy_content_| to the passed window.
63 window_ = new_parent_window;
64 web_view_ = NULL; 102 web_view_ = NULL;
65
66 // Move the view to the new window and show it there.
67 HideOriginalContent();
68 } 103 }
69 104
70 void ContentProxy::ShowOriginalContent() { 105 void ContentProxy::ShowOriginalContent() {
71 // Hide our content. 106 if (web_view_ && !content_visible_) {
oshima 2014/09/22 16:10:28 don't you have to change content_visible_? Rathe
Mr4D (OOO till 08-26) 2014/09/23 19:07:34 Yes, it's better to set it. I didn't want to use
72 HideProxyContent();
73
74 if (web_view_) {
75 // Show the original |web_view_| again. 107 // Show the original |web_view_| again.
76 web_view_->SetFastResize(false); 108 web_view_->SetFastResize(false);
77 // If the content is loaded, we ask it to relayout itself since the 109 // 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 110 // dimensions might have changed. If not, we will reload new content and no
79 // layout is required for the old content. 111 // layout is required for the old content.
80 if (content_loaded_) 112 if (content_loaded_)
81 web_view_->Layout(); 113 web_view_->Layout();
82 web_view_->GetWebContents()->GetNativeView()->Show(); 114 web_view_->GetWebContents()->GetNativeView()->Show();
83 web_view_->SetVisible(true); 115 web_view_->SetVisible(true);
84 } 116 }
85 } 117 }
86 118
87 void ContentProxy::HideOriginalContent() { 119 void ContentProxy::HideOriginalContent() {
88 if (web_view_) { 120 if (web_view_ && content_visible_) {
89 // Hide the |web_view_|. 121 // Hide the |web_view_|.
90 // TODO(skuhne): We might consider removing the view from the window while 122 // 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 123 // it's hidden - it should work the same way as show/hide and does not have
92 // any window re-ordering effect. 124 // any window re-ordering effect.
93 web_view_->GetWebContents()->GetNativeView()->Hide(); 125 web_view_->GetWebContents()->GetNativeView()->Hide();
94 web_view_->SetVisible(false); 126 web_view_->SetVisible(false);
95 // Don't allow the content to get resized with window size changes. 127 // Don't allow the content to get resized with window size changes.
96 web_view_->SetFastResize(true); 128 web_view_->SetFastResize(true);
oshima 2014/09/22 18:26:05 We may not want to resize at all when hidden? It m
Mr4D (OOO till 08-26) 2014/09/23 19:07:33 An excellent idea. I was thinking of maybe doing w
129 content_visible_ = false;
97 } 130 }
98
99 // Show our replacement content.
100 ShowProxyContent();
101 } 131 }
102 132
103 void ContentProxy::CreateProxyContent() { 133 void ContentProxy::CreateProxyContent() {
104 // For the time being we create only a solid color here. 134 // Unit tests might not have a |web_view_|.
105 // TODO(skuhne): Replace with copying the drawn content into |proxy_content_| 135 if (!web_view_)
106 // instead. 136 return;
107 CreateSolidProxyContent(); 137
138 content::RenderViewHost* host =
139 web_view_->GetWebContents()->GetRenderViewHost();
140 DCHECK(host && host->GetView());
141 gfx::Size source = host->GetView()->GetViewBounds().size();
142 gfx::Size target = gfx::Size(source.width() / 2, source.height() / 2);
143 host->CopyFromBackingStore(
144 gfx::Rect(),
145 target,
146 base::Bind(&ContentProxy::ContentReadBackAsImage,
147 proxy_content_to_image_factory_.GetWeakPtr()),
sadrul 2014/09/22 16:13:32 InvalidateWeakPtrs() first, so that we ignore an e
Mr4D (OOO till 08-26) 2014/09/23 19:07:34 This function gets only called once through the co
148 kAlpha_8_SkColorType);
108 } 149 }
109 150
110 void ContentProxy::CreateSolidProxyContent() { 151 void ContentProxy::ContentReadBackAsImage(bool success,
111 proxy_content_.reset(new views::View()); 152 const SkBitmap& bitmap) {
112 proxy_content_->set_owned_by_client(); 153 // Now we can hide the content.
113 proxy_content_->set_background( 154 HideOriginalContent();
sadrul 2014/09/22 16:13:32 Should we hide only if the PNG encoding works? (i.
Mr4D (OOO till 08-26) 2014/09/23 19:07:34 I chose this location since I think its the best l
114 views::Background::CreateSolidBackground(background_color_)); 155
156 if (!success || bitmap.empty() || bitmap.isNull())
157 return;
158
159 // While we are encoding the image, we keep the current image as reference
160 // to have something for the overview mode to grab. Once we have the encoded
161 // PNG, we will get rid of this.
162 image_ = gfx::Image::CreateFrom1xBitmap(bitmap);
163
164 scoped_refptr<ProxyImageData> png_image = new ProxyImageData();
165 png_image->EncodeImage(
166 bitmap,
167 base::Bind(&ContentProxy::OnContentImageEncodeComplete,
168 proxy_content_to_image_factory_.GetWeakPtr(),
169 png_image));
115 } 170 }
116 171
117 void ContentProxy::ShowProxyContent() { 172 void ContentProxy::OnContentImageEncodeComplete(
118 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window_); 173 scoped_refptr<ProxyImageData> image) {
119 DCHECK(widget); 174 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 175
126 void ContentProxy::HideProxyContent() { 176 // From now on we decode the image as needed to save memory.
127 views::Widget* widget = views::Widget::GetWidgetForNativeWindow(window_); 177 image_ = gfx::Image();
sadrul 2014/09/22 16:13:33 Call image_ something else, to clarify that it is
Mr4D (OOO till 08-26) 2014/09/23 19:07:33 Done.
128 views::View* client_view = widget->client_view();
129 client_view->RemoveChildView(proxy_content_.get());
130 } 178 }
131 179
132 } // namespace athena 180 } // namespace athena
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698