From 26fe139e970cdd45e011c2a947f7527ea475c667 Mon Sep 17 00:00:00 2001 From: Michael James Gratton Date: Wed, 23 Nov 2016 23:55:54 +1100 Subject: [PATCH] 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-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 5d535a38..430c353d 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 99911ae8..46aed754 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 cid_resources = new Gee.HashMap(); + 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 cda1da59..99948674 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 e417aeb5..a49b1133 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 +);