Bug 376927 - add path flattening API to thebes. r=vlad
--- a/gfx/thebes/public/Makefile.in
+++ b/gfx/thebes/public/Makefile.in
@@ -12,16 +12,17 @@ REQUIRES = cairo
EXPORTS = gfxASurface.h \
gfxAlphaRecovery.h \
gfxColor.h \
gfxContext.h \
gfxFont.h \
gfxImageSurface.h \
gfxMatrix.h \
+ gfxPath.h \
gfxPattern.h \
gfxPlatform.h \
gfxPoint.h \
gfxRect.h \
gfxSkipChars.h \
gfxTypes.h \
gfxTextRunCache.h \
$(NULL)
--- a/gfx/thebes/public/gfxContext.h
+++ b/gfx/thebes/public/gfxContext.h
@@ -42,16 +42,17 @@
#include "gfxTypes.h"
#include "gfxASurface.h"
#include "gfxColor.h"
#include "gfxPoint.h"
#include "gfxRect.h"
#include "gfxMatrix.h"
#include "gfxPattern.h"
+#include "gfxPath.h"
typedef struct _cairo cairo_t;
/**
* This is the main class for doing actual drawing. It is initialized using
* a surface and can be drawn on. It manages various state information like
* a current transformation matrix (CTM), a current path, current color,
* etc.
@@ -511,14 +512,19 @@ public:
PRBool PointInStroke(const gfxPoint& pt);
/**
** Extents - returns user space extent of current path
**/
gfxRect GetUserFillExtent();
gfxRect GetUserStrokeExtent();
+ /**
+ ** Obtaining a "flattened" path - path converted to all line segments
+ **/
+ already_AddRefed<gfxFlattenedPath> GetFlattenedPath();
+
private:
cairo_t *mCairo;
nsRefPtr<gfxASurface> mSurface;
};
#endif /* GFX_CONTEXT_H */
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/public/gfxPath.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is IBM Corporation code.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef GFX_PATH_H
+#define GFX_PATH_H
+
+#include "gfxTypes.h"
+
+struct gfxPoint;
+typedef struct cairo_path cairo_path_t;
+
+class THEBES_API gfxFlattenedPath {
+ THEBES_INLINE_DECL_REFCOUNTING(gfxPath)
+
+public:
+ gfxFlattenedPath(cairo_path_t *aPath);
+ ~gfxFlattenedPath();
+
+ /**
+ * Returns calculated total length of path
+ */
+ gfxFloat GetLength();
+
+ /**
+ * Returns a point a certain distance along the path. Return is
+ * first or last point of the path if the requested length offset
+ * is outside the range for the path.
+ * @param aOffset offset inpath parameter space (x=length, y=normal offset)
+ * @param aAngle optional - output tangent
+ */
+ gfxPoint FindPoint(gfxPoint aOffset,
+ gfxFloat *aAngle = nsnull);
+
+protected:
+ cairo_path_t *mPath;
+};
+
+#endif
--- a/gfx/thebes/src/Makefile.in
+++ b/gfx/thebes/src/Makefile.in
@@ -21,19 +21,20 @@ REQUIRES = \
$(NULL)
CPPSRCS = \
gfxASurface.cpp \
gfxAlphaRecovery.cpp \
gfxContext.cpp \
gfxImageSurface.cpp \
gfxFont.cpp \
+ gfxFontMissingGlyphs.cpp \
gfxFontTest.cpp \
gfxMatrix.cpp \
- gfxFontMissingGlyphs.cpp \
+ gfxPath.cpp \
gfxPattern.cpp \
gfxPlatform.cpp \
gfxRect.cpp \
gfxSkipChars.cpp \
gfxTextRunCache.cpp \
$(NULL)
ifdef MOZ_TREE_CAIRO
--- a/gfx/thebes/src/gfxContext.cpp
+++ b/gfx/thebes/src/gfxContext.cpp
@@ -699,8 +699,17 @@ gfxContext::GetUserFillExtent()
gfxRect
gfxContext::GetUserStrokeExtent()
{
double xmin, ymin, xmax, ymax;
cairo_stroke_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
}
+
+already_AddRefed<gfxFlattenedPath>
+gfxContext::GetFlattenedPath()
+{
+ gfxFlattenedPath *path =
+ new gfxFlattenedPath(cairo_copy_path_flat(mCairo));
+ NS_IF_ADDREF(path);
+ return path;
+}
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/src/gfxPath.cpp
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is IBM Corporation code.
+ *
+ * The Initial Developer of the Original Code is IBM Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "gfxPath.h"
+#include "gfxPoint.h"
+
+#include "cairo.h"
+
+gfxFlattenedPath::gfxFlattenedPath(cairo_path_t *aPath) : mPath(aPath)
+{
+}
+
+gfxFlattenedPath::~gfxFlattenedPath()
+{
+ cairo_path_destroy(mPath);
+}
+
+static gfxFloat
+CalcSubLengthAndAdvance(cairo_path_data_t *aData,
+ gfxPoint &aPathStart, gfxPoint &aCurrent)
+{
+ float sublength = 0;
+
+ switch (aData->header.type) {
+ case CAIRO_PATH_MOVE_TO:
+ {
+ aCurrent = aPathStart = gfxPoint(aData[1].point.x,
+ aData[1].point.y);
+ break;
+ }
+ case CAIRO_PATH_LINE_TO:
+ {
+ gfxPoint diff =
+ gfxPoint(aData[1].point.x, aData[1].point.y) - aCurrent;
+ sublength = sqrt(diff.x * diff.x + diff.y * diff.y);
+ aCurrent = gfxPoint(aData[1].point.x, aData[1].point.y);
+ break;
+ }
+ case CAIRO_PATH_CURVE_TO:
+ /* should never happen with a flattened path */
+ NS_WARNING("curve_to in flattened path");
+ break;
+ case CAIRO_PATH_CLOSE_PATH:
+ {
+ gfxPoint diff = aPathStart - aCurrent;
+ sublength = sqrt(diff.x * diff.x + diff.y * diff.y);
+ aCurrent = aPathStart;
+ break;
+ }
+ }
+ return sublength;
+}
+
+gfxFloat
+gfxFlattenedPath::GetLength()
+{
+ gfxPoint start(0, 0); // start of current subpath
+ gfxPoint current(0, 0); // current point
+ gfxFloat length = 0; // current summed length
+
+ for (PRInt32 i = 0;
+ i < mPath->num_data;
+ i += mPath->data[i].header.length) {
+ length += CalcSubLengthAndAdvance(&mPath->data[i], start, current);
+ }
+ return length;
+}
+
+gfxPoint
+gfxFlattenedPath::FindPoint(gfxPoint aOffset, gfxFloat *aAngle)
+{
+ gfxPoint start(0, 0); // start of current subpath
+ gfxPoint current(0, 0); // current point
+ gfxFloat length = 0; // current summed length
+
+ for (PRInt32 i = 0;
+ i < mPath->num_data;
+ i += mPath->data[i].header.length) {
+ gfxPoint prev = current;
+
+ gfxFloat sublength = CalcSubLengthAndAdvance(&mPath->data[i],
+ start, current);
+
+ gfxPoint diff = current - prev;
+ if (aAngle)
+ *aAngle = atan2(diff.y, diff.x);
+
+ if (sublength != 0 && length + sublength >= aOffset.x) {
+ gfxFloat ratio = (aOffset.x - length) / sublength;
+ gfxFloat normalization =
+ 1.0 / sqrt(diff.x * diff.x + diff.y * diff.y);
+
+ return prev * (1.0f - ratio) + current * ratio +
+ gfxPoint(-diff.y, diff.x) * aOffset.y * normalization;
+ }
+ length += sublength;
+ }
+
+ // requested offset is past the end of the path - return last point
+ return current;
+}