Bug 897960 - walker should support mozbrowser iframes. Patch A. r=dcamp
authorPaul Rouget <paul@mozilla.com>
Sun, 08 Sep 2013 10:58:00 +0200
changeset 146202 a160246e2f61a8df9d629530ed5442e8b37a2c45
parent 146136 81f13346eb7ca2ea12d046230eab8e6ad82ab544
child 146203 d16b6b1b953e539536a7b259b412500db0d2f807
push id25245
push userryanvm@gmail.com
push dateMon, 09 Sep 2013 20:57:55 +0000
treeherdermozilla-central@a468b2e34b04 [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. Patch A. 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;
+    }
+  },
 };