Backed out 2 changesets (bug 878032) because of Windows build bustage
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 19 Jun 2013 17:35:21 -0400
changeset 147198 5b3196ad66f40b7ca578461155f279fa0c6fca8e
parent 147197 72a95da7099f2c843131be85109815b54f676d07
child 147199 f0380ec657f82a13f37732d1b4c8d99d99c2ce78
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs878032
milestone24.0a1
backs out3cb61a7d57461117b4140c10c1c0cfcff5c3d0bd
627c03f469d882f08cb0d4a2c557d1e0396ea2d1
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
Backed out 2 changesets (bug 878032) because of Windows build bustage Backed out changeset 3cb61a7d5746 (bug 878032) Backed out changeset 627c03f469d8 (bug 878032) Landed on a CLOSED TREE
gfx/2d/BaseRect.h
gfx/2d/DrawTargetD2D.cpp
gfx/2d/DrawTargetD2D.h
gfx/2d/HelpersD2D.h
gfx/2d/PathD2D.cpp
gfx/2d/unittest/TestDrawTargetBase.cpp
--- a/gfx/2d/BaseRect.h
+++ b/gfx/2d/BaseRect.h
@@ -84,20 +84,20 @@ struct BaseRect {
   }
   // Returns the rectangle containing the intersection of the points
   // (including edges) of *this and aRect. If there are no points in that
   // intersection, returns an empty rectangle with x/y set to the std::max of the x/y
   // of *this and aRect.
   Sub Intersect(const Sub& aRect) const
   {
     Sub result;
-    result.x = std::max<T>(x, aRect.x);
-    result.y = std::max<T>(y, aRect.y);
-    result.width = std::min<T>(XMost(), aRect.XMost()) - result.x;
-    result.height = std::min<T>(YMost(), aRect.YMost()) - result.y;
+    result.x = std::max(x, aRect.x);
+    result.y = std::max(y, aRect.y);
+    result.width = std::min(XMost(), aRect.XMost()) - result.x;
+    result.height = std::min(YMost(), aRect.YMost()) - result.y;
     if (result.width < 0 || result.height < 0) {
       result.SizeTo(0, 0);
     }
     return result;
   }
   // Sets *this to be the rectangle containing the intersection of the points
   // (including edges) of *this and aRect. If there are no points in that
   // intersection, sets *this to be an empty rectangle with x/y set to the std::max
--- a/gfx/2d/DrawTargetD2D.cpp
+++ b/gfx/2d/DrawTargetD2D.cpp
@@ -108,17 +108,17 @@ public:
       // clipping information.
       RefPtr<ID2D1RectangleGeometry> rectGeom;
       factory()->CreateRectangleGeometry(D2D1::Rect(Float(clipBounds.x),
                                                     Float(clipBounds.y),
                                                     Float(clipBounds.XMost()),
                                                     Float(clipBounds.YMost())),
                                          byRef(rectGeom));
 
-      mClippedArea = IntersectGeometry(mClippedArea, rectGeom);
+      mClippedArea = mDT->Intersect(mClippedArea, rectGeom);
     }
   }
 
   ID2D1Factory *factory() { return mDT->factory(); }
 
   ~AutoSaveRestoreClippedOut()
   {
     if (!mOldSurfBitmap) {
@@ -157,21 +157,16 @@ private:
 
   // If we have an operator unbound by the source, this will contain a bitmap
   // with the old dest surface data.
   RefPtr<ID2D1Bitmap> mOldSurfBitmap;
   // This contains the area drawing is clipped to.
   RefPtr<ID2D1Geometry> mClippedArea;
 };
 
-ID2D1Factory *D2DFactory()
-{
-  return DrawTargetD2D::factory();
-}
-
 DrawTargetD2D::DrawTargetD2D()
   : mCurrentCachedLayer(0)
   , mClipsArePushed(false)
   , mPrivateData(nullptr)
 {
 }
 
 DrawTargetD2D::~DrawTargetD2D()
@@ -1722,16 +1717,50 @@ DrawTargetD2D::FinalizeRTForOperation(Co
   }
 
   mDevice->OMSetBlendState(GetBlendStateForOperator(aOperator), nullptr, 0xffffffff);
   
   SetScissorToRect(nullptr);
   mDevice->Draw(4, 0);
 }
 
+TemporaryRef<ID2D1Geometry>
+DrawTargetD2D::ConvertRectToGeometry(const D2D1_RECT_F& aRect)
+{
+  RefPtr<ID2D1RectangleGeometry> rectGeom;
+  factory()->CreateRectangleGeometry(&aRect, byRef(rectGeom));
+  return rectGeom.forget();
+}
+
+TemporaryRef<ID2D1Geometry>
+DrawTargetD2D::GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform)
+{
+  RefPtr<ID2D1PathGeometry> tmpGeometry;
+  factory()->CreatePathGeometry(byRef(tmpGeometry));
+  RefPtr<ID2D1GeometrySink> currentSink;
+  tmpGeometry->Open(byRef(currentSink));
+  aGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
+                      aTransform, currentSink);
+  currentSink->Close();
+  return tmpGeometry;
+}
+
+TemporaryRef<ID2D1Geometry>
+DrawTargetD2D::Intersect(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB)
+{
+  RefPtr<ID2D1PathGeometry> pathGeom;
+  factory()->CreatePathGeometry(byRef(pathGeom));
+  RefPtr<ID2D1GeometrySink> sink;
+  pathGeom->Open(byRef(sink));
+  aGeometryA->CombineWithGeometry(aGeometryB, D2D1_COMBINE_MODE_INTERSECT, nullptr, sink);
+  sink->Close();
+
+  return pathGeom;
+}
+
 static D2D1_RECT_F
 IntersectRect(const D2D1_RECT_F& aRect1, const D2D1_RECT_F& aRect2)
 {
   D2D1_RECT_F result;
   result.left = max(aRect1.left, aRect2.left);
   result.top = max(aRect1.top, aRect2.top);
   result.right = min(aRect1.right, aRect2.right);
   result.bottom = min(aRect1.bottom, aRect2.bottom);
@@ -2257,17 +2286,17 @@ DrawTargetD2D::CreateBrushForPattern(con
     default:
       {
         RefPtr<DataSourceSurface> dataSurf = pat->mSurface->GetDataSurface();
         if (!dataSurf) {
           gfxWarning() << "Invalid surface type.";
           return nullptr;
         }
 
-        bitmap = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, pat->mExtendMode, mat, mRT); 
+        bitmap = CreatePartialBitmapForSurface(dataSurf, mat, pat->mExtendMode); 
         if (!bitmap) {
           return nullptr;
         }
       }
       break;
     }
     
     mRT->CreateBitmapBrush(bitmap,
@@ -2279,16 +2308,90 @@ DrawTargetD2D::CreateBrushForPattern(con
 
     return bmBrush;
   }
 
   gfxWarning() << "Invalid pattern type detected.";
   return nullptr;
 }
 
+TemporaryRef<ID2D1StrokeStyle>
+DrawTargetD2D::CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions)
+{
+  RefPtr<ID2D1StrokeStyle> style;
+
+  D2D1_CAP_STYLE capStyle;
+  D2D1_LINE_JOIN joinStyle;
+
+  switch (aStrokeOptions.mLineCap) {
+  case CAP_BUTT:
+    capStyle = D2D1_CAP_STYLE_FLAT;
+    break;
+  case CAP_ROUND:
+    capStyle = D2D1_CAP_STYLE_ROUND;
+    break;
+  case CAP_SQUARE:
+    capStyle = D2D1_CAP_STYLE_SQUARE;
+    break;
+  }
+
+  switch (aStrokeOptions.mLineJoin) {
+  case JOIN_MITER:
+    joinStyle = D2D1_LINE_JOIN_MITER;
+    break;
+  case JOIN_MITER_OR_BEVEL:
+    joinStyle = D2D1_LINE_JOIN_MITER_OR_BEVEL;
+    break;
+  case JOIN_ROUND:
+    joinStyle = D2D1_LINE_JOIN_ROUND;
+    break;
+  case JOIN_BEVEL:
+    joinStyle = D2D1_LINE_JOIN_BEVEL;
+    break;
+  }
+
+
+  HRESULT hr;
+  if (aStrokeOptions.mDashPattern) {
+    typedef vector<Float> FloatVector;
+    // D2D "helpfully" multiplies the dash pattern by the line width.
+    // That's not what cairo does, or is what <canvas>'s dash wants.
+    // So fix the multiplication in advance.
+    Float lineWidth = aStrokeOptions.mLineWidth;
+    FloatVector dash(aStrokeOptions.mDashPattern,
+                     aStrokeOptions.mDashPattern + aStrokeOptions.mDashLength);
+    for (FloatVector::iterator it = dash.begin(); it != dash.end(); ++it) {
+      *it /= lineWidth;
+    }
+
+    hr = factory()->CreateStrokeStyle(
+      D2D1::StrokeStyleProperties(capStyle, capStyle,
+                                  capStyle, joinStyle,
+                                  aStrokeOptions.mMiterLimit,
+                                  D2D1_DASH_STYLE_CUSTOM,
+                                  aStrokeOptions.mDashOffset),
+      &dash[0], // data() is not C++98, although it's in recent gcc
+                // and VC10's STL
+      dash.size(),
+      byRef(style));
+  } else {
+    hr = factory()->CreateStrokeStyle(
+      D2D1::StrokeStyleProperties(capStyle, capStyle,
+                                  capStyle, joinStyle,
+                                  aStrokeOptions.mMiterLimit),
+      nullptr, 0, byRef(style));
+  }
+
+  if (FAILED(hr)) {
+    gfxWarning() << "Failed to create Direct2D stroke style.";
+  }
+
+  return style;
+}
+
 TemporaryRef<ID3D10Texture2D>
 DrawTargetD2D::CreateGradientTexture(const GradientStopsD2D *aStops)
 {
   CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, 4096, 1, 1, 1);
 
   std::vector<D2D1_GRADIENT_STOP> rawStops;
   rawStops.resize(aStops->mStopCollection->GetGradientStopCount());
   aStops->mStopCollection->GetGradientStops(&rawStops.front(), rawStops.size());
@@ -2416,16 +2519,141 @@ DrawTargetD2D::CreateTextureForAnalysis(
 
   if (FAILED(hr)) {
     return nullptr;
   }
 
   return tex;
 }
 
+TemporaryRef<ID2D1Bitmap>
+DrawTargetD2D::CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix &aMatrix, ExtendMode aExtendMode)
+{
+  RefPtr<ID2D1Bitmap> bitmap;
+
+  // This is where things get complicated. The source surface was
+  // created for a surface that was too large to fit in a texture.
+  // We'll need to figure out if we can work with a partial upload
+  // or downsample in software.
+
+  Matrix transform = mTransform;
+  Matrix invTransform = transform = aMatrix * transform;
+  if (!invTransform.Invert()) {
+    // Singular transform, nothing to be drawn.
+    return nullptr;
+  }
+
+  Rect rect(0, 0, Float(mSize.width), Float(mSize.height));
+
+  // Calculate the rectangle of the source mapped to our surface.
+  rect = invTransform.TransformBounds(rect);
+  rect.RoundOut();
+
+  IntSize size = aSurface->GetSize();
+
+  Rect uploadRect(0, 0, Float(size.width), Float(size.height));
+
+  // Limit the uploadRect as much as possible without supporting discontiguous uploads 
+  //
+  //                               region we will paint from
+  //   uploadRect
+  //   .---------------.              .---------------.         resulting uploadRect
+  //   |               |rect          |               |
+  //   |          .---------.         .----.     .----.          .---------------.
+  //   |          |         |  ---->  |    |     |    |   ---->  |               |
+  //   |          '---------'         '----'     '----'          '---------------'
+  //   '---------------'              '---------------'
+  //
+  //
+
+  if (uploadRect.Contains(rect)) {
+    // Extend mode is irrelevant, the displayed rect is completely contained
+    // by the source bitmap.
+    uploadRect = rect;
+  } else if (aExtendMode == EXTEND_CLAMP && uploadRect.Intersects(rect)) {
+    // Calculate the rectangle on the source bitmap that touches our
+    // surface, and upload that, for EXTEND_CLAMP we can actually guarantee
+    // correct behaviour in this case.
+    uploadRect = uploadRect.Intersect(rect);
+
+    // We now proceed to check if we can limit at least one dimension of the
+    // upload rect safely without looking at extend mode.
+  } else if (rect.x >= 0 && rect.XMost() < size.width) {
+    uploadRect.x = rect.x;
+    uploadRect.width = rect.width;
+  } else if (rect.y >= 0 && rect.YMost() < size.height) {
+    uploadRect.y = rect.y;
+    uploadRect.height = rect.height;
+  }
+
+
+  int stride = aSurface->Stride();
+
+  if (uploadRect.width <= mRT->GetMaximumBitmapSize() &&
+      uploadRect.height <= mRT->GetMaximumBitmapSize()) {
+
+    // A partial upload will suffice.
+    mRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)),
+                      aSurface->GetData() + int(uploadRect.x) * 4 + int(uploadRect.y) * stride,
+                      stride,
+                      D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())),
+                      byRef(bitmap));
+
+    aMatrix.Translate(uploadRect.x, uploadRect.y);
+
+    return bitmap;
+  } else {
+    int Bpp = BytesPerPixel(aSurface->GetFormat());
+
+    if (Bpp != 4) {
+      // This shouldn't actually happen in practice!
+      MOZ_ASSERT(false);
+      return nullptr;
+    }
+
+    ImageHalfScaler scaler(aSurface->GetData(), stride, size);
+
+    // Calculate the maximum width/height of the image post transform.
+    Point topRight = transform * Point(Float(size.width), 0);
+    Point topLeft = transform * Point(0, 0);
+    Point bottomRight = transform * Point(Float(size.width), Float(size.height));
+    Point bottomLeft = transform * Point(0, Float(size.height));
+    
+    IntSize scaleSize;
+
+    scaleSize.width = int32_t(max(Distance(topRight, topLeft),
+                                  Distance(bottomRight, bottomLeft)));
+    scaleSize.height = int32_t(max(Distance(topRight, bottomRight),
+                                   Distance(topLeft, bottomLeft)));
+
+    if (unsigned(scaleSize.width) > mRT->GetMaximumBitmapSize()) {
+      // Ok, in this case we'd really want a downscale of a part of the bitmap,
+      // perhaps we can do this later but for simplicity let's do something
+      // different here and assume it's good enough, this should be rare!
+      scaleSize.width = 4095;
+    }
+    if (unsigned(scaleSize.height) > mRT->GetMaximumBitmapSize()) {
+      scaleSize.height = 4095;
+    }
+
+    scaler.ScaleForSize(scaleSize);
+
+    IntSize newSize = scaler.GetSize();
+    
+    mRT->CreateBitmap(D2D1::SizeU(newSize.width, newSize.height),
+                      scaler.GetScaledData(), scaler.GetStride(),
+                      D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())),
+                      byRef(bitmap));
+
+    aMatrix.Scale(Float(size.width / newSize.width),
+                  Float(size.height / newSize.height));
+    return bitmap;
+  }
+}
+
 void
 DrawTargetD2D::SetupEffectForRadialGradient(const RadialGradientPattern *aPattern)
 {
   mPrivateData->mEffect->GetTechniqueByName("SampleRadialGradient")->GetPassByIndex(0)->Apply(0);
   mPrivateData->mEffect->GetVariableByName("MaskTexCoords")->AsVector()->
     SetFloatVector(ShaderConstantRectD3D10(0, 0, 1.0f, 1.0f));
 
   float dimensions[] = { float(mSize.width), float(mSize.height), 0, 0 };
--- a/gfx/2d/DrawTargetD2D.h
+++ b/gfx/2d/DrawTargetD2D.h
@@ -129,16 +129,17 @@ public:
   bool Init(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
   bool InitD3D10Data();
   uint32_t GetByteSize() const;
   TemporaryRef<ID2D1Layer> GetCachedLayer();
   void PopCachedLayer(ID2D1RenderTarget *aRT);
 
   static ID2D1Factory *factory();
   static void CleanupD2D();
+  static TemporaryRef<ID2D1StrokeStyle> CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions);
   static IDWriteFactory *GetDWriteFactory();
 
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetD2D(" << this << ")";
     return stream.str();
   }
 
@@ -186,28 +187,37 @@ private:
 
   bool FillGlyphsManual(ScaledFontDWrite *aFont,
                         const GlyphBuffer &aBuffer,
                         const Color &aColor,
                         IDWriteRenderingParams *aParams,
                         const DrawOptions &aOptions = DrawOptions());
 
   TemporaryRef<ID2D1RenderTarget> CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aFormat);
+  TemporaryRef<ID2D1Geometry> ConvertRectToGeometry(const D2D1_RECT_F& aRect);
+  TemporaryRef<ID2D1Geometry> GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform);
+  TemporaryRef<ID2D1Geometry> Intersect(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB);
 
   // This returns the clipped geometry, in addition it returns aClipBounds which
   // represents the intersection of all pixel-aligned rectangular clips that
   // are currently set. The returned clipped geometry must be clipped by these
   // bounds to correctly reflect the total clip. This is in device space.
   TemporaryRef<ID2D1Geometry> GetClippedGeometry(IntRect *aClipBounds);
 
   TemporaryRef<ID2D1Brush> CreateBrushForPattern(const Pattern &aPattern, Float aAlpha = 1.0f);
 
   TemporaryRef<ID3D10Texture2D> CreateGradientTexture(const GradientStopsD2D *aStops);
   TemporaryRef<ID3D10Texture2D> CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, const IntRect &aBounds);
 
+  // This creates a (partially) uploaded bitmap for a DataSourceSurface. It
+  // uploads the minimum requirement and possibly downscales. It adjusts the
+  // input Matrix to compensate.
+  TemporaryRef<ID2D1Bitmap> CreatePartialBitmapForSurface(DataSourceSurface *aSurface, Matrix &aMatrix,
+                                                          ExtendMode aExtendMode);
+
   void SetupEffectForRadialGradient(const RadialGradientPattern *aPattern);
   void SetupStateForRendering();
 
   // Set the scissor rect to a certain IntRects, resets the scissor rect to
   // surface bounds when NULL is specified.
   void SetScissorToRect(IntRect *aRect);
 
   void PushD2DLayer(ID2D1RenderTarget *aRT, ID2D1Geometry *aGeometry, ID2D1Layer *aLayer, const D2D1_MATRIX_3X2_F &aTransform);
--- a/gfx/2d/HelpersD2D.h
+++ b/gfx/2d/HelpersD2D.h
@@ -3,31 +3,24 @@
  * 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 MOZILLA_GFX_HELPERSD2D_H_
 #define MOZILLA_GFX_HELPERSD2D_H_
 
 #include "moz-d2d1-1.h"
 
-#include <vector>
-
 #include <dwrite.h>
 #include "2D.h"
-#include "Logging.h"
-#include "Tools.h"
-#include "ImageScaling.h"
 
 #include "ScaledFontDWrite.h"
 
 namespace mozilla {
 namespace gfx {
 
-ID2D1Factory* D2DFactory();
-
 static inline D2D1_POINT_2F D2DPoint(const Point &aPoint)
 {
   return D2D1::Point2F(aPoint.x, aPoint.y);
 }
 
 static inline D2D1_SIZE_U D2DIntSize(const IntSize &aSize)
 {
   return D2D1::SizeU(aSize.width, aSize.height);
@@ -250,250 +243,12 @@ DWriteGlyphRunFromGlyphs(const GlyphBuff
     
   run->bidiLevel = 0;
   run->fontFace = aFont->mFontFace;
   run->fontEmSize = aFont->GetSize();
   run->glyphCount = aGlyphs.mNumGlyphs;
   run->isSideways = FALSE;
 }
 
-static TemporaryRef<ID2D1Geometry>
-ConvertRectToGeometry(const D2D1_RECT_F& aRect)
-{
-  RefPtr<ID2D1RectangleGeometry> rectGeom;
-  D2DFactory()->CreateRectangleGeometry(&aRect, byRef(rectGeom));
-  return rectGeom.forget();
-}
-
-static TemporaryRef<ID2D1Geometry>
-GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTransform)
-{
-  RefPtr<ID2D1PathGeometry> tmpGeometry;
-  D2DFactory()->CreatePathGeometry(byRef(tmpGeometry));
-  RefPtr<ID2D1GeometrySink> currentSink;
-  tmpGeometry->Open(byRef(currentSink));
-  aGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
-                      aTransform, currentSink);
-  currentSink->Close();
-  return tmpGeometry;
-}
-
-static TemporaryRef<ID2D1Geometry>
-IntersectGeometry(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB)
-{
-  RefPtr<ID2D1PathGeometry> pathGeom;
-  D2DFactory()->CreatePathGeometry(byRef(pathGeom));
-  RefPtr<ID2D1GeometrySink> sink;
-  pathGeom->Open(byRef(sink));
-  aGeometryA->CombineWithGeometry(aGeometryB, D2D1_COMBINE_MODE_INTERSECT, nullptr, sink);
-  sink->Close();
-
-  return pathGeom;
-}
-
-static TemporaryRef<ID2D1StrokeStyle>
-CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions)
-{
-  RefPtr<ID2D1StrokeStyle> style;
-
-  D2D1_CAP_STYLE capStyle;
-  D2D1_LINE_JOIN joinStyle;
-
-  switch (aStrokeOptions.mLineCap) {
-  case CAP_BUTT:
-    capStyle = D2D1_CAP_STYLE_FLAT;
-    break;
-  case CAP_ROUND:
-    capStyle = D2D1_CAP_STYLE_ROUND;
-    break;
-  case CAP_SQUARE:
-    capStyle = D2D1_CAP_STYLE_SQUARE;
-    break;
-  }
-
-  switch (aStrokeOptions.mLineJoin) {
-  case JOIN_MITER:
-    joinStyle = D2D1_LINE_JOIN_MITER;
-    break;
-  case JOIN_MITER_OR_BEVEL:
-    joinStyle = D2D1_LINE_JOIN_MITER_OR_BEVEL;
-    break;
-  case JOIN_ROUND:
-    joinStyle = D2D1_LINE_JOIN_ROUND;
-    break;
-  case JOIN_BEVEL:
-    joinStyle = D2D1_LINE_JOIN_BEVEL;
-    break;
-  }
-
-
-  HRESULT hr;
-  if (aStrokeOptions.mDashPattern) {
-    typedef std::vector<Float> FloatVector;
-    // D2D "helpfully" multiplies the dash pattern by the line width.
-    // That's not what cairo does, or is what <canvas>'s dash wants.
-    // So fix the multiplication in advance.
-    Float lineWidth = aStrokeOptions.mLineWidth;
-    FloatVector dash(aStrokeOptions.mDashPattern,
-                     aStrokeOptions.mDashPattern + aStrokeOptions.mDashLength);
-    for (FloatVector::iterator it = dash.begin(); it != dash.end(); ++it) {
-      *it /= lineWidth;
-    }
-
-    hr = D2DFactory()->CreateStrokeStyle(
-      D2D1::StrokeStyleProperties(capStyle, capStyle,
-                                  capStyle, joinStyle,
-                                  aStrokeOptions.mMiterLimit,
-                                  D2D1_DASH_STYLE_CUSTOM,
-                                  aStrokeOptions.mDashOffset),
-      &dash[0], // data() is not C++98, although it's in recent gcc
-                // and VC10's STL
-      dash.size(),
-      byRef(style));
-  } else {
-    hr = D2DFactory()->CreateStrokeStyle(
-      D2D1::StrokeStyleProperties(capStyle, capStyle,
-                                  capStyle, joinStyle,
-                                  aStrokeOptions.mMiterLimit),
-      nullptr, 0, byRef(style));
-  }
-
-  if (FAILED(hr)) {
-    gfxWarning() << "Failed to create Direct2D stroke style.";
-  }
-
-  return style;
-}
-
-// This creates a (partially) uploaded bitmap for a DataSourceSurface. It
-// uploads the minimum requirement and possibly downscales. It adjusts the
-// input Matrix to compensate.
-static TemporaryRef<ID2D1Bitmap>
-CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestinationTransform,
-                              const IntSize &aDestinationSize, ExtendMode aExtendMode,
-                              Matrix &aSourceTransform, ID2D1RenderTarget *aRT)
-{
-  RefPtr<ID2D1Bitmap> bitmap;
-
-  // This is where things get complicated. The source surface was
-  // created for a surface that was too large to fit in a texture.
-  // We'll need to figure out if we can work with a partial upload
-  // or downsample in software.
-
-  Matrix transform = aDestinationTransform;
-  Matrix invTransform = transform = aSourceTransform * transform;
-  if (!invTransform.Invert()) {
-    // Singular transform, nothing to be drawn.
-    return nullptr;
-  }
-
-  Rect rect(0, 0, Float(aDestinationSize.width), Float(aDestinationSize.height));
-
-  // Calculate the rectangle of the source mapped to our surface.
-  rect = invTransform.TransformBounds(rect);
-  rect.RoundOut();
-
-  IntSize size = aSurface->GetSize();
-
-  Rect uploadRect(0, 0, Float(size.width), Float(size.height));
-
-  // Limit the uploadRect as much as possible without supporting discontiguous uploads 
-  //
-  //                               region we will paint from
-  //   uploadRect
-  //   .---------------.              .---------------.         resulting uploadRect
-  //   |               |rect          |               |
-  //   |          .---------.         .----.     .----.          .---------------.
-  //   |          |         |  ---->  |    |     |    |   ---->  |               |
-  //   |          '---------'         '----'     '----'          '---------------'
-  //   '---------------'              '---------------'
-  //
-  //
-
-  if (uploadRect.Contains(rect)) {
-    // Extend mode is irrelevant, the displayed rect is completely contained
-    // by the source bitmap.
-    uploadRect = rect;
-  } else if (aExtendMode == EXTEND_CLAMP && uploadRect.Intersects(rect)) {
-    // Calculate the rectangle on the source bitmap that touches our
-    // surface, and upload that, for EXTEND_CLAMP we can actually guarantee
-    // correct behaviour in this case.
-    uploadRect = uploadRect.Intersect(rect);
-
-    // We now proceed to check if we can limit at least one dimension of the
-    // upload rect safely without looking at extend mode.
-  } else if (rect.x >= 0 && rect.XMost() < size.width) {
-    uploadRect.x = rect.x;
-    uploadRect.width = rect.width;
-  } else if (rect.y >= 0 && rect.YMost() < size.height) {
-    uploadRect.y = rect.y;
-    uploadRect.height = rect.height;
-  }
-
-
-  int stride = aSurface->Stride();
-
-  if (uploadRect.width <= aRT->GetMaximumBitmapSize() &&
-      uploadRect.height <= aRT->GetMaximumBitmapSize()) {
-
-    // A partial upload will suffice.
-    aRT->CreateBitmap(D2D1::SizeU(uint32_t(uploadRect.width), uint32_t(uploadRect.height)),
-                      aSurface->GetData() + int(uploadRect.x) * 4 + int(uploadRect.y) * stride,
-                      stride,
-                      D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())),
-                      byRef(bitmap));
-
-    aSourceTransform.Translate(uploadRect.x, uploadRect.y);
-
-    return bitmap;
-  } else {
-    int Bpp = BytesPerPixel(aSurface->GetFormat());
-
-    if (Bpp != 4) {
-      // This shouldn't actually happen in practice!
-      MOZ_ASSERT(false);
-      return nullptr;
-    }
-
-    ImageHalfScaler scaler(aSurface->GetData(), stride, size);
-
-    // Calculate the maximum width/height of the image post transform.
-    Point topRight = transform * Point(Float(size.width), 0);
-    Point topLeft = transform * Point(0, 0);
-    Point bottomRight = transform * Point(Float(size.width), Float(size.height));
-    Point bottomLeft = transform * Point(0, Float(size.height));
-    
-    IntSize scaleSize;
-
-    scaleSize.width = int32_t(max(Distance(topRight, topLeft),
-                                  Distance(bottomRight, bottomLeft)));
-    scaleSize.height = int32_t(max(Distance(topRight, bottomRight),
-                                   Distance(topLeft, bottomLeft)));
-
-    if (unsigned(scaleSize.width) > aRT->GetMaximumBitmapSize()) {
-      // Ok, in this case we'd really want a downscale of a part of the bitmap,
-      // perhaps we can do this later but for simplicity let's do something
-      // different here and assume it's good enough, this should be rare!
-      scaleSize.width = 4095;
-    }
-    if (unsigned(scaleSize.height) > aRT->GetMaximumBitmapSize()) {
-      scaleSize.height = 4095;
-    }
-
-    scaler.ScaleForSize(scaleSize);
-
-    IntSize newSize = scaler.GetSize();
-    
-    aRT->CreateBitmap(D2D1::SizeU(newSize.width, newSize.height),
-                      scaler.GetScaledData(), scaler.GetStride(),
-                      D2D1::BitmapProperties(D2DPixelFormat(aSurface->GetFormat())),
-                      byRef(bitmap));
-
-    aSourceTransform.Scale(Float(size.width / newSize.width),
-                           Float(size.height / newSize.height));
-    return bitmap;
-  }
-}
-
 }
 }
 
 #endif /* MOZILLA_GFX_HELPERSD2D_H_ */
--- a/gfx/2d/PathD2D.cpp
+++ b/gfx/2d/PathD2D.cpp
@@ -309,17 +309,18 @@ PathD2D::ContainsPoint(const Point &aPoi
 
 bool
 PathD2D::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
                              const Point &aPoint,
                              const Matrix &aTransform) const
 {
   BOOL result;
 
-  RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
+  RefPtr<ID2D1StrokeStyle> strokeStyle =
+    DrawTargetD2D::CreateStrokeStyleForOptions(aStrokeOptions);
   HRESULT hr = mGeometry->StrokeContainsPoint(D2DPoint(aPoint),
                                               aStrokeOptions.mLineWidth,
                                               strokeStyle,
                                               D2DMatrix(aTransform),
                                               &result);
 
   if (FAILED(hr)) {
     // Log
@@ -345,17 +346,18 @@ PathD2D::GetBounds(const Matrix &aTransf
 }
 
 Rect
 PathD2D::GetStrokedBounds(const StrokeOptions &aStrokeOptions,
                           const Matrix &aTransform) const
 {
   D2D1_RECT_F bounds;
 
-  RefPtr<ID2D1StrokeStyle> strokeStyle = CreateStrokeStyleForOptions(aStrokeOptions);
+  RefPtr<ID2D1StrokeStyle> strokeStyle =
+    DrawTargetD2D::CreateStrokeStyleForOptions(aStrokeOptions);
   HRESULT hr =
     mGeometry->GetWidenedBounds(aStrokeOptions.mLineWidth, strokeStyle,
                                 D2DMatrix(aTransform), &bounds);
 
   if (FAILED(hr)) {
     gfxWarning() << "Failed to get stroked bounds for path. Code: " << hr;
     bounds.bottom = bounds.left = bounds.right = bounds.top = 0;
   }
--- a/gfx/2d/unittest/TestDrawTargetBase.cpp
+++ b/gfx/2d/unittest/TestDrawTargetBase.cpp
@@ -1,109 +1,109 @@
 /* -*- Mode: C++; tab-width: 20; 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 "TestDrawTargetBase.h"
-#include <sstream>
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace std;
-
-TestDrawTargetBase::TestDrawTargetBase()
-{
-  REGISTER_TEST(TestDrawTargetBase, Initialized);
-  REGISTER_TEST(TestDrawTargetBase, FillCompletely);
-  REGISTER_TEST(TestDrawTargetBase, FillRect);
-}
-
-void
-TestDrawTargetBase::Initialized()
-{
-  VERIFY(mDT);
-}
-
-void
-TestDrawTargetBase::FillCompletely()
-{
-  mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f)));
-
-  RefreshSnapshot();
-
-  VerifyAllPixels(Color(0, 0.5f, 0, 1.0f));
-}
-
-void
-TestDrawTargetBase::FillRect()
-{
-  mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f)));
-  mDT->FillRect(Rect(50, 50, 50, 50), ColorPattern(Color(0.5f, 0, 0, 1.0f)));
-
-  RefreshSnapshot();
-
-  VerifyPixel(IntPoint(49, 49), Color(0, 0.5f, 0, 1.0f));
-  VerifyPixel(IntPoint(50, 50), Color(0.5f, 0, 0, 1.0f));
-  VerifyPixel(IntPoint(99, 99), Color(0.5f, 0, 0, 1.0f));
-  VerifyPixel(IntPoint(100, 100), Color(0, 0.5f, 0, 1.0f));
-}
-
-void
-TestDrawTargetBase::RefreshSnapshot()
-{
-  RefPtr<SourceSurface> snapshot = mDT->Snapshot();
-  mDataSnapshot = snapshot->GetDataSurface();
-}
-
-void
-TestDrawTargetBase::VerifyAllPixels(const Color &aColor)
-{
-  uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData();
-
-  uint32_t expected = RGBAPixelFromColor(aColor);
-
-  for (int y = 0; y < DT_HEIGHT; y++) {
-    for (int x = 0; x < DT_WIDTH; x++) {
-      if (colVal[y * (mDataSnapshot->Stride() / 4) + x] != expected) {
-        LogMessage("VerifyAllPixels Failed\n");
-        mTestFailed = true;
-        return;
-      }
-    }
-  }
-}
-
-void
-TestDrawTargetBase::VerifyPixel(const IntPoint &aPoint, mozilla::gfx::Color &aColor)
-{
-  uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData();
-
-  uint32_t expected = RGBAPixelFromColor(aColor);
-  uint32_t rawActual = colVal[aPoint.y * (mDataSnapshot->Stride() / 4) + aPoint.x];
-
-  if (rawActual != expected) {
-    stringstream message;
-    uint32_t actb = rawActual & 0xFF;
-    uint32_t actg = (rawActual & 0xFF00) >> 8;
-    uint32_t actr = (rawActual & 0xFF0000) >> 16;
-    uint32_t acta = (rawActual & 0xFF000000) >> 24;
-    uint32_t expb = expected & 0xFF;
-    uint32_t expg = (expected & 0xFF00) >> 8;
-    uint32_t expr = (expected & 0xFF0000) >> 16;
-    uint32_t expa = (expected & 0xFF000000) >> 24;
-
-    message << "Verify Pixel (" << aPoint.x << "x" << aPoint.y << ") Failed."
-      " Expected (" << expr << "," << expg << "," << expb << "," << expa << ") "
-      " Got (" << actr << "," << actg << "," << actb << "," << acta << ")\n";
-
-    LogMessage(message.str());
-    mTestFailed = true;
-    return;
-  }
-}
-
-uint32_t
-TestDrawTargetBase::RGBAPixelFromColor(const Color &aColor)
-{
-  return uint8_t((aColor.b * 255) + 0.5f) | uint8_t((aColor.g * 255) + 0.5f) << 8 |
-         uint8_t((aColor.r * 255) + 0.5f) << 16 | uint8_t((aColor.a * 255) + 0.5f) << 24;
-}
+
+#include "TestDrawTargetBase.h"
+#include <sstream>
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace std;
+
+TestDrawTargetBase::TestDrawTargetBase()
+{
+  REGISTER_TEST(TestDrawTargetBase, Initialized);
+  REGISTER_TEST(TestDrawTargetBase, FillCompletely);
+  REGISTER_TEST(TestDrawTargetBase, FillRect);
+}
+
+void
+TestDrawTargetBase::Initialized()
+{
+  VERIFY(mDT);
+}
+
+void
+TestDrawTargetBase::FillCompletely()
+{
+  mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f)));
+
+  RefreshSnapshot();
+
+  VerifyAllPixels(Color(0, 0.5f, 0, 1.0f));
+}
+
+void
+TestDrawTargetBase::FillRect()
+{
+  mDT->FillRect(Rect(0, 0, DT_WIDTH, DT_HEIGHT), ColorPattern(Color(0, 0.5f, 0, 1.0f)));
+  mDT->FillRect(Rect(50, 50, 50, 50), ColorPattern(Color(0.5f, 0, 0, 1.0f)));
+
+  RefreshSnapshot();
+
+  VerifyPixel(IntPoint(49, 49), Color(0, 0.5f, 0, 1.0f));
+  VerifyPixel(IntPoint(50, 50), Color(0.5f, 0, 0, 1.0f));
+  VerifyPixel(IntPoint(99, 99), Color(0.5f, 0, 0, 1.0f));
+  VerifyPixel(IntPoint(100, 100), Color(0, 0.5f, 0, 1.0f));
+}
+
+void
+TestDrawTargetBase::RefreshSnapshot()
+{
+  RefPtr<SourceSurface> snapshot = mDT->Snapshot();
+  mDataSnapshot = snapshot->GetDataSurface();
+}
+
+void
+TestDrawTargetBase::VerifyAllPixels(const Color &aColor)
+{
+  uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData();
+
+  uint32_t expected = RGBAPixelFromColor(aColor);
+
+  for (int y = 0; y < DT_HEIGHT; y++) {
+    for (int x = 0; x < DT_WIDTH; x++) {
+      if (colVal[y * (mDataSnapshot->Stride() / 4) + x] != expected) {
+        LogMessage("VerifyAllPixels Failed\n");
+        mTestFailed = true;
+        return;
+      }
+    }
+  }
+}
+
+void
+TestDrawTargetBase::VerifyPixel(const IntPoint &aPoint, mozilla::gfx::Color &aColor)
+{
+  uint32_t *colVal = (uint32_t*)mDataSnapshot->GetData();
+
+  uint32_t expected = RGBAPixelFromColor(aColor);
+  uint32_t rawActual = colVal[aPoint.y * (mDataSnapshot->Stride() / 4) + aPoint.x];
+
+  if (rawActual != expected) {
+    stringstream message;
+    uint32_t actb = rawActual & 0xFF;
+    uint32_t actg = (rawActual & 0xFF00) >> 8;
+    uint32_t actr = (rawActual & 0xFF0000) >> 16;
+    uint32_t acta = (rawActual & 0xFF000000) >> 24;
+    uint32_t expb = expected & 0xFF;
+    uint32_t expg = (expected & 0xFF00) >> 8;
+    uint32_t expr = (expected & 0xFF0000) >> 16;
+    uint32_t expa = (expected & 0xFF000000) >> 24;
+
+    message << "Verify Pixel (" << aPoint.x << "x" << aPoint.y << ") Failed."
+      " Expected (" << expr << "," << expg << "," << expb << "," << expa << ") "
+      " Got (" << actr << "," << actg << "," << actb << "," << acta << ")\n";
+
+    LogMessage(message.str());
+    mTestFailed = true;
+    return;
+  }
+}
+
+uint32_t
+TestDrawTargetBase::RGBAPixelFromColor(const Color &aColor)
+{
+  return uint8_t((aColor.b * 255) + 0.5f) | uint8_t((aColor.g * 255) + 0.5f) << 8 |
+         uint8_t((aColor.r * 255) + 0.5f) << 16 | uint8_t((aColor.a * 255) + 0.5f) << 24;
+}