Bug 1083215, part 2 - Convert drawing of HTML image map area focus to Moz2D. r=mattwoodrow
authorJonathan Watt <jwatt@jwatt.org>
Thu, 16 Oct 2014 10:51:14 +0100
changeset 210705 3874e8dcb61d7628c08f9c97553ffa23a655ab5d
parent 210704 4fa7741a7e90d98b6dae3fa114cc62103f471df4
child 210706 77f3ca1fe052ca3eced92af99221e29a7fc6c36b
child 210724 9ec96af338983dcfc96f11c5b3538674c1788f1b
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersmattwoodrow
bugs1083215
milestone36.0a1
Bug 1083215, part 2 - Convert drawing of HTML image map area focus to Moz2D. r=mattwoodrow
layout/base/nsLayoutUtils.h
layout/generic/nsImageFrame.cpp
layout/generic/nsImageMap.cpp
layout/generic/nsImageMap.h
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2,16 +2,17 @@
 /* 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/. */
 
 #ifndef nsLayoutUtils_h__
 #define nsLayoutUtils_h__
 
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/ArrayUtils.h"
 #include "nsChangeHint.h"
 #include "nsAutoPtr.h"
 #include "nsFrameList.h"
 #include "mozilla/layout/FrameChildList.h"
 #include "nsThreadUtils.h"
 #include "nsIPrincipal.h"
 #include "GraphicsFilter.h"
 #include "nsCSSPseudoElements.h"
@@ -113,19 +114,22 @@ struct DisplayPortMarginsPropertyData {
  */
 class nsLayoutUtils
 {
   typedef ::GraphicsFilter GraphicsFilter;
   typedef mozilla::dom::DOMRectList DOMRectList;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
   typedef mozilla::gfx::SourceSurface SourceSurface;
+  typedef mozilla::gfx::Color Color;
   typedef mozilla::gfx::DrawTarget DrawTarget;
+  typedef mozilla::gfx::Float Float;
   typedef mozilla::gfx::Rect Rect;
   typedef mozilla::gfx::Matrix4x4 Matrix4x4;
+  typedef mozilla::gfx::StrokeOptions StrokeOptions;
 
 public:
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef FrameMetrics::ViewID ViewID;
   typedef mozilla::CSSPoint CSSPoint;
   typedef mozilla::CSSSize CSSSize;
   typedef mozilla::LayerMargin LayerMargin;
   typedef mozilla::LayoutDeviceIntSize LayoutDeviceIntSize;
@@ -1475,16 +1479,39 @@ public:
                             imgIContainer*      aImage,
                             GraphicsFilter      aGraphicsFilter,
                             const nsRect&       aDest,
                             const nsRect&       aFill,
                             const nsPoint&      aAnchor,
                             const nsRect&       aDirty,
                             uint32_t            aImageFlags);
 
+  static inline Color NSColorToColor(nscolor aColor) {
+    return Color(NS_GET_R(aColor)/255.0,
+                 NS_GET_G(aColor)/255.0,
+                 NS_GET_B(aColor)/255.0,
+                 NS_GET_A(aColor)/255.0);
+  }
+
+  static inline void InitDashPattern(StrokeOptions& aStrokeOptions,
+                                     uint8_t aBorderStyle) {
+    if (aBorderStyle == NS_STYLE_BORDER_STYLE_DOTTED) {
+      static Float dot[] = { 1.f, 1.f };
+      aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dot);
+      aStrokeOptions.mDashPattern = dot;
+    } else if (aBorderStyle == NS_STYLE_BORDER_STYLE_DASHED) {
+      static Float dash[] = { 5.f, 5.f };
+      aStrokeOptions.mDashLength = MOZ_ARRAY_LENGTH(dash);
+      aStrokeOptions.mDashPattern = dash;
+    } else {
+      aStrokeOptions.mDashLength = 0;
+      aStrokeOptions.mDashPattern = nullptr;
+    }
+  }
+
   /**
    * Convert an nsRect to a gfxRect.
    */
   static gfxRect RectToGfxRect(const nsRect& aRect,
                                int32_t aAppUnitsPerDevPixel);
 
   static gfxPoint PointToGfxPoint(const nsPoint& aPoint,
                                   int32_t aAppUnitsPerPixel) {
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -2,18 +2,21 @@
 /* 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/. */
 
 /* rendering object for replaced elements with image data */
 
 #include "nsImageFrame.h"
 
+#include "gfx2DGlue.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EventStates.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/Helpers.h"
 #include "mozilla/MouseEvents.h"
 
 #include "nsCOMPtr.h"
 #include "nsIImageLoadingContent.h"
 #include "nsString.h"
 #include "nsPrintfCString.h"
 #include "nsPresContext.h"
 #include "nsRenderingContext.h"
@@ -65,16 +68,17 @@
 #include "nsBlockFrame.h"
 #include "nsStyleStructInlines.h"
 
 #include "mozilla/Preferences.h"
 
 #include "mozilla/dom/Link.h"
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 
 // sizes (pixels) for image icon, padding and border frame
 #define ICON_SIZE        (16)
 #define ICON_PADDING     (3)
 #define ALT_BORDER_WIDTH (1)
 
 
 //we must add hooks soon
@@ -1287,29 +1291,29 @@ nsImageFrame::DisplayAltFeedback(nsRende
     }
   }
 
   aRenderingContext.ThebesContext()->Restore();
 }
 
 #ifdef DEBUG
 static void PaintDebugImageMap(nsIFrame* aFrame, nsRenderingContext* aCtx,
-     const nsRect& aDirtyRect, nsPoint aPt) {
+                               const nsRect& aDirtyRect, nsPoint aPt)
+{
   nsImageFrame* f = static_cast<nsImageFrame*>(aFrame);
   nsRect inner = f->GetInnerArea() + aPt;
-
-  aCtx->SetColor(NS_RGB(0, 0, 0));
-  aCtx->ThebesContext()->Save();
   gfxPoint devPixelOffset =
     nsLayoutUtils::PointToGfxPoint(inner.TopLeft(),
                                    aFrame->PresContext()->AppUnitsPerDevPixel());
-  aCtx->ThebesContext()->SetMatrix(
-    aCtx->ThebesContext()->CurrentMatrix().Translate(devPixelOffset));
-  f->GetImageMap()->Draw(aFrame, *aCtx);
-  aCtx->ThebesContext()->Restore();
+  DrawTarget* drawTarget = aCtx->GetDrawTarget();
+  AutoRestoreTransform autoRestoreTransform(drawTarget);
+  drawTarget->SetTransform(
+    drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
+  f->GetImageMap()->Draw(aFrame, *drawTarget,
+                         ColorPattern(Color(0.f, 0.f, 0.f, 1.f)));
 }
 #endif
 
 void
 nsDisplayImage::Paint(nsDisplayListBuilder* aBuilder,
                       nsRenderingContext* aCtx) {
   uint32_t flags = imgIContainer::FLAG_NONE;
   if (aBuilder->ShouldSyncDecodeImages()) {
@@ -1453,42 +1457,46 @@ nsDisplayImage::ConfigureLayer(ImageLaye
   aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
 }
 
 void
 nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
                          const nsRect& aDirtyRect, imgIContainer* aImage,
                          uint32_t aFlags)
 {
+  DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
+
   // Render the image into our content area (the area inside
   // the borders and padding)
   NS_ASSERTION(GetInnerArea().width == mComputedSize.width, "bad width");
   nsRect inner = GetInnerArea() + aPt;
   nsRect dest(inner.TopLeft(), mComputedSize);
   dest.y -= GetContinuationOffset();
 
   nsLayoutUtils::DrawSingleImage(&aRenderingContext, PresContext(), aImage,
     nsLayoutUtils::GetGraphicsFilterForFrame(this), dest, aDirtyRect,
     nullptr, aFlags);
 
   nsImageMap* map = GetImageMap();
-  if (nullptr != map) {
-    aRenderingContext.ThebesContext()->Save();
+  if (map) {
     gfxPoint devPixelOffset =
       nsLayoutUtils::PointToGfxPoint(inner.TopLeft(),
                                      PresContext()->AppUnitsPerDevPixel());
-    aRenderingContext.ThebesContext()->SetMatrix(
-      aRenderingContext.ThebesContext()->CurrentMatrix().Translate(devPixelOffset));
-    aRenderingContext.SetColor(NS_RGB(255, 255, 255));
-    aRenderingContext.SetLineStyle(nsLineStyle_kSolid);
-    map->Draw(this, aRenderingContext);
-    aRenderingContext.SetColor(NS_RGB(0, 0, 0));
-    aRenderingContext.SetLineStyle(nsLineStyle_kDotted);
-    map->Draw(this, aRenderingContext);
-    aRenderingContext.ThebesContext()->Restore();
+    AutoRestoreTransform autoRestoreTransform(drawTarget);
+    drawTarget->SetTransform(
+      drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset)));
+
+    // solid white stroke:
+    map->Draw(this, *drawTarget, ColorPattern(Color(1.f, 1.f, 1.f, 1.f)));
+
+    // then dashed black stroke over the top:
+    StrokeOptions strokeOptions;
+    nsLayoutUtils::InitDashPattern(strokeOptions, NS_STYLE_BORDER_STYLE_DOTTED);
+    map->Draw(this, *drawTarget, ColorPattern(Color(0.f, 0.f, 0.f, 1.f)),
+              strokeOptions);
   }
 }
 
 void
 nsImageFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                const nsRect&           aDirtyRect,
                                const nsDisplayListSet& aLists)
 {
--- a/layout/generic/nsImageMap.cpp
+++ b/layout/generic/nsImageMap.cpp
@@ -4,16 +4,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/gfx/PathHelpers.h"
 #include "nsString.h"
 #include "nsReadableUtils.h"
 #include "nsRenderingContext.h"
 #include "nsPresContext.h"
 #include "nsNameSpaceManager.h"
 #include "nsGkAtoms.h"
 #include "nsImageFrame.h"
 #include "nsCoord.h"
@@ -21,26 +22,29 @@
 #include "nsIStringBundle.h"
 #include "nsContentUtils.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 using namespace mozilla;
+using namespace mozilla::gfx;
 
 class Area {
 public:
   explicit Area(nsIContent* aArea);
   virtual ~Area();
 
   virtual void ParseCoords(const nsAString& aSpec);
 
   virtual bool IsInside(nscoord x, nscoord y) const = 0;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) = 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;
   nscoord* mCoords;
   int32_t mNumCoords;
   bool mHasFocus;
@@ -262,45 +266,44 @@ void Area::HasFocus(bool aHasFocus)
 
 //----------------------------------------------------------------------
 
 class DefaultArea : public Area {
 public:
   explicit DefaultArea(nsIContent* aArea);
 
   virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE;
 };
 
 DefaultArea::DefaultArea(nsIContent* aArea)
   : Area(aArea)
 {
 }
 
 bool DefaultArea::IsInside(nscoord x, nscoord y) const
 {
   return true;
 }
 
-void DefaultArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+void DefaultArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                       const ColorPattern& aColor,
+                       const StrokeOptions& aStrokeOptions)
 {
   if (mHasFocus) {
-    nsRect r = aFrame->GetRect();
-    r.MoveTo(0, 0);
-    nscoord x1 = r.x;
-    nscoord y1 = r.y;
+    nsRect r(nsPoint(0, 0), aFrame->GetSize());
     const nscoord kOnePixel = nsPresContext::CSSPixelsToAppUnits(1);
-    nscoord x2 = r.XMost() - kOnePixel;
-    nscoord y2 = r.YMost() - kOnePixel;
-    // XXX aRC.DrawRect(r) result is ugly, that's why we use DrawLine.
-    aRC.DrawLine(x1, y1, x1, y2);
-    aRC.DrawLine(x1, y2, x2, y2);
-    aRC.DrawLine(x1, y1, x2, y1);
-    aRC.DrawLine(x2, y1, x2, y2);
+    r.width -= kOnePixel;
+    r.height -= kOnePixel;
+    Rect rect =
+      ToRect(nsLayoutUtils::RectToGfxRect(r, aFrame->PresContext()->AppUnitsPerDevPixel()));
+    StrokeSnappedEdgesOfRect(rect, aDrawTarget, aColor, aStrokeOptions);
   }
 }
 
 void DefaultArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
 {
   aRect = aFrame->GetRect();
   aRect.MoveTo(0, 0);
 }
@@ -308,17 +311,19 @@ void DefaultArea::GetRect(nsIFrame* aFra
 //----------------------------------------------------------------------
 
 class RectArea : public Area {
 public:
   explicit RectArea(nsIContent* aArea);
 
   virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE;
   virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE;
 };
 
 RectArea::RectArea(nsIContent* aArea)
   : Area(aArea)
 {
 }
 
@@ -370,30 +375,32 @@ bool RectArea::IsInside(nscoord x, nscoo
                  "Someone screwed up RectArea::ParseCoords");
     if ((x >= x1) && (x <= x2) && (y >= y1) && (y <= y2)) {
       return true;
     }
   }
   return false;
 }
 
-void RectArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+void RectArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions)
 {
   if (mHasFocus) {
     if (mNumCoords >= 4) {
       nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
       nscoord y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
       nscoord x2 = nsPresContext::CSSPixelsToAppUnits(mCoords[2]);
       nscoord y2 = nsPresContext::CSSPixelsToAppUnits(mCoords[3]);
       NS_ASSERTION(x1 <= x2 && y1 <= y2,
                    "Someone screwed up RectArea::ParseCoords");
-      aRC.DrawLine(x1, y1, x1, y2);
-      aRC.DrawLine(x1, y2, x2, y2);
-      aRC.DrawLine(x1, y1, x2, y1);
-      aRC.DrawLine(x2, y1, x2, y2);
+      nsRect r(x1, y1, x2 - x1, y2 - y1);
+      Rect rect =
+        ToRect(nsLayoutUtils::RectToGfxRect(r, aFrame->PresContext()->AppUnitsPerDevPixel()));
+      StrokeSnappedEdgesOfRect(rect, aDrawTarget, aColor, aStrokeOptions);
     }
   }
 }
 
 void RectArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
 {
   if (mNumCoords >= 4) {
     nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
@@ -410,17 +417,19 @@ void RectArea::GetRect(nsIFrame* aFrame,
 //----------------------------------------------------------------------
 
 class PolyArea : public Area {
 public:
   explicit PolyArea(nsIContent* aArea);
 
   virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE;
   virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE;
 };
 
 PolyArea::PolyArea(nsIContent* aArea)
   : Area(aArea)
 {
 }
 
@@ -502,33 +511,46 @@ bool PolyArea::IsInside(nscoord x, nscoo
     }
     if ((intersects & 1) != 0) {
       return true;
     }
   }
   return false;
 }
 
-void PolyArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+void PolyArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions)
 {
   if (mHasFocus) {
     if (mNumCoords >= 6) {
-      nscoord x0 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
-      nscoord y0 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
-      nscoord x1, y1;
+      // Where possible, we want all horizontal and vertical lines to align on
+      // pixel rows or columns, and to start at pixel boundaries so that one
+      // pixel dashing neatly sits on pixels to give us neat lines. To achieve
+      // that we draw each line segment as a separate path, snapping it to
+      // device pixels if applicable.
+      nsPresContext* pc = aFrame->PresContext();
+      Point p1(pc->CSSPixelsToDevPixels(mCoords[0]),
+               pc->CSSPixelsToDevPixels(mCoords[1]));
+      Point p2, p1snapped, p2snapped;
       for (int32_t i = 2; i < mNumCoords; i += 2) {
-        x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[i]);
-        y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[i+1]);
-        aRC.DrawLine(x0, y0, x1, y1);
-        x0 = x1;
-        y0 = y1;
+        p2.x = pc->CSSPixelsToDevPixels(mCoords[i]);
+        p2.y = pc->CSSPixelsToDevPixels(mCoords[i+1]);
+        p1snapped = p1;
+        p2snapped = p2;
+        SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget);
+        aDrawTarget.StrokeLine(p1snapped, p2snapped, aColor, aStrokeOptions);
+        p1 = p2;
       }
-      x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
-      y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
-      aRC.DrawLine(x0, y0, x1, y1);
+      p2.x = pc->CSSPixelsToDevPixels(mCoords[0]);
+      p2.y = pc->CSSPixelsToDevPixels(mCoords[1]);
+      p1snapped = p1;
+      p2snapped = p2;
+      SnapLineToDevicePixelsForStroking(p1snapped, p2snapped, aDrawTarget);
+      aDrawTarget.StrokeLine(p1snapped, p2snapped, aColor, aStrokeOptions);
     }
   }
 }
 
 void PolyArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
 {
   if (mNumCoords >= 6) {
     nscoord x1, x2, y1, y2, xtmp, ytmp;
@@ -550,17 +572,19 @@ void PolyArea::GetRect(nsIFrame* aFrame,
 //----------------------------------------------------------------------
 
 class CircleArea : public Area {
 public:
   explicit CircleArea(nsIContent* aArea);
 
   virtual void ParseCoords(const nsAString& aSpec) MOZ_OVERRIDE;
   virtual bool IsInside(nscoord x, nscoord y) const MOZ_OVERRIDE;
-  virtual void Draw(nsIFrame* aFrame, nsRenderingContext& aRC) MOZ_OVERRIDE;
+  virtual void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                    const ColorPattern& aColor,
+                    const StrokeOptions& aStrokeOptions) MOZ_OVERRIDE;
   virtual void GetRect(nsIFrame* aFrame, nsRect& aRect) MOZ_OVERRIDE;
 };
 
 CircleArea::CircleArea(nsIContent* aArea)
   : Area(aArea)
 {
 }
 
@@ -609,30 +633,33 @@ bool CircleArea::IsInside(nscoord x, nsc
     nscoord dist = (dx * dx) + (dy * dy);
     if (dist <= (radius * radius)) {
       return true;
     }
   }
   return false;
 }
 
-void CircleArea::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+void CircleArea::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                      const ColorPattern& aColor,
+                      const StrokeOptions& aStrokeOptions)
 {
   if (mHasFocus) {
     if (mNumCoords >= 3) {
-      nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
-      nscoord y1 = nsPresContext::CSSPixelsToAppUnits(mCoords[1]);
-      nscoord radius = nsPresContext::CSSPixelsToAppUnits(mCoords[2]);
-      if (radius < 0) {
+      Point center(aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[0]),
+                   aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[1]));
+      Float diameter =
+        2 * aFrame->PresContext()->CSSPixelsToDevPixels(mCoords[2]);
+      if (diameter <= 0) {
         return;
       }
-      nscoord x = x1 - radius;
-      nscoord y = y1 - radius;
-      nscoord w = 2 * radius;
-      aRC.DrawEllipse(x, y, w, w);
+      RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
+      AppendEllipseToPath(builder, center, Size(diameter, diameter));
+      RefPtr<Path> circle = builder->Finish();
+      aDrawTarget.Stroke(circle, aColor, aStrokeOptions);
     }
   }
 }
 
 void CircleArea::GetRect(nsIFrame* aFrame, nsRect& aRect)
 {
   if (mNumCoords >= 3) {
     nscoord x1 = nsPresContext::CSSPixelsToAppUnits(mCoords[0]);
@@ -863,22 +890,24 @@ nsImageMap::GetArea(nscoord aX, nscoord 
 
 nsIContent*
 nsImageMap::GetAreaAt(uint32_t aIndex) const
 {
   return mAreas.ElementAt(aIndex)->mArea;
 }
 
 void
-nsImageMap::Draw(nsIFrame* aFrame, nsRenderingContext& aRC)
+nsImageMap::Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+                 const ColorPattern& aColor,
+                 const StrokeOptions& aStrokeOptions)
 {
   uint32_t i, n = mAreas.Length();
   for (i = 0; i < n; i++) {
     Area* area = mAreas.ElementAt(i);
-    area->Draw(aFrame, aRC);
+    area->Draw(aFrame, aDrawTarget, aColor, aStrokeOptions);
   }
 }
 
 void
 nsImageMap::MaybeUpdateAreas(nsIContent *aContent)
 {
   if (aContent == mMap || mContainsBlockContents) {
     UpdateAreas();
--- a/layout/generic/nsImageMap.h
+++ b/layout/generic/nsImageMap.h
@@ -3,32 +3,37 @@
  * 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/. */
 
 /* code for HTML client-side image maps */
 
 #ifndef nsImageMap_h
 #define nsImageMap_h
 
+#include "mozilla/gfx/2D.h"
 #include "nsCOMPtr.h"
 #include "nsCoord.h"
 #include "nsTArray.h"
 #include "nsStubMutationObserver.h"
 #include "nsIDOMEventListener.h"
 
 class Area;
 class nsRenderingContext;
 class nsImageFrame;
 class nsIFrame;
 class nsIContent;
 struct nsRect;
 
 class nsImageMap MOZ_FINAL : public nsStubMutationObserver,
                              public nsIDOMEventListener
 {
+  typedef mozilla::gfx::DrawTarget DrawTarget;
+  typedef mozilla::gfx::ColorPattern ColorPattern;
+  typedef mozilla::gfx::StrokeOptions StrokeOptions;
+
 public:
   nsImageMap();
 
   nsresult Init(nsImageFrame* aImageFrame, nsIContent* aMap);
 
   /**
    * Return the first area element (in content order) for the given aX,aY pixel
    * coordinate or nullptr if the coordinate is outside all areas.
@@ -40,17 +45,19 @@ public:
    */
   uint32_t AreaCount() const { return mAreas.Length(); }
 
   /**
    * Return area element at the given index.
    */
   nsIContent* GetAreaAt(uint32_t aIndex) const;
 
-  void Draw(nsIFrame* aFrame, nsRenderingContext& aRC);
+  void Draw(nsIFrame* aFrame, DrawTarget& aDrawTarget,
+            const ColorPattern& aColor,
+            const StrokeOptions& aStrokeOptions = StrokeOptions());
   
   /** 
    * Called just before the nsImageFrame releases us. 
    * Used to break the cycle caused by the DOM listener.
    */
   void Destroy();
   
   // nsISupports