Bug 1317937: Disallow <a> as <area> in image maps. r?mats draft
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 08 Nov 2017 16:28:44 +0100
changeset 695006 95c6a81ea899ca20691d9cff17a9eea5f998982f
parent 695005 ca7d3b875cc083a2769b7e9bf08381c204498755
child 739487 85baad08358aa48003e88d8f99290369975b28c8
push id88302
push userbmo:emilio@crisal.io
push dateWed, 08 Nov 2017 16:26:12 +0000
reviewersmats
bugs1317937
milestone58.0a1
Bug 1317937: Disallow <a> as <area> in image maps. r?mats MozReview-Commit-ID: JTZgVMV7bZr
layout/generic/nsImageMap.cpp
layout/generic/nsImageMap.h
--- a/layout/generic/nsImageMap.cpp
+++ b/layout/generic/nsImageMap.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* code for HTML client-side image maps */
 
 #include "nsImageMap.h"
 
 #include "mozilla/dom/Element.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
+#include "mozilla/dom/HTMLAreaElement.h"
 #include "mozilla/gfx/PathHelpers.h"
 #include "mozilla/UniquePtr.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsPresContext.h"
 #include "nsNameSpaceManager.h"
 #include "nsGkAtoms.h"
 #include "nsImageFrame.h"
@@ -25,43 +26,44 @@
 #include "ImageLayers.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::gfx;
+using namespace mozilla::dom;
 
 class Area {
 public:
-  explicit Area(nsIContent* aArea);
+  explicit Area(HTMLAreaElement* aArea);
   virtual ~Area();
 
   virtual void ParseCoords(const nsAString& aSpec);
 
   virtual bool IsInside(nscoord x, nscoord y) const = 0;
   virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
                     const ColorPattern& aColor,
                     const StrokeOptions& aStrokeOptions) = 0;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) = 0;
 
   void HasFocus(bool aHasFocus);
 
-  nsCOMPtr<nsIContent> mArea;
+  RefPtr<HTMLAreaElement> mArea;
   UniquePtr<nscoord[]> mCoords;
   int32_t mNumCoords;
   bool mHasFocus;
 };
 
-Area::Area(nsIContent* aArea)
+Area::Area(HTMLAreaElement* aArea)
   : mArea(aArea)
 {
   MOZ_COUNT_CTOR(Area);
-  NS_PRECONDITION(mArea, "How did that happen?");
+  MOZ_ASSERT(mArea, "How did that happen?");
   mNumCoords = 0;
   mHasFocus = false;
 }
 
 Area::~Area()
 {
   MOZ_COUNT_DTOR(Area);
 }
@@ -262,26 +264,26 @@ void Area::HasFocus(bool aHasFocus)
 {
   mHasFocus = aHasFocus;
 }
 
 //----------------------------------------------------------------------
 
 class DefaultArea : public Area {
 public:
-  explicit DefaultArea(nsIContent* aArea);
+  explicit DefaultArea(HTMLAreaElement* aArea);
 
   virtual bool IsInside(nscoord x, nscoord y) const override;
   virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
                     const ColorPattern& aColor,
                     const StrokeOptions& aStrokeOptions) override;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) override;
 };
 
-DefaultArea::DefaultArea(nsIContent* aArea)
+DefaultArea::DefaultArea(HTMLAreaElement* aArea)
   : Area(aArea)
 {
 }
 
 bool DefaultArea::IsInside(nscoord x, nscoord y) const
 {
   return true;
 }
@@ -306,27 +308,27 @@ void DefaultArea::GetRect(nsIFrame* aFra
   aRect = aFrame->GetRect();
   aRect.MoveTo(0, 0);
 }
 
 //----------------------------------------------------------------------
 
 class RectArea : public Area {
 public:
-  explicit RectArea(nsIContent* aArea);
+  explicit RectArea(HTMLAreaElement* aArea);
 
   virtual void ParseCoords(const nsAString& aSpec) override;
   virtual bool IsInside(nscoord x, nscoord y) const override;
   virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
                     const ColorPattern& aColor,
                     const StrokeOptions& aStrokeOptions) override;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) override;
 };
 
-RectArea::RectArea(nsIContent* aArea)
+RectArea::RectArea(HTMLAreaElement* aArea)
   : Area(aArea)
 {
 }
 
 void RectArea::ParseCoords(const nsAString& aSpec)
 {
   Area::ParseCoords(aSpec);
 
@@ -412,27 +414,27 @@ void RectArea::GetRect(nsIFrame* aFrame,
     aRect.SetRect(x1, y1, x2, y2);
   }
 }
 
 //----------------------------------------------------------------------
 
 class PolyArea : public Area {
 public:
-  explicit PolyArea(nsIContent* aArea);
+  explicit PolyArea(HTMLAreaElement* aArea);
 
   virtual void ParseCoords(const nsAString& aSpec) override;
   virtual bool IsInside(nscoord x, nscoord y) const override;
   virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
                     const ColorPattern& aColor,
                     const StrokeOptions& aStrokeOptions) override;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) override;
 };
 
-PolyArea::PolyArea(nsIContent* aArea)
+PolyArea::PolyArea(HTMLAreaElement* aArea)
   : Area(aArea)
 {
 }
 
 void PolyArea::ParseCoords(const nsAString& aSpec)
 {
   Area::ParseCoords(aSpec);
 
@@ -569,27 +571,27 @@ void PolyArea::GetRect(nsIFrame* aFrame,
     aRect.SetRect(x1, y1, x2, y2);
   }
 }
 
 //----------------------------------------------------------------------
 
 class CircleArea : public Area {
 public:
-  explicit CircleArea(nsIContent* aArea);
+  explicit CircleArea(HTMLAreaElement* aArea);
 
   virtual void ParseCoords(const nsAString& aSpec) override;
   virtual bool IsInside(nscoord x, nscoord y) const override;
   virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
                     const ColorPattern& aColor,
                     const StrokeOptions& aStrokeOptions) override;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) override;
 };
 
-CircleArea::CircleArea(nsIContent* aArea)
+CircleArea::CircleArea(HTMLAreaElement* aArea)
   : Area(aArea)
 {
 }
 
 void CircleArea::ParseCoords(const nsAString& aSpec)
 {
   Area::ParseCoords(aSpec);
 
@@ -742,72 +744,57 @@ nsImageMap::Init(nsImageFrame* aImageFra
   mMap = aMap;
   mMap->AddMutationObserver(this);
 
   // "Compile" the areas in the map into faster access versions
   UpdateAreas();
 }
 
 void
-nsImageMap::SearchForAreas(nsIContent* aParent, bool& aFoundArea,
-                           bool& aFoundAnchor)
+nsImageMap::SearchForAreas(nsIContent* aParent)
 {
-  uint32_t i, n = aParent->GetChildCount();
-
-  // Look for <area> or <a> elements. We'll use whichever type we find first.
-  for (i = 0; i < n; i++) {
-    nsIContent *child = aParent->GetChildAt(i);
-
-    // If we haven't determined that the map element contains an
-    // <a> element yet, then look for <area>.
-    if (!aFoundAnchor && child->IsHTMLElement(nsGkAtoms::area)) {
-      aFoundArea = true;
-      AddArea(child);
+  // Look for <area> elements.
+  for (nsIContent* child = aParent->GetFirstChild();
+       child;
+       child = child->GetNextSibling()) {
+    if (auto* area = HTMLAreaElement::FromContent(child)) {
+      AddArea(area);
 
       // Continue to next child. This stops mConsiderWholeSubtree from
       // getting set. It also makes us ignore children of <area>s which
       // is consistent with how we react to dynamic insertion of such
       // children.
       continue;
     }
 
-    // If we haven't determined that the map element contains an
-    // <area> element yet, then look for <a>.
-    if (!aFoundArea && child->IsHTMLElement(nsGkAtoms::a)) {
-      aFoundAnchor = true;
-      AddArea(child);
-    }
-
     if (child->IsElement()) {
       mConsiderWholeSubtree = true;
-      SearchForAreas(child, aFoundArea, aFoundAnchor);
+      SearchForAreas(child);
     }
   }
 }
 
 void
 nsImageMap::UpdateAreas()
 {
   // Get rid of old area data
   FreeAreas();
 
-  bool foundArea = false;
-  bool foundAnchor = false;
   mConsiderWholeSubtree = false;
+  SearchForAreas(mMap);
 
-  SearchForAreas(mMap, foundArea, foundAnchor);
 #ifdef ACCESSIBILITY
   if (nsAccessibilityService* accService = GetAccService()) {
     accService->UpdateImageMap(mImageFrame);
   }
 #endif
 }
 
 void
-nsImageMap::AddArea(nsIContent* aArea)
+nsImageMap::AddArea(HTMLAreaElement* aArea)
 {
   static nsIContent::AttrValuesArray strings[] =
     {&nsGkAtoms::rect, &nsGkAtoms::rectangle,
      &nsGkAtoms::circle, &nsGkAtoms::circ,
      &nsGkAtoms::_default,
      &nsGkAtoms::poly, &nsGkAtoms::polygon,
      nullptr};
 
--- a/layout/generic/nsImageMap.h
+++ b/layout/generic/nsImageMap.h
@@ -17,16 +17,22 @@
 #include "nsIDOMEventListener.h"
 
 class Area;
 class nsImageFrame;
 class nsIFrame;
 class nsIContent;
 struct nsRect;
 
+namespace mozilla {
+namespace dom {
+class HTMLAreaElement;
+}
+}
+
 class nsImageMap final : public nsStubMutationObserver,
                          public nsIDOMEventListener
 {
   typedef mozilla::gfx::DrawTarget DrawTarget;
   typedef mozilla::gfx::ColorPattern ColorPattern;
   typedef mozilla::gfx::StrokeOptions StrokeOptions;
 
 public:
@@ -77,21 +83,20 @@ public:
                                    nsRect& aBounds);
 
 protected:
   virtual ~nsImageMap();
 
   void FreeAreas();
 
   void UpdateAreas();
-  void SearchForAreas(nsIContent* aParent,
-                      bool& aFoundArea,
-                      bool& aFoundAnchor);
 
-  void AddArea(nsIContent* aArea);
+  void SearchForAreas(nsIContent* aParent);
+
+  void AddArea(mozilla::dom::HTMLAreaElement* aArea);
 
   void MaybeUpdateAreas(nsIContent *aContent);
 
   nsImageFrame* mImageFrame;  // the frame that owns us
   nsCOMPtr<nsIContent> mMap;
   AutoTArray<Area*, 8> mAreas; // almost always has some entries
 
   // This is set when we search for all area children and tells us whether we