toolkit/modules/RemoteWebProgress.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/modules/RemoteWebProgress.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,200 @@
     1.4 +// -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     1.5 +// This Source Code Form is subject to the terms of the Mozilla Public
     1.6 +// License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 +// file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.8 +
     1.9 +this.EXPORTED_SYMBOLS = ["RemoteWebProgressManager"];
    1.10 +
    1.11 +const Ci = Components.interfaces;
    1.12 +const Cc = Components.classes;
    1.13 +const Cu = Components.utils;
    1.14 +
    1.15 +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    1.16 +
    1.17 +function newURI(spec)
    1.18 +{
    1.19 +    return Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService)
    1.20 +                                                    .newURI(spec, null, null);
    1.21 +}
    1.22 +
    1.23 +function RemoteWebProgressRequest(spec)
    1.24 +{
    1.25 +  this.uri = newURI(spec);
    1.26 +}
    1.27 +
    1.28 +RemoteWebProgressRequest.prototype = {
    1.29 +  QueryInterface : XPCOMUtils.generateQI([Ci.nsIChannel]),
    1.30 +
    1.31 +  get URI() { return this.uri.clone(); }
    1.32 +};
    1.33 +
    1.34 +function RemoteWebProgress(aManager, aIsTopLevel) {
    1.35 +  this._manager = aManager;
    1.36 +
    1.37 +  this._isLoadingDocument = false;
    1.38 +  this._DOMWindow = null;
    1.39 +  this._isTopLevel = aIsTopLevel;
    1.40 +  this._loadType = 0;
    1.41 +}
    1.42 +
    1.43 +RemoteWebProgress.prototype = {
    1.44 +  NOTIFY_STATE_REQUEST:  0x00000001,
    1.45 +  NOTIFY_STATE_DOCUMENT: 0x00000002,
    1.46 +  NOTIFY_STATE_NETWORK:  0x00000004,
    1.47 +  NOTIFY_STATE_WINDOW:   0x00000008,
    1.48 +  NOTIFY_STATE_ALL:      0x0000000f,
    1.49 +  NOTIFY_PROGRESS:       0x00000010,
    1.50 +  NOTIFY_STATUS:         0x00000020,
    1.51 +  NOTIFY_SECURITY:       0x00000040,
    1.52 +  NOTIFY_LOCATION:       0x00000080,
    1.53 +  NOTIFY_REFRESH:        0x00000100,
    1.54 +  NOTIFY_ALL:            0x000001ff,
    1.55 +
    1.56 +  get isLoadingDocument() { return this._isLoadingDocument },
    1.57 +  get DOMWindow() { return this._DOMWindow; },
    1.58 +  get DOMWindowID() { return 0; },
    1.59 +  get isTopLevel() { return this._isTopLevel },
    1.60 +  get loadType() { return this._loadType; },
    1.61 +
    1.62 +  addProgressListener: function (aListener) {
    1.63 +    this._manager.addProgressListener(aListener);
    1.64 +  },
    1.65 +
    1.66 +  removeProgressListener: function (aListener) {
    1.67 +    this._manager.removeProgressListener(aListener);
    1.68 +  }
    1.69 +};
    1.70 +
    1.71 +function RemoteWebProgressManager (aBrowser) {
    1.72 +  this._browser = aBrowser;
    1.73 +  this._topLevelWebProgress = new RemoteWebProgress(this, true);
    1.74 +  this._progressListeners = [];
    1.75 +
    1.76 +  this._browser.messageManager.addMessageListener("Content:StateChange", this);
    1.77 +  this._browser.messageManager.addMessageListener("Content:LocationChange", this);
    1.78 +  this._browser.messageManager.addMessageListener("Content:SecurityChange", this);
    1.79 +  this._browser.messageManager.addMessageListener("Content:StatusChange", this);
    1.80 +}
    1.81 +
    1.82 +RemoteWebProgressManager.prototype = {
    1.83 +  get topLevelWebProgress() {
    1.84 +    return this._topLevelWebProgress;
    1.85 +  },
    1.86 +
    1.87 +  addProgressListener: function (aListener) {
    1.88 +    let listener = aListener.QueryInterface(Ci.nsIWebProgressListener);
    1.89 +    this._progressListeners.push(listener);
    1.90 +  },
    1.91 +
    1.92 +  removeProgressListener: function (aListener) {
    1.93 +    this._progressListeners =
    1.94 +      this._progressListeners.filter(l => l != aListener);
    1.95 +  },
    1.96 +
    1.97 +  _fixSSLStatusAndState: function (aStatus, aState) {
    1.98 +    let deserialized = null;
    1.99 +    if (aStatus) {
   1.100 +      let helper = Cc["@mozilla.org/network/serialization-helper;1"]
   1.101 +                    .getService(Components.interfaces.nsISerializationHelper);
   1.102 +
   1.103 +      deserialized = helper.deserializeObject(aStatus)
   1.104 +      deserialized.QueryInterface(Ci.nsISSLStatus);
   1.105 +    }
   1.106 +
   1.107 +    // We must check the Extended Validation (EV) state here, on the chrome
   1.108 +    // process, because NSS is needed for that determination.
   1.109 +    if (deserialized && deserialized.isExtendedValidation)
   1.110 +      aState |= Ci.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
   1.111 +
   1.112 +    return [deserialized, aState];
   1.113 +  },
   1.114 +
   1.115 +  setCurrentURI: function (aURI) {
   1.116 +    // This function is simpler than nsDocShell::SetCurrentURI since
   1.117 +    // it doesn't have to deal with child docshells.
   1.118 +    let webNavigation = this._browser.webNavigation;
   1.119 +    webNavigation._currentURI = aURI;
   1.120 +
   1.121 +    let webProgress = this.topLevelWebProgress;
   1.122 +    for (let p of this._progressListeners) {
   1.123 +      p.onLocationChange(webProgress, null, aURI);
   1.124 +    }
   1.125 +  },
   1.126 +
   1.127 +  _callProgressListeners: function(methodName, ...args) {
   1.128 +    for (let p of this._progressListeners) {
   1.129 +      if (p[methodName]) {
   1.130 +        try {
   1.131 +          p[methodName].apply(p, args);
   1.132 +        } catch (ex) {
   1.133 +          Cu.reportError("RemoteWebProgress failed to call " + methodName + ": " + ex + "\n");
   1.134 +        }
   1.135 +      }
   1.136 +    }
   1.137 +  },
   1.138 +
   1.139 +  receiveMessage: function (aMessage) {
   1.140 +    let json = aMessage.json;
   1.141 +    let objects = aMessage.objects;
   1.142 +
   1.143 +    // The top-level WebProgress is always the same, but because we don't
   1.144 +    // really have a concept of subframes/content we always creat a new object
   1.145 +    // for those.
   1.146 +    let webProgress = json.isTopLevel ? this._topLevelWebProgress
   1.147 +                                      : new RemoteWebProgress(this, false);
   1.148 +
   1.149 +    // The WebProgressRequest object however is always dynamic.
   1.150 +    let request = json.requestURI ? new RemoteWebProgressRequest(json.requestURI)
   1.151 +                                  : null;
   1.152 +
   1.153 +    // Update the actual WebProgress fields.
   1.154 +    webProgress._isLoadingDocument = json.isLoadingDocument;
   1.155 +    webProgress._DOMWindow = objects.DOMWindow;
   1.156 +    webProgress._loadType = json.loadType;
   1.157 +
   1.158 +    if (json.isTopLevel) {
   1.159 +      this._browser._contentWindow = objects.contentWindow;
   1.160 +      this._browser._documentContentType = json.documentContentType;
   1.161 +    }
   1.162 +
   1.163 +    switch (aMessage.name) {
   1.164 +    case "Content:StateChange":
   1.165 +      this._callProgressListeners("onStateChange", webProgress, request, json.stateFlags, json.status);
   1.166 +      break;
   1.167 +
   1.168 +    case "Content:LocationChange":
   1.169 +      let location = newURI(json.location);
   1.170 +      let flags = json.flags;
   1.171 +
   1.172 +      if (json.isTopLevel) {
   1.173 +        this._browser.webNavigation._currentURI = location;
   1.174 +        this._browser.webNavigation.canGoBack = json.canGoBack;
   1.175 +        this._browser.webNavigation.canGoForward = json.canGoForward;
   1.176 +        this._browser._characterSet = json.charset;
   1.177 +        this._browser._documentURI = newURI(json.documentURI);
   1.178 +        this._browser._imageDocument = null;
   1.179 +      }
   1.180 +
   1.181 +      this._callProgressListeners("onLocationChange", webProgress, request, location, flags);
   1.182 +      break;
   1.183 +
   1.184 +    case "Content:SecurityChange":
   1.185 +      let [status, state] = this._fixSSLStatusAndState(json.status, json.state);
   1.186 +
   1.187 +      if (json.isTopLevel) {
   1.188 +        // Invoking this getter triggers the generation of the underlying object,
   1.189 +        // which we need to access with ._securityUI, because .securityUI returns
   1.190 +        // a wrapper that makes _update inaccessible.
   1.191 +        void this._browser.securityUI;
   1.192 +        this._browser._securityUI._update(status, state);
   1.193 +      }
   1.194 +
   1.195 +      this._callProgressListeners("onSecurityChange", webProgress, request, state);
   1.196 +      break;
   1.197 +
   1.198 +    case "Content:StatusChange":
   1.199 +      this._callProgressListeners("onStatusChange", webProgress, request, json.status, json.message);
   1.200 +      break;
   1.201 +    }
   1.202 +  }
   1.203 +};

mercurial