[geary/bug/728002-webkit2: 23/140] Initial pass at getting the HTML document's height from the web process.



commit 26fe139e970cdd45e011c2a947f7527ea475c667
Author: Michael James Gratton <mike vee net>
Date:   Wed Nov 23 23:55:54 2016 +1100

    Initial pass at getting the HTML document's height from the web process.
    
    * bindings/vapi/javascriptcore-4.0.vapi: Add some methods to
      GlobalContext for accessing JSValues as ints.
    
    * src/client/components/client-web-view.vala
      (ClientWebView): Hook up UserContentManager script messages handler and
      handler implementation for "preferredHeightChanged", update the new
      preferred_height prop on the class, and queue a resize. Hook those
      values up to the GTK allocation machinery.
      (ClientWebView::get_int_result): Convenience method for getting an int
      from a JavascriptResult.
      (ClientWebView::get_preferred_height): Report back values as reported
      by messages from the script handler.
      (ClientWebView::register_message_handler): Convenience method for
      registering script messages handlers.
    
    * src/client/conversation-viewer/conversation-web-view.vala
      (ConversationWebView): Remove now-redundant GTK allocation machinery.
    
    * ui/client-web-view.js: Post a message to preferredHeightChanged when
      the page is sorta-kinda loaded.

 bindings/vapi/javascriptcore-4.0.vapi              |    7 +++
 src/client/components/client-web-view.vala         |   52 ++++++++++++++++++++
 .../conversation-viewer/conversation-web-view.vala |   34 -------------
 ui/client-web-view.js                              |    3 +
 4 files changed, 62 insertions(+), 34 deletions(-)
---
diff --git a/bindings/vapi/javascriptcore-4.0.vapi b/bindings/vapi/javascriptcore-4.0.vapi
index 5d535a3..430c353 100644
--- a/bindings/vapi/javascriptcore-4.0.vapi
+++ b/bindings/vapi/javascriptcore-4.0.vapi
@@ -6,6 +6,13 @@ namespace JS {
        [CCode (cname = "JSGlobalContextRef")]
     [SimpleType]
        public struct GlobalContext {
+
+        [CCode (cname = "JSValueIsNumber")]
+        public bool isNumber(JS.Value value);
+
+        [CCode (cname = "JSValueToNumber")]
+        public double toNumber(JS.Value value, out JS.Value err);
+
        }
 
        [CCode (cname = "JSValueRef")]
diff --git a/src/client/components/client-web-view.vala b/src/client/components/client-web-view.vala
index 99911ae..46aed75 100644
--- a/src/client/components/client-web-view.vala
+++ b/src/client/components/client-web-view.vala
@@ -6,11 +6,15 @@
  * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
+protected errordomain JSError { TYPE }
+
 public class ClientWebView : WebKit.WebView {
 
 
+    /** URI Scheme and delimiter for images loaded by Content-ID. */
     public const string CID_PREFIX = "cid:";
 
+    private const string PREFERRED_HEIGHT_MESSAGE = "preferredHeightChanged";
     private const double ZOOM_DEFAULT = 1.0;
     private const double ZOOM_FACTOR = 0.1;
 
@@ -70,6 +74,17 @@ public class ClientWebView : WebKit.WebView {
         );
     }
 
+    protected static int get_int_result(WebKit.JavascriptResult result)
+        throws JSError {
+        JS.GlobalContext context = result.get_global_context();
+        JS.Value value = result.get_value();
+        if (!context.isNumber(value)) {
+            throw new JSError.TYPE("Value is not a number");
+        }
+        JS.Value? err = null;
+        return (int) context.toNumber(value, out err);
+    }
+
     private static inline uint to_wk2_font_size(Pango.FontDescription font) {
         Gdk.Screen? screen = Gdk.Screen.get_default();
         double dpi = screen != null ? screen.get_resolution() : 96.0;
@@ -82,6 +97,7 @@ public class ClientWebView : WebKit.WebView {
 
 
     public bool is_loaded { get; private set; default = false; }
+
     public string allow_prefix { get; private set; default = ""; }
 
     private string _document_font;
@@ -117,6 +133,8 @@ public class ClientWebView : WebKit.WebView {
     private Gee.Map<string,Geary.Memory.Buffer> cid_resources =
         new Gee.HashMap<string,Geary.Memory.Buffer>();
 
+    private int preferred_height = 0;
+
 
     /** Emitted when a user clicks a link in this web view. */
     public signal void link_activated(string uri);
@@ -156,6 +174,18 @@ public class ClientWebView : WebKit.WebView {
                 }
             });
 
+        content_manager.script_message_received[PREFERRED_HEIGHT_MESSAGE].connect(
+            (result) => {
+                try {
+                    this.preferred_height = get_int_result(result);
+                    queue_resize();
+                } catch (JSError err) {
+                    debug("Could not get preferred height: %s", err.message);
+                }
+            });
+
+        register_message_handler(PREFERRED_HEIGHT_MESSAGE);
+
         GearyApplication.instance.config.bind(Configuration.CONVERSATION_VIEWER_ZOOM_KEY, this, 
"zoom_level");
         this.scroll_event.connect(on_scroll_event);
 
@@ -214,6 +244,22 @@ public class ClientWebView : WebKit.WebView {
         this.zoom_level -= (this.zoom_level * ZOOM_FACTOR);
     }
 
+    // XXX Surely since we are doing height-for-width, we should be
+    // overriding get_preferred_height_for_width here, but that
+    // doesn't seem to work.
+    public override void get_preferred_height(out int minimum_height,
+                                              out int natural_height) {
+        minimum_height = natural_height = this.preferred_height;
+    }
+
+    // Overridden since we always what the view to be sized according
+    // to the available space in the parent, not by the width of the
+    // web view.
+    public override void get_preferred_width(out int minimum_height,
+                                             out int natural_height) {
+        minimum_height = natural_height = 0;
+    }
+
     internal void handle_cid_request(WebKit.URISchemeRequest request) {
         string cid = request.get_uri().substring(CID_PREFIX.length);
         Geary.Memory.Buffer? buf = this.cid_resources[cid];
@@ -227,6 +273,12 @@ public class ClientWebView : WebKit.WebView {
         }
     }
 
+    protected inline void register_message_handler(string name) {
+        if (!get_user_content_manager().register_script_message_handler(name)) {
+            debug("Failed to register script message handler: %s", name);
+        }
+    }
+
     // Only allow string-based page loads, and notify but ignore if
     // the user attempts to click on a link. Deny everything else.
     private bool on_decide_policy(WebKit.WebView view,
diff --git a/src/client/conversation-viewer/conversation-web-view.vala 
b/src/client/conversation-viewer/conversation-web-view.vala
index cda1da5..9994867 100644
--- a/src/client/conversation-viewer/conversation-web-view.vala
+++ b/src/client/conversation-viewer/conversation-web-view.vala
@@ -73,38 +73,4 @@ public class ConversationWebView : ClientWebView {
         // XXX
     }
 
-    // Overridden since WebKitGTK+ 2.4.10 at least doesn't want to
-    // report a useful height. In combination with the rules from
-    // ui/conversation-web-view.css we can get an accurate idea of
-    // the actual height of the content from the BODY element, but
-    // only once loaded.
-    public override void get_preferred_height(out int minimum_height,
-                                              out int natural_height) {
-        // Silence the "How does the code know the size to allocate?"
-        // warning in GTK 3.20-ish.
-        base.get_preferred_height(out minimum_height, out natural_height);
-
-        long offset_height = 0; // XXX set me
-
-        if (offset_height > 0) {
-            // Avoid multiple notify signals?
-            if (!this.is_height_valid) {
-                this.is_height_valid = true;
-            }
-        }
-
-        minimum_height = natural_height = (int) offset_height;
-    }
-
-    // Overridden since we always what the view to be sized according
-    // to the available space in the parent, not by the width of the
-    // web view.
-    public override void get_preferred_width(out int minimum_height,
-                                             out int natural_height) {
-        // Silence the "How does the code know the size to allocate?"
-        // warning in GTK 3.20-ish.
-        base.get_preferred_width(out minimum_height, out natural_height);
-        minimum_height = natural_height = 0;
-    }
-
 }
diff --git a/ui/client-web-view.js b/ui/client-web-view.js
index e417aeb..a49b113 100644
--- a/ui/client-web-view.js
+++ b/ui/client-web-view.js
@@ -5,3 +5,6 @@
  * (version 2.1 or later). See the COPYING file in this distribution.
  */
 
+window.webkit.messageHandlers.preferredHeightChanged.postMessage(
+    window.document.documentElement.offsetHeight
+);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]