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

Side by Side Diff: components/zoom/zoom_controller.cc

Issue 2630583002: Add setting to isolate zoom changes by default. (Closed)
Patch Set: Add more tests. Created 3 years, 11 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "components/zoom/zoom_controller.h" 5 #include "components/zoom/zoom_controller.h"
6 6
7 #include "components/zoom/zoom_event_manager.h" 7 #include "components/zoom/zoom_event_manager.h"
8 #include "components/zoom/zoom_observer.h" 8 #include "components/zoom/zoom_observer.h"
9 #include "content/public/browser/browser_context.h"
9 #include "content/public/browser/host_zoom_map.h" 10 #include "content/public/browser/host_zoom_map.h"
10 #include "content/public/browser/navigation_details.h" 11 #include "content/public/browser/navigation_details.h"
11 #include "content/public/browser/navigation_entry.h" 12 #include "content/public/browser/navigation_entry.h"
12 #include "content/public/browser/render_process_host.h" 13 #include "content/public/browser/render_process_host.h"
13 #include "content/public/browser/render_view_host.h" 14 #include "content/public/browser/render_view_host.h"
15 #include "content/public/browser/storage_partition.h"
14 #include "content/public/browser/web_contents.h" 16 #include "content/public/browser/web_contents.h"
15 #include "content/public/common/page_type.h" 17 #include "content/public/common/page_type.h"
16 #include "content/public/common/page_zoom.h" 18 #include "content/public/common/page_zoom.h"
17 #include "net/base/url_util.h" 19 #include "net/base/url_util.h"
18 20
19 DEFINE_WEB_CONTENTS_USER_DATA_KEY(zoom::ZoomController); 21 DEFINE_WEB_CONTENTS_USER_DATA_KEY(zoom::ZoomController);
20 22
21 namespace zoom { 23 namespace zoom {
22 24
23 double ZoomController::GetZoomLevelForWebContents( 25 double ZoomController::GetZoomLevelForWebContents(
24 const content::WebContents* web_contents) { 26 const content::WebContents* web_contents) {
25 if (!web_contents) 27 if (!web_contents)
26 return 0.0; 28 return 0.0;
27 29
28 auto* zoom_controller = FromWebContents(web_contents); 30 auto* zoom_controller = FromWebContents(web_contents);
29 if (zoom_controller) 31 if (zoom_controller)
30 return zoom_controller->GetZoomLevel(); 32 return zoom_controller->GetZoomLevel();
31 33
32 return content::HostZoomMap::GetZoomLevel(web_contents); 34 return content::HostZoomMap::GetZoomLevel(web_contents);
33 } 35 }
34 36
35 ZoomController::ZoomController(content::WebContents* web_contents) 37 ZoomController::ZoomController(content::WebContents* web_contents)
36 : content::WebContentsObserver(web_contents), 38 : content::WebContentsObserver(web_contents),
37 can_show_bubble_(true), 39 can_show_bubble_(true),
38 zoom_mode_(ZOOM_MODE_DEFAULT), 40 default_per_origin_(true),
39 zoom_level_(1.0), 41 zoom_level_(1.0),
40 browser_context_(web_contents->GetBrowserContext()) { 42 browser_context_(web_contents->GetBrowserContext()) {
41 host_zoom_map_ = content::HostZoomMap::GetForWebContents(web_contents); 43 host_zoom_map_ = content::HostZoomMap::GetForWebContents(web_contents);
42 zoom_level_ = host_zoom_map_->GetDefaultZoomLevel(); 44 zoom_level_ = host_zoom_map_->GetDefaultZoomLevel();
43 45
46 // TODO Should we use GetStoragePartition with the SiteInstance?
wjmaclean 2017/01/19 21:09:05 If we have the SiteInstance, then it's preferable
Kevin McNee 2017/02/03 20:11:54 Done.
47 content::ZoomLevelDelegate* zoom_level_delegate =
48 content::BrowserContext::GetDefaultStoragePartition(browser_context_)
49 ->GetZoomLevelDelegate();
50 if (zoom_level_delegate) {
51 default_per_origin_ = zoom_level_delegate->GetIsOriginScopePref();
52 default_zoom_scope_subscription_ =
53 zoom_level_delegate->RegisterDefaultZoomScopeCallback(
54 base::Bind(&ZoomController::OnDefaultZoomScopeChanged,
55 base::Unretained(this)));
wjmaclean 2017/01/19 21:09:05 Is this safe? What if the WebContents that owns us
Kevin McNee 2017/02/01 20:29:40 Good point. Once this ZoomController is destroyed
Kevin McNee 2017/02/03 20:11:54 Done.
56 }
57 zoom_mode_ = default_per_origin_ ? ZOOM_MODE_DEFAULT : ZOOM_MODE_ISOLATED;
58
59 // When in isolated zoom, a temporary zoom level needs to be set to override
60 // any existing per-host zoom levels.
61 // If this WebContents is a clone of another, don't overwrite the temporary
62 // level we've inherited.
63 int render_process_id = web_contents->GetRenderProcessHost()->GetID();
64 int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID();
65 if (zoom_mode_ == ZOOM_MODE_ISOLATED &&
66 !host_zoom_map_->UsesTemporaryZoomLevel(render_process_id,
67 render_view_id)) {
68 host_zoom_map_->SetTemporaryZoomLevel(render_process_id, render_view_id,
69 zoom_level_);
70 }
71
44 zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback( 72 zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(
45 base::Bind(&ZoomController::OnZoomLevelChanged, base::Unretained(this))); 73 base::Bind(&ZoomController::OnZoomLevelChanged, base::Unretained(this)));
46 74
47 UpdateState(std::string()); 75 UpdateState(std::string());
48 } 76 }
49 77
50 ZoomController::~ZoomController() {} 78 ZoomController::~ZoomController() {}
51 79
52 bool ZoomController::IsAtDefaultZoom() const { 80 bool ZoomController::IsAtDefaultZoom() const {
53 return content::ZoomValuesEqual(GetZoomLevel(), GetDefaultZoomLevel()); 81 return content::ZoomValuesEqual(GetZoomLevel(), GetDefaultZoomLevel());
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 content::HostZoomMap* zoom_map = 200 content::HostZoomMap* zoom_map =
173 content::HostZoomMap::GetForWebContents(web_contents()); 201 content::HostZoomMap::GetForWebContents(web_contents());
174 DCHECK(zoom_map); 202 DCHECK(zoom_map);
175 int render_process_id = web_contents()->GetRenderProcessHost()->GetID(); 203 int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
176 int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID(); 204 int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
177 double original_zoom_level = GetZoomLevel(); 205 double original_zoom_level = GetZoomLevel();
178 206
179 DCHECK(!event_data_); 207 DCHECK(!event_data_);
180 event_data_.reset(new ZoomChangedEventData( 208 event_data_.reset(new ZoomChangedEventData(
181 web_contents(), original_zoom_level, original_zoom_level, new_mode, 209 web_contents(), original_zoom_level, original_zoom_level, new_mode,
182 new_mode != ZOOM_MODE_DEFAULT)); 210 new_mode !=
211 (default_per_origin_ ? ZOOM_MODE_DEFAULT : ZOOM_MODE_ISOLATED)));
183 212
184 switch (new_mode) { 213 switch (new_mode) {
185 case ZOOM_MODE_DEFAULT: { 214 case ZOOM_MODE_DEFAULT: {
186 content::NavigationEntry* entry = 215 content::NavigationEntry* entry =
187 web_contents()->GetController().GetLastCommittedEntry(); 216 web_contents()->GetController().GetLastCommittedEntry();
188 217
189 if (entry) { 218 if (entry) {
190 GURL url = content::HostZoomMap::GetURLFromEntry(entry); 219 GURL url = content::HostZoomMap::GetURLFromEntry(entry);
191 std::string host = net::GetHostOrSpecFromURL(url); 220 std::string host = net::GetHostOrSpecFromURL(url);
192 221
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 break; 282 break;
254 } 283 }
255 } 284 }
256 // Any event data we've stored should have been consumed by this point. 285 // Any event data we've stored should have been consumed by this point.
257 DCHECK(!event_data_); 286 DCHECK(!event_data_);
258 287
259 zoom_mode_ = new_mode; 288 zoom_mode_ = new_mode;
260 } 289 }
261 290
262 void ZoomController::ResetZoomModeOnNavigationIfNeeded(const GURL& url) { 291 void ZoomController::ResetZoomModeOnNavigationIfNeeded(const GURL& url) {
263 if (zoom_mode_ != ZOOM_MODE_ISOLATED && zoom_mode_ != ZOOM_MODE_MANUAL) 292 if ((!default_per_origin_ || zoom_mode_ != ZOOM_MODE_ISOLATED) &&
293 zoom_mode_ != ZOOM_MODE_MANUAL)
264 return; 294 return;
265 295
266 int render_process_id = web_contents()->GetRenderProcessHost()->GetID(); 296 int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
267 int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID(); 297 int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
268 content::HostZoomMap* zoom_map = 298 content::HostZoomMap* zoom_map =
269 content::HostZoomMap::GetForWebContents(web_contents()); 299 content::HostZoomMap::GetForWebContents(web_contents());
300 double old_zoom_level = GetZoomLevel();
301 // Set |zoom_level_| after calling GetZoomLevel() so we get the correct old
302 // zoom level if we're resetting from manual.
270 zoom_level_ = zoom_map->GetDefaultZoomLevel(); 303 zoom_level_ = zoom_map->GetDefaultZoomLevel();
271 double old_zoom_level = zoom_map->GetZoomLevel(web_contents()); 304 ZoomMode new_mode;
272 double new_zoom_level = zoom_map->GetZoomLevelForHostAndScheme( 305 double new_zoom_level;
273 url.scheme(), net::GetHostOrSpecFromURL(url)); 306 if (default_per_origin_) {
307 new_mode = ZOOM_MODE_DEFAULT;
308 new_zoom_level = zoom_map->GetZoomLevelForHostAndScheme(
309 url.scheme(), net::GetHostOrSpecFromURL(url));
310 } else {
311 new_mode = ZOOM_MODE_ISOLATED;
312 new_zoom_level = zoom_level_;
313 }
274 event_data_.reset(new ZoomChangedEventData(web_contents(), old_zoom_level, 314 event_data_.reset(new ZoomChangedEventData(web_contents(), old_zoom_level,
275 new_zoom_level, ZOOM_MODE_DEFAULT, 315 new_zoom_level, new_mode,
276 false /* can_show_bubble */)); 316 false /* can_show_bubble */));
277 // The call to ClearTemporaryZoomLevel() doesn't generate any events from 317 if (default_per_origin_) {
278 // HostZoomMap, but the call to UpdateState() at the end of this function 318 // The call to ClearTemporaryZoomLevel() doesn't generate any events from
279 // will notify our observers. 319 // HostZoomMap, but the call to UpdateState() at the end of this function
280 // Note: it's possible the render_process/view ids have disappeared (e.g. 320 // will notify our observers.
281 // if we navigated to a new origin), but this won't cause a problem in the 321 // Note: it's possible the render_process/view ids have disappeared (e.g.
282 // call below. 322 // if we navigated to a new origin), but this won't cause a problem in the
283 zoom_map->ClearTemporaryZoomLevel(render_process_id, render_view_id); 323 // call below.
284 zoom_mode_ = ZOOM_MODE_DEFAULT; 324 zoom_map->ClearTemporaryZoomLevel(render_process_id, render_view_id);
325 } else {
326 // If we're resetting to isolated zoom, a temporary zoom level needs to
327 // be set to override any existing per-host zoom levels.
328 zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
329 new_zoom_level);
330 }
331 zoom_mode_ = new_mode;
332 }
333
334 void ZoomController::UpdateZoomModeOnScopeChangeIfNeeded() {
335 if (zoom_mode_ != ZOOM_MODE_DEFAULT && zoom_mode_ != ZOOM_MODE_ISOLATED)
336 return;
337
338 // When going from per-tab to per-host, if there isn't an existing per-host
339 // zoom level set, the first ZoomController (that has set a non-default
340 // temporary zoom level) to be notified of the scope change will set the
341 // per-host zoom level.
342 // TODO Is this acceptable behaviour?
343 SetZoomMode(default_per_origin_ ? ZOOM_MODE_DEFAULT : ZOOM_MODE_ISOLATED);
285 } 344 }
286 345
287 void ZoomController::DidNavigateMainFrame( 346 void ZoomController::DidNavigateMainFrame(
288 const content::LoadCommittedDetails& details, 347 const content::LoadCommittedDetails& details,
289 const content::FrameNavigateParams& params) { 348 const content::FrameNavigateParams& params) {
290 if (details.entry && details.entry->GetPageType() == content::PAGE_TYPE_ERROR) 349 if (details.entry && details.entry->GetPageType() == content::PAGE_TYPE_ERROR)
291 content::HostZoomMap::SendErrorPageZoomLevelRefresh(web_contents()); 350 content::HostZoomMap::SendErrorPageZoomLevelRefresh(web_contents());
292 351
293 if (!details.is_in_page) 352 if (!details.is_in_page)
294 ResetZoomModeOnNavigationIfNeeded(params.url); 353 ResetZoomModeOnNavigationIfNeeded(params.url);
295 354
296 // If the main frame's content has changed, the new page may have a different 355 // If the main frame's content has changed, the new page may have a different
297 // zoom level from the old one. 356 // zoom level from the old one.
298 UpdateState(std::string()); 357 UpdateState(std::string());
299 DCHECK(!event_data_); 358 DCHECK(!event_data_);
300 } 359 }
301 360
302 void ZoomController::WebContentsDestroyed() { 361 void ZoomController::WebContentsDestroyed() {
303 // At this point we should no longer be sending any zoom events with this 362 // At this point we should no longer be sending any zoom events with this
304 // WebContents. 363 // WebContents.
305 observers_.Clear(); 364 observers_.Clear();
306 } 365 }
307 366
308 void ZoomController::RenderFrameHostChanged( 367 void ZoomController::RenderFrameHostChanged(
309 content::RenderFrameHost* old_host, 368 content::RenderFrameHost* old_host,
310 content::RenderFrameHost* new_host) { 369 content::RenderFrameHost* new_host) {
311 // If our associated HostZoomMap changes, update our event subscription.
312 content::HostZoomMap* new_host_zoom_map = 370 content::HostZoomMap* new_host_zoom_map =
313 content::HostZoomMap::GetForWebContents(web_contents()); 371 content::HostZoomMap::GetForWebContents(web_contents());
372
373 // The HostZoomMap records temporary zoom levels per RenderView. When zooming
374 // is per-tab and our RenderView changes, we need to copy the level for our
375 // new RenderView so that the tab's zoom level is preserved.
376 if (old_host && !default_per_origin_ && zoom_mode_ == ZOOM_MODE_ISOLATED) {
377 new_host_zoom_map->PreserveTemporaryZoomLevelFrom(
378 host_zoom_map_, old_host, new_host);
379 }
380
381 // If our associated HostZoomMap changes, update our event subscription.
314 if (new_host_zoom_map == host_zoom_map_) 382 if (new_host_zoom_map == host_zoom_map_)
315 return; 383 return;
316 384
317 host_zoom_map_ = new_host_zoom_map; 385 host_zoom_map_ = new_host_zoom_map;
318 zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback( 386 zoom_subscription_ = host_zoom_map_->AddZoomLevelChangedCallback(
319 base::Bind(&ZoomController::OnZoomLevelChanged, base::Unretained(this))); 387 base::Bind(&ZoomController::OnZoomLevelChanged, base::Unretained(this)));
320 } 388 }
321 389
390 void ZoomController::PreserveTemporaryZoomLevel(
391 content::WebContents* old_web_contents,
392 content::WebContents* new_web_contents) const {
393 if (default_per_origin_ || zoom_mode_ != ZOOM_MODE_ISOLATED)
wjmaclean 2017/01/19 21:09:05 Again, something like |is_per_origin| or |zoom_is_
Kevin McNee 2017/02/03 22:51:34 Done.
394 return;
395
396 content::RenderFrameHost* old_host = old_web_contents->GetMainFrame();
397 content::RenderFrameHost* new_host = new_web_contents->GetMainFrame();
398 const content::HostZoomMap* old_host_zoom_map =
399 content::HostZoomMap::GetForWebContents(old_web_contents);
400 content::HostZoomMap* new_host_zoom_map =
401 content::HostZoomMap::GetForWebContents(new_web_contents);
402
403 new_host_zoom_map->PreserveTemporaryZoomLevelFrom(
404 old_host_zoom_map, old_host, new_host);
405 }
406
407 void ZoomController::DidCloneToNewWebContents(
408 content::WebContents* old_web_contents,
409 content::WebContents* new_web_contents) {
410 // If a WebContents is cloned when zooming is per-tab, have the clone inherit
411 // the original's zoom level.
412 PreserveTemporaryZoomLevel(old_web_contents, new_web_contents);
413 }
414
415 void ZoomController::WebContentsReplaced(
416 content::WebContents* old_web_contents,
417 content::WebContents* new_web_contents) {
418 // A tab may replace its WebContents with another, but from the user's
419 // perspective, this is still the same tab, so we need to preserve the
420 // per-tab zoom.
421 PreserveTemporaryZoomLevel(old_web_contents, new_web_contents);
422 }
423
322 void ZoomController::OnZoomLevelChanged( 424 void ZoomController::OnZoomLevelChanged(
323 const content::HostZoomMap::ZoomLevelChange& change) { 425 const content::HostZoomMap::ZoomLevelChange& change) {
324 UpdateState(change.host); 426 UpdateState(change.host);
325 } 427 }
326 428
429 void ZoomController::OnDefaultZoomScopeChanged() {
430 default_per_origin_ = !default_per_origin_;
431 UpdateZoomModeOnScopeChangeIfNeeded();
432 }
433
327 void ZoomController::UpdateState(const std::string& host) { 434 void ZoomController::UpdateState(const std::string& host) {
328 // If |host| is empty, all observers should be updated. 435 // If |host| is empty, all observers should be updated.
329 if (!host.empty()) { 436 if (!host.empty()) {
330 // Use the navigation entry's URL instead of the WebContents' so virtual 437 // Use the navigation entry's URL instead of the WebContents' so virtual
331 // URLs work (e.g. chrome://settings). http://crbug.com/153950 438 // URLs work (e.g. chrome://settings). http://crbug.com/153950
332 content::NavigationEntry* entry = 439 content::NavigationEntry* entry =
333 web_contents()->GetController().GetLastCommittedEntry(); 440 web_contents()->GetController().GetLastCommittedEntry();
334 if (!entry || 441 if (!entry ||
335 host != net::GetHostOrSpecFromURL( 442 host != net::GetHostOrSpecFromURL(
336 content::HostZoomMap::GetURLFromEntry(entry))) { 443 content::HostZoomMap::GetURLFromEntry(entry))) {
(...skipping 29 matching lines...) Expand all
366 int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID(); 473 int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
367 host_zoom_map_->SetPageScaleFactorIsOneForView(render_process_id, 474 host_zoom_map_->SetPageScaleFactorIsOneForView(render_process_id,
368 render_view_id, is_one); 475 render_view_id, is_one);
369 } 476 }
370 477
371 bool ZoomController::PageScaleFactorIsOne() const { 478 bool ZoomController::PageScaleFactorIsOne() const {
372 return content::HostZoomMap::PageScaleFactorIsOne(web_contents()); 479 return content::HostZoomMap::PageScaleFactorIsOne(web_contents());
373 } 480 }
374 481
375 } // namespace zoom 482 } // namespace zoom
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698