Bug 926258 - Implement a Moz2D version of gfxPath. r=Bas
authorMatt Woodrow <mwoodrow@mozilla.com>
Tue, 15 Oct 2013 16:23:21 +1300
changeset 150750 21793156b6eab2ceb759819292c85c8f0342baa2
parent 150749 b37762151fbd464bec0d58217c935499a1d1f44c
child 150760 febfe3c7732bfb52252e77fa293046ad2e8ec41f
child 150789 3b75e10dac5d70c39d2c0f613873c191a4e1aa58
push id25464
push usercbook@mozilla.com
push dateTue, 15 Oct 2013 08:26:45 +0000
treeherdermozilla-central@21793156b6ea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBas
bugs926258
milestone27.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 926258 - Implement a Moz2D version of gfxPath. r=Bas
gfx/2d/2D.h
gfx/thebes/gfxContext.cpp
gfx/thebes/gfxContext.h
gfx/thebes/gfxPath.cpp
gfx/thebes/gfxPath.h
--- a/gfx/2d/2D.h
+++ b/gfx/2d/2D.h
@@ -443,16 +443,21 @@ public:
    */
   virtual Rect GetStrokedBounds(const StrokeOptions &aStrokeOptions,
                                 const Matrix &aTransform = Matrix()) const = 0;
 
   /* This gets the fillrule this path's builder was created with. This is not
    * mutable.
    */
   virtual FillRule GetFillRule() const = 0;
+
+  virtual Float ComputeLength() { return 0; }
+
+  virtual Point ComputePointAtLength(Float aLength,
+                                     Point* aTangent) { return Point(); }
 };
 
 /* The PathBuilder class allows path creation. Once finish is called on the
  * pathbuilder it may no longer be written to.
  */
 class PathBuilder : public PathSink
 {
 public:
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -270,35 +270,41 @@ gfxContext::ClosePath()
   if (mCairo) {
     cairo_close_path(mCairo);
   } else {
     EnsurePathBuilder();
     mPathBuilder->Close();
   }
 }
 
-already_AddRefed<gfxPath> gfxContext::CopyPath() const
+already_AddRefed<gfxPath> gfxContext::CopyPath()
+{
+  nsRefPtr<gfxPath> path;
+  if (mCairo) {
+    path = new gfxPath(cairo_copy_path(mCairo));
+  } else {
+    EnsurePath();
+    path = new gfxPath(mPath);
+  }
+  return path.forget();
+}
+
+void gfxContext::SetPath(gfxPath* path)
 {
   if (mCairo) {
-    nsRefPtr<gfxPath> path = new gfxPath(cairo_copy_path(mCairo));
-    return path.forget();
-  } else {
-    // XXX - This is not yet supported for Azure.
-    return nullptr;
-  }
-}
-
-void gfxContext::AppendPath(gfxPath* path)
-{
-  if (mCairo) {
+    cairo_new_path(mCairo);
     if (path->mPath->status == CAIRO_STATUS_SUCCESS && path->mPath->num_data != 0)
         cairo_append_path(mCairo, path->mPath);
   } else {
-    // XXX - This is not yet supported for Azure.
-    return;
+    MOZ_ASSERT(path->mMoz2DPath, "Can't mix cairo and azure paths!");
+    MOZ_ASSERT(path->mMoz2DPath->GetBackendType() == mDT->GetType());
+    mPath = path->mMoz2DPath;
+    mPathBuilder = nullptr;
+    mPathIsRect = false;
+    mTransformChanged = false;
   }
 }
 
 gfxPoint
 gfxContext::CurrentPoint()
 {
   if (mCairo) {
     double x, y;
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -126,22 +126,22 @@ public:
      *
      * Filling a path will implicitly close it.
      */
     void ClosePath();
 
     /**
      * Copies the current path and returns the copy.
      */
-    already_AddRefed<gfxPath> CopyPath() const;
+    already_AddRefed<gfxPath> CopyPath();
 
     /**
      * Appends the given path to the current path.
      */
-    void AppendPath(gfxPath* path);
+    void SetPath(gfxPath* path);
 
     /**
      * Moves the pen to a new point without drawing a line.
      */
     void MoveTo(const gfxPoint& pt);
 
     /**
      * Creates a new subpath starting at the current point.
@@ -876,18 +876,17 @@ public:
 
     /**
      * If no path is saved, does nothing. Else replaces the context's path with
      * a copy of the saved one, and clears the saved path.
      */
     void Restore()
     {
         if (mPath) {
-            mContext->NewPath();
-            mContext->AppendPath(mPath);
+            mContext->SetPath(mPath);
             mPath = nullptr;
         }
     }
 
 private:
     gfxContext *mContext;
 
     nsRefPtr<gfxPath> mPath;
--- a/gfx/thebes/gfxPath.cpp
+++ b/gfx/thebes/gfxPath.cpp
@@ -2,25 +2,35 @@
  * 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 "gfxPath.h"
 #include "gfxPoint.h"
 #include "gfxPlatform.h"
 #include "gfxASurface.h"
+#include "mozilla/gfx/2D.h"
 
 #include "cairo.h"
 
+using namespace mozilla::gfx;
+
 gfxPath::gfxPath(cairo_path_t* aPath)
   : mPath(aPath)
   , mFlattenedPath(nullptr)
 {
 }
 
+gfxPath::gfxPath(Path* aPath)
+  : mPath(nullptr)
+  , mFlattenedPath(nullptr)
+  , mMoz2DPath(aPath)
+{
+}
+
 gfxPath::~gfxPath()
 {
     cairo_path_destroy(mPath);
     cairo_path_destroy(mFlattenedPath);
 }
 
 void
 gfxPath::EnsureFlattenedPath()
@@ -70,16 +80,20 @@ CalcSubLengthAndAdvance(cairo_path_data_
         }
     }
     return sublength;
 }
 
 gfxFloat
 gfxPath::GetLength()
 {
+    if (mMoz2DPath) {
+        return mMoz2DPath->ComputeLength();
+    }
+
     EnsureFlattenedPath();
 
     gfxPoint start(0, 0);     // start of current subpath
     gfxPoint current(0, 0);   // current point
     gfxFloat length = 0;      // current summed length
 
     for (int32_t i = 0;
          i < mFlattenedPath->num_data;
@@ -87,16 +101,30 @@ gfxPath::GetLength()
         length += CalcSubLengthAndAdvance(&mFlattenedPath->data[i], start, current);
     }
     return length;
 }
 
 gfxPoint
 gfxPath::FindPoint(gfxPoint aOffset, gfxFloat *aAngle)
 {
+    if (mMoz2DPath) {
+        Point tangent; // Unit vector tangent to the point we find.
+        Point result = mMoz2DPath->ComputePointAtLength(aOffset.x, &tangent);
+
+        // The y value of aOffset is the offset along the normal vector to apply
+        Point normal(-tangent.y, tangent.x);
+        result += normal * aOffset.y;
+
+        if (aAngle)
+            *aAngle = atan2(tangent.y, tangent.x);
+
+        return gfxPoint(result.x, result.y);
+    }
+
     EnsureFlattenedPath();
 
     gfxPoint start(0, 0);     // start of current subpath
     gfxPoint current(0, 0);   // current point
     gfxFloat length = 0;      // current summed length
 
     for (int32_t i = 0;
          i < mFlattenedPath->num_data;
--- a/gfx/thebes/gfxPath.h
+++ b/gfx/thebes/gfxPath.h
@@ -3,32 +3,40 @@
  * 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 GFX_PATH_H
 #define GFX_PATH_H
 
 #include "gfxTypes.h"
 #include "nsISupportsImpl.h"
+#include "mozilla/RefPtr.h"
 
 class gfxContext;
 struct gfxPoint;
 typedef struct cairo_path cairo_path_t;
 
+namespace mozilla {
+namespace gfx {
+class Path;
+}
+}
+
 /**
  * Class representing a path. Can be created by copying the current path
  * of a gfxContext.
  */
 class gfxPath {
     NS_INLINE_DECL_REFCOUNTING(gfxPath)
 
     friend class gfxContext;
 
 protected:
     gfxPath(cairo_path_t* aPath);
+    gfxPath(mozilla::gfx::Path* aPath);
 
     void EnsureFlattenedPath();
 
 public:
     virtual ~gfxPath();
     
     /**
      * Returns calculated total length of path
@@ -43,11 +51,12 @@ public:
      * @param aAngle optional - output tangent
      */
     gfxPoint FindPoint(gfxPoint aOffset,
                        gfxFloat* aAngle = nullptr);
 
 protected:
     cairo_path_t* mPath;
     cairo_path_t* mFlattenedPath;
+    mozilla::RefPtr<mozilla::gfx::Path> mMoz2DPath;
 };
 
 #endif