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.
This commit is contained in:
Michael James Gratton 2016-11-23 23:55:54 +11:00
parent 09c9a398f7
commit 26fe139e97
4 changed files with 62 additions and 34 deletions

View file

@ -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")]

View file

@ -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,

View file

@ -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;
}
}

View file

@ -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
);