1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/metro/base/content/bindings/browser.xml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1303 @@ 1.4 +<?xml version="1.0"?> 1.5 + 1.6 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.7 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.9 + 1.10 +<!DOCTYPE bindings [ 1.11 + <!ENTITY % findBarDTD SYSTEM "chrome://global/locale/findbar.dtd" > 1.12 + %findBarDTD; 1.13 +]> 1.14 + 1.15 +<bindings id="browser-bindings" 1.16 + xmlns="http://www.mozilla.org/xbl" 1.17 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 1.18 + 1.19 + <binding id="local-browser" extends="chrome://global/content/bindings/browser.xml#browser"> 1.20 + <implementation type="application/javascript" 1.21 + implements="nsIObserver, nsIDOMEventListener, nsIMessageListener"> 1.22 + 1.23 + <constructor> 1.24 + <![CDATA[ 1.25 + this._frameLoader = 1.26 + this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader; 1.27 + this._contentViewManager = 1.28 + this._frameLoader.QueryInterface(Components.interfaces.nsIContentViewManager); 1.29 + 1.30 + let prefService = 1.31 + Components.classes["@mozilla.org/preferences-service;1"] 1.32 + .getService(Components.interfaces.nsIPrefBranch); 1.33 + this._cacheRatioWidth = 1.34 + Math.max(1, prefService.getIntPref("toolkit.browser.cacheRatioWidth") / 1000); 1.35 + this._cacheRatioHeight = 1.36 + Math.max(1, prefService.getIntPref("toolkit.browser.cacheRatioHeight") / 1000); 1.37 + 1.38 + if (this._contentViewPrototype) { 1.39 + this._contentViewPrototype.kDieTime = prefService.getIntPref("toolkit.browser.contentViewExpire"); 1.40 + } 1.41 + 1.42 + this.messageManager.loadFrameScript("chrome://browser/content/bindings/browser.js", true); 1.43 + this.messageManager.addMessageListener("DOMTitleChanged", this._messageListenerLocal); 1.44 + this.messageManager.addMessageListener("DOMLinkAdded", this._messageListenerLocal); 1.45 + this.messageManager.addMessageListener("pageshow", this._messageListenerLocal); 1.46 + this.messageManager.addMessageListener("pagehide", this._messageListenerLocal); 1.47 + this.messageManager.addMessageListener("DOMPopupBlocked", this._messageListenerLocal); 1.48 + this.messageManager.addMessageListener("MozScrolledAreaChanged", this._messageListenerLocal); 1.49 + this.messageManager.addMessageListener("Content:UpdateDisplayPort", this._messageListenerLocal); 1.50 + 1.51 + this._webProgress._init(); 1.52 + 1.53 + // Remove event listeners added by toolkit <browser> binding. 1.54 + this.removeEventListener("pageshow", this.onPageShow, true); 1.55 + this.removeEventListener("pagehide", this.onPageHide, true); 1.56 + this.removeEventListener("DOMPopupBlocked", this.onPopupBlocked, true); 1.57 + 1.58 + this.setAttribute("autoscrollpopup", "autoscrollerid"); 1.59 + ]]> 1.60 + </constructor> 1.61 + 1.62 + <field name="_searchEngines">[]</field> 1.63 + <property name="searchEngines" 1.64 + onget="return this._searchEngines" 1.65 + readonly="true"/> 1.66 + 1.67 + <field name="_documentURI">null</field> 1.68 + <property name="documentURI" 1.69 + onget="return this._documentURI ? this._ios.newURI(this._documentURI, null, null) : null" 1.70 + readonly="true"/> 1.71 + 1.72 + <field name="contentWindowId">null</field> 1.73 + 1.74 + <field name="_contentTitle">null</field> 1.75 + 1.76 + <field name="_ios"> 1.77 + Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService); 1.78 + </field> 1.79 + 1.80 + <!-- 1.81 + * Point Conversion Routines - browsers may be shifted by UI such that 1.82 + * a client point in an event does not coincide with a css position. 1.83 + * Examples include the notification bar, which pushes the browser down, 1.84 + * or deck movement when forms are positioned above the keyboard. 1.85 + * 1.86 + * Client to browser conversion: 1.87 + * 1.88 + * ptClientToBrowser 1.89 + * Convert client coordinates in device pixels to page-relative 1.90 + * coordinates in CSS pixels. 1.91 + * 1.92 + * @param aClientX, aClientY - client coordinates to convert. 1.93 + * @param aIgnoreScroll ignore root frame scroll. 1.94 + * @param aIgnoreScale ignore current scale factor. 1.95 + * @return { x: converted x coordinate, y: converted y coordinate } 1.96 + * 1.97 + * rectClientToBrowser 1.98 + * Convert a client Rect() in device pixels to page-relative 1.99 + * coordinates in CSS pixels. 1.100 + * 1.101 + * @param aRect - client Rect to convert. 1.102 + * @param aIgnoreScroll ignore root frame scroll. 1.103 + * @param aIgnoreScale ignore current scale factor. 1.104 + * @return converted Rect() 1.105 + * 1.106 + * ctobx, ctoby 1.107 + * Convert individual x and y coordinates. 1.108 + * 1.109 + * @param aX or aY - browser coordinate 1.110 + * @param aIgnoreScroll ignore root frame scroll. 1.111 + * @param aIgnoreScale ignore current scale factor. 1.112 + * @return converted coordinate 1.113 + * 1.114 + * Browser to client conversion: 1.115 + * 1.116 + * ptBrowserToClient 1.117 + * Convert browser coordinates in css pixels to client (screen) coordinates 1.118 + * in device pixels. Useful in positioning UI elements at event targets. 1.119 + * 1.120 + * @param aBrowserX, aBrowserY - browser coordinates to convert. 1.121 + * @param aIgnoreScroll ignore root frame scroll. 1.122 + * @param aIgnoreScale ignore current scale factor. 1.123 + * @return { x: converted x coordinate, y: converted y coordinate } 1.124 + * 1.125 + * msgBrowserToClient 1.126 + * Converts a message manager message with coordinates stored in 1.127 + * aMessage.json.xPos, aMessage.json.yPos. 1.128 + * 1.129 + * @param aMessage - message manager message 1.130 + * @param aIgnoreScroll ignore root frame scroll. 1.131 + * @param aIgnoreScale ignore current scale factor. 1.132 + * @return { x: converted x coordinate, y: converted y coordinate } 1.133 + * 1.134 + * rectBrowserToClient 1.135 + * Converts a rect (left, top, right, bottom). 1.136 + * 1.137 + * @param aRect - rect to convert 1.138 + * @param aIgnoreScroll ignore root frame scroll. 1.139 + * @param aIgnoreScale ignore current scale factor. 1.140 + * @return { left:, top:, right:, bottom: } 1.141 + * 1.142 + * btocx, btocy 1.143 + * Convert individual x and y coordinates. 1.144 + * 1.145 + * @param aX or aY - client coordinate 1.146 + * @param aIgnoreScroll ignore root frame scroll. 1.147 + * @param aIgnoreScale ignore current scale factor. 1.148 + * @return converted coordinate 1.149 + --> 1.150 + <method name="ptClientToBrowser"> 1.151 + <parameter name="aClientX"/> 1.152 + <parameter name="aClientY"/> 1.153 + <parameter name="aIgnoreScroll"/> 1.154 + <parameter name="aIgnoreScale"/> 1.155 + <body> 1.156 + <![CDATA[ 1.157 + let ignoreScroll = aIgnoreScroll || false; 1.158 + let ignoreScale = aIgnoreScale || false; 1.159 + 1.160 + let bcr = this.getBoundingClientRect(); 1.161 + 1.162 + let scrollX = 0; 1.163 + let scrollY = 0; 1.164 + if (!ignoreScroll) { 1.165 + let scroll = this.getRootView().getPosition(); 1.166 + scrollX = scroll.x; 1.167 + scrollY = scroll.y; 1.168 + } 1.169 + 1.170 + let scale = 1; 1.171 + if (!ignoreScale) { 1.172 + scale = this.scale; 1.173 + } 1.174 + 1.175 + return { 1.176 + x: (aClientX - bcr.left) / scale + scrollX, 1.177 + y: (aClientY - bcr.top) / scale + scrollY 1.178 + }; 1.179 + ]]> 1.180 + </body> 1.181 + </method> 1.182 + 1.183 + <method name="rectClientToBrowser"> 1.184 + <parameter name="aClientRect"/> 1.185 + <parameter name="aIgnoreScroll"/> 1.186 + <parameter name="aIgnoreScale"/> 1.187 + <body> 1.188 + <![CDATA[ 1.189 + let ignoreScroll = aIgnoreScroll || false; 1.190 + let ignoreScale = aIgnoreScale || false; 1.191 + 1.192 + let scrollX = 0; 1.193 + let scrollY = 0; 1.194 + if (!ignoreScroll) { 1.195 + let scroll = this.getRootView().getPosition(); 1.196 + scrollX = scroll.x; 1.197 + scrollY = scroll.y; 1.198 + } 1.199 + 1.200 + let scale = 1; 1.201 + if (!ignoreScale) { 1.202 + scale = this.scale; 1.203 + } 1.204 + 1.205 + let bcr = this.getBoundingClientRect(); 1.206 + let clientRect = Rect.fromRect(aClientRect); 1.207 + return new Rect( 1.208 + (clientRect.x - bcr.left) / scale + scrollX, 1.209 + (clientRect.y - bcr.top) / scale + scrollY, 1.210 + clientRect.width / scale, 1.211 + clientRect.height / scale 1.212 + ); 1.213 + ]]> 1.214 + </body> 1.215 + </method> 1.216 + 1.217 + <method name="ctobx"> 1.218 + <parameter name="aX"/> 1.219 + <parameter name="aIgnoreScroll"/> 1.220 + <parameter name="aIgnoreScale"/> 1.221 + <body> 1.222 + <![CDATA[ 1.223 + let y = 0; 1.224 + let result = this.ptClientToBrowser(aX, y, aIgnoreScroll, aIgnoreScale); 1.225 + return result.x; 1.226 + ]]> 1.227 + </body> 1.228 + </method> 1.229 + 1.230 + <method name="ctoby"> 1.231 + <parameter name="aY"/> 1.232 + <parameter name="aIgnoreScroll"/> 1.233 + <parameter name="aIgnoreScale"/> 1.234 + <body> 1.235 + <![CDATA[ 1.236 + let x = 0; 1.237 + let result = this.ptClientToBrowser(x, aY, aIgnoreScroll, aIgnoreScale); 1.238 + return result.y; 1.239 + ]]> 1.240 + </body> 1.241 + </method> 1.242 + 1.243 + <method name="ptBrowserToClient"> 1.244 + <parameter name="aBrowserX"/> 1.245 + <parameter name="aBrowserY"/> 1.246 + <parameter name="aIgnoreScroll"/> 1.247 + <parameter name="aIgnoreScale"/> 1.248 + <body> 1.249 + <![CDATA[ 1.250 + let ignoreScroll = aIgnoreScroll || false; 1.251 + let ignoreScale = aIgnoreScale || false; 1.252 + 1.253 + let bcr = this.getBoundingClientRect(); 1.254 + 1.255 + let scrollX = 0; 1.256 + let scrollY = 0; 1.257 + if (!ignoreScroll) { 1.258 + let scroll = this.getRootView().getPosition(); 1.259 + scrollX = scroll.x; 1.260 + scrollY = scroll.y; 1.261 + } 1.262 + 1.263 + let scale = 1; 1.264 + if (!ignoreScale) { 1.265 + scale = this.scale; 1.266 + } 1.267 + 1.268 + return { 1.269 + x: (aBrowserX * scale - scrollX + bcr.left), 1.270 + y: (aBrowserY * scale - scrollY + bcr.top) 1.271 + }; 1.272 + ]]> 1.273 + </body> 1.274 + </method> 1.275 + 1.276 + <method name="msgBrowserToClient"> 1.277 + <parameter name="aMessage"/> 1.278 + <parameter name="aIgnoreScroll"/> 1.279 + <parameter name="aIgnoreScale"/> 1.280 + <body> 1.281 + <![CDATA[ 1.282 + let x = aMessage.json.xPos; 1.283 + let y = aMessage.json.yPos; 1.284 + return this.ptBrowserToClient(x, y, aIgnoreScroll, aIgnoreScale); 1.285 + ]]> 1.286 + </body> 1.287 + </method> 1.288 + 1.289 + <method name="rectBrowserToClient"> 1.290 + <parameter name="aRect"/> 1.291 + <parameter name="aIgnoreScroll"/> 1.292 + <parameter name="aIgnoreScale"/> 1.293 + <body> 1.294 + <![CDATA[ 1.295 + let left = aRect.left; 1.296 + let top = aRect.top; 1.297 + let right = aRect.right; 1.298 + let bottom = aRect.bottom; 1.299 + let a = this.ptBrowserToClient(left, top, aIgnoreScroll, aIgnoreScale); 1.300 + let b = this.ptBrowserToClient(right, bottom, aIgnoreScroll, aIgnoreScale); 1.301 + return { 1.302 + left: a.x, 1.303 + top: a.y, 1.304 + right: b.x, 1.305 + bottom: b.y 1.306 + }; 1.307 + ]]> 1.308 + </body> 1.309 + </method> 1.310 + 1.311 + <method name="btocx"> 1.312 + <parameter name="aX"/> 1.313 + <parameter name="aIgnoreScroll"/> 1.314 + <parameter name="aIgnoreScale"/> 1.315 + <body> 1.316 + <![CDATA[ 1.317 + let y = 0; 1.318 + let result = this.ptBrowserToClient(aX, y, aIgnoreScroll, aIgnoreScale); 1.319 + return result.x; 1.320 + ]]> 1.321 + </body> 1.322 + </method> 1.323 + 1.324 + <method name="btocy"> 1.325 + <parameter name="aY"/> 1.326 + <parameter name="aIgnoreScroll"/> 1.327 + <parameter name="aIgnoreScale"/> 1.328 + <body> 1.329 + <![CDATA[ 1.330 + let x = 0; 1.331 + let result = this.ptBrowserToClient(x, aY, aIgnoreScroll, aIgnoreScale); 1.332 + return result.y; 1.333 + ]]> 1.334 + </body> 1.335 + </method> 1.336 + 1.337 + <property name="scale"> 1.338 + <getter><![CDATA[ 1.339 + let cwu = this.contentDocument 1.340 + .defaultView 1.341 + .QueryInterface(Components.interfaces.nsIInterfaceRequestor) 1.342 + .getInterface(Components.interfaces.nsIDOMWindowUtils); 1.343 + let resx = {}, resy = {}; 1.344 + cwu.getResolution(resx, resy); 1.345 + // Resolution set by the apzc and is symmetric. 1.346 + return resx.value; 1.347 + ]]></getter> 1.348 + </property> 1.349 + 1.350 + <field name="_messageListenerLocal"><![CDATA[ 1.351 + ({ 1.352 + self: this, 1.353 + receiveMessage: function receiveMessage(aMessage) { 1.354 + let self = this.self; 1.355 + let json = aMessage.json; 1.356 + 1.357 + switch (aMessage.name) { 1.358 + case "DOMPopupBlocked": 1.359 + self.onPopupBlocked(aMessage); 1.360 + break; 1.361 + 1.362 + case "pageshow": 1.363 + self.onPageShow(aMessage); 1.364 + 1.365 + if (!self.mIconURL && self._documentURI) { 1.366 + let iconURL = null; 1.367 + if (self.shouldLoadFavicon()) { 1.368 + // Use documentURI in the favicon construction so that we 1.369 + // do the right thing with about:-style error pages. Bug 515188 1.370 + iconURL = self.documentURI.prePath + "/favicon.ico"; 1.371 + } 1.372 + self.loadFavicon(iconURL, null); 1.373 + } 1.374 + break; 1.375 + 1.376 + case "pagehide": 1.377 + self.onPageHide(aMessage); 1.378 + break; 1.379 + 1.380 + case "DOMTitleChanged": 1.381 + self._contentTitle = json.title; 1.382 + break; 1.383 + 1.384 + case "DOMLinkAdded": 1.385 + // ignore results from subdocuments 1.386 + if (json.windowId != self.contentWindowId) 1.387 + return; 1.388 + 1.389 + let linkType = self._getLinkType(json); 1.390 + switch(linkType) { 1.391 + case "icon": 1.392 + self.loadFavicon(json.href, json.charset); 1.393 + break; 1.394 + case "search": 1.395 + self._searchEngines.push({ title: json.title, href: json.href }); 1.396 + break; 1.397 + } 1.398 + break; 1.399 + 1.400 + case "MozScrolledAreaChanged": { 1.401 + self._contentDocumentWidth = json.width; 1.402 + self._contentDocumentHeight = json.height; 1.403 + self._contentDocumentLeft = (json.left < 0) ? json.left : 0; 1.404 + 1.405 + // Recalculate whether the visible area is actually in bounds 1.406 + let view = self.getRootView(); 1.407 + view.scrollBy(0, 0); 1.408 + break; 1.409 + } 1.410 + 1.411 + case "Content:UpdateDisplayPort": { 1.412 + // Recalculate whether the visible area is actually in bounds 1.413 + let view = self.getRootView(); 1.414 + view.scrollBy(0, 0); 1.415 + view._updateCacheViewport(); 1.416 + break; 1.417 + } 1.418 + } 1.419 + } 1.420 + }) 1.421 + ]]></field> 1.422 + 1.423 + <method name="loadFavicon"> 1.424 + <parameter name="aURL"/> 1.425 + <parameter name="aCharset"/> 1.426 + <body><![CDATA[ 1.427 + try { // newURI call is throwing for chrome URI 1.428 + let iconURI = this._ios.newURI(aURL, aCharset, null); 1.429 + if (gFaviconService.isFailedFavicon(iconURI)) 1.430 + return; 1.431 + 1.432 + gFaviconService.setAndFetchFaviconForPage(this.currentURI, iconURI, true, 1.433 + gFaviconService.FAVICON_LOAD_NON_PRIVATE); 1.434 + this.mIconURL = iconURI.spec; 1.435 + } catch (e) { 1.436 + this.mIconURL = null; 1.437 + } 1.438 + ]]></body> 1.439 + </method> 1.440 + 1.441 + <method name="shouldLoadFavicon"> 1.442 + <body><![CDATA[ 1.443 + let docURI = this.documentURI; 1.444 + return (docURI && ("schemeIs" in docURI) && 1.445 + (docURI.schemeIs("http") || docURI.schemeIs("https"))); 1.446 + ]]></body> 1.447 + </method> 1.448 + 1.449 + <method name="_getLinkType"> 1.450 + <parameter name="aLink" /> 1.451 + <body><![CDATA[ 1.452 + let type = ""; 1.453 + if (/\bicon\b/i.test(aLink.rel)) { 1.454 + type = "icon"; 1.455 + } 1.456 + else if (/\bsearch\b/i.test(aLink.rel) && aLink.type && aLink.title) { 1.457 + let linkType = aLink.type.replace(/^\s+|\s*(?:;.*)?$/g, "").toLowerCase(); 1.458 + if (linkType == "application/opensearchdescription+xml" && /^(?:https?|ftp):/i.test(aLink.href)) { 1.459 + type = "search"; 1.460 + } 1.461 + } 1.462 + 1.463 + return type; 1.464 + ]]></body> 1.465 + </method> 1.466 + 1.467 + <field name="_webProgress"><![CDATA[ 1.468 + ({ 1.469 + _browser: this, 1.470 + 1.471 + _init: function() { 1.472 + this._browser.messageManager.addMessageListener("Content:StateChange", this); 1.473 + this._browser.messageManager.addMessageListener("Content:LocationChange", this); 1.474 + this._browser.messageManager.addMessageListener("Content:SecurityChange", this); 1.475 + }, 1.476 + 1.477 + receiveMessage: function(aMessage) { 1.478 + let json = aMessage.json; 1.479 + switch (aMessage.name) { 1.480 + case "Content:StateChange": 1.481 + this._browser.updateWindowId(json.contentWindowId); 1.482 + break; 1.483 + 1.484 + case "Content:LocationChange": 1.485 + try { 1.486 + let locationURI = this._browser._ios.newURI(json.location, null, null); 1.487 + this._browser.webNavigation._currentURI = locationURI; 1.488 + this._browser.webNavigation.canGoBack = json.canGoBack; 1.489 + this._browser.webNavigation.canGoForward = json.canGoForward; 1.490 + this._browser._charset = json.charset; 1.491 + } catch(e) {} 1.492 + 1.493 + if (this._browser.updateWindowId(json.contentWindowId)) { 1.494 + this._browser._documentURI = json.documentURI; 1.495 + this._browser._searchEngines = []; 1.496 + } 1.497 + break; 1.498 + 1.499 + case "Content:SecurityChange": 1.500 + let serhelper = Components.classes["@mozilla.org/network/serialization-helper;1"] 1.501 + .getService(Components.interfaces.nsISerializationHelper); 1.502 + let SSLStatus = json.SSLStatusAsString ? serhelper.deserializeObject(json.SSLStatusAsString) : null; 1.503 + if (SSLStatus) { 1.504 + SSLStatus.QueryInterface(Components.interfaces.nsISSLStatus); 1.505 + // We must check the Extended Validation (EV) state here, on the chrome 1.506 + // process, because NSS is needed for that determination. 1.507 + if (SSLStatus && SSLStatus.isExtendedValidation) { 1.508 + json.state |= Components.interfaces.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL; 1.509 + } 1.510 + } 1.511 + 1.512 + let data = this._getIdentityData(SSLStatus); 1.513 + this._browser.updateWindowId(json.contentWindowId); 1.514 + break; 1.515 + } 1.516 + }, 1.517 + 1.518 + /** 1.519 + * Helper to parse out the important parts of the SSL cert for use in constructing 1.520 + * identity UI strings 1.521 + */ 1.522 + _getIdentityData: function(status) { 1.523 + let result = {}; 1.524 + 1.525 + if (status) { 1.526 + let cert = status.serverCert; 1.527 + 1.528 + // Human readable name of Subject 1.529 + result.subjectOrg = cert.organization; 1.530 + 1.531 + // SubjectName fields, broken up for individual access 1.532 + if (cert.subjectName) { 1.533 + result.subjectNameFields = {}; 1.534 + cert.subjectName.split(",").forEach(function(v) { 1.535 + var field = v.split("="); 1.536 + if (field[1]) 1.537 + this[field[0]] = field[1]; 1.538 + }, result.subjectNameFields); 1.539 + 1.540 + // Call out city, state, and country specifically 1.541 + result.city = result.subjectNameFields.L; 1.542 + result.state = result.subjectNameFields.ST; 1.543 + result.country = result.subjectNameFields.C; 1.544 + } 1.545 + 1.546 + // Human readable name of Certificate Authority 1.547 + result.caOrg = cert.issuerOrganization || cert.issuerCommonName; 1.548 + 1.549 + if (!this._overrideService) 1.550 + this._overrideService = Components.classes["@mozilla.org/security/certoverride;1"] 1.551 + .getService(Components.interfaces.nsICertOverrideService); 1.552 + 1.553 + // Check whether this site is a security exception. 1.554 + let currentURI = this._browser.webNavigation._currentURI; 1.555 + if (currentURI) { 1.556 + result.isException = this._overrideService.hasMatchingOverride(currentURI.asciiHost, currentURI.port, cert, {}, {}); 1.557 + } else { 1.558 + result.isException = false; 1.559 + } 1.560 + } 1.561 + 1.562 + return result; 1.563 + } 1.564 + }) 1.565 + ]]></field> 1.566 + 1.567 + <property name="webProgress" 1.568 + readonly="true" 1.569 + onget="return null"/> 1.570 + 1.571 + <method name="onPageShow"> 1.572 + <parameter name="aMessage"/> 1.573 + <body> 1.574 + <![CDATA[ 1.575 + this.attachFormFill(); 1.576 + if (this.pageReport) { 1.577 + var json = aMessage.json; 1.578 + var i = 0; 1.579 + while (i < this.pageReport.length) { 1.580 + // Filter out irrelevant reports. 1.581 + if (this.pageReport[i].requestingWindowId == json.windowId) 1.582 + i++; 1.583 + else 1.584 + this.pageReport.splice(i, 1); 1.585 + } 1.586 + if (this.pageReport.length == 0) { 1.587 + this.pageReport = null; 1.588 + this.updatePageReport(); 1.589 + } 1.590 + } 1.591 + ]]> 1.592 + </body> 1.593 + </method> 1.594 + 1.595 + <method name="onPageHide"> 1.596 + <parameter name="aMessage"/> 1.597 + <body> 1.598 + <![CDATA[ 1.599 + if (this.pageReport) { 1.600 + this.pageReport = null; 1.601 + this.updatePageReport(); 1.602 + } 1.603 + // Delete the feeds cache if we're hiding the topmost page 1.604 + // (as opposed to one of its iframes). 1.605 + if (this.feeds && aMessage.target == this) 1.606 + this.feeds = null; 1.607 + 1.608 + this._contentWindowWidth = aMessage.json.contentWindowWidth; 1.609 + this._contentWindowHeight = aMessage.json.contentWindowHeight; 1.610 + ]]> 1.611 + </body> 1.612 + </method> 1.613 + 1.614 + <method name="onPopupBlocked"> 1.615 + <parameter name="aMessage"/> 1.616 + <body> 1.617 + <![CDATA[ 1.618 + if (!this.pageReport) { 1.619 + this.pageReport = []; 1.620 + } 1.621 + 1.622 + let json = aMessage.json; 1.623 + // XXX Replacing requestingWindow && requestingDocument affects 1.624 + // http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#500 1.625 + var obj = { 1.626 + requestingWindowId: json.windowId, 1.627 + popupWindowURI: this._ios.newURI(json.popupWindowURI.spec, json.popupWindowURI.charset, null), 1.628 + popupWindowFeatures: json.popupWindowFeatures, 1.629 + popupWindowName: json.popupWindowName 1.630 + }; 1.631 + 1.632 + this.pageReport.push(obj); 1.633 + this.pageReport.reported = false; 1.634 + this.updatePageReport(); 1.635 + ]]> 1.636 + </body> 1.637 + </method> 1.638 + 1.639 + <field name="_frameLoader">null</field> 1.640 + <field name="_contentViewManager">null</field> 1.641 + 1.642 + <!-- 1.643 + * Returns the current content viewport bounds in browser coordinates 1.644 + * taking into account zoom and scroll. 1.645 + * 1.646 + * @return Rect() 1.647 + --> 1.648 + <property name="contentViewportBounds"> 1.649 + <getter><![CDATA[ 1.650 + return this.rectClientToBrowser(this.getBoundingClientRect()); 1.651 + ]]></getter> 1.652 + </property> 1.653 + 1.654 + <!-- Dimensions of content window --> 1.655 + <field name="_contentWindowWidth">0</field> 1.656 + <field name="_contentWindowHeight">0</field> 1.657 + <property name="contentWindowWidth" 1.658 + onget="return this._contentWindowWidth;" 1.659 + readonly="true"/> 1.660 + <property name="contentWindowHeight" 1.661 + onget="return this._contentWindowHeight;" 1.662 + readonly="true"/> 1.663 + 1.664 + <!-- Dimensions of content document --> 1.665 + <field name="_contentDocumentWidth">0</field> 1.666 + <field name="_contentDocumentHeight">0</field> 1.667 + <property name="contentDocumentWidth" 1.668 + onget="return this._contentDocumentWidth;" 1.669 + readonly="true"/> 1.670 + <property name="contentDocumentHeight" 1.671 + onget="return this._contentDocumentHeight;" 1.672 + readonly="true"/> 1.673 + 1.674 + <!-- If this attribute is negative this indicate the document is rtl and 1.675 + some operations like panning or calculating the cache area should 1.676 + take it into account. This is useless for non-remote browser --> 1.677 + <field name="_contentDocumentLeft">0</field> 1.678 + 1.679 + <!-- These counters are used to update the cached viewport after they reach a certain 1.680 + threshold when scrolling --> 1.681 + <field name="_cacheRatioWidth">1</field> 1.682 + <field name="_cacheRatioHeight">1</field> 1.683 + 1.684 + <!-- Used in remote tabs only. --> 1.685 + <method name="_updateCSSViewport"> 1.686 + <body/> 1.687 + </method> 1.688 + 1.689 + <!-- Sets size of CSS viewport, which affects how page is layout. --> 1.690 + <method name="setWindowSize"> 1.691 + <parameter name="width"/> 1.692 + <parameter name="height"/> 1.693 + <body> 1.694 + <![CDATA[ 1.695 + this._contentWindowWidth = width; 1.696 + this._contentWindowHeight = height; 1.697 + this.messageManager.sendAsyncMessage("Content:SetWindowSize", { 1.698 + width: width, 1.699 + height: height 1.700 + }); 1.701 + 1.702 + // If the window size is changing, make sure the displayport is in sync 1.703 + this.getRootView()._updateCacheViewport(); 1.704 + ]]> 1.705 + </body> 1.706 + </method> 1.707 + 1.708 + <method name="getRootView"> 1.709 + <body> 1.710 + <![CDATA[ 1.711 + return this._contentView; 1.712 + ]]> 1.713 + </body> 1.714 + </method> 1.715 + 1.716 + <field name="_contentViewPrototype"><![CDATA[ 1.717 + ({ 1.718 + _scrollbox: null, 1.719 + 1.720 + init: function(aElement) { 1.721 + this._scrollbox = aElement.scrollBoxObject; 1.722 + }, 1.723 + 1.724 + isRoot: function() { 1.725 + return false; 1.726 + }, 1.727 + 1.728 + scrollBy: function(x, y) { 1.729 + this._scrollbox.scrollBy(x,y); 1.730 + }, 1.731 + 1.732 + scrollTo: function(x, y) { 1.733 + this._scrollbox.scrollTo(x,y); 1.734 + }, 1.735 + 1.736 + getPosition: function() { 1.737 + let x = {}, y = {}; 1.738 + this._scrollbox.getPosition(x, y); 1.739 + return { x: x.value, y: y.value }; 1.740 + } 1.741 + }) 1.742 + ]]> 1.743 + </field> 1.744 + 1.745 + <method name="getViewAt"> 1.746 + <parameter name="x"/> 1.747 + <parameter name="y"/> 1.748 + <body> 1.749 + <![CDATA[ 1.750 + let cwu = this.contentDocument.defaultView.QueryInterface(Components.interfaces.nsIInterfaceRequestor) 1.751 + .getInterface(Components.interfaces.nsIDOMWindowUtils); 1.752 + let elt = cwu.elementFromPoint(x, y, false, false); 1.753 + 1.754 + while (elt && !elt.scrollBoxObject) 1.755 + elt = elt.parentNode; 1.756 + 1.757 + if (!elt) 1.758 + return this._contentView; 1.759 + 1.760 + let cv = Object.create(this._contentViewPrototype); 1.761 + cv.init(elt); 1.762 + return cv; 1.763 + ]]> 1.764 + </body> 1.765 + </method> 1.766 + 1.767 + <field name="_contentView"><![CDATA[ 1.768 + ({ 1.769 + self: this, 1.770 + 1.771 + _updateCacheViewport: function() { 1.772 + }, 1.773 + 1.774 + isRoot: function() { 1.775 + return true; 1.776 + }, 1.777 + 1.778 + scrollBy: function(x, y) { 1.779 + let self = this.self; 1.780 + self.contentWindow.scrollBy(x, y); 1.781 + }, 1.782 + 1.783 + scrollTo: function(x, y) { 1.784 + let self = this.self; 1.785 + x = Math.floor(Math.max(0, Math.min(self.contentDocumentWidth, x))); 1.786 + y = Math.floor(Math.max(0, Math.min(self.contentDocumentHeight, y))); 1.787 + self.contentWindow.scrollTo(x, y); 1.788 + }, 1.789 + 1.790 + getPosition: function() { 1.791 + let self = this.self; 1.792 + let scrollX = {}, scrollY = {}; 1.793 + let cwu = self.contentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor). 1.794 + getInterface(Components.interfaces.nsIDOMWindowUtils); 1.795 + cwu.getScrollXY(false, scrollX, scrollY); 1.796 + return { x: scrollX.value, y: scrollY.value }; 1.797 + }, 1.798 + 1.799 + toString: function() { 1.800 + return "[View Local]"; 1.801 + } 1.802 + }) 1.803 + ]]> 1.804 + </field> 1.805 + 1.806 + <method name="updateWindowId"> 1.807 + <parameter name="aNewId"/> 1.808 + <body><![CDATA[ 1.809 + if (this.contentWindowId != aNewId) { 1.810 + this.contentWindowId = aNewId; 1.811 + return true; 1.812 + } 1.813 + return false; 1.814 + ]]></body> 1.815 + </method> 1.816 + 1.817 + <field name="_active">false</field> 1.818 + <property name="active" onget="return this._active;"> 1.819 + <setter><![CDATA[ 1.820 + // Do not change displayport on local tabs! 1.821 + this._active = val; 1.822 + this.docShellIsActive = this._active; 1.823 + ]]></setter> 1.824 + </property> 1.825 + </implementation> 1.826 + </binding> 1.827 + 1.828 + <binding id="remote-browser" extends="#local-browser"> 1.829 + <implementation type="application/javascript" implements="nsIObserver, nsIDOMEventListener, nsIMessageListener"> 1.830 + <property name="autoscrollEnabled"> 1.831 + <getter> 1.832 + <![CDATA[ 1.833 + throw "autoscrollEnabled: Supports Remote?"; 1.834 + ]]> 1.835 + </getter> 1.836 + </property> 1.837 + 1.838 + <property name="docShell" 1.839 + readonly="true"> 1.840 + <getter><![CDATA[ 1.841 + return { 1.842 + forcedCharset : this._charset, 1.843 + parentCharset : "", 1.844 + parentCharsetSource : 0 1.845 + } 1.846 + ]]></getter> 1.847 + </property> 1.848 + 1.849 + <field name="_contentTitle">null</field> 1.850 + 1.851 + <property name="contentTitle" 1.852 + onget="return this._contentTitle;" 1.853 + readonly="true"/> 1.854 + 1.855 + <field name="_remoteWebNavigation">null</field> 1.856 + <property name="webNavigation" readonly="true"> 1.857 + <getter> 1.858 + <![CDATA[ 1.859 + if (!this._remoteWebNavigation) { 1.860 + let jsm = "resource://gre/modules/RemoteWebNavigation.jsm"; 1.861 + let RemoteWebNavigation = Components.utils.import(jsm, {}).RemoteWebNavigation; 1.862 + this._remoteWebNavigation = new RemoteWebNavigation(this); 1.863 + } 1.864 + return this._remoteWebNavigation; 1.865 + ]]> 1.866 + </getter> 1.867 + </property> 1.868 + 1.869 + <property name="contentWindow" 1.870 + readonly="true" 1.871 + onget="return null"/> 1.872 + 1.873 + <property name="sessionHistory" 1.874 + onget="return null" 1.875 + readonly="true"/> 1.876 + 1.877 + <property name="markupDocumentViewer" 1.878 + onget="return null" 1.879 + readonly="true"/> 1.880 + 1.881 + <property name="contentViewerEdit" 1.882 + onget="return null" 1.883 + readonly="true"/> 1.884 + 1.885 + <property name="contentViewerFile" 1.886 + onget="return null" 1.887 + readonly="true"/> 1.888 + 1.889 + <field name="_charset"></field> 1.890 + 1.891 + <constructor> 1.892 + <![CDATA[ 1.893 + this.messageManager.addMessageListener("scroll", this._messageListenerRemote); 1.894 + ]]> 1.895 + </constructor> 1.896 + 1.897 + <field name="scrollSync">true</field> 1.898 + 1.899 + <field name="_messageListenerRemote"><![CDATA[ 1.900 + ({ 1.901 + self: this, 1.902 + receiveMessage: function receiveMessage(aMessage) { 1.903 + let self = this.self; 1.904 + let json = aMessage.json; 1.905 + 1.906 + switch (aMessage.name) { 1.907 + case "scroll": 1.908 + if (!json.isRoot) 1.909 + return; 1.910 + if (!self.scrollSync) 1.911 + return; 1.912 + this.doScroll(json.scrollOffset.x, json.scrollOffset.y, 0); 1.913 + break; 1.914 + } 1.915 + }, 1.916 + 1.917 + doScroll: function doScroll(aX, aY, aCount) { 1.918 + let self = this.self; 1.919 + 1.920 + // Use floor so that we always guarantee top-left corner of content is visible. 1.921 + let view = self.getRootView(); 1.922 + view.scrollTo(Math.floor(aX * self.scale), Math.floor(aY * self.scale)); 1.923 + 1.924 + let position = view.getPosition(); 1.925 + if ((position.x != aX * self.scale || position.y != aY * self.scale) && aCount < 3) { 1.926 + setTimeout((function() { 1.927 + this.doScroll(aX, aY, ++aCount); 1.928 + }).bind(this), 0); 1.929 + } 1.930 + } 1.931 + }) 1.932 + ]]></field> 1.933 + 1.934 + <!-- Keep a store of temporary content views. --> 1.935 + <field name="_contentViews">({})</field> 1.936 + 1.937 + <!-- There is a point before a page has loaded where a root content view 1.938 + may not exist. We use this so that we don't have to worry about doing 1.939 + an if check every time we want to scroll. --> 1.940 + <field name="_contentNoop"><![CDATA[ 1.941 + ({ 1.942 + _updateCacheViewport: function() {}, 1.943 + _getViewportSize: function() {}, 1.944 + 1.945 + isRoot: function() { 1.946 + return true; 1.947 + }, 1.948 + 1.949 + _scale: 1, 1.950 + _setScale: function(scale) {}, 1.951 + scrollBy: function(x, y) {}, 1.952 + scrollTo: function(x, y) {}, 1.953 + getPosition: function() { 1.954 + return { x: 0, y: 0 }; 1.955 + } 1.956 + }) 1.957 + ]]></field> 1.958 + 1.959 + <field name="_contentViewPrototype"><![CDATA[ 1.960 + ({ 1.961 + self: this, 1.962 + _id: null, 1.963 + _contentView: null, 1.964 + _timeout: null, 1.965 + _pixelsPannedSinceRefresh: { x: 0, y: 0 }, 1.966 + _lastPanTime: 0, 1.967 + 1.968 + kDieTime: 3000, 1.969 + 1.970 + /** 1.971 + * Die if we haven't panned in a while. 1.972 + * 1.973 + * Since we keep a map of active content views, we need to regularly 1.974 + * check if they are necessary so that every single thing the user 1.975 + * pans is not kept in memory forever. 1.976 + */ 1.977 + _dieIfOld: function() { 1.978 + if (Date.now() - this._lastPanTime >= this.kDieTime) 1.979 + this._die(); 1.980 + else 1.981 + // This doesn't need to be exact, just be sure to clean up at some point. 1.982 + this._timeout = setTimeout(this._dieIfOld.bind(this), this.kDieTime); 1.983 + }, 1.984 + 1.985 + /** Cleanup after ourselves. */ 1.986 + _die: function() { 1.987 + let timeout = this._timeout; 1.988 + if (timeout) { 1.989 + clearTimeout(timeout); 1.990 + this._timeout = null; 1.991 + } 1.992 + 1.993 + if (this._contentView && Math.abs(this._pixelsPannedSinceRefresh) > 0) 1.994 + this._updateCacheViewport(); 1.995 + 1.996 + // We expect contentViews to contain our ID. If not, something bad 1.997 + // happened. 1.998 + delete this.self._contentViews[this._id]; 1.999 + }, 1.1000 + 1.1001 + /** 1.1002 + * Given the cache size and the viewport size, this determines where the cache 1.1003 + * should start relative to the scroll position. This adjusts the position based 1.1004 + * on which direction the user is panning, so that we use our cache as 1.1005 + * effectively as possible. 1.1006 + * 1.1007 + * @param aDirection Negative means user is panning to the left or above 1.1008 + * Zero means user did not pan 1.1009 + * Positive means user is panning to the right or below 1.1010 + * @param aViewportSize The width or height of the viewport 1.1011 + * @param aCacheSize The width or height of the displayport 1.1012 + */ 1.1013 + _getRelativeCacheStart: function(aDirection, aViewportSize, aCacheSize) { 1.1014 + // Remember that this is relative to the viewport scroll position. 1.1015 + // Let's assume we are thinking about the y-axis. 1.1016 + // The extreme cases: 1.1017 + // |0| would mean that there is no content available above 1.1018 + // |aViewportSize - aCacheSize| would mean no content available below 1.1019 + // 1.1020 + // Taking the average of the extremes puts equal amounts of cache on the 1.1021 + // top and bottom of the viewport. If we think of this like a weighted 1.1022 + // average, .5 is the sweet spot where equals amounts of content are 1.1023 + // above and below the visible area. 1.1024 + // 1.1025 + // This weight is therefore how much of the cache is above (or to the 1.1026 + // left) the visible area. 1.1027 + let cachedAbove = .5; 1.1028 + 1.1029 + // If panning down, leave only 25% of the non-visible cache above. 1.1030 + if (aDirection > 0) 1.1031 + cachedAbove = .25; 1.1032 + 1.1033 + // If panning up, Leave 75% of the non-visible cache above. 1.1034 + if (aDirection < 0) 1.1035 + cachedAbove = .75; 1.1036 + 1.1037 + return (aViewportSize - aCacheSize) * cachedAbove; 1.1038 + }, 1.1039 + 1.1040 + /** Determine size of the pixel cache. */ 1.1041 + _getCacheSize: function(viewportSize) { 1.1042 + let self = this.self; 1.1043 + let contentView = this._contentView; 1.1044 + 1.1045 + let cacheWidth = self._cacheRatioWidth * viewportSize.width; 1.1046 + let cacheHeight = self._cacheRatioHeight * viewportSize.height; 1.1047 + let contentSize = this._getContentSize(); 1.1048 + let contentWidth = contentSize.width; 1.1049 + let contentHeight = contentSize.height; 1.1050 + 1.1051 + // There are common cases, such as long skinny pages, where our cache size is 1.1052 + // bigger than our content size. In those cases, we take that sliver of leftover 1.1053 + // space and apply it to the other dimension. 1.1054 + if (contentWidth < cacheWidth) { 1.1055 + cacheHeight += (cacheWidth - contentWidth) * cacheHeight / cacheWidth; 1.1056 + cacheWidth = contentWidth; 1.1057 + } else if (contentHeight < cacheHeight) { 1.1058 + cacheWidth += (cacheHeight - contentHeight) * cacheWidth / cacheHeight; 1.1059 + cacheHeight = contentHeight; 1.1060 + } 1.1061 + 1.1062 + return { width: cacheWidth, height: cacheHeight }; 1.1063 + }, 1.1064 + 1.1065 + _sendDisplayportUpdate: function(scrollX, scrollY) { 1.1066 + let self = this.self; 1.1067 + if (!self.active) 1.1068 + return; 1.1069 + 1.1070 + let contentView = this._contentView; 1.1071 + let viewportSize = this._getViewportSize(); 1.1072 + let cacheSize = this._getCacheSize(viewportSize); 1.1073 + let cacheX = this._getRelativeCacheStart(this._pixelsPannedSinceRefresh.x, viewportSize.width, cacheSize.width) + contentView.scrollX; 1.1074 + let cacheY = this._getRelativeCacheStart(this._pixelsPannedSinceRefresh.y, viewportSize.height, cacheSize.height) + contentView.scrollY; 1.1075 + let contentSize = this._getContentSize(); 1.1076 + 1.1077 + // Use our pixels efficiently and don't try to cache things outside of content 1.1078 + // boundaries (The left bound can be negative because of RTL). 1.1079 + 1.1080 + let rootScale = self.scale; 1.1081 + let leftBound = self._contentDocumentLeft * rootScale; 1.1082 + let bounds = new Rect(leftBound, 0, contentSize.width, contentSize.height); 1.1083 + let displayport = new Rect(cacheX, cacheY, cacheSize.width, cacheSize.height); 1.1084 + displayport.translateInside(bounds); 1.1085 + 1.1086 + self.messageManager.sendAsyncMessage("Content:SetCacheViewport", { 1.1087 + scrollX: Math.round(scrollX) / rootScale, 1.1088 + scrollY: Math.round(scrollY) / rootScale, 1.1089 + x: Math.round(displayport.x) / rootScale, 1.1090 + y: Math.round(displayport.y) / rootScale, 1.1091 + w: Math.round(displayport.width) / rootScale, 1.1092 + h: Math.round(displayport.height) / rootScale, 1.1093 + scale: rootScale, 1.1094 + id: contentView.id 1.1095 + }); 1.1096 + 1.1097 + this._pixelsPannedSinceRefresh.x = 0; 1.1098 + this._pixelsPannedSinceRefresh.y = 0; 1.1099 + }, 1.1100 + 1.1101 + _updateCSSViewport: function() { 1.1102 + let contentView = this._contentView; 1.1103 + this._sendDisplayportUpdate(contentView.scrollX, 1.1104 + contentView.scrollY); 1.1105 + }, 1.1106 + 1.1107 + /** 1.1108 + * The cache viewport is what parts of content is cached in the parent process for 1.1109 + * fast scrolling. This syncs that up with the current projection viewport. 1.1110 + */ 1.1111 + _updateCacheViewport: function() { 1.1112 + // Do not update scroll values for content. 1.1113 + if (this.isRoot()) 1.1114 + this._sendDisplayportUpdate(-1, -1); 1.1115 + else { 1.1116 + let contentView = this._contentView; 1.1117 + this._sendDisplayportUpdate(contentView.scrollX, 1.1118 + contentView.scrollY); 1.1119 + } 1.1120 + }, 1.1121 + 1.1122 + _getContentSize: function() { 1.1123 + let self = this.self; 1.1124 + return { width: this._contentView.contentWidth, 1.1125 + height: this._contentView.contentHeight }; 1.1126 + }, 1.1127 + 1.1128 + _getViewportSize: function() { 1.1129 + let self = this.self; 1.1130 + if (this.isRoot()) { 1.1131 + let bcr = self.getBoundingClientRect(); 1.1132 + return { width: bcr.width, height: bcr.height }; 1.1133 + } else { 1.1134 + return { width: this._contentView.viewportWidth, 1.1135 + height: this._contentView.viewportHeight }; 1.1136 + } 1.1137 + }, 1.1138 + 1.1139 + init: function(contentView) { 1.1140 + let self = this.self; 1.1141 + 1.1142 + this._contentView = contentView; 1.1143 + this._id = contentView.id; 1.1144 + this._scale = 1; 1.1145 + self._contentViews[this._id] = this; 1.1146 + 1.1147 + if (!this.isRoot()) { 1.1148 + // Non-root content views are short lived. 1.1149 + this._timeout = setTimeout(this._dieIfOld.bind(this), this.kDieTime); 1.1150 + // This iframe may not have a display port yet, so build up a cache 1.1151 + // immediately. 1.1152 + this._updateCacheViewport(); 1.1153 + } 1.1154 + }, 1.1155 + 1.1156 + isRoot: function() { 1.1157 + return this.self._contentViewManager.rootContentView == this._contentView; 1.1158 + }, 1.1159 + 1.1160 + scrollBy: function(x, y) { 1.1161 + let self = this.self; 1.1162 + 1.1163 + // Bounding content rectangle is in device pixels 1.1164 + let contentView = this._contentView; 1.1165 + let viewportSize = this._getViewportSize(); 1.1166 + let contentSize = this._getContentSize(); 1.1167 + // Calculate document dimensions in device pixels 1.1168 + let scrollRangeX = contentSize.width - viewportSize.width; 1.1169 + let scrollRangeY = contentSize.height - viewportSize.height; 1.1170 + 1.1171 + let leftOffset = self._contentDocumentLeft * this._scale; 1.1172 + x = Math.floor(Math.max(leftOffset, Math.min(scrollRangeX + leftOffset, contentView.scrollX + x))) - contentView.scrollX; 1.1173 + y = Math.floor(Math.max(0, Math.min(scrollRangeY, contentView.scrollY + y))) - contentView.scrollY; 1.1174 + 1.1175 + if (x == 0 && y == 0) 1.1176 + return; 1.1177 + 1.1178 + contentView.scrollBy(x, y); 1.1179 + 1.1180 + this._lastPanTime = Date.now(); 1.1181 + 1.1182 + this._pixelsPannedSinceRefresh.x += x; 1.1183 + this._pixelsPannedSinceRefresh.y += y; 1.1184 + if (Math.abs(this._pixelsPannedSinceRefresh.x) > 20 || 1.1185 + Math.abs(this._pixelsPannedSinceRefresh.y) > 20) 1.1186 + this._updateCacheViewport(); 1.1187 + }, 1.1188 + 1.1189 + scrollTo: function(x, y) { 1.1190 + let contentView = this._contentView; 1.1191 + this.scrollBy(x - contentView.scrollX, y - contentView.scrollY); 1.1192 + }, 1.1193 + 1.1194 + _setScale: function _setScale(scale) { 1.1195 + this._scale = scale; 1.1196 + this._contentView.setScale(scale, scale); 1.1197 + }, 1.1198 + 1.1199 + getPosition: function() { 1.1200 + let contentView = this._contentView; 1.1201 + return { x: contentView.scrollX, y: contentView.scrollY }; 1.1202 + } 1.1203 + }) 1.1204 + ]]> 1.1205 + </field> 1.1206 + 1.1207 + <!-- The ratio of CSS pixels to device pixels. --> 1.1208 + <property name="scale"> 1.1209 + <getter><![CDATA[ 1.1210 + return this.getRootView()._scale; 1.1211 + ]]></getter> 1.1212 + <setter><![CDATA[ 1.1213 + if (val <= 0 || val == this.scale) 1.1214 + return; 1.1215 + 1.1216 + let rootView = this.getRootView(); 1.1217 + rootView._setScale(val); 1.1218 + 1.1219 + return val; 1.1220 + ]]></setter> 1.1221 + </property> 1.1222 + 1.1223 + <method name="_getView"> 1.1224 + <parameter name="contentView"/> 1.1225 + <body> 1.1226 + <![CDATA[ 1.1227 + if (!contentView) return null; 1.1228 + 1.1229 + // See if we have cached it. 1.1230 + let id = contentView.id; 1.1231 + let jsContentView = this._contentViews[id]; 1.1232 + if (jsContentView) { 1.1233 + // Content view may have changed if it became inactive for a 1.1234 + // little while. 1.1235 + jsContentView._contentView = contentView; 1.1236 + return jsContentView; 1.1237 + } 1.1238 + 1.1239 + // Not cached. Create it. 1.1240 + jsContentView = Object.create(this._contentViewPrototype); 1.1241 + jsContentView.init(contentView); 1.1242 + return jsContentView; 1.1243 + ]]> 1.1244 + </body> 1.1245 + </method> 1.1246 + 1.1247 + <!-- Get root content view. --> 1.1248 + <method name="getRootView"> 1.1249 + <body> 1.1250 + <![CDATA[ 1.1251 + let contentView = this._contentViewManager.rootContentView; 1.1252 + return this._getView(contentView) || this._contentNoop; 1.1253 + ]]> 1.1254 + </body> 1.1255 + </method> 1.1256 + 1.1257 + <!-- Get contentView for position (x, y) relative to the browser element --> 1.1258 + <method name="getViewAt"> 1.1259 + <parameter name="x"/> 1.1260 + <parameter name="y"/> 1.1261 + <body> 1.1262 + <![CDATA[ 1.1263 + let manager = this._contentViewManager; 1.1264 + let contentView = manager.getContentViewsIn(x, y, 0, 0, 0, 0)[0] || 1.1265 + manager.rootContentView; 1.1266 + return this._getView(contentView); 1.1267 + ]]> 1.1268 + </body> 1.1269 + </method> 1.1270 + 1.1271 + <!-- Synchronize the CSS viewport with the projection viewport. --> 1.1272 + <method name="_updateCSSViewport"> 1.1273 + <body> 1.1274 + <![CDATA[ 1.1275 + let rootView = this.getRootView(); 1.1276 + rootView._updateCSSViewport(); 1.1277 + ]]> 1.1278 + </body> 1.1279 + </method> 1.1280 + 1.1281 + <property name="active" onget="return this._active;"> 1.1282 + <setter><![CDATA[ 1.1283 + this._active = val; 1.1284 + let keepVisible = false; 1.1285 + this.messageManager.sendAsyncMessage((val ? "Content:Activate" : "Content:Deactivate"), { keepviewport: keepVisible }); 1.1286 + if (val) 1.1287 + this.getRootView()._updateCacheViewport(); 1.1288 + ]]></setter> 1.1289 + </property> 1.1290 + 1.1291 + <field name="_remoteFinder">null</field> 1.1292 + <property name="finder" readonly="true"> 1.1293 + <getter><![CDATA[ 1.1294 + if (!this._remoteFinder) { 1.1295 + let jsm = "resource://gre/modules/RemoteFinder.jsm"; 1.1296 + let RemoteFinder = Cu.import(jsm, {}).RemoteFinder; 1.1297 + this._remoteFinder = new RemoteFinder(this); 1.1298 + } 1.1299 + return this._remoteFinder; 1.1300 + ]]></getter> 1.1301 + </property> 1.1302 + </implementation> 1.1303 + 1.1304 + </binding> 1.1305 + 1.1306 +</bindings>