Bug 727942 - boundaries of imagemap may be incorrect when page is zoomed, r=marcoz
authorAlexander Surkov <surkov.alexander@gmail.com>
Sat, 24 Mar 2012 02:05:09 +0900
changeset 93481 a5f39c72791d997476cef64645b526f2f199098d
parent 93480 aa32e30bab3457f9df10ff1979b94b2d291ceb62
child 93482 52825f4226e65d2b2434aa4befee046d73cd2c80
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcoz
bugs727942
milestone14.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 727942 - boundaries of imagemap may be incorrect when page is zoomed, r=marcoz
accessible/src/html/nsHTMLImageMapAccessible.cpp
accessible/src/html/nsHTMLImageMapAccessible.h
accessible/tests/mochitest/bounds/test_zoom.html
accessible/tests/mochitest/common.js
accessible/tests/mochitest/layout.js
--- a/accessible/src/html/nsHTMLImageMapAccessible.cpp
+++ b/accessible/src/html/nsHTMLImageMapAccessible.cpp
@@ -211,63 +211,16 @@ nsHTMLAreaAccessible::Description(nsStri
   aDescription.Truncate();
 
   // Still to do - follow IE's standard here
   nsCOMPtr<nsIDOMHTMLAreaElement> area(do_QueryInterface(mContent));
   if (area) 
     area->GetShape(aDescription);
 }
 
-NS_IMETHODIMP
-nsHTMLAreaAccessible::GetBounds(PRInt32 *aX, PRInt32 *aY,
-                                PRInt32 *aWidth, PRInt32 *aHeight)
-{
-  NS_ENSURE_ARG_POINTER(aX);
-  *aX = 0;
-  NS_ENSURE_ARG_POINTER(aY);
-  *aY = 0;
-  NS_ENSURE_ARG_POINTER(aWidth);
-  *aWidth = 0;
-  NS_ENSURE_ARG_POINTER(aHeight);
-  *aHeight = 0;
-
-  if (IsDefunct())
-    return NS_ERROR_FAILURE;
-
-  // Essentially this uses GetRect on mAreas of nsImageMap from nsImageFrame.
-  nsPresContext *presContext = GetPresContext();
-  NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
-
-  nsIFrame *frame = GetFrame();
-  NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
-  nsImageFrame *imageFrame = do_QueryFrame(frame);
-
-  nsImageMap* map = imageFrame->GetImageMap();
-  NS_ENSURE_TRUE(map, NS_ERROR_FAILURE);
-
-  nsRect rect;
-  nsresult rv = map->GetBoundsForAreaContent(mContent, rect);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  *aX = presContext->AppUnitsToDevPixels(rect.x);
-  *aY = presContext->AppUnitsToDevPixels(rect.y);
-
-  // XXX Areas are screwy; they return their rects as a pair of points, one pair
-  // stored into the width and height.
-  *aWidth  = presContext->AppUnitsToDevPixels(rect.width - rect.x);
-  *aHeight = presContext->AppUnitsToDevPixels(rect.height - rect.y);
-
-  // Put coords in absolute screen coords
-  nsIntRect orgRectPixels = frame->GetScreenRectExternal();
-  *aX += orgRectPixels.x;
-  *aY += orgRectPixels.y;
-
-  return NS_OK;
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLAreaAccessible: nsAccessNode public
 
 bool
 nsHTMLAreaAccessible::IsPrimaryForNode() const
 {
   // Make HTML area DOM element not accessible. HTML image map accessible
   // manages its tree itself.
@@ -321,8 +274,30 @@ nsHTMLAreaAccessible::EndOffset()
 ////////////////////////////////////////////////////////////////////////////////
 // nsHTMLAreaAccessible: nsAccessible protected
 
 void
 nsHTMLAreaAccessible::CacheChildren()
 {
   // No children for aria accessible.
 }
+
+void
+nsHTMLAreaAccessible::GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame)
+{
+  nsIFrame* frame = GetFrame();
+  if (!frame)
+    return;
+
+  nsImageFrame* imageFrame = do_QueryFrame(frame);
+  nsImageMap* map = imageFrame->GetImageMap();
+
+  nsresult rv = map->GetBoundsForAreaContent(mContent, aBounds);
+  if (NS_FAILED(rv))
+    return;
+
+  // XXX Areas are screwy; they return their rects as a pair of points, one pair
+  // stored into the width and height.
+  aBounds.width -= aBounds.x;
+  aBounds.height -= aBounds.y;
+
+  *aBoundingFrame = frame;
+}
--- a/accessible/src/html/nsHTMLImageMapAccessible.h
+++ b/accessible/src/html/nsHTMLImageMapAccessible.h
@@ -91,20 +91,16 @@ nsAccessible::AsImageMap()
  * Accessible for image map areas - must be child of image.
  */
 class nsHTMLAreaAccessible : public nsHTMLLinkAccessible
 {
 public:
 
   nsHTMLAreaAccessible(nsIContent* aContent, nsDocAccessible* aDoc);
 
-  // nsIAccessible
-
-  NS_IMETHOD GetBounds(PRInt32 *x, PRInt32 *y, PRInt32 *width, PRInt32 *height);
-
   // nsAccessNode
   virtual bool IsPrimaryForNode() const;
 
   // nsAccessible
   virtual void Description(nsString& aDescription);
   virtual nsresult GetNameInternal(nsAString& aName);
   virtual PRUint64 NativeState();
   virtual nsAccessible* ChildAtPoint(PRInt32 aX, PRInt32 aY,
@@ -113,11 +109,12 @@ public:
   // HyperLinkAccessible
   virtual PRUint32 StartOffset();
   virtual PRUint32 EndOffset();
 
 protected:
 
   // nsAccessible
   virtual void CacheChildren();
+  virtual void GetBoundsRect(nsRect& aBounds, nsIFrame** aBoundingFrame);
 };
 
 #endif  
--- a/accessible/tests/mochitest/bounds/test_zoom.html
+++ b/accessible/tests/mochitest/bounds/test_zoom.html
@@ -2,48 +2,68 @@
 <html>
 <head>
   <title>Accessible boundaries when page is zoomed</title>
   <link rel="stylesheet" type="text/css"
         href="chrome://mochikit/content/tests/SimpleTest/test.css" />
 
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
 
   <script type="application/javascript"
           src="../common.js"></script>
   <script type="application/javascript"
           src="../role.js"></script>
   <script type="application/javascript"
           src="../layout.js"></script>
   <script type="application/javascript"
           src="../browser.js"></script>
 
   <script type="application/javascript">
     function doTest()
     {
       var tabDocument = currentTabDocument();
-      var p1 = tabDocument.body.firstElementChild;
-      var p2 = tabDocument.body.lastElementChild;
+      var p1 = tabDocument.getElementById("p1");
+      var p2 = tabDocument.getElementById("p2");
+
+      var imgMap = tabDocument.getElementById("imgmap");
+      ensureImageMapTree(imgMap);
+      var imgMapAcc = getAccessible(imgMap);
+      var area = imgMapAcc.firstChild;
 
       testBounds(p1);
       testBounds(p2);
+      testBounds(area);
 
       zoomDocument(tabDocument, 2.0);
 
       testBounds(p1);
       testBounds(p2);
+      testBounds(area);
 
       closeBrowserWindow();
       SimpleTest.finish();
     }
 
+    var url = "data:text/html,<html><body>";
+    url += "<p id='p1'>para 1</p><p id='p2'>para 2</p>";
+    url += "<map name='atoz_map' id='map'>";
+    url += "  <area id='area1' href='http%3A%2F%2Fmozilla.org'";
+    url += "        coords=17,0,30,14' alt='mozilla.org' shape='rect'>";
+    url += "</map>";
+    url += "<img id='imgmap' width='447' height='15'";
+    url += "     usemap='%23atoz_map'";
+    url += "     src='chrome%3A%2F%2Fmochitests%2Fcontent%2Fa11y%2Faccessible%2Fletters.gif'>";
+    url += "</body></html>";
+
     SimpleTest.waitForExplicitFinish();
     openBrowserWindow(doTest,
-                      "data:text/html,<html><body><p>para 1</p><p>para 2</p></body></html>",
+                      url,
                       { left: 0, top: 0, width: 600, height: 600 });
   </script>
 </head>
 <body>
 
   <a target="_blank"
      href="https://bugzilla.mozilla.org/show_bug.cgi?id=650241"
      title="Location returned by accessibles incorrect when page zoomed">
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -489,17 +489,19 @@ function testDefunctAccessible(aAcc, aNo
 /**
  * Ensure that image map accessible tree is created.
  */
 function ensureImageMapTree(aID)
 {
   // XXX: We send a useless mouse move to the image to force it to setup its
   // image map, because flushing layout won't do it. Hopefully bug 135040
   // will make this not suck.
-  synthesizeMouse(getNode(aID), 10, 10, { type: "mousemove" });
+  var image = getNode(aID);
+  synthesizeMouse(image, 10, 10, { type: "mousemove" },
+                  image.ownerDocument.defaultView);
 
   // XXX This may affect a11y more than other code because imagemaps may not
   // get drawn or have an mouse event over them. Bug 570322 tracks a11y
   // dealing with this.
   todo(false, "Need to remove this image map workaround.");
 }
 
 /**
--- a/accessible/tests/mochitest/layout.js
+++ b/accessible/tests/mochitest/layout.js
@@ -102,21 +102,47 @@ function getBounds(aID)
 }
 
 /**
  * Return DOM node coordinates relative the screen and its size in device
  * pixels.
  */
 function getBoundsForDOMElm(aID)
 {
+  var x = 0, y = 0, width = 0, height = 0;
+
   var elm = getNode(aID);
+  if (elm.localName == "area") {
+    var mapName = elm.parentNode.getAttribute("name");
+    var selector = "[usemap='#" + mapName + "']";
+    var img = elm.ownerDocument.querySelector(selector);
+
+    var areaCoords = elm.coords.split(",");
+    var areaX = parseInt(areaCoords[0]);
+    var areaY = parseInt(areaCoords[1]);
+    var areaWidth = parseInt(areaCoords[2]) - areaX;
+    var areaHeight = parseInt(areaCoords[3]) - areaY;
+
+    var rect = img.getBoundingClientRect();
+    x = rect.left + areaX;
+    y = rect.top + areaY;
+    width = areaWidth;
+    height = areaHeight;
+  }
+  else {
+    var rect = elm.getBoundingClientRect();
+    x = rect.left;
+    y = rect.top;
+    width = rect.width;
+    height = rect.height;
+  }
+
   var elmWindow = elm.ownerDocument.defaultView;
   var winUtil = elmWindow.
     QueryInterface(Components.interfaces.nsIInterfaceRequestor).
     getInterface(Components.interfaces.nsIDOMWindowUtils);
 
   var ratio = winUtil.screenPixelsPerCSSPixel;
-  var rect = elm.getBoundingClientRect();
-  return [ (rect.left + elmWindow.mozInnerScreenX) * ratio,
-           (rect.top + elmWindow.mozInnerScreenY) * ratio,
-           rect.width * ratio,
-           rect.height * ratio ];
+  return [ (x + elmWindow.mozInnerScreenX) * ratio,
+           (y + elmWindow.mozInnerScreenY) * ratio,
+           width * ratio,
+           height * ratio ];
 }