Bug 716802 - Implement new 2D API functions. r=gwright
authorMatt Woodrow <mwoodrow@mozilla.com>
Thu, 19 Jan 2012 17:48:33 +1300
changeset 86086 e190ab5f22406055898c48248a2b6c671a839ada
parent 86085 79b026da30f0a730b0afeec8a8e2fcca53dc306b
child 86087 be4ed2c8f4461406f58939a1b7c08423f09d2fa8
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgwright
bugs716802
milestone12.0a1
Bug 716802 - Implement new 2D API functions. r=gwright
gfx/2d/DrawTargetSkia.cpp
gfx/2d/DrawTargetSkia.h
--- a/gfx/2d/DrawTargetSkia.cpp
+++ b/gfx/2d/DrawTargetSkia.cpp
@@ -60,18 +60,19 @@ SkColor ColorToSkColor(const Color &colo
 {
   //XXX: do a better job converting to int
   return SkColorSetARGB(color.a*aAlpha*255.0, color.r*255.0, color.g*255.0, color.b*255.0);
 }
 
 class GradientStopsSkia : public GradientStops
 {
 public:
-  GradientStopsSkia(const std::vector<GradientStop>& aStops, uint32_t aNumStops)
+  GradientStopsSkia(const std::vector<GradientStop>& aStops, uint32_t aNumStops, ExtendMode aExtendMode)
     : mCount(aNumStops)
+    , mExtendMode(aExtendMode)
   {
     if (mCount == 0) {
       return;
     }
 
     // Skia gradients always require a stop at 0.0 and 1.0, insert these if
     // we don't have them.
     uint32_t shift = 0;
@@ -98,16 +99,17 @@ public:
     }
   }
 
   BackendType GetBackendType() const { return BACKEND_SKIA; }
 
   std::vector<SkColor> mColors;
   std::vector<SkScalar> mPositions;
   int mCount;
+  ExtendMode mExtendMode;
 };
 
 SkXfermode::Mode
 GfxOpToSkiaOp(CompositionOp op)
 {
   switch (op)
   {
     case OP_OVER:
@@ -203,22 +205,99 @@ ExtendModeToTileMode(ExtendMode aMode)
     case EXTEND_REPEAT:
       return SkShader::kRepeat_TileMode;
     case EXTEND_REFLECT:
       return SkShader::kMirror_TileMode;
   }
   return SkShader::kClamp_TileMode;
 }
 
+void SetPaintPattern(SkPaint& aPaint, const Pattern& aPattern, Float aAlpha = 1.0)
+{
+  switch (aPattern.GetType()) {
+    case PATTERN_COLOR: {
+      Color color = static_cast<const ColorPattern&>(aPattern).mColor;
+      aPaint.setColor(ColorToSkColor(color, aAlpha));
+      break;
+    }
+    case PATTERN_LINEAR_GRADIENT: {
+      const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
+      GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
+      SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode);
+
+      if (stops->mCount >= 2) {
+        SkPoint points[2];
+        points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y));
+        points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y));
+
+        SkShader* shader = SkGradientShader::CreateLinear(points, 
+                                                          &stops->mColors.front(), 
+                                                          &stops->mPositions.front(), 
+                                                          stops->mCount, 
+                                                          mode);
+        SkMatrix mat;
+        GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
+        shader->setLocalMatrix(mat);
+        SkSafeUnref(aPaint.setShader(shader));
+      } else {
+        aPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
+      }
+      break;
+    }
+    case PATTERN_RADIAL_GRADIENT: {
+      const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern);
+      GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
+      SkShader::TileMode mode = ExtendModeToTileMode(stops->mExtendMode);
+
+      if (stops->mCount >= 2) {
+        SkPoint points[2];
+        points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y));
+        points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y));
+
+        SkShader* shader = SkGradientShader::CreateTwoPointRadial(points[0], 
+                                                                  SkFloatToScalar(pat.mRadius1),
+                                                                  points[1], 
+                                                                  SkFloatToScalar(pat.mRadius2),
+                                                                  &stops->mColors.front(), 
+                                                                  &stops->mPositions.front(), 
+                                                                  stops->mCount, 
+                                                                  mode);
+        SkMatrix mat;
+        GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
+        shader->setLocalMatrix(mat);
+        SkSafeUnref(aPaint.setShader(shader));
+      } else {
+        aPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
+      }
+      break;
+    }
+    case PATTERN_SURFACE: {
+      const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
+      const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(pat.mSurface.get())->GetBitmap();
+
+      SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode);
+      SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode);
+      SkMatrix mat;
+      GfxMatrixToSkiaMatrix(pat.mMatrix, mat);
+      shader->setLocalMatrix(mat);
+      SkSafeUnref(aPaint.setShader(shader));
+      if (pat.mFilter == FILTER_POINT) {
+        aPaint.setFilterBitmap(false);
+      }
+      break;
+    }
+  }
+}
+
 struct AutoPaintSetup {
   AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions, const Pattern& aPattern)
     : mNeedsRestore(false), mAlpha(1.0)
   {
     Init(aCanvas, aOptions);
-    SetPattern(aPattern);
+    SetPaintPattern(mPaint, aPattern, mAlpha);
   }
 
   AutoPaintSetup(SkCanvas *aCanvas, const DrawOptions& aOptions)
     : mNeedsRestore(false), mAlpha(1.0)
   {
     Init(aCanvas, aOptions);
   }
 
@@ -256,70 +335,16 @@ struct AutoPaintSetup {
       mNeedsRestore = true;
     } else {
       mPaint.setAlpha(aOptions.mAlpha*255.0);
       mAlpha = aOptions.mAlpha;
     }
     mPaint.setFilterBitmap(true);
   }
 
-  void SetPattern(const Pattern& aPattern)
-  {
-    if (aPattern.GetType() == PATTERN_COLOR) {
-      Color color = static_cast<const ColorPattern&>(aPattern).mColor;
-      mPaint.setColor(ColorToSkColor(color, mAlpha));
-    } else if (aPattern.GetType() == PATTERN_LINEAR_GRADIENT) {
-      const LinearGradientPattern& pat = static_cast<const LinearGradientPattern&>(aPattern);
-      GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
-
-      if (stops->mCount >= 2) {
-        SkPoint points[2];
-        points[0] = SkPoint::Make(SkFloatToScalar(pat.mBegin.x), SkFloatToScalar(pat.mBegin.y));
-        points[1] = SkPoint::Make(SkFloatToScalar(pat.mEnd.x), SkFloatToScalar(pat.mEnd.y));
-
-        SkShader* shader = SkGradientShader::CreateLinear(points, 
-                                                          &stops->mColors.front(), 
-                                                          &stops->mPositions.front(), 
-                                                          stops->mCount, 
-                                                          SkShader::kClamp_TileMode);
-        SkSafeUnref(mPaint.setShader(shader));
-      } else {
-        mPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
-      }
-    } else if (aPattern.GetType() == PATTERN_RADIAL_GRADIENT) {
-      const RadialGradientPattern& pat = static_cast<const RadialGradientPattern&>(aPattern);
-      GradientStopsSkia *stops = static_cast<GradientStopsSkia*>(pat.mStops.get());
-
-      if (stops->mCount >= 2) {
-        SkPoint points[2];
-        points[0] = SkPoint::Make(SkFloatToScalar(pat.mCenter1.x), SkFloatToScalar(pat.mCenter1.y));
-        points[1] = SkPoint::Make(SkFloatToScalar(pat.mCenter2.x), SkFloatToScalar(pat.mCenter2.y));
-
-        SkShader* shader = SkGradientShader::CreateTwoPointRadial(points[0], 
-                                                                  SkFloatToScalar(pat.mRadius1),
-                                                                  points[1], 
-                                                                  SkFloatToScalar(pat.mRadius2),
-                                                                  &stops->mColors.front(), 
-                                                                  &stops->mPositions.front(), 
-                                                                  stops->mCount, 
-                                                                  SkShader::kClamp_TileMode);
-        SkSafeUnref(mPaint.setShader(shader));
-      } else {
-        mPaint.setColor(SkColorSetARGB(0, 0, 0, 0));
-      }
-    } else {
-      const SurfacePattern& pat = static_cast<const SurfacePattern&>(aPattern);
-      const SkBitmap& bitmap = static_cast<SourceSurfaceSkia*>(pat.mSurface.get())->GetBitmap();
-
-      SkShader::TileMode mode = ExtendModeToTileMode(pat.mExtendMode);
-      SkShader* shader = SkShader::CreateBitmapShader(bitmap, mode, mode);
-      SkSafeUnref(mPaint.setShader(shader));
-    }
-  }
-
   // TODO: Maybe add an operator overload to access this easier?
   SkPaint mPaint;
   bool mNeedsRestore;
   SkCanvas* mCanvas;
   Float mAlpha;
 };
 
 void
@@ -537,16 +562,46 @@ DrawTargetSkia::FillGlyphs(ScaledFont *a
     indices[i] = aBuffer.mGlyphs[i].mIndex;
     offsets[i].fX = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.x);
     offsets[i].fY = SkFloatToScalar(aBuffer.mGlyphs[i].mPosition.y);
   }
 
   mCanvas->drawPosText(&indices.front(), aBuffer.mNumGlyphs*2, &offsets.front(), paint.mPaint);
 }
 
+void
+DrawTargetSkia::Mask(const Pattern &aSource,
+                     const Pattern &aMask,
+                     const DrawOptions &aOptions)
+{
+  MarkChanged();
+  AutoPaintSetup paint(mCanvas.get(), aOptions, aSource);
+
+  SkPaint maskPaint;
+  SetPaintPattern(maskPaint, aMask);
+  
+  SkLayerRasterizer *raster = new SkLayerRasterizer();
+  raster->addLayer(maskPaint);
+  SkSafeUnref(paint.mPaint.setRasterizer(raster));
+
+  // Skia only uses the mask rasterizer when we are drawing a path/rect.
+  // Take our destination bounds and convert them into user space to use
+  // as the path to draw.
+  SkPath path;
+  path.addRect(SkRect::MakeWH(mSize.width, mSize.height));
+ 
+  Matrix temp = mTransform;
+  temp.Invert();
+  SkMatrix mat;
+  GfxMatrixToSkiaMatrix(temp, mat);
+  path.transform(mat);
+
+  mCanvas->drawPath(path, paint.mPaint);
+}
+
 TemporaryRef<SourceSurface>
 DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData,
                                              const IntSize &aSize,
                                              int32_t aStride,
                                              SurfaceFormat aFormat) const
 {
   RefPtr<SourceSurfaceSkia> newSurf = new SourceSurfaceSkia();
 
@@ -620,16 +675,31 @@ DrawTargetSkia::Init(const IntSize &aSiz
 
   mDevice = device.get();
   mCanvas = canvas.get();
   mFormat = aFormat;
   return true;
 }
 
 void
+DrawTargetSkia::Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat)
+{
+  mBitmap.setConfig(GfxFormatToSkiaConfig(aFormat), aSize.width, aSize.height, aStride);
+  mBitmap.setPixels(aData);
+  
+  SkAutoTUnref<SkDevice> device(new SkDevice(mBitmap));
+  SkAutoTUnref<SkCanvas> canvas(new SkCanvas(device.get()));
+  mSize = aSize;
+
+  mDevice = device.get();
+  mCanvas = canvas.get();
+  mFormat = aFormat;
+}
+
+void
 DrawTargetSkia::SetTransform(const Matrix& aTransform)
 {
   SkMatrix mat;
   GfxMatrixToSkiaMatrix(aTransform, mat);
   mCanvas->setMatrix(mat);
   mTransform = aTransform;
 }
 
@@ -661,32 +731,41 @@ DrawTargetSkia::PushClip(const Path *aPa
   }
 
   const PathSkia *skiaPath = static_cast<const PathSkia*>(aPath);
   mCanvas->save(SkCanvas::kClip_SaveFlag);
   mCanvas->clipPath(skiaPath->GetPath());
 }
 
 void
+DrawTargetSkia::PushClipRect(const Rect& aRect)
+{
+  SkRect rect = RectToSkRect(aRect);
+
+  mCanvas->save(SkCanvas::kClip_SaveFlag);
+  mCanvas->clipRect(rect);
+}
+
+void
 DrawTargetSkia::PopClip()
 {
   mCanvas->restore();
 }
 
 TemporaryRef<GradientStops>
 DrawTargetSkia::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode) const
 {
   std::vector<GradientStop> stops;
   stops.resize(aNumStops);
   for (uint32_t i = 0; i < aNumStops; i++) {
     stops[i] = aStops[i];
   }
   std::stable_sort(stops.begin(), stops.end());
   
-  return new GradientStopsSkia(stops, aNumStops);
+  return new GradientStopsSkia(stops, aNumStops, aExtendMode);
 }
 
 void
 DrawTargetSkia::AppendSnapshot(SourceSurfaceSkia* aSnapshot)
 {
   mSnapshots.push_back(aSnapshot);
 }
 
--- a/gfx/2d/DrawTargetSkia.h
+++ b/gfx/2d/DrawTargetSkia.h
@@ -96,35 +96,35 @@ public:
                     const Pattern &aPattern,
                     const DrawOptions &aOptions = DrawOptions());
   virtual void FillGlyphs(ScaledFont *aFont,
                           const GlyphBuffer &aBuffer,
                           const Pattern &aPattern,
                           const DrawOptions &aOptions = DrawOptions());
   virtual void Mask(const Pattern &aSource,
                     const Pattern &aMask,
-                    const DrawOptions &aOptions = DrawOptions())
-  { return; }
+                    const DrawOptions &aOptions = DrawOptions());
   virtual void PushClip(const Path *aPath);
-  virtual void PushClipRect(const Rect &aRect) { }
+  virtual void PushClipRect(const Rect& aRect);
   virtual void PopClip();
   virtual TemporaryRef<SourceSurface> CreateSourceSurfaceFromData(unsigned char *aData,
                                                             const IntSize &aSize,
                                                             int32_t aStride,
                                                             SurfaceFormat aFormat) const;
   virtual TemporaryRef<SourceSurface> OptimizeSourceSurface(SourceSurface *aSurface) const;
   virtual TemporaryRef<SourceSurface>
     CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const;
   virtual TemporaryRef<DrawTarget>
     CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const;
   virtual TemporaryRef<PathBuilder> CreatePathBuilder(FillRule aFillRule = FILL_WINDING) const;
   virtual TemporaryRef<GradientStops> CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode = EXTEND_CLAMP) const;
   virtual void SetTransform(const Matrix &aTransform);
 
   bool Init(const IntSize &aSize, SurfaceFormat aFormat);
+  void Init(unsigned char* aData, const IntSize &aSize, int32_t aStride, SurfaceFormat aFormat);
   
   operator std::string() const {
     std::stringstream stream;
     stream << "DrawTargetSkia(" << this << ")";
     return stream.str();
   }
 private:
   friend class SourceSurfaceSkia;
@@ -133,14 +133,13 @@ private:
 
   void MarkChanged();
 
   IntSize mSize;
   SkBitmap mBitmap;
   SkRefPtr<SkCanvas> mCanvas;
   SkRefPtr<SkDevice> mDevice;
   nsRefPtr<gfxImageSurface> mImageSurface;
-  SurfaceFormat mFormat;
   vector<SourceSurfaceSkia*> mSnapshots;
 };
 
 }
 }