browser/metro/base/content/bindings/browser.xml

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 <?xml version="1.0"?>
michael@0 2
michael@0 3 <!-- This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 - License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
michael@0 6
michael@0 7 <!DOCTYPE bindings [
michael@0 8 <!ENTITY % findBarDTD SYSTEM "chrome://global/locale/findbar.dtd" >
michael@0 9 %findBarDTD;
michael@0 10 ]>
michael@0 11
michael@0 12 <bindings id="browser-bindings"
michael@0 13 xmlns="http://www.mozilla.org/xbl"
michael@0 14 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
michael@0 15
michael@0 16 <binding id="local-browser" extends="chrome://global/content/bindings/browser.xml#browser">
michael@0 17 <implementation type="application/javascript"
michael@0 18 implements="nsIObserver, nsIDOMEventListener, nsIMessageListener">
michael@0 19
michael@0 20 <constructor>
michael@0 21 <![CDATA[
michael@0 22 this._frameLoader =
michael@0 23 this.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader;
michael@0 24 this._contentViewManager =
michael@0 25 this._frameLoader.QueryInterface(Components.interfaces.nsIContentViewManager);
michael@0 26
michael@0 27 let prefService =
michael@0 28 Components.classes["@mozilla.org/preferences-service;1"]
michael@0 29 .getService(Components.interfaces.nsIPrefBranch);
michael@0 30 this._cacheRatioWidth =
michael@0 31 Math.max(1, prefService.getIntPref("toolkit.browser.cacheRatioWidth") / 1000);
michael@0 32 this._cacheRatioHeight =
michael@0 33 Math.max(1, prefService.getIntPref("toolkit.browser.cacheRatioHeight") / 1000);
michael@0 34
michael@0 35 if (this._contentViewPrototype) {
michael@0 36 this._contentViewPrototype.kDieTime = prefService.getIntPref("toolkit.browser.contentViewExpire");
michael@0 37 }
michael@0 38
michael@0 39 this.messageManager.loadFrameScript("chrome://browser/content/bindings/browser.js", true);
michael@0 40 this.messageManager.addMessageListener("DOMTitleChanged", this._messageListenerLocal);
michael@0 41 this.messageManager.addMessageListener("DOMLinkAdded", this._messageListenerLocal);
michael@0 42 this.messageManager.addMessageListener("pageshow", this._messageListenerLocal);
michael@0 43 this.messageManager.addMessageListener("pagehide", this._messageListenerLocal);
michael@0 44 this.messageManager.addMessageListener("DOMPopupBlocked", this._messageListenerLocal);
michael@0 45 this.messageManager.addMessageListener("MozScrolledAreaChanged", this._messageListenerLocal);
michael@0 46 this.messageManager.addMessageListener("Content:UpdateDisplayPort", this._messageListenerLocal);
michael@0 47
michael@0 48 this._webProgress._init();
michael@0 49
michael@0 50 // Remove event listeners added by toolkit <browser> binding.
michael@0 51 this.removeEventListener("pageshow", this.onPageShow, true);
michael@0 52 this.removeEventListener("pagehide", this.onPageHide, true);
michael@0 53 this.removeEventListener("DOMPopupBlocked", this.onPopupBlocked, true);
michael@0 54
michael@0 55 this.setAttribute("autoscrollpopup", "autoscrollerid");
michael@0 56 ]]>
michael@0 57 </constructor>
michael@0 58
michael@0 59 <field name="_searchEngines">[]</field>
michael@0 60 <property name="searchEngines"
michael@0 61 onget="return this._searchEngines"
michael@0 62 readonly="true"/>
michael@0 63
michael@0 64 <field name="_documentURI">null</field>
michael@0 65 <property name="documentURI"
michael@0 66 onget="return this._documentURI ? this._ios.newURI(this._documentURI, null, null) : null"
michael@0 67 readonly="true"/>
michael@0 68
michael@0 69 <field name="contentWindowId">null</field>
michael@0 70
michael@0 71 <field name="_contentTitle">null</field>
michael@0 72
michael@0 73 <field name="_ios">
michael@0 74 Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
michael@0 75 </field>
michael@0 76
michael@0 77 <!--
michael@0 78 * Point Conversion Routines - browsers may be shifted by UI such that
michael@0 79 * a client point in an event does not coincide with a css position.
michael@0 80 * Examples include the notification bar, which pushes the browser down,
michael@0 81 * or deck movement when forms are positioned above the keyboard.
michael@0 82 *
michael@0 83 * Client to browser conversion:
michael@0 84 *
michael@0 85 * ptClientToBrowser
michael@0 86 * Convert client coordinates in device pixels to page-relative
michael@0 87 * coordinates in CSS pixels.
michael@0 88 *
michael@0 89 * @param aClientX, aClientY - client coordinates to convert.
michael@0 90 * @param aIgnoreScroll ignore root frame scroll.
michael@0 91 * @param aIgnoreScale ignore current scale factor.
michael@0 92 * @return { x: converted x coordinate, y: converted y coordinate }
michael@0 93 *
michael@0 94 * rectClientToBrowser
michael@0 95 * Convert a client Rect() in device pixels to page-relative
michael@0 96 * coordinates in CSS pixels.
michael@0 97 *
michael@0 98 * @param aRect - client Rect to convert.
michael@0 99 * @param aIgnoreScroll ignore root frame scroll.
michael@0 100 * @param aIgnoreScale ignore current scale factor.
michael@0 101 * @return converted Rect()
michael@0 102 *
michael@0 103 * ctobx, ctoby
michael@0 104 * Convert individual x and y coordinates.
michael@0 105 *
michael@0 106 * @param aX or aY - browser coordinate
michael@0 107 * @param aIgnoreScroll ignore root frame scroll.
michael@0 108 * @param aIgnoreScale ignore current scale factor.
michael@0 109 * @return converted coordinate
michael@0 110 *
michael@0 111 * Browser to client conversion:
michael@0 112 *
michael@0 113 * ptBrowserToClient
michael@0 114 * Convert browser coordinates in css pixels to client (screen) coordinates
michael@0 115 * in device pixels. Useful in positioning UI elements at event targets.
michael@0 116 *
michael@0 117 * @param aBrowserX, aBrowserY - browser coordinates to convert.
michael@0 118 * @param aIgnoreScroll ignore root frame scroll.
michael@0 119 * @param aIgnoreScale ignore current scale factor.
michael@0 120 * @return { x: converted x coordinate, y: converted y coordinate }
michael@0 121 *
michael@0 122 * msgBrowserToClient
michael@0 123 * Converts a message manager message with coordinates stored in
michael@0 124 * aMessage.json.xPos, aMessage.json.yPos.
michael@0 125 *
michael@0 126 * @param aMessage - message manager message
michael@0 127 * @param aIgnoreScroll ignore root frame scroll.
michael@0 128 * @param aIgnoreScale ignore current scale factor.
michael@0 129 * @return { x: converted x coordinate, y: converted y coordinate }
michael@0 130 *
michael@0 131 * rectBrowserToClient
michael@0 132 * Converts a rect (left, top, right, bottom).
michael@0 133 *
michael@0 134 * @param aRect - rect to convert
michael@0 135 * @param aIgnoreScroll ignore root frame scroll.
michael@0 136 * @param aIgnoreScale ignore current scale factor.
michael@0 137 * @return { left:, top:, right:, bottom: }
michael@0 138 *
michael@0 139 * btocx, btocy
michael@0 140 * Convert individual x and y coordinates.
michael@0 141 *
michael@0 142 * @param aX or aY - client coordinate
michael@0 143 * @param aIgnoreScroll ignore root frame scroll.
michael@0 144 * @param aIgnoreScale ignore current scale factor.
michael@0 145 * @return converted coordinate
michael@0 146 -->
michael@0 147 <method name="ptClientToBrowser">
michael@0 148 <parameter name="aClientX"/>
michael@0 149 <parameter name="aClientY"/>
michael@0 150 <parameter name="aIgnoreScroll"/>
michael@0 151 <parameter name="aIgnoreScale"/>
michael@0 152 <body>
michael@0 153 <![CDATA[
michael@0 154 let ignoreScroll = aIgnoreScroll || false;
michael@0 155 let ignoreScale = aIgnoreScale || false;
michael@0 156
michael@0 157 let bcr = this.getBoundingClientRect();
michael@0 158
michael@0 159 let scrollX = 0;
michael@0 160 let scrollY = 0;
michael@0 161 if (!ignoreScroll) {
michael@0 162 let scroll = this.getRootView().getPosition();
michael@0 163 scrollX = scroll.x;
michael@0 164 scrollY = scroll.y;
michael@0 165 }
michael@0 166
michael@0 167 let scale = 1;
michael@0 168 if (!ignoreScale) {
michael@0 169 scale = this.scale;
michael@0 170 }
michael@0 171
michael@0 172 return {
michael@0 173 x: (aClientX - bcr.left) / scale + scrollX,
michael@0 174 y: (aClientY - bcr.top) / scale + scrollY
michael@0 175 };
michael@0 176 ]]>
michael@0 177 </body>
michael@0 178 </method>
michael@0 179
michael@0 180 <method name="rectClientToBrowser">
michael@0 181 <parameter name="aClientRect"/>
michael@0 182 <parameter name="aIgnoreScroll"/>
michael@0 183 <parameter name="aIgnoreScale"/>
michael@0 184 <body>
michael@0 185 <![CDATA[
michael@0 186 let ignoreScroll = aIgnoreScroll || false;
michael@0 187 let ignoreScale = aIgnoreScale || false;
michael@0 188
michael@0 189 let scrollX = 0;
michael@0 190 let scrollY = 0;
michael@0 191 if (!ignoreScroll) {
michael@0 192 let scroll = this.getRootView().getPosition();
michael@0 193 scrollX = scroll.x;
michael@0 194 scrollY = scroll.y;
michael@0 195 }
michael@0 196
michael@0 197 let scale = 1;
michael@0 198 if (!ignoreScale) {
michael@0 199 scale = this.scale;
michael@0 200 }
michael@0 201
michael@0 202 let bcr = this.getBoundingClientRect();
michael@0 203 let clientRect = Rect.fromRect(aClientRect);
michael@0 204 return new Rect(
michael@0 205 (clientRect.x - bcr.left) / scale + scrollX,
michael@0 206 (clientRect.y - bcr.top) / scale + scrollY,
michael@0 207 clientRect.width / scale,
michael@0 208 clientRect.height / scale
michael@0 209 );
michael@0 210 ]]>
michael@0 211 </body>
michael@0 212 </method>
michael@0 213
michael@0 214 <method name="ctobx">
michael@0 215 <parameter name="aX"/>
michael@0 216 <parameter name="aIgnoreScroll"/>
michael@0 217 <parameter name="aIgnoreScale"/>
michael@0 218 <body>
michael@0 219 <![CDATA[
michael@0 220 let y = 0;
michael@0 221 let result = this.ptClientToBrowser(aX, y, aIgnoreScroll, aIgnoreScale);
michael@0 222 return result.x;
michael@0 223 ]]>
michael@0 224 </body>
michael@0 225 </method>
michael@0 226
michael@0 227 <method name="ctoby">
michael@0 228 <parameter name="aY"/>
michael@0 229 <parameter name="aIgnoreScroll"/>
michael@0 230 <parameter name="aIgnoreScale"/>
michael@0 231 <body>
michael@0 232 <![CDATA[
michael@0 233 let x = 0;
michael@0 234 let result = this.ptClientToBrowser(x, aY, aIgnoreScroll, aIgnoreScale);
michael@0 235 return result.y;
michael@0 236 ]]>
michael@0 237 </body>
michael@0 238 </method>
michael@0 239
michael@0 240 <method name="ptBrowserToClient">
michael@0 241 <parameter name="aBrowserX"/>
michael@0 242 <parameter name="aBrowserY"/>
michael@0 243 <parameter name="aIgnoreScroll"/>
michael@0 244 <parameter name="aIgnoreScale"/>
michael@0 245 <body>
michael@0 246 <![CDATA[
michael@0 247 let ignoreScroll = aIgnoreScroll || false;
michael@0 248 let ignoreScale = aIgnoreScale || false;
michael@0 249
michael@0 250 let bcr = this.getBoundingClientRect();
michael@0 251
michael@0 252 let scrollX = 0;
michael@0 253 let scrollY = 0;
michael@0 254 if (!ignoreScroll) {
michael@0 255 let scroll = this.getRootView().getPosition();
michael@0 256 scrollX = scroll.x;
michael@0 257 scrollY = scroll.y;
michael@0 258 }
michael@0 259
michael@0 260 let scale = 1;
michael@0 261 if (!ignoreScale) {
michael@0 262 scale = this.scale;
michael@0 263 }
michael@0 264
michael@0 265 return {
michael@0 266 x: (aBrowserX * scale - scrollX + bcr.left),
michael@0 267 y: (aBrowserY * scale - scrollY + bcr.top)
michael@0 268 };
michael@0 269 ]]>
michael@0 270 </body>
michael@0 271 </method>
michael@0 272
michael@0 273 <method name="msgBrowserToClient">
michael@0 274 <parameter name="aMessage"/>
michael@0 275 <parameter name="aIgnoreScroll"/>
michael@0 276 <parameter name="aIgnoreScale"/>
michael@0 277 <body>
michael@0 278 <![CDATA[
michael@0 279 let x = aMessage.json.xPos;
michael@0 280 let y = aMessage.json.yPos;
michael@0 281 return this.ptBrowserToClient(x, y, aIgnoreScroll, aIgnoreScale);
michael@0 282 ]]>
michael@0 283 </body>
michael@0 284 </method>
michael@0 285
michael@0 286 <method name="rectBrowserToClient">
michael@0 287 <parameter name="aRect"/>
michael@0 288 <parameter name="aIgnoreScroll"/>
michael@0 289 <parameter name="aIgnoreScale"/>
michael@0 290 <body>
michael@0 291 <![CDATA[
michael@0 292 let left = aRect.left;
michael@0 293 let top = aRect.top;
michael@0 294 let right = aRect.right;
michael@0 295 let bottom = aRect.bottom;
michael@0 296 let a = this.ptBrowserToClient(left, top, aIgnoreScroll, aIgnoreScale);
michael@0 297 let b = this.ptBrowserToClient(right, bottom, aIgnoreScroll, aIgnoreScale);
michael@0 298 return {
michael@0 299 left: a.x,
michael@0 300 top: a.y,
michael@0 301 right: b.x,
michael@0 302 bottom: b.y
michael@0 303 };
michael@0 304 ]]>
michael@0 305 </body>
michael@0 306 </method>
michael@0 307
michael@0 308 <method name="btocx">
michael@0 309 <parameter name="aX"/>
michael@0 310 <parameter name="aIgnoreScroll"/>
michael@0 311 <parameter name="aIgnoreScale"/>
michael@0 312 <body>
michael@0 313 <![CDATA[
michael@0 314 let y = 0;
michael@0 315 let result = this.ptBrowserToClient(aX, y, aIgnoreScroll, aIgnoreScale);
michael@0 316 return result.x;
michael@0 317 ]]>
michael@0 318 </body>
michael@0 319 </method>
michael@0 320
michael@0 321 <method name="btocy">
michael@0 322 <parameter name="aY"/>
michael@0 323 <parameter name="aIgnoreScroll"/>
michael@0 324 <parameter name="aIgnoreScale"/>
michael@0 325 <body>
michael@0 326 <![CDATA[
michael@0 327 let x = 0;
michael@0 328 let result = this.ptBrowserToClient(x, aY, aIgnoreScroll, aIgnoreScale);
michael@0 329 return result.y;
michael@0 330 ]]>
michael@0 331 </body>
michael@0 332 </method>
michael@0 333
michael@0 334 <property name="scale">
michael@0 335 <getter><![CDATA[
michael@0 336 let cwu = this.contentDocument
michael@0 337 .defaultView
michael@0 338 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
michael@0 339 .getInterface(Components.interfaces.nsIDOMWindowUtils);
michael@0 340 let resx = {}, resy = {};
michael@0 341 cwu.getResolution(resx, resy);
michael@0 342 // Resolution set by the apzc and is symmetric.
michael@0 343 return resx.value;
michael@0 344 ]]></getter>
michael@0 345 </property>
michael@0 346
michael@0 347 <field name="_messageListenerLocal"><![CDATA[
michael@0 348 ({
michael@0 349 self: this,
michael@0 350 receiveMessage: function receiveMessage(aMessage) {
michael@0 351 let self = this.self;
michael@0 352 let json = aMessage.json;
michael@0 353
michael@0 354 switch (aMessage.name) {
michael@0 355 case "DOMPopupBlocked":
michael@0 356 self.onPopupBlocked(aMessage);
michael@0 357 break;
michael@0 358
michael@0 359 case "pageshow":
michael@0 360 self.onPageShow(aMessage);
michael@0 361
michael@0 362 if (!self.mIconURL && self._documentURI) {
michael@0 363 let iconURL = null;
michael@0 364 if (self.shouldLoadFavicon()) {
michael@0 365 // Use documentURI in the favicon construction so that we
michael@0 366 // do the right thing with about:-style error pages. Bug 515188
michael@0 367 iconURL = self.documentURI.prePath + "/favicon.ico";
michael@0 368 }
michael@0 369 self.loadFavicon(iconURL, null);
michael@0 370 }
michael@0 371 break;
michael@0 372
michael@0 373 case "pagehide":
michael@0 374 self.onPageHide(aMessage);
michael@0 375 break;
michael@0 376
michael@0 377 case "DOMTitleChanged":
michael@0 378 self._contentTitle = json.title;
michael@0 379 break;
michael@0 380
michael@0 381 case "DOMLinkAdded":
michael@0 382 // ignore results from subdocuments
michael@0 383 if (json.windowId != self.contentWindowId)
michael@0 384 return;
michael@0 385
michael@0 386 let linkType = self._getLinkType(json);
michael@0 387 switch(linkType) {
michael@0 388 case "icon":
michael@0 389 self.loadFavicon(json.href, json.charset);
michael@0 390 break;
michael@0 391 case "search":
michael@0 392 self._searchEngines.push({ title: json.title, href: json.href });
michael@0 393 break;
michael@0 394 }
michael@0 395 break;
michael@0 396
michael@0 397 case "MozScrolledAreaChanged": {
michael@0 398 self._contentDocumentWidth = json.width;
michael@0 399 self._contentDocumentHeight = json.height;
michael@0 400 self._contentDocumentLeft = (json.left < 0) ? json.left : 0;
michael@0 401
michael@0 402 // Recalculate whether the visible area is actually in bounds
michael@0 403 let view = self.getRootView();
michael@0 404 view.scrollBy(0, 0);
michael@0 405 break;
michael@0 406 }
michael@0 407
michael@0 408 case "Content:UpdateDisplayPort": {
michael@0 409 // Recalculate whether the visible area is actually in bounds
michael@0 410 let view = self.getRootView();
michael@0 411 view.scrollBy(0, 0);
michael@0 412 view._updateCacheViewport();
michael@0 413 break;
michael@0 414 }
michael@0 415 }
michael@0 416 }
michael@0 417 })
michael@0 418 ]]></field>
michael@0 419
michael@0 420 <method name="loadFavicon">
michael@0 421 <parameter name="aURL"/>
michael@0 422 <parameter name="aCharset"/>
michael@0 423 <body><![CDATA[
michael@0 424 try { // newURI call is throwing for chrome URI
michael@0 425 let iconURI = this._ios.newURI(aURL, aCharset, null);
michael@0 426 if (gFaviconService.isFailedFavicon(iconURI))
michael@0 427 return;
michael@0 428
michael@0 429 gFaviconService.setAndFetchFaviconForPage(this.currentURI, iconURI, true,
michael@0 430 gFaviconService.FAVICON_LOAD_NON_PRIVATE);
michael@0 431 this.mIconURL = iconURI.spec;
michael@0 432 } catch (e) {
michael@0 433 this.mIconURL = null;
michael@0 434 }
michael@0 435 ]]></body>
michael@0 436 </method>
michael@0 437
michael@0 438 <method name="shouldLoadFavicon">
michael@0 439 <body><![CDATA[
michael@0 440 let docURI = this.documentURI;
michael@0 441 return (docURI && ("schemeIs" in docURI) &&
michael@0 442 (docURI.schemeIs("http") || docURI.schemeIs("https")));
michael@0 443 ]]></body>
michael@0 444 </method>
michael@0 445
michael@0 446 <method name="_getLinkType">
michael@0 447 <parameter name="aLink" />
michael@0 448 <body><![CDATA[
michael@0 449 let type = "";
michael@0 450 if (/\bicon\b/i.test(aLink.rel)) {
michael@0 451 type = "icon";
michael@0 452 }
michael@0 453 else if (/\bsearch\b/i.test(aLink.rel) && aLink.type && aLink.title) {
michael@0 454 let linkType = aLink.type.replace(/^\s+|\s*(?:;.*)?$/g, "").toLowerCase();
michael@0 455 if (linkType == "application/opensearchdescription+xml" && /^(?:https?|ftp):/i.test(aLink.href)) {
michael@0 456 type = "search";
michael@0 457 }
michael@0 458 }
michael@0 459
michael@0 460 return type;
michael@0 461 ]]></body>
michael@0 462 </method>
michael@0 463
michael@0 464 <field name="_webProgress"><![CDATA[
michael@0 465 ({
michael@0 466 _browser: this,
michael@0 467
michael@0 468 _init: function() {
michael@0 469 this._browser.messageManager.addMessageListener("Content:StateChange", this);
michael@0 470 this._browser.messageManager.addMessageListener("Content:LocationChange", this);
michael@0 471 this._browser.messageManager.addMessageListener("Content:SecurityChange", this);
michael@0 472 },
michael@0 473
michael@0 474 receiveMessage: function(aMessage) {
michael@0 475 let json = aMessage.json;
michael@0 476 switch (aMessage.name) {
michael@0 477 case "Content:StateChange":
michael@0 478 this._browser.updateWindowId(json.contentWindowId);
michael@0 479 break;
michael@0 480
michael@0 481 case "Content:LocationChange":
michael@0 482 try {
michael@0 483 let locationURI = this._browser._ios.newURI(json.location, null, null);
michael@0 484 this._browser.webNavigation._currentURI = locationURI;
michael@0 485 this._browser.webNavigation.canGoBack = json.canGoBack;
michael@0 486 this._browser.webNavigation.canGoForward = json.canGoForward;
michael@0 487 this._browser._charset = json.charset;
michael@0 488 } catch(e) {}
michael@0 489
michael@0 490 if (this._browser.updateWindowId(json.contentWindowId)) {
michael@0 491 this._browser._documentURI = json.documentURI;
michael@0 492 this._browser._searchEngines = [];
michael@0 493 }
michael@0 494 break;
michael@0 495
michael@0 496 case "Content:SecurityChange":
michael@0 497 let serhelper = Components.classes["@mozilla.org/network/serialization-helper;1"]
michael@0 498 .getService(Components.interfaces.nsISerializationHelper);
michael@0 499 let SSLStatus = json.SSLStatusAsString ? serhelper.deserializeObject(json.SSLStatusAsString) : null;
michael@0 500 if (SSLStatus) {
michael@0 501 SSLStatus.QueryInterface(Components.interfaces.nsISSLStatus);
michael@0 502 // We must check the Extended Validation (EV) state here, on the chrome
michael@0 503 // process, because NSS is needed for that determination.
michael@0 504 if (SSLStatus && SSLStatus.isExtendedValidation) {
michael@0 505 json.state |= Components.interfaces.nsIWebProgressListener.STATE_IDENTITY_EV_TOPLEVEL;
michael@0 506 }
michael@0 507 }
michael@0 508
michael@0 509 let data = this._getIdentityData(SSLStatus);
michael@0 510 this._browser.updateWindowId(json.contentWindowId);
michael@0 511 break;
michael@0 512 }
michael@0 513 },
michael@0 514
michael@0 515 /**
michael@0 516 * Helper to parse out the important parts of the SSL cert for use in constructing
michael@0 517 * identity UI strings
michael@0 518 */
michael@0 519 _getIdentityData: function(status) {
michael@0 520 let result = {};
michael@0 521
michael@0 522 if (status) {
michael@0 523 let cert = status.serverCert;
michael@0 524
michael@0 525 // Human readable name of Subject
michael@0 526 result.subjectOrg = cert.organization;
michael@0 527
michael@0 528 // SubjectName fields, broken up for individual access
michael@0 529 if (cert.subjectName) {
michael@0 530 result.subjectNameFields = {};
michael@0 531 cert.subjectName.split(",").forEach(function(v) {
michael@0 532 var field = v.split("=");
michael@0 533 if (field[1])
michael@0 534 this[field[0]] = field[1];
michael@0 535 }, result.subjectNameFields);
michael@0 536
michael@0 537 // Call out city, state, and country specifically
michael@0 538 result.city = result.subjectNameFields.L;
michael@0 539 result.state = result.subjectNameFields.ST;
michael@0 540 result.country = result.subjectNameFields.C;
michael@0 541 }
michael@0 542
michael@0 543 // Human readable name of Certificate Authority
michael@0 544 result.caOrg = cert.issuerOrganization || cert.issuerCommonName;
michael@0 545
michael@0 546 if (!this._overrideService)
michael@0 547 this._overrideService = Components.classes["@mozilla.org/security/certoverride;1"]
michael@0 548 .getService(Components.interfaces.nsICertOverrideService);
michael@0 549
michael@0 550 // Check whether this site is a security exception.
michael@0 551 let currentURI = this._browser.webNavigation._currentURI;
michael@0 552 if (currentURI) {
michael@0 553 result.isException = this._overrideService.hasMatchingOverride(currentURI.asciiHost, currentURI.port, cert, {}, {});
michael@0 554 } else {
michael@0 555 result.isException = false;
michael@0 556 }
michael@0 557 }
michael@0 558
michael@0 559 return result;
michael@0 560 }
michael@0 561 })
michael@0 562 ]]></field>
michael@0 563
michael@0 564 <property name="webProgress"
michael@0 565 readonly="true"
michael@0 566 onget="return null"/>
michael@0 567
michael@0 568 <method name="onPageShow">
michael@0 569 <parameter name="aMessage"/>
michael@0 570 <body>
michael@0 571 <![CDATA[
michael@0 572 this.attachFormFill();
michael@0 573 if (this.pageReport) {
michael@0 574 var json = aMessage.json;
michael@0 575 var i = 0;
michael@0 576 while (i < this.pageReport.length) {
michael@0 577 // Filter out irrelevant reports.
michael@0 578 if (this.pageReport[i].requestingWindowId == json.windowId)
michael@0 579 i++;
michael@0 580 else
michael@0 581 this.pageReport.splice(i, 1);
michael@0 582 }
michael@0 583 if (this.pageReport.length == 0) {
michael@0 584 this.pageReport = null;
michael@0 585 this.updatePageReport();
michael@0 586 }
michael@0 587 }
michael@0 588 ]]>
michael@0 589 </body>
michael@0 590 </method>
michael@0 591
michael@0 592 <method name="onPageHide">
michael@0 593 <parameter name="aMessage"/>
michael@0 594 <body>
michael@0 595 <![CDATA[
michael@0 596 if (this.pageReport) {
michael@0 597 this.pageReport = null;
michael@0 598 this.updatePageReport();
michael@0 599 }
michael@0 600 // Delete the feeds cache if we're hiding the topmost page
michael@0 601 // (as opposed to one of its iframes).
michael@0 602 if (this.feeds && aMessage.target == this)
michael@0 603 this.feeds = null;
michael@0 604
michael@0 605 this._contentWindowWidth = aMessage.json.contentWindowWidth;
michael@0 606 this._contentWindowHeight = aMessage.json.contentWindowHeight;
michael@0 607 ]]>
michael@0 608 </body>
michael@0 609 </method>
michael@0 610
michael@0 611 <method name="onPopupBlocked">
michael@0 612 <parameter name="aMessage"/>
michael@0 613 <body>
michael@0 614 <![CDATA[
michael@0 615 if (!this.pageReport) {
michael@0 616 this.pageReport = [];
michael@0 617 }
michael@0 618
michael@0 619 let json = aMessage.json;
michael@0 620 // XXX Replacing requestingWindow && requestingDocument affects
michael@0 621 // http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#500
michael@0 622 var obj = {
michael@0 623 requestingWindowId: json.windowId,
michael@0 624 popupWindowURI: this._ios.newURI(json.popupWindowURI.spec, json.popupWindowURI.charset, null),
michael@0 625 popupWindowFeatures: json.popupWindowFeatures,
michael@0 626 popupWindowName: json.popupWindowName
michael@0 627 };
michael@0 628
michael@0 629 this.pageReport.push(obj);
michael@0 630 this.pageReport.reported = false;
michael@0 631 this.updatePageReport();
michael@0 632 ]]>
michael@0 633 </body>
michael@0 634 </method>
michael@0 635
michael@0 636 <field name="_frameLoader">null</field>
michael@0 637 <field name="_contentViewManager">null</field>
michael@0 638
michael@0 639 <!--
michael@0 640 * Returns the current content viewport bounds in browser coordinates
michael@0 641 * taking into account zoom and scroll.
michael@0 642 *
michael@0 643 * @return Rect()
michael@0 644 -->
michael@0 645 <property name="contentViewportBounds">
michael@0 646 <getter><![CDATA[
michael@0 647 return this.rectClientToBrowser(this.getBoundingClientRect());
michael@0 648 ]]></getter>
michael@0 649 </property>
michael@0 650
michael@0 651 <!-- Dimensions of content window -->
michael@0 652 <field name="_contentWindowWidth">0</field>
michael@0 653 <field name="_contentWindowHeight">0</field>
michael@0 654 <property name="contentWindowWidth"
michael@0 655 onget="return this._contentWindowWidth;"
michael@0 656 readonly="true"/>
michael@0 657 <property name="contentWindowHeight"
michael@0 658 onget="return this._contentWindowHeight;"
michael@0 659 readonly="true"/>
michael@0 660
michael@0 661 <!-- Dimensions of content document -->
michael@0 662 <field name="_contentDocumentWidth">0</field>
michael@0 663 <field name="_contentDocumentHeight">0</field>
michael@0 664 <property name="contentDocumentWidth"
michael@0 665 onget="return this._contentDocumentWidth;"
michael@0 666 readonly="true"/>
michael@0 667 <property name="contentDocumentHeight"
michael@0 668 onget="return this._contentDocumentHeight;"
michael@0 669 readonly="true"/>
michael@0 670
michael@0 671 <!-- If this attribute is negative this indicate the document is rtl and
michael@0 672 some operations like panning or calculating the cache area should
michael@0 673 take it into account. This is useless for non-remote browser -->
michael@0 674 <field name="_contentDocumentLeft">0</field>
michael@0 675
michael@0 676 <!-- These counters are used to update the cached viewport after they reach a certain
michael@0 677 threshold when scrolling -->
michael@0 678 <field name="_cacheRatioWidth">1</field>
michael@0 679 <field name="_cacheRatioHeight">1</field>
michael@0 680
michael@0 681 <!-- Used in remote tabs only. -->
michael@0 682 <method name="_updateCSSViewport">
michael@0 683 <body/>
michael@0 684 </method>
michael@0 685
michael@0 686 <!-- Sets size of CSS viewport, which affects how page is layout. -->
michael@0 687 <method name="setWindowSize">
michael@0 688 <parameter name="width"/>
michael@0 689 <parameter name="height"/>
michael@0 690 <body>
michael@0 691 <![CDATA[
michael@0 692 this._contentWindowWidth = width;
michael@0 693 this._contentWindowHeight = height;
michael@0 694 this.messageManager.sendAsyncMessage("Content:SetWindowSize", {
michael@0 695 width: width,
michael@0 696 height: height
michael@0 697 });
michael@0 698
michael@0 699 // If the window size is changing, make sure the displayport is in sync
michael@0 700 this.getRootView()._updateCacheViewport();
michael@0 701 ]]>
michael@0 702 </body>
michael@0 703 </method>
michael@0 704
michael@0 705 <method name="getRootView">
michael@0 706 <body>
michael@0 707 <![CDATA[
michael@0 708 return this._contentView;
michael@0 709 ]]>
michael@0 710 </body>
michael@0 711 </method>
michael@0 712
michael@0 713 <field name="_contentViewPrototype"><![CDATA[
michael@0 714 ({
michael@0 715 _scrollbox: null,
michael@0 716
michael@0 717 init: function(aElement) {
michael@0 718 this._scrollbox = aElement.scrollBoxObject;
michael@0 719 },
michael@0 720
michael@0 721 isRoot: function() {
michael@0 722 return false;
michael@0 723 },
michael@0 724
michael@0 725 scrollBy: function(x, y) {
michael@0 726 this._scrollbox.scrollBy(x,y);
michael@0 727 },
michael@0 728
michael@0 729 scrollTo: function(x, y) {
michael@0 730 this._scrollbox.scrollTo(x,y);
michael@0 731 },
michael@0 732
michael@0 733 getPosition: function() {
michael@0 734 let x = {}, y = {};
michael@0 735 this._scrollbox.getPosition(x, y);
michael@0 736 return { x: x.value, y: y.value };
michael@0 737 }
michael@0 738 })
michael@0 739 ]]>
michael@0 740 </field>
michael@0 741
michael@0 742 <method name="getViewAt">
michael@0 743 <parameter name="x"/>
michael@0 744 <parameter name="y"/>
michael@0 745 <body>
michael@0 746 <![CDATA[
michael@0 747 let cwu = this.contentDocument.defaultView.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
michael@0 748 .getInterface(Components.interfaces.nsIDOMWindowUtils);
michael@0 749 let elt = cwu.elementFromPoint(x, y, false, false);
michael@0 750
michael@0 751 while (elt && !elt.scrollBoxObject)
michael@0 752 elt = elt.parentNode;
michael@0 753
michael@0 754 if (!elt)
michael@0 755 return this._contentView;
michael@0 756
michael@0 757 let cv = Object.create(this._contentViewPrototype);
michael@0 758 cv.init(elt);
michael@0 759 return cv;
michael@0 760 ]]>
michael@0 761 </body>
michael@0 762 </method>
michael@0 763
michael@0 764 <field name="_contentView"><![CDATA[
michael@0 765 ({
michael@0 766 self: this,
michael@0 767
michael@0 768 _updateCacheViewport: function() {
michael@0 769 },
michael@0 770
michael@0 771 isRoot: function() {
michael@0 772 return true;
michael@0 773 },
michael@0 774
michael@0 775 scrollBy: function(x, y) {
michael@0 776 let self = this.self;
michael@0 777 self.contentWindow.scrollBy(x, y);
michael@0 778 },
michael@0 779
michael@0 780 scrollTo: function(x, y) {
michael@0 781 let self = this.self;
michael@0 782 x = Math.floor(Math.max(0, Math.min(self.contentDocumentWidth, x)));
michael@0 783 y = Math.floor(Math.max(0, Math.min(self.contentDocumentHeight, y)));
michael@0 784 self.contentWindow.scrollTo(x, y);
michael@0 785 },
michael@0 786
michael@0 787 getPosition: function() {
michael@0 788 let self = this.self;
michael@0 789 let scrollX = {}, scrollY = {};
michael@0 790 let cwu = self.contentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
michael@0 791 getInterface(Components.interfaces.nsIDOMWindowUtils);
michael@0 792 cwu.getScrollXY(false, scrollX, scrollY);
michael@0 793 return { x: scrollX.value, y: scrollY.value };
michael@0 794 },
michael@0 795
michael@0 796 toString: function() {
michael@0 797 return "[View Local]";
michael@0 798 }
michael@0 799 })
michael@0 800 ]]>
michael@0 801 </field>
michael@0 802
michael@0 803 <method name="updateWindowId">
michael@0 804 <parameter name="aNewId"/>
michael@0 805 <body><![CDATA[
michael@0 806 if (this.contentWindowId != aNewId) {
michael@0 807 this.contentWindowId = aNewId;
michael@0 808 return true;
michael@0 809 }
michael@0 810 return false;
michael@0 811 ]]></body>
michael@0 812 </method>
michael@0 813
michael@0 814 <field name="_active">false</field>
michael@0 815 <property name="active" onget="return this._active;">
michael@0 816 <setter><![CDATA[
michael@0 817 // Do not change displayport on local tabs!
michael@0 818 this._active = val;
michael@0 819 this.docShellIsActive = this._active;
michael@0 820 ]]></setter>
michael@0 821 </property>
michael@0 822 </implementation>
michael@0 823 </binding>
michael@0 824
michael@0 825 <binding id="remote-browser" extends="#local-browser">
michael@0 826 <implementation type="application/javascript" implements="nsIObserver, nsIDOMEventListener, nsIMessageListener">
michael@0 827 <property name="autoscrollEnabled">
michael@0 828 <getter>
michael@0 829 <![CDATA[
michael@0 830 throw "autoscrollEnabled: Supports Remote?";
michael@0 831 ]]>
michael@0 832 </getter>
michael@0 833 </property>
michael@0 834
michael@0 835 <property name="docShell"
michael@0 836 readonly="true">
michael@0 837 <getter><![CDATA[
michael@0 838 return {
michael@0 839 forcedCharset : this._charset,
michael@0 840 parentCharset : "",
michael@0 841 parentCharsetSource : 0
michael@0 842 }
michael@0 843 ]]></getter>
michael@0 844 </property>
michael@0 845
michael@0 846 <field name="_contentTitle">null</field>
michael@0 847
michael@0 848 <property name="contentTitle"
michael@0 849 onget="return this._contentTitle;"
michael@0 850 readonly="true"/>
michael@0 851
michael@0 852 <field name="_remoteWebNavigation">null</field>
michael@0 853 <property name="webNavigation" readonly="true">
michael@0 854 <getter>
michael@0 855 <![CDATA[
michael@0 856 if (!this._remoteWebNavigation) {
michael@0 857 let jsm = "resource://gre/modules/RemoteWebNavigation.jsm";
michael@0 858 let RemoteWebNavigation = Components.utils.import(jsm, {}).RemoteWebNavigation;
michael@0 859 this._remoteWebNavigation = new RemoteWebNavigation(this);
michael@0 860 }
michael@0 861 return this._remoteWebNavigation;
michael@0 862 ]]>
michael@0 863 </getter>
michael@0 864 </property>
michael@0 865
michael@0 866 <property name="contentWindow"
michael@0 867 readonly="true"
michael@0 868 onget="return null"/>
michael@0 869
michael@0 870 <property name="sessionHistory"
michael@0 871 onget="return null"
michael@0 872 readonly="true"/>
michael@0 873
michael@0 874 <property name="markupDocumentViewer"
michael@0 875 onget="return null"
michael@0 876 readonly="true"/>
michael@0 877
michael@0 878 <property name="contentViewerEdit"
michael@0 879 onget="return null"
michael@0 880 readonly="true"/>
michael@0 881
michael@0 882 <property name="contentViewerFile"
michael@0 883 onget="return null"
michael@0 884 readonly="true"/>
michael@0 885
michael@0 886 <field name="_charset"></field>
michael@0 887
michael@0 888 <constructor>
michael@0 889 <![CDATA[
michael@0 890 this.messageManager.addMessageListener("scroll", this._messageListenerRemote);
michael@0 891 ]]>
michael@0 892 </constructor>
michael@0 893
michael@0 894 <field name="scrollSync">true</field>
michael@0 895
michael@0 896 <field name="_messageListenerRemote"><![CDATA[
michael@0 897 ({
michael@0 898 self: this,
michael@0 899 receiveMessage: function receiveMessage(aMessage) {
michael@0 900 let self = this.self;
michael@0 901 let json = aMessage.json;
michael@0 902
michael@0 903 switch (aMessage.name) {
michael@0 904 case "scroll":
michael@0 905 if (!json.isRoot)
michael@0 906 return;
michael@0 907 if (!self.scrollSync)
michael@0 908 return;
michael@0 909 this.doScroll(json.scrollOffset.x, json.scrollOffset.y, 0);
michael@0 910 break;
michael@0 911 }
michael@0 912 },
michael@0 913
michael@0 914 doScroll: function doScroll(aX, aY, aCount) {
michael@0 915 let self = this.self;
michael@0 916
michael@0 917 // Use floor so that we always guarantee top-left corner of content is visible.
michael@0 918 let view = self.getRootView();
michael@0 919 view.scrollTo(Math.floor(aX * self.scale), Math.floor(aY * self.scale));
michael@0 920
michael@0 921 let position = view.getPosition();
michael@0 922 if ((position.x != aX * self.scale || position.y != aY * self.scale) && aCount < 3) {
michael@0 923 setTimeout((function() {
michael@0 924 this.doScroll(aX, aY, ++aCount);
michael@0 925 }).bind(this), 0);
michael@0 926 }
michael@0 927 }
michael@0 928 })
michael@0 929 ]]></field>
michael@0 930
michael@0 931 <!-- Keep a store of temporary content views. -->
michael@0 932 <field name="_contentViews">({})</field>
michael@0 933
michael@0 934 <!-- There is a point before a page has loaded where a root content view
michael@0 935 may not exist. We use this so that we don't have to worry about doing
michael@0 936 an if check every time we want to scroll. -->
michael@0 937 <field name="_contentNoop"><![CDATA[
michael@0 938 ({
michael@0 939 _updateCacheViewport: function() {},
michael@0 940 _getViewportSize: function() {},
michael@0 941
michael@0 942 isRoot: function() {
michael@0 943 return true;
michael@0 944 },
michael@0 945
michael@0 946 _scale: 1,
michael@0 947 _setScale: function(scale) {},
michael@0 948 scrollBy: function(x, y) {},
michael@0 949 scrollTo: function(x, y) {},
michael@0 950 getPosition: function() {
michael@0 951 return { x: 0, y: 0 };
michael@0 952 }
michael@0 953 })
michael@0 954 ]]></field>
michael@0 955
michael@0 956 <field name="_contentViewPrototype"><![CDATA[
michael@0 957 ({
michael@0 958 self: this,
michael@0 959 _id: null,
michael@0 960 _contentView: null,
michael@0 961 _timeout: null,
michael@0 962 _pixelsPannedSinceRefresh: { x: 0, y: 0 },
michael@0 963 _lastPanTime: 0,
michael@0 964
michael@0 965 kDieTime: 3000,
michael@0 966
michael@0 967 /**
michael@0 968 * Die if we haven't panned in a while.
michael@0 969 *
michael@0 970 * Since we keep a map of active content views, we need to regularly
michael@0 971 * check if they are necessary so that every single thing the user
michael@0 972 * pans is not kept in memory forever.
michael@0 973 */
michael@0 974 _dieIfOld: function() {
michael@0 975 if (Date.now() - this._lastPanTime >= this.kDieTime)
michael@0 976 this._die();
michael@0 977 else
michael@0 978 // This doesn't need to be exact, just be sure to clean up at some point.
michael@0 979 this._timeout = setTimeout(this._dieIfOld.bind(this), this.kDieTime);
michael@0 980 },
michael@0 981
michael@0 982 /** Cleanup after ourselves. */
michael@0 983 _die: function() {
michael@0 984 let timeout = this._timeout;
michael@0 985 if (timeout) {
michael@0 986 clearTimeout(timeout);
michael@0 987 this._timeout = null;
michael@0 988 }
michael@0 989
michael@0 990 if (this._contentView && Math.abs(this._pixelsPannedSinceRefresh) > 0)
michael@0 991 this._updateCacheViewport();
michael@0 992
michael@0 993 // We expect contentViews to contain our ID. If not, something bad
michael@0 994 // happened.
michael@0 995 delete this.self._contentViews[this._id];
michael@0 996 },
michael@0 997
michael@0 998 /**
michael@0 999 * Given the cache size and the viewport size, this determines where the cache
michael@0 1000 * should start relative to the scroll position. This adjusts the position based
michael@0 1001 * on which direction the user is panning, so that we use our cache as
michael@0 1002 * effectively as possible.
michael@0 1003 *
michael@0 1004 * @param aDirection Negative means user is panning to the left or above
michael@0 1005 * Zero means user did not pan
michael@0 1006 * Positive means user is panning to the right or below
michael@0 1007 * @param aViewportSize The width or height of the viewport
michael@0 1008 * @param aCacheSize The width or height of the displayport
michael@0 1009 */
michael@0 1010 _getRelativeCacheStart: function(aDirection, aViewportSize, aCacheSize) {
michael@0 1011 // Remember that this is relative to the viewport scroll position.
michael@0 1012 // Let's assume we are thinking about the y-axis.
michael@0 1013 // The extreme cases:
michael@0 1014 // |0| would mean that there is no content available above
michael@0 1015 // |aViewportSize - aCacheSize| would mean no content available below
michael@0 1016 //
michael@0 1017 // Taking the average of the extremes puts equal amounts of cache on the
michael@0 1018 // top and bottom of the viewport. If we think of this like a weighted
michael@0 1019 // average, .5 is the sweet spot where equals amounts of content are
michael@0 1020 // above and below the visible area.
michael@0 1021 //
michael@0 1022 // This weight is therefore how much of the cache is above (or to the
michael@0 1023 // left) the visible area.
michael@0 1024 let cachedAbove = .5;
michael@0 1025
michael@0 1026 // If panning down, leave only 25% of the non-visible cache above.
michael@0 1027 if (aDirection > 0)
michael@0 1028 cachedAbove = .25;
michael@0 1029
michael@0 1030 // If panning up, Leave 75% of the non-visible cache above.
michael@0 1031 if (aDirection < 0)
michael@0 1032 cachedAbove = .75;
michael@0 1033
michael@0 1034 return (aViewportSize - aCacheSize) * cachedAbove;
michael@0 1035 },
michael@0 1036
michael@0 1037 /** Determine size of the pixel cache. */
michael@0 1038 _getCacheSize: function(viewportSize) {
michael@0 1039 let self = this.self;
michael@0 1040 let contentView = this._contentView;
michael@0 1041
michael@0 1042 let cacheWidth = self._cacheRatioWidth * viewportSize.width;
michael@0 1043 let cacheHeight = self._cacheRatioHeight * viewportSize.height;
michael@0 1044 let contentSize = this._getContentSize();
michael@0 1045 let contentWidth = contentSize.width;
michael@0 1046 let contentHeight = contentSize.height;
michael@0 1047
michael@0 1048 // There are common cases, such as long skinny pages, where our cache size is
michael@0 1049 // bigger than our content size. In those cases, we take that sliver of leftover
michael@0 1050 // space and apply it to the other dimension.
michael@0 1051 if (contentWidth < cacheWidth) {
michael@0 1052 cacheHeight += (cacheWidth - contentWidth) * cacheHeight / cacheWidth;
michael@0 1053 cacheWidth = contentWidth;
michael@0 1054 } else if (contentHeight < cacheHeight) {
michael@0 1055 cacheWidth += (cacheHeight - contentHeight) * cacheWidth / cacheHeight;
michael@0 1056 cacheHeight = contentHeight;
michael@0 1057 }
michael@0 1058
michael@0 1059 return { width: cacheWidth, height: cacheHeight };
michael@0 1060 },
michael@0 1061
michael@0 1062 _sendDisplayportUpdate: function(scrollX, scrollY) {
michael@0 1063 let self = this.self;
michael@0 1064 if (!self.active)
michael@0 1065 return;
michael@0 1066
michael@0 1067 let contentView = this._contentView;
michael@0 1068 let viewportSize = this._getViewportSize();
michael@0 1069 let cacheSize = this._getCacheSize(viewportSize);
michael@0 1070 let cacheX = this._getRelativeCacheStart(this._pixelsPannedSinceRefresh.x, viewportSize.width, cacheSize.width) + contentView.scrollX;
michael@0 1071 let cacheY = this._getRelativeCacheStart(this._pixelsPannedSinceRefresh.y, viewportSize.height, cacheSize.height) + contentView.scrollY;
michael@0 1072 let contentSize = this._getContentSize();
michael@0 1073
michael@0 1074 // Use our pixels efficiently and don't try to cache things outside of content
michael@0 1075 // boundaries (The left bound can be negative because of RTL).
michael@0 1076
michael@0 1077 let rootScale = self.scale;
michael@0 1078 let leftBound = self._contentDocumentLeft * rootScale;
michael@0 1079 let bounds = new Rect(leftBound, 0, contentSize.width, contentSize.height);
michael@0 1080 let displayport = new Rect(cacheX, cacheY, cacheSize.width, cacheSize.height);
michael@0 1081 displayport.translateInside(bounds);
michael@0 1082
michael@0 1083 self.messageManager.sendAsyncMessage("Content:SetCacheViewport", {
michael@0 1084 scrollX: Math.round(scrollX) / rootScale,
michael@0 1085 scrollY: Math.round(scrollY) / rootScale,
michael@0 1086 x: Math.round(displayport.x) / rootScale,
michael@0 1087 y: Math.round(displayport.y) / rootScale,
michael@0 1088 w: Math.round(displayport.width) / rootScale,
michael@0 1089 h: Math.round(displayport.height) / rootScale,
michael@0 1090 scale: rootScale,
michael@0 1091 id: contentView.id
michael@0 1092 });
michael@0 1093
michael@0 1094 this._pixelsPannedSinceRefresh.x = 0;
michael@0 1095 this._pixelsPannedSinceRefresh.y = 0;
michael@0 1096 },
michael@0 1097
michael@0 1098 _updateCSSViewport: function() {
michael@0 1099 let contentView = this._contentView;
michael@0 1100 this._sendDisplayportUpdate(contentView.scrollX,
michael@0 1101 contentView.scrollY);
michael@0 1102 },
michael@0 1103
michael@0 1104 /**
michael@0 1105 * The cache viewport is what parts of content is cached in the parent process for
michael@0 1106 * fast scrolling. This syncs that up with the current projection viewport.
michael@0 1107 */
michael@0 1108 _updateCacheViewport: function() {
michael@0 1109 // Do not update scroll values for content.
michael@0 1110 if (this.isRoot())
michael@0 1111 this._sendDisplayportUpdate(-1, -1);
michael@0 1112 else {
michael@0 1113 let contentView = this._contentView;
michael@0 1114 this._sendDisplayportUpdate(contentView.scrollX,
michael@0 1115 contentView.scrollY);
michael@0 1116 }
michael@0 1117 },
michael@0 1118
michael@0 1119 _getContentSize: function() {
michael@0 1120 let self = this.self;
michael@0 1121 return { width: this._contentView.contentWidth,
michael@0 1122 height: this._contentView.contentHeight };
michael@0 1123 },
michael@0 1124
michael@0 1125 _getViewportSize: function() {
michael@0 1126 let self = this.self;
michael@0 1127 if (this.isRoot()) {
michael@0 1128 let bcr = self.getBoundingClientRect();
michael@0 1129 return { width: bcr.width, height: bcr.height };
michael@0 1130 } else {
michael@0 1131 return { width: this._contentView.viewportWidth,
michael@0 1132 height: this._contentView.viewportHeight };
michael@0 1133 }
michael@0 1134 },
michael@0 1135
michael@0 1136 init: function(contentView) {
michael@0 1137 let self = this.self;
michael@0 1138
michael@0 1139 this._contentView = contentView;
michael@0 1140 this._id = contentView.id;
michael@0 1141 this._scale = 1;
michael@0 1142 self._contentViews[this._id] = this;
michael@0 1143
michael@0 1144 if (!this.isRoot()) {
michael@0 1145 // Non-root content views are short lived.
michael@0 1146 this._timeout = setTimeout(this._dieIfOld.bind(this), this.kDieTime);
michael@0 1147 // This iframe may not have a display port yet, so build up a cache
michael@0 1148 // immediately.
michael@0 1149 this._updateCacheViewport();
michael@0 1150 }
michael@0 1151 },
michael@0 1152
michael@0 1153 isRoot: function() {
michael@0 1154 return this.self._contentViewManager.rootContentView == this._contentView;
michael@0 1155 },
michael@0 1156
michael@0 1157 scrollBy: function(x, y) {
michael@0 1158 let self = this.self;
michael@0 1159
michael@0 1160 // Bounding content rectangle is in device pixels
michael@0 1161 let contentView = this._contentView;
michael@0 1162 let viewportSize = this._getViewportSize();
michael@0 1163 let contentSize = this._getContentSize();
michael@0 1164 // Calculate document dimensions in device pixels
michael@0 1165 let scrollRangeX = contentSize.width - viewportSize.width;
michael@0 1166 let scrollRangeY = contentSize.height - viewportSize.height;
michael@0 1167
michael@0 1168 let leftOffset = self._contentDocumentLeft * this._scale;
michael@0 1169 x = Math.floor(Math.max(leftOffset, Math.min(scrollRangeX + leftOffset, contentView.scrollX + x))) - contentView.scrollX;
michael@0 1170 y = Math.floor(Math.max(0, Math.min(scrollRangeY, contentView.scrollY + y))) - contentView.scrollY;
michael@0 1171
michael@0 1172 if (x == 0 && y == 0)
michael@0 1173 return;
michael@0 1174
michael@0 1175 contentView.scrollBy(x, y);
michael@0 1176
michael@0 1177 this._lastPanTime = Date.now();
michael@0 1178
michael@0 1179 this._pixelsPannedSinceRefresh.x += x;
michael@0 1180 this._pixelsPannedSinceRefresh.y += y;
michael@0 1181 if (Math.abs(this._pixelsPannedSinceRefresh.x) > 20 ||
michael@0 1182 Math.abs(this._pixelsPannedSinceRefresh.y) > 20)
michael@0 1183 this._updateCacheViewport();
michael@0 1184 },
michael@0 1185
michael@0 1186 scrollTo: function(x, y) {
michael@0 1187 let contentView = this._contentView;
michael@0 1188 this.scrollBy(x - contentView.scrollX, y - contentView.scrollY);
michael@0 1189 },
michael@0 1190
michael@0 1191 _setScale: function _setScale(scale) {
michael@0 1192 this._scale = scale;
michael@0 1193 this._contentView.setScale(scale, scale);
michael@0 1194 },
michael@0 1195
michael@0 1196 getPosition: function() {
michael@0 1197 let contentView = this._contentView;
michael@0 1198 return { x: contentView.scrollX, y: contentView.scrollY };
michael@0 1199 }
michael@0 1200 })
michael@0 1201 ]]>
michael@0 1202 </field>
michael@0 1203
michael@0 1204 <!-- The ratio of CSS pixels to device pixels. -->
michael@0 1205 <property name="scale">
michael@0 1206 <getter><![CDATA[
michael@0 1207 return this.getRootView()._scale;
michael@0 1208 ]]></getter>
michael@0 1209 <setter><![CDATA[
michael@0 1210 if (val <= 0 || val == this.scale)
michael@0 1211 return;
michael@0 1212
michael@0 1213 let rootView = this.getRootView();
michael@0 1214 rootView._setScale(val);
michael@0 1215
michael@0 1216 return val;
michael@0 1217 ]]></setter>
michael@0 1218 </property>
michael@0 1219
michael@0 1220 <method name="_getView">
michael@0 1221 <parameter name="contentView"/>
michael@0 1222 <body>
michael@0 1223 <![CDATA[
michael@0 1224 if (!contentView) return null;
michael@0 1225
michael@0 1226 // See if we have cached it.
michael@0 1227 let id = contentView.id;
michael@0 1228 let jsContentView = this._contentViews[id];
michael@0 1229 if (jsContentView) {
michael@0 1230 // Content view may have changed if it became inactive for a
michael@0 1231 // little while.
michael@0 1232 jsContentView._contentView = contentView;
michael@0 1233 return jsContentView;
michael@0 1234 }
michael@0 1235
michael@0 1236 // Not cached. Create it.
michael@0 1237 jsContentView = Object.create(this._contentViewPrototype);
michael@0 1238 jsContentView.init(contentView);
michael@0 1239 return jsContentView;
michael@0 1240 ]]>
michael@0 1241 </body>
michael@0 1242 </method>
michael@0 1243
michael@0 1244 <!-- Get root content view. -->
michael@0 1245 <method name="getRootView">
michael@0 1246 <body>
michael@0 1247 <![CDATA[
michael@0 1248 let contentView = this._contentViewManager.rootContentView;
michael@0 1249 return this._getView(contentView) || this._contentNoop;
michael@0 1250 ]]>
michael@0 1251 </body>
michael@0 1252 </method>
michael@0 1253
michael@0 1254 <!-- Get contentView for position (x, y) relative to the browser element -->
michael@0 1255 <method name="getViewAt">
michael@0 1256 <parameter name="x"/>
michael@0 1257 <parameter name="y"/>
michael@0 1258 <body>
michael@0 1259 <![CDATA[
michael@0 1260 let manager = this._contentViewManager;
michael@0 1261 let contentView = manager.getContentViewsIn(x, y, 0, 0, 0, 0)[0] ||
michael@0 1262 manager.rootContentView;
michael@0 1263 return this._getView(contentView);
michael@0 1264 ]]>
michael@0 1265 </body>
michael@0 1266 </method>
michael@0 1267
michael@0 1268 <!-- Synchronize the CSS viewport with the projection viewport. -->
michael@0 1269 <method name="_updateCSSViewport">
michael@0 1270 <body>
michael@0 1271 <![CDATA[
michael@0 1272 let rootView = this.getRootView();
michael@0 1273 rootView._updateCSSViewport();
michael@0 1274 ]]>
michael@0 1275 </body>
michael@0 1276 </method>
michael@0 1277
michael@0 1278 <property name="active" onget="return this._active;">
michael@0 1279 <setter><![CDATA[
michael@0 1280 this._active = val;
michael@0 1281 let keepVisible = false;
michael@0 1282 this.messageManager.sendAsyncMessage((val ? "Content:Activate" : "Content:Deactivate"), { keepviewport: keepVisible });
michael@0 1283 if (val)
michael@0 1284 this.getRootView()._updateCacheViewport();
michael@0 1285 ]]></setter>
michael@0 1286 </property>
michael@0 1287
michael@0 1288 <field name="_remoteFinder">null</field>
michael@0 1289 <property name="finder" readonly="true">
michael@0 1290 <getter><![CDATA[
michael@0 1291 if (!this._remoteFinder) {
michael@0 1292 let jsm = "resource://gre/modules/RemoteFinder.jsm";
michael@0 1293 let RemoteFinder = Cu.import(jsm, {}).RemoteFinder;
michael@0 1294 this._remoteFinder = new RemoteFinder(this);
michael@0 1295 }
michael@0 1296 return this._remoteFinder;
michael@0 1297 ]]></getter>
michael@0 1298 </property>
michael@0 1299 </implementation>
michael@0 1300
michael@0 1301 </binding>
michael@0 1302
michael@0 1303 </bindings>

mercurial