Bug 566081 - Inspect doesn't work inside iframes, r=gavin
authorMihai Sucan <msucan@mozilla.com>
Fri, 30 Jul 2010 08:30:55 -0300
changeset 48411 bd9d89e48566ff17bff0866c5717f23f5c95ab94
parent 48410 76cdb7d5f48c389184f75bfdd54c68510b2aed23
child 48412 3c512fbfd912254cf379b0df435e7474c35feab0
push id14718
push userrcampbell@mozilla.com
push dateFri, 30 Jul 2010 11:31:33 +0000
treeherderautoland@b45b63b9283f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgavin
bugs566081
milestone2.0b3pre
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 566081 - Inspect doesn't work inside iframes, r=gavin
browser/base/content/inspector.js
browser/base/content/test/Makefile.in
browser/base/content/test/browser_inspector_iframeTest.js
--- a/browser/base/content/inspector.js
+++ b/browser/base/content/inspector.js
@@ -18,16 +18,17 @@
  *
  * The Initial Developer of the Original Code is
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Rob Campbell <rcampbell@mozilla.com> (original author)
+ *   Mihai Șucan <mihai.sucan@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -255,17 +256,18 @@ PanelHighlighter.prototype = {
     let b = {
       x: clientRect.right - browserRect.left,
       y: clientRect.bottom - browserRect.top
     };
 
     // Get midpoint of diagonal line.
     let midpoint = this.midPoint(a, b);
 
-    return this.win.document.elementFromPoint(midpoint.x, midpoint.y);
+    return InspectorUI.elementFromPoint(this.win.document, midpoint.x,
+      midpoint.y);
   },
 
   /**
    * Is this.node highlightable?
    *
    * @returns boolean
    */
   isNodeHighlightable: function PanelHighlighter_isNodeHighlightable()
@@ -307,18 +309,18 @@ PanelHighlighter.prototype = {
    *        The MouseEvent triggering the method.
    */
   handleMouseMove: function PanelHighlighter_handleMouseMove(aEvent)
   {
     if (!InspectorUI.inspecting) {
       return;
     }
     let browserRect = this.browser.getBoundingClientRect();
-    let element = this.win.document.elementFromPoint(aEvent.clientX -
-      browserRect.left, aEvent.clientY - browserRect.top);
+    let element = InspectorUI.elementFromPoint(this.win.document,
+      aEvent.clientX - browserRect.left, aEvent.clientY - browserRect.top);
     if (element && element != this.node) {
       InspectorUI.inspectNode(element);
     }
   },
 };
 
 ///////////////////////////////////////////////////////////////////////////
 //// InspectorTreeView
@@ -852,18 +854,18 @@ var InspectorUI = {
         switch (event.keyCode) {
           case KeyEvent.DOM_VK_RETURN:
           case KeyEvent.DOM_VK_ESCAPE:
             this.stopInspecting();
             break;
         }
         break;
       case "mousemove":
-        let element = this.win.document.elementFromPoint(event.clientX,
-          event.clientY);
+        let element = this.elementFromPoint(event.target.ownerDocument,
+          event.clientX, event.clientY);
         if (element && element != this.node) {
           this.inspectNode(element);
         }
         break;
       case "click":
         this.stopInspecting();
         break;
       case "scroll":
@@ -926,16 +928,45 @@ var InspectorUI = {
   {
     this.highlighter.highlightNode(aNode);
     this.selectEventsSuppressed = true;
     this.treeView.selectedNode = aNode;
     this.selectEventsSuppressed = false;
     this.updateStylePanel(aNode);
   },
 
+  /**
+   * Find an element from the given coordinates. This method descends through 
+   * frames to find the element the user clicked inside frames.
+   *
+   * @param DOMDocument aDocument the document to look into.
+   * @param integer aX
+   * @param integer aY
+   * @returns Node|null the element node found at the given coordinates.
+   */
+  elementFromPoint: function IUI_elementFromPoint(aDocument, aX, aY)
+  {
+    let node = aDocument.elementFromPoint(aX, aY);
+    if (node && node.contentDocument) {
+      switch (node.nodeName.toLowerCase()) {
+        case "iframe":
+          let rect = node.getBoundingClientRect();
+          aX -= rect.left;
+          aY -= rect.top;
+
+        case "frame":
+          let subnode = this.elementFromPoint(node.contentDocument, aX, aY);
+          if (subnode) {
+            node = subnode;
+          }
+      }
+    }
+    return node;
+  },
+
   ///////////////////////////////////////////////////////////////////////////
   //// Utility functions
 
   /**
    * debug logging facility
    * @param msg
    *        text message to send to the log
    */
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -143,16 +143,17 @@ endif
                  browser_discovery.js \
                  browser_drag.js \
                  browser_gestureSupport.js \
                  browser_getshortcutoruri.js \
                  browser_inspector_initialization.js \
                  browser_inspector_treeSelection.js \
                  browser_inspector_highlighter.js \
                  browser_inspector_stylePanel.js \
+                 browser_inspector_iframeTest.js \
                  browser_pageInfo.js \
                  browser_page_style_menu.js \
                  browser_pinnedTabs.js \
                  browser_plainTextLinks.js \
                  browser_pluginnotification.js \
                  browser_popupUI.js \
                  browser_relatedTabs.js \
                  browser_sanitize-passwordDisabledHosts.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_inspector_iframeTest.js
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Inspector iframe Tests.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Rob Campbell <rcampbell@mozilla.com>
+ *   Mihai Șucan <mihai.sucan@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let doc;
+let div1;
+let div2;
+let iframe1;
+let iframe2;
+
+function createDocument()
+{
+  doc.title = "Inspector iframe Tests";
+
+  iframe1 = doc.createElement('iframe');
+
+  iframe1.addEventListener("load", function () {
+    iframe1.removeEventListener("load", arguments.callee, false);
+
+    div1 = iframe1.contentDocument.createElement('div');
+    div1.textContent = 'little div';
+    iframe1.contentDocument.body.appendChild(div1);
+
+    iframe2 = iframe1.contentDocument.createElement('iframe');
+
+    iframe2.addEventListener('load', function () {
+      iframe2.removeEventListener("load", arguments.callee, false);
+
+      div2 = iframe2.contentDocument.createElement('div');
+      div2.textContent = 'nested div';
+      iframe2.contentDocument.body.appendChild(div2);
+
+      setupIframeTests();
+    }, false);
+
+    iframe2.src = 'data:text/html,nested iframe';
+    iframe1.contentDocument.body.appendChild(iframe2);
+  }, false);
+
+  iframe1.src = 'data:text/html,little iframe';
+  doc.body.appendChild(iframe1);
+}
+
+function setupIframeTests()
+{
+  document.addEventListener("popupshown", runIframeTests, false);
+  InspectorUI.toggleInspectorUI();
+}
+
+function runIframeTests(evt)
+{
+  if (evt.target.id != "inspector-panel")
+    return true;
+
+  document.removeEventListener("popupshown", runIframeTests, false);
+  document.addEventListener("popupshown", performTestComparisons1, false);
+
+  EventUtils.synthesizeMouse(div1, 2, 2, {type: "mousemove"},
+    iframe1.contentWindow);
+}
+
+function performTestComparisons1(evt)
+{
+  if (evt.target.id != "highlighter-panel")
+    return true;
+
+  document.removeEventListener("popupshown", performTestComparisons1, false);
+
+  is(InspectorUI.treeView.selectedNode, div1, "selection matches div1 node");
+  is(InspectorUI.highlighter.highlitNode, div1, "highlighter matches selection");
+
+  document.addEventListener("popupshown", performTestComparisons2, false);
+
+  EventUtils.synthesizeMouse(div2, 2, 2, {type: "mousemove"},
+    iframe2.contentWindow);
+}
+
+function performTestComparisons2(evt)
+{
+  if (evt.target.id != "highlighter-panel")
+    return true;
+
+  document.removeEventListener("popupshown", performTestComparisons2, false);
+
+  is(InspectorUI.treeView.selectedNode, div2, "selection matches div2 node");
+  is(InspectorUI.highlighter.highlitNode, div2, "highlighter matches selection");
+
+  executeSoon(finishUp);
+}
+
+function finishUp() {
+  InspectorUI.closeInspectorUI();
+  gBrowser.removeCurrentTab();
+  finish();
+}
+
+function test()
+{
+  waitForExplicitFinish();
+  gBrowser.selectedTab = gBrowser.addTab();
+  gBrowser.selectedBrowser.addEventListener("load", function() {
+    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
+    doc = content.document;
+    waitForFocus(createDocument, content);
+  }, true);
+  
+  content.location = "data:text/html,iframe tests for inspector";
+}
+