Bug 897960 - walker should support mozbrowser iframes. r=dcamp
☠☠ backed out by 78128ed0ce26 ☠ ☠
authorPaul Rouget <paul@mozilla.com>
Sun, 08 Sep 2013 10:58:00 +0200
changeset 146124 86b5d8778fc4a5dc978351962c1ce8da096a01b3
parent 146123 944426b6b680b85c66ad929d303cdc572e0b1c89
child 146125 fab07b9d6dee1b52ede6e8049e8c904369512c15
push id25242
push useremorley@mozilla.com
push dateMon, 09 Sep 2013 12:13:52 +0000
treeherdermozilla-central@218d4334d29e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdcamp
bugs897960
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 897960 - walker should support mozbrowser iframes. r=dcamp
toolkit/devtools/LayoutHelpers.jsm
--- a/toolkit/devtools/LayoutHelpers.jsm
+++ b/toolkit/devtools/LayoutHelpers.jsm
@@ -8,24 +8,25 @@ const Cu = Components.utils;
 const Ci = Components.interfaces;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "PlatformKeys", function() {
-  return Services.strings.createBundle(
-    "chrome://global-platform/locale/platformKeys.properties");
-});
-
 this.EXPORTED_SYMBOLS = ["LayoutHelpers"];
 
-this.LayoutHelpers = LayoutHelpers = {
+this.LayoutHelpers = LayoutHelpers = function(aTopLevelWindow) {
+  this._topDocShell = aTopLevelWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                     .getInterface(Ci.nsIWebNavigation)
+                                     .QueryInterface(Ci.nsIDocShell);
+}
+
+LayoutHelpers.prototype = {
 
   /**
    * Compute the position and the dimensions for the visible portion
    * of a node, relativalely to the root window.
    *
    * @param nsIDOMNode aNode
    *        a DOM element to be highlighted
    */
@@ -65,32 +66,37 @@ this.LayoutHelpers = LayoutHelpers = {
       if (rect.top < 0) {
         rect.height += rect.top;
         rect.top = 0;
       }
 
       // Selection has been clipped to fit in its own window.
 
       // Are we in the top-level window?
-      if (frameWin.parent === frameWin || !frameWin.frameElement) {
+      if (this.isTopLevelWindow(frameWin)) {
+        break;
+      }
+
+      let frameElement = this.getFrameElement(frameWin);
+      if (!frameElement) {
         break;
       }
 
       // We are in an iframe.
       // We take into account the parent iframe position and its
       // offset (borders and padding).
-      let frameRect = frameWin.frameElement.getBoundingClientRect();
+      let frameRect = frameElement.getBoundingClientRect();
 
       let [offsetTop, offsetLeft] =
-        this.getIframeContentOffset(frameWin.frameElement);
+        this.getIframeContentOffset(frameElement);
 
       rect.top += frameRect.top + offsetTop;
       rect.left += frameRect.left + offsetLeft;
 
-      frameWin = frameWin.parent;
+      frameWin = this.getParentWindow(frameWin);
     }
 
     return rect;
   },
 
   /**
    * Compute the absolute position and the dimensions of a node, relativalely
    * to the root window.
@@ -110,32 +116,37 @@ this.LayoutHelpers = LayoutHelpers = {
             left: clientRect.left + aContentWindow.pageXOffset,
             width: clientRect.width,
             height: clientRect.height};
 
     // We iterate through all the parent windows.
     while (true) {
 
       // Are we in the top-level window?
-      if (frameWin.parent === frameWin || !frameWin.frameElement) {
+      if (this.isTopLevelWindow(frameWin)) {
+        break;
+      }
+
+      let frameElement = this.getFrameElement(frameWin);
+      if (!frameElement) {
         break;
       }
 
       // We are in an iframe.
       // We take into account the parent iframe position and its
       // offset (borders and padding).
-      let frameRect = frameWin.frameElement.getBoundingClientRect();
+      let frameRect = frameElement.getBoundingClientRect();
 
       let [offsetTop, offsetLeft] =
-        this.getIframeContentOffset(frameWin.frameElement);
+        this.getIframeContentOffset(frameElement);
 
       rect.top += frameRect.top + offsetTop;
       rect.left += frameRect.left + offsetLeft;
 
-      frameWin = frameWin.parent;
+      frameWin = this.getParentWindow(frameWin);
     }
 
     return rect;
   },
 
   /**
    * Returns iframe content offset (iframe border + padding).
    * Note: this function shouldn't need to exist, had the platform provided a
@@ -198,17 +209,17 @@ this.LayoutHelpers = LayoutHelpers = {
    */
   getElementFromPoint: function LH_elementFromPoint(aDocument, aX, aY) {
     let node = aDocument.elementFromPoint(aX, aY);
     if (node && node.contentDocument) {
       if (node instanceof Ci.nsIDOMHTMLIFrameElement) {
         let rect = node.getBoundingClientRect();
 
         // Gap between the iframe and its content window.
-        let [offsetTop, offsetLeft] = LayoutHelpers.getIframeContentOffset(node);
+        let [offsetTop, offsetLeft] = this.getIframeContentOffset(node);
 
         aX -= rect.left + offsetLeft;
         aY -= rect.top + offsetTop;
 
         if (aX < 0 || aY < 0) {
           // Didn't reach the content document, still over the iframe.
           return node;
         }
@@ -291,19 +302,20 @@ this.LayoutHelpers = LayoutHelpers = {
 
       if (xAllowed && (leftToRight <= 0 || rightToLeft <= 0)) {
         win.scroll(win.scrollX + clientRect.left
                    - (win.innerWidth - elem.offsetWidth) / 2,
                    win.scrollY);
       }
     }
 
-    if (win.parent !== win) {
+    if (!this.isTopLevelWindow(win)) {
       // We are inside an iframe.
-      LH_scrollIntoViewIfNeeded(win.frameElement, centered);
+      let frameElement = this.getFrameElement(win);
+      this.scrollIntoViewIfNeeded(frameElement, centered);
     }
   },
 
   /**
    * Check if a node and its document are still alive
    * and attached to the window.
    *
    * @param aNode
@@ -317,68 +329,65 @@ this.LayoutHelpers = LayoutHelpers = {
       return connected;
     } catch (e) {
       // "can't access dead object" error
       return false;
     }
   },
 
   /**
-   * Prettifies the modifier keys for an element.
-   *
-   * @param Node aElemKey
-   *        The key element to get the modifiers from.
-   * @param boolean aAllowCloverleaf
-   *        Pass true to use the cloverleaf symbol instead of a descriptive string.
-   * @return string
-   *         A prettified and properly separated modifier keys string.
+   * like win.parent === win, but goes through mozbrowsers and mozapps iframes.
    */
-  prettyKey: function LH_prettyKey(aElemKey, aAllowCloverleaf)
-  {
-    let elemString = "";
-    let elemMod = aElemKey.getAttribute("modifiers");
+  isTopLevelWindow: function LH_isTopLevelWindow(win) {
+    let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                   .getInterface(Ci.nsIWebNavigation)
+                   .QueryInterface(Ci.nsIDocShell);
 
-    if (elemMod.match("accel")) {
-      if (Services.appinfo.OS == "Darwin") {
-        // XXX bug 779642 Use "Cmd-" literal vs. cloverleaf meta-key until
-        // Orion adds variable height lines.
-        if (!aAllowCloverleaf) {
-          elemString += "Cmd-";
-        } else {
-          elemString += PlatformKeys.GetStringFromName("VK_META") +
-                        PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-        }
-      } else {
-        elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
-                      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-      }
-    }
-    if (elemMod.match("access")) {
-      if (Services.appinfo.OS == "Darwin") {
-        elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
-                      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-      } else {
-        elemString += PlatformKeys.GetStringFromName("VK_ALT") +
-                      PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-      }
-    }
-    if (elemMod.match("shift")) {
-      elemString += PlatformKeys.GetStringFromName("VK_SHIFT") +
-                    PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-    }
-    if (elemMod.match("alt")) {
-      elemString += PlatformKeys.GetStringFromName("VK_ALT") +
-                    PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-    }
-    if (elemMod.match("ctrl") || elemMod.match("control")) {
-      elemString += PlatformKeys.GetStringFromName("VK_CONTROL") +
-                    PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
-    }
-    if (elemMod.match("meta")) {
-      elemString += PlatformKeys.GetStringFromName("VK_META") +
-                    PlatformKeys.GetStringFromName("MODIFIER_SEPARATOR");
+    return docShell === this._topDocShell;
+  },
+
+  /**
+   * like win.parent, but goes through mozbrowsers and mozapps iframes.
+   */
+  getParentWindow: function LH_getParentWindow(win) {
+    if (this.isTopLevelWindow(win)) {
+      return null;
     }
 
-    return elemString +
-      (aElemKey.getAttribute("keycode").replace(/^.*VK_/, "") ||
-       aElemKey.getAttribute("key")).toUpperCase();
-  }
+    let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                   .getInterface(Ci.nsIWebNavigation)
+                   .QueryInterface(Ci.nsIDocShell);
+
+    if (docShell.isBrowserOrApp) {
+      let parentDocShell = docShell.getSameTypeParentIgnoreBrowserAndAppBoundaries();
+      return parentDocShell.contentViewer.DOMDocument.defaultView;
+    } else {
+      return win.parent;
+    }
+  },
+
+  /**
+   * like win.frameElement, but goes through mozbrowsers and mozapps iframes.
+   */
+  getFrameElement: function LH_getFrameElement(win) {
+    if (this.isTopLevelWindow(win)) {
+      return null;
+    }
+
+    let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                   .getInterface(Ci.nsIWebNavigation)
+                   .QueryInterface(Ci.nsIDocShell);
+
+    if (docShell.isBrowserOrApp) {
+      let parentDocShell = docShell.getSameTypeParentIgnoreBrowserAndAppBoundaries();
+      let parentDoc = parentDocShell.contentViewer.DOMDocument;
+      let allIframes = parentDoc.querySelectorAll("iframe");
+      for (let f of allIframes) {
+        if (f.contentWindow === win) {
+          return f;
+        }
+      }
+      return null;
+    } else {
+      return win.frameElement;
+    }
+  },
 };