Browse Source

add zoom behaviour code from chromium and make pdf viewer use manual zoom behaviour to match chromium

Heilig Benedek 7 years ago
parent
commit
0f4341da42

+ 29 - 20
atom/browser/ui/webui/pdf_viewer_handler.cc

@@ -8,6 +8,9 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/stream_handle.h"
 #include "content/public/browser/stream_info.h"
 #include "content/public/browser/web_contents.h"
@@ -90,15 +93,15 @@ void PdfViewerHandler::RegisterMessages() {
 }
 
 void PdfViewerHandler::OnJavascriptAllowed() {
-  auto host_zoom_map =
-      content::HostZoomMap::GetForWebContents(web_ui()->GetWebContents());
-  host_zoom_map_subscription_ =
-      host_zoom_map->AddZoomLevelChangedCallback(base::Bind(
-          &PdfViewerHandler::OnZoomLevelChanged, base::Unretained(this)));
+  auto zoom_controller = WebContentsZoomController::FromWebContents(
+    web_ui()->GetWebContents());
+  zoom_controller->AddObserver(this);
 }
 
 void PdfViewerHandler::OnJavascriptDisallowed() {
-  host_zoom_map_subscription_.reset();
+  auto zoom_controller = WebContentsZoomController::FromWebContents(
+    web_ui()->GetWebContents());
+  zoom_controller->RemoveObserver(this);
 }
 
 void PdfViewerHandler::Initialize(const base::ListValue* args) {
@@ -116,6 +119,11 @@ void PdfViewerHandler::Initialize(const base::ListValue* args) {
   } else {
     initialize_callback_id_ = callback_id->CreateDeepCopy();
   }
+  
+  auto zoom_controller = WebContentsZoomController::FromWebContents(
+    web_ui()->GetWebContents());
+  zoom_controller->SetZoomMode(WebContentsZoomController::ZOOM_MODE_MANUAL);
+  zoom_controller->SetZoomLevel(0);
 }
 
 void PdfViewerHandler::GetDefaultZoom(const base::ListValue* args) {
@@ -125,9 +133,9 @@ void PdfViewerHandler::GetDefaultZoom(const base::ListValue* args) {
   const base::Value* callback_id;
   CHECK(args->Get(0, &callback_id));
 
-  auto host_zoom_map =
-      content::HostZoomMap::GetForWebContents(web_ui()->GetWebContents());
-  double zoom_level = host_zoom_map->GetDefaultZoomLevel();
+  auto zoom_controller = WebContentsZoomController::FromWebContents(
+    web_ui()->GetWebContents());
+  double zoom_level = zoom_controller->GetDefaultZoomLevel();
   ResolveJavascriptCallback(
       *callback_id,
       base::Value(content::ZoomLevelToZoomFactor(zoom_level)));
@@ -140,8 +148,9 @@ void PdfViewerHandler::GetInitialZoom(const base::ListValue* args) {
   const base::Value* callback_id;
   CHECK(args->Get(0, &callback_id));
 
-  double zoom_level =
-      content::HostZoomMap::GetZoomLevel(web_ui()->GetWebContents());
+  auto zoom_controller = WebContentsZoomController::FromWebContents(
+    web_ui()->GetWebContents());
+  double zoom_level = zoom_controller->GetZoomLevel();
   ResolveJavascriptCallback(
       *callback_id,
       base::Value(content::ZoomLevelToZoomFactor(zoom_level)));
@@ -156,8 +165,9 @@ void PdfViewerHandler::SetZoom(const base::ListValue* args) {
   double zoom_level = 0.0;
   CHECK(args->GetDouble(1, &zoom_level));
 
-  content::HostZoomMap::SetZoomLevel(web_ui()->GetWebContents(),
-                                     zoom_level);
+  auto zoom_controller = WebContentsZoomController::FromWebContents(
+    web_ui()->GetWebContents());
+  zoom_controller->SetZoomLevel(zoom_level);
   ResolveJavascriptCallback(*callback_id, base::Value(zoom_level));
 }
 
@@ -198,13 +208,12 @@ void PdfViewerHandler::Reload(const base::ListValue* args) {
   web_ui()->GetWebContents()->ReloadFocusedFrame(false);
 }
 
-void PdfViewerHandler::OnZoomLevelChanged(
-    const content::HostZoomMap::ZoomLevelChange& change) {
-  if (change.host == kPdfViewerUIHost) {
-    CallJavascriptFunction(
-        "cr.webUIListenerCallback", base::StringValue("onZoomLevelChanged"),
-        base::Value(
-            content::ZoomLevelToZoomFactor(change.zoom_level)));
+void PdfViewerHandler::OnZoomLevelChanged(content::WebContents* web_contents,
+    double level, bool is_temporary) {
+  if (web_ui()->GetWebContents() == web_contents) {
+    CallJavascriptFunction("cr.webUIListenerCallback", 
+      base::StringValue("onZoomLevelChanged"),
+      base::Value(content::ZoomLevelToZoomFactor(level)));
   }
 }
 

+ 5 - 5
atom/browser/ui/webui/pdf_viewer_handler.h

@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "atom/browser/web_contents_zoom_controller.h"
 #include "base/macros.h"
 #include "content/public/browser/host_zoom_map.h"
 #include "content/public/browser/web_ui_message_handler.h"
@@ -21,7 +22,8 @@ struct StreamInfo;
 
 namespace atom {
 
-class PdfViewerHandler : public content::WebUIMessageHandler {
+class PdfViewerHandler : public content::WebUIMessageHandler,
+                         public WebContentsZoomController::Observer {
  public:
   explicit PdfViewerHandler(const std::string& original_url);
   ~PdfViewerHandler() override;
@@ -41,11 +43,9 @@ class PdfViewerHandler : public content::WebUIMessageHandler {
   void SetZoom(const base::ListValue* args);
   void GetStrings(const base::ListValue* args);
   void Reload(const base::ListValue* args);
-  void OnZoomLevelChanged(const content::HostZoomMap::ZoomLevelChange& change);
+  void OnZoomLevelChanged(content::WebContents* web_contents, double level, 
+      bool is_temporary);
 
-  // Keeps track of events related to zooming.
-  std::unique_ptr<content::HostZoomMap::Subscription>
-      host_zoom_map_subscription_;
   std::unique_ptr<base::Value> initialize_callback_id_;
   content::StreamInfo* stream_;
   std::string original_url_;

+ 136 - 9
atom/browser/web_contents_zoom_controller.cc

@@ -21,6 +21,8 @@ namespace atom {
 WebContentsZoomController::WebContentsZoomController(
     content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
+      zoom_mode_(ZOOM_MODE_DEFAULT),
+      zoom_level_(1.0),
       old_process_id_(-1),
       old_view_id_(-1),
       embedder_zoom_controller_(nullptr) {
@@ -47,24 +49,44 @@ void WebContentsZoomController::SetEmbedderZoomController(
 
 void WebContentsZoomController::SetZoomLevel(double level) {
   if (!web_contents()->GetRenderViewHost()->IsRenderViewLive() ||
-      content::ZoomValuesEqual(GetZoomLevel(), level))
+      content::ZoomValuesEqual(GetZoomLevel(), level) ||
+      zoom_mode_ == ZOOM_MODE_DISABLED)
     return;
 
   int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
   int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
-  if (host_zoom_map_->UsesTemporaryZoomLevel(render_process_id,
-                                             render_view_id)) {
-    host_zoom_map_->ClearTemporaryZoomLevel(render_process_id, render_view_id);
+
+  if (zoom_mode_ == ZOOM_MODE_MANUAL) {
+    zoom_level_ = level;
+
+    for (Observer& observer : observers_)
+      observer.OnZoomLevelChanged(web_contents(), level, true);
+
+    return;
   }
 
-  content::HostZoomMap::SetZoomLevel(web_contents(), level);
-  // Notify observers of zoom level changes.
-  for (Observer& observer : observers_)
-    observer.OnZoomLevelChanged(web_contents(), level, false);
+  content::HostZoomMap* zoom_map =
+      content::HostZoomMap::GetForWebContents(web_contents());
+  if (zoom_mode_ == ZOOM_MODE_ISOLATED || 
+      zoom_map->UsesTemporaryZoomLevel(render_process_id, render_view_id)) {
+    zoom_map->SetTemporaryZoomLevel(
+      render_process_id, render_view_id, level);
+    // Notify observers of zoom level changes.
+    for (Observer& observer : observers_)
+      observer.OnZoomLevelChanged(web_contents(), level, true);
+  } else {
+    content::HostZoomMap::SetZoomLevel(web_contents(), level);
+
+    // Notify observers of zoom level changes.
+    for (Observer& observer : observers_)
+      observer.OnZoomLevelChanged(web_contents(), level, false);
+  }
 }
 
 double WebContentsZoomController::GetZoomLevel() {
-  return content::HostZoomMap::GetZoomLevel(web_contents());
+  return zoom_mode_ == ZOOM_MODE_MANUAL
+             ? zoom_level_
+             : content::HostZoomMap::GetZoomLevel(web_contents());
 }
 
 void WebContentsZoomController::SetDefaultZoomFactor(double factor) {
@@ -91,6 +113,110 @@ bool WebContentsZoomController::UsesTemporaryZoomLevel() {
                                                 render_view_id);
 }
 
+
+void WebContentsZoomController::SetZoomMode(ZoomMode new_mode) {
+  if (new_mode == zoom_mode_)
+    return;
+
+  content::HostZoomMap* zoom_map =
+      content::HostZoomMap::GetForWebContents(web_contents());
+  int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
+  int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+  double original_zoom_level = GetZoomLevel();
+
+  switch (new_mode) {
+    case ZOOM_MODE_DEFAULT: {
+      content::NavigationEntry* entry =
+          web_contents()->GetController().GetLastCommittedEntry();
+
+      if (entry) {
+        GURL url = content::HostZoomMap::GetURLFromEntry(entry);
+        std::string host = net::GetHostOrSpecFromURL(url);
+
+        if (zoom_map->HasZoomLevel(url.scheme(), host)) {
+          // If there are other tabs with the same origin, then set this tab's
+          // zoom level to match theirs. The temporary zoom level will be
+          // cleared below, but this call will make sure this tab re-draws at
+          // the correct zoom level.
+          double origin_zoom_level =
+              zoom_map->GetZoomLevelForHostAndScheme(url.scheme(), host);
+          zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
+                                          origin_zoom_level);
+        } else {
+          // The host will need a level prior to removing the temporary level.
+          // We don't want the zoom level to change just because we entered
+          // default mode.
+          zoom_map->SetZoomLevelForHost(host, original_zoom_level);
+        }
+      }
+      // Remove per-tab zoom data for this tab. No event callback expected.
+      zoom_map->ClearTemporaryZoomLevel(render_process_id, render_view_id);
+      break;
+    }
+    case ZOOM_MODE_ISOLATED: {
+      // Unless the zoom mode was |ZOOM_MODE_DISABLED| before this call, the
+      // page needs an initial isolated zoom back to the same level it was at
+      // in the other mode.
+      if (zoom_mode_ != ZOOM_MODE_DISABLED) {
+        zoom_map->SetTemporaryZoomLevel(render_process_id, render_view_id,
+                                        original_zoom_level);
+      } else {
+        // When we don't call any HostZoomMap set functions, we send the event
+        // manually.
+        for (Observer& observer : observers_)
+          observer.OnZoomLevelChanged(web_contents(), original_zoom_level, 
+            false);
+      }
+      break;
+    }
+    case ZOOM_MODE_MANUAL: {
+      // Unless the zoom mode was |ZOOM_MODE_DISABLED| before this call, the
+      // page needs to be resized to the default zoom. While in manual mode,
+      // the zoom level is handled independently.
+      if (zoom_mode_ != ZOOM_MODE_DISABLED) {
+        zoom_map->SetTemporaryZoomLevel(
+          render_process_id, render_view_id, GetDefaultZoomLevel());
+        zoom_level_ = original_zoom_level;
+      } else {
+        // When we don't call any HostZoomMap set functions, we send the event
+        // manually.
+        for (Observer& observer : observers_)
+          observer.OnZoomLevelChanged(web_contents(), original_zoom_level, 
+            false);
+      }
+      break;
+    }
+    case ZOOM_MODE_DISABLED: {
+      // The page needs to be zoomed back to default before disabling the zoom
+      zoom_map->SetTemporaryZoomLevel(
+        render_process_id, render_view_id, GetDefaultZoomLevel());
+      break;
+    }
+  }
+
+  zoom_mode_ = new_mode;
+}
+
+
+void WebContentsZoomController::ResetZoomModeOnNavigationIfNeeded(
+    const GURL& url) {
+  if (zoom_mode_ != ZOOM_MODE_ISOLATED && zoom_mode_ != ZOOM_MODE_MANUAL)
+    return;
+
+  int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
+  int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
+  content::HostZoomMap* zoom_map =
+      content::HostZoomMap::GetForWebContents(web_contents());
+  zoom_level_ = zoom_map->GetDefaultZoomLevel();
+  double new_zoom_level = zoom_map->GetZoomLevelForHostAndScheme(
+      url.scheme(), net::GetHostOrSpecFromURL(url));
+  for (Observer& observer : observers_)
+    observer.OnZoomLevelChanged(web_contents(), new_zoom_level, 
+      false);
+  zoom_map->ClearTemporaryZoomLevel(render_process_id, render_view_id);
+  zoom_mode_ = ZOOM_MODE_DEFAULT;
+}
+
 void WebContentsZoomController::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
   if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted())
@@ -101,6 +227,7 @@ void WebContentsZoomController::DidFinishNavigation(
     return;
   }
 
+  ResetZoomModeOnNavigationIfNeeded(navigation_handle->GetURL());
   SetZoomFactorOnNavigationIfNeeded(navigation_handle->GetURL());
 }
 

+ 40 - 0
atom/browser/web_contents_zoom_controller.h

@@ -28,6 +28,26 @@ class WebContentsZoomController
    protected:
     virtual ~Observer() {}
   };
+  
+  // Defines how zoom changes are handled.
+  enum ZoomMode {
+    // Results in default zoom behavior, i.e. zoom changes are handled
+    // automatically and on a per-origin basis, meaning that other tabs
+    // navigated to the same origin will also zoom.
+    ZOOM_MODE_DEFAULT,
+    // Results in zoom changes being handled automatically, but on a per-tab
+    // basis. Tabs in this zoom mode will not be affected by zoom changes in
+    // other tabs, and vice versa.
+    ZOOM_MODE_ISOLATED,
+    // Overrides the automatic handling of zoom changes. The |onZoomChange|
+    // event will still be dispatched, but the page will not actually be zoomed.
+    // These zoom changes can be handled manually by listening for the
+    // |onZoomChange| event. Zooming in this mode is also on a per-tab basis.
+    ZOOM_MODE_MANUAL,
+    // Disables all zooming in this tab. The tab will revert to the default
+    // zoom level, and all attempted zoom changes will be ignored.
+    ZOOM_MODE_DISABLED,
+  };
 
   explicit WebContentsZoomController(content::WebContents* web_contents);
   ~WebContentsZoomController() override;
@@ -45,6 +65,20 @@ class WebContentsZoomController
   void SetTemporaryZoomLevel(double level);
   bool UsesTemporaryZoomLevel();
 
+  // Sets the zoom mode, which defines zoom behavior (see enum ZoomMode).
+  void SetZoomMode(ZoomMode zoom_mode);
+  
+  void ResetZoomModeOnNavigationIfNeeded(const GURL& url);
+
+  ZoomMode zoom_mode() const { return zoom_mode_; }
+
+  // Convenience method to get default zoom level. Implemented here for
+  // inlining.
+  double GetDefaultZoomLevel() const {
+    return content::HostZoomMap::GetForWebContents(web_contents())
+        ->GetDefaultZoomLevel();
+  }
+
  protected:
   // content::WebContentsObserver:
   void DidFinishNavigation(content::NavigationHandle* handle) override;
@@ -58,6 +92,12 @@ class WebContentsZoomController
   // Called after a navigation has committed to set default zoom factor.
   void SetZoomFactorOnNavigationIfNeeded(const GURL& url);
 
+  // The current zoom mode.
+  ZoomMode zoom_mode_;
+
+  // Current zoom level.
+  double zoom_level_;
+
   // kZoomFactor.
   double default_zoom_factor_;
   double temporary_zoom_level_;