Bug 979692 - Calculate hit detection and fill in region parameter to mouse events. r=roc
☠☠ backed out by 9a26e571fd46 ☠ ☠
authorRik Cabanier <cabanier@adobe.com>
Mon, 12 May 2014 15:52:00 +0200
changeset 183743 1f34d528c0f12425e4d9bfa2d2214b7c46f2064f
parent 183742 45ea7a49ecec4f150cb2844c6b501958865e372b
child 183744 2ee1b111863627ff72a81b222ecad5f0f0b4cb6e
push id43651
push usercbook@mozilla.com
push dateMon, 19 May 2014 10:07:02 +0000
treeherdermozilla-inbound@2ee1b1118636 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs979692
milestone32.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 979692 - Calculate hit detection and fill in region parameter to mouse events. r=roc
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/CanvasRenderingContext2D.h
content/html/content/public/HTMLCanvasElement.h
content/html/content/src/HTMLCanvasElement.cpp
dom/events/MouseEvent.cpp
widget/MouseEvents.h
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -1105,16 +1105,27 @@ CanvasRenderingContext2D::GetImageBuffer
   if (!data || data->GetSize() != IntSize(mWidth, mHeight)) {
     return;
   }
 
   *aImageBuffer = SurfaceToPackedBGRA(data);
   *aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
 }
 
+nsString CanvasRenderingContext2D::GetHitRegion(const mozilla::gfx::Point& aPoint)
+{
+  for (unsigned int x = 0 ; x < mHitRegionsOptions.Length(); x++) {
+    RegionInfo& info = mHitRegionsOptions[x];
+    if (info.mPath->ContainsPoint(aPoint, Matrix())) {
+      return info.mId;
+    }
+  }
+  return nsString();
+}
+
 NS_IMETHODIMP
 CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
                                          const char16_t *aEncoderOptions,
                                          nsIInputStream **aStream)
 {
   nsCString enccid("@mozilla.org/image/encoder;2?type=");
   enccid += aMimeType;
   nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -532,16 +532,21 @@ public:
                                 transform * aCP3);
     }
   }
 
   friend class CanvasRenderingContext2DUserData;
 
   virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
 
+
+  // Given a point, return hit region ID if it exists
+  nsString GetHitRegion(const mozilla::gfx::Point& aPoint);
+
+
   // return true and fills in the bound rect if element has a hit region.
   bool GetHitRegionRect(Element* aElement, nsRect& aRect);
 
 protected:
   nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
                              uint32_t aWidth, uint32_t aHeight,
                              JSObject** aRetval);
 
--- a/content/html/content/public/HTMLCanvasElement.h
+++ b/content/html/content/public/HTMLCanvasElement.h
@@ -180,16 +180,18 @@ public:
                            bool aNotify) MOZ_OVERRIDE;
 
   virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName,
                              bool aNotify) MOZ_OVERRIDE;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
   nsresult CopyInnerTo(mozilla::dom::Element* aDest);
 
+  virtual nsresult PreHandleEvent(mozilla::EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
+
   /*
    * Helpers called by various users of Canvas
    */
 
   already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
                                                CanvasLayer *aOldLayer,
                                                LayerManager *aManager);
   // Should return true if the canvas layer should always be marked inactive.
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -1,38 +1,42 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+   /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/HTMLCanvasElement.h"
 
 #include "ImageEncoder.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "Layers.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/CanvasRenderingContext2D.h"
 #include "mozilla/dom/HTMLCanvasElementBinding.h"
 #include "mozilla/dom/UnionTypes.h"
+#include "mozilla/dom/MouseEvent.h"
+#include "mozilla/EventDispatcher.h"
 #include "mozilla/gfx/Rect.h"
+#include "mozilla/MouseEvents.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "nsAttrValueInlines.h"
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsDOMFile.h"
 #include "nsDOMJSUtils.h"
 #include "nsFrameManager.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsITimer.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsIXPConnect.h"
 #include "nsJSUtils.h"
+#include "nsLayoutUtils.h"
 #include "nsMathUtils.h"
 #include "nsNetUtil.h"
 #include "nsStreamUtils.h"
 #include "ActiveLayerTracker.h"
 
 #ifdef MOZ_WEBGL
 #include "../canvas/src/WebGL2Context.h"
 #endif
@@ -283,16 +287,44 @@ HTMLCanvasElement::CopyInnerTo(Element* 
       context2d->DrawImage(element,
                            0.0, 0.0, err);
       rv = err.ErrorCode();
     }
   }
   return rv;
 }
 
+nsresult HTMLCanvasElement::PreHandleEvent(EventChainPreVisitor& aVisitor)
+{
+  if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT) {
+    WidgetMouseEventBase* evt = (WidgetMouseEventBase*)aVisitor.mEvent;
+    if (evt) {
+      nsCOMPtr<nsISupports> cxt;
+      GetContext(NS_LITERAL_STRING("2d"), getter_AddRefs(cxt));
+      nsRefPtr<CanvasRenderingContext2D> context2d =
+        static_cast<CanvasRenderingContext2D*>(cxt.get());
+
+      if (context2d) {
+        nsIFrame *frame = GetPrimaryFrame();
+        if (!frame)
+          return NS_OK;
+        nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(evt, frame);
+        nsRect paddingRect = frame->GetContentRectRelativeToSelf();
+        Point hitpoint;
+        hitpoint.x = (ptInRoot.x - paddingRect.x) / AppUnitsPerCSSPixel();
+        hitpoint.y = (ptInRoot.y - paddingRect.y) / AppUnitsPerCSSPixel();
+
+        evt->region = context2d->GetHitRegion(hitpoint);
+        aVisitor.mCanHandle = true;
+      }
+    }
+  }
+  return nsGenericHTMLElement::PreHandleEvent(aVisitor);
+}
+
 nsChangeHint
 HTMLCanvasElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
                                           int32_t aModType) const
 {
   nsChangeHint retval =
     nsGenericHTMLElement::GetAttributeChangeHint(aAttribute, aModType);
   if (aAttribute == nsGkAtoms::width ||
       aAttribute == nsGkAtoms::height)
--- a/dom/events/MouseEvent.cpp
+++ b/dom/events/MouseEvent.cpp
@@ -294,16 +294,20 @@ MouseEvent::GetRelatedTarget()
   }
   return nullptr;
 }
 
 void
 MouseEvent::GetRegion(nsAString& aRegion)
 {
   SetDOMStringToNull(aRegion);
+  WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
+  if (mouseEventBase) {
+    aRegion = mouseEventBase->region;
+  }
 }
 
 NS_IMETHODIMP
 MouseEvent::GetMozMovementX(int32_t* aMovementX)
 {
   NS_ENSURE_ARG_POINTER(aMovementX);
   *aMovementX = MozMovementX();
 
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -121,16 +121,19 @@ public:
   int16_t buttons;
 
   // Finger or touch pressure of event. It ranges between 0.0 and 1.0.
   float pressure;
 
   // Possible values at nsIDOMMouseEvent
   uint16_t inputSource;
 
+  // ID of the canvas HitRegion
+  nsString region;
+
   void AssignMouseEventBaseData(const WidgetMouseEventBase& aEvent,
                                 bool aCopyTargets)
   {
     AssignInputEventData(aEvent, aCopyTargets);
 
     relatedTarget = aCopyTargets ? aEvent.relatedTarget : nullptr;
     button = aEvent.button;
     buttons = aEvent.buttons;