[PathKit] Add various path effects
API Changes (nothing should be breaking): - Exposes conic, although all output formats (SVG, Canvas) need conics to be approximated with quads. Tests have been added to verify this happens. - Add .dash(), .trim(), .stroke() and examples for them. - Expose Stroke enums (StrokeJoin, StrokeCap) Adds tests for the cubic part and clean up a few spacing things. There are some changes to the C++ code to simplify the build - otherwise, I need to appease the linker and add add in a bunch of files that may or may not get optimized out. Best make them not even be compiled, just to make sure. Bug: skia:8216 Change-Id: I1da3aaab1891f14a5b3dc01bb6523b4fd9a87b04 Reviewed-on: https://skia-review.googlesource.com/146650 Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
3214f92fe9
commit
97d6d98402
@ -44,7 +44,7 @@ fi
|
|||||||
# Use -O0 for larger builds (but generally quicker)
|
# Use -O0 for larger builds (but generally quicker)
|
||||||
# Use -Oz for (much slower, but smaller/faster) production builds
|
# Use -Oz for (much slower, but smaller/faster) production builds
|
||||||
export EMCC_CLOSURE_ARGS="--externs $BASE_DIR/helper_externs.js "
|
export EMCC_CLOSURE_ARGS="--externs $BASE_DIR/helper_externs.js "
|
||||||
RELEASE_CONF="-Oz --closure 1 -s EVAL_CTORS=1"
|
RELEASE_CONF="-Oz --closure 1 -s EVAL_CTORS=1 --llvm-lto 3"
|
||||||
if [[ $@ == *test* ]]; then
|
if [[ $@ == *test* ]]; then
|
||||||
echo "Building a Testing/Profiling build"
|
echo "Building a Testing/Profiling build"
|
||||||
RELEASE_CONF="-O2 --profiling -DPATHKIT_TESTING -DSK_RELEASE"
|
RELEASE_CONF="-O2 --profiling -DPATHKIT_TESTING -DSK_RELEASE"
|
||||||
@ -73,12 +73,19 @@ mkdir -p $BUILD_DIR
|
|||||||
em++ $RELEASE_CONF -std=c++14 \
|
em++ $RELEASE_CONF -std=c++14 \
|
||||||
-Iinclude/config \
|
-Iinclude/config \
|
||||||
-Iinclude/core \
|
-Iinclude/core \
|
||||||
|
-Iinclude/effects \
|
||||||
|
-Iinclude/gpu \
|
||||||
-Iinclude/pathops \
|
-Iinclude/pathops \
|
||||||
-Iinclude/private \
|
-Iinclude/private \
|
||||||
-Iinclude/utils \
|
-Iinclude/utils \
|
||||||
-Isrc/core \
|
-Isrc/core \
|
||||||
|
-Isrc/gpu \
|
||||||
|
-Isrc/shaders \
|
||||||
|
-Isrc/opts \
|
||||||
|
-Isrc/utils \
|
||||||
--bind \
|
--bind \
|
||||||
--pre-js $BASE_DIR/helper.js \
|
--pre-js $BASE_DIR/helper.js \
|
||||||
|
-DWEB_ASSEMBLY=1 \
|
||||||
-fno-rtti -fno-exceptions -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0 \
|
-fno-rtti -fno-exceptions -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=0 \
|
||||||
$WASM_CONF \
|
$WASM_CONF \
|
||||||
-s MODULARIZE=1 \
|
-s MODULARIZE=1 \
|
||||||
@ -91,22 +98,40 @@ $WASM_CONF \
|
|||||||
-s STRICT=1 \
|
-s STRICT=1 \
|
||||||
$OUTPUT \
|
$OUTPUT \
|
||||||
$BASE_DIR/pathkit_wasm_bindings.cpp \
|
$BASE_DIR/pathkit_wasm_bindings.cpp \
|
||||||
|
src/core/SkAnalyticEdge.cpp \
|
||||||
src/core/SkArenaAlloc.cpp \
|
src/core/SkArenaAlloc.cpp \
|
||||||
|
src/core/SkEdge.cpp \
|
||||||
|
src/core/SkEdgeBuilder.cpp \
|
||||||
|
src/core/SkEdgeClipper.cpp \
|
||||||
|
src/core/SkFDot6Constants.cpp \
|
||||||
|
src/core/SkFlattenable.cpp \
|
||||||
src/core/SkGeometry.cpp \
|
src/core/SkGeometry.cpp \
|
||||||
|
src/core/SkLineClipper.cpp \
|
||||||
src/core/SkMallocPixelRef.cpp \
|
src/core/SkMallocPixelRef.cpp \
|
||||||
src/core/SkMath.cpp \
|
src/core/SkMath.cpp \
|
||||||
src/core/SkMatrix.cpp \
|
src/core/SkMatrix.cpp \
|
||||||
|
src/core/SkOpts.cpp \
|
||||||
|
src/core/SkPaint.cpp \
|
||||||
src/core/SkPath.cpp \
|
src/core/SkPath.cpp \
|
||||||
|
src/core/SkPathEffect.cpp \
|
||||||
|
src/core/SkPathMeasure.cpp \
|
||||||
src/core/SkPathRef.cpp \
|
src/core/SkPathRef.cpp \
|
||||||
src/core/SkPoint.cpp \
|
src/core/SkPoint.cpp \
|
||||||
|
src/core/SkRRect.cpp \
|
||||||
src/core/SkRect.cpp \
|
src/core/SkRect.cpp \
|
||||||
src/core/SkStream.cpp \
|
src/core/SkStream.cpp \
|
||||||
src/core/SkString.cpp \
|
src/core/SkString.cpp \
|
||||||
src/core/SkStringUtils.cpp \
|
src/core/SkStringUtils.cpp \
|
||||||
|
src/core/SkStroke.cpp \
|
||||||
|
src/core/SkStrokeRec.cpp \
|
||||||
|
src/core/SkStrokerPriv.cpp \
|
||||||
src/core/SkUtils.cpp \
|
src/core/SkUtils.cpp \
|
||||||
|
src/effects/SkDashPathEffect.cpp \
|
||||||
|
src/effects/SkTrimPathEffect.cpp \
|
||||||
src/pathops/*.cpp \
|
src/pathops/*.cpp \
|
||||||
src/ports/SkDebug_stdio.cpp \
|
src/ports/SkDebug_stdio.cpp \
|
||||||
src/ports/SkMemory_malloc.cpp \
|
src/ports/SkMemory_malloc.cpp \
|
||||||
|
src/utils/SkDashPath.cpp \
|
||||||
src/utils/SkParse.cpp \
|
src/utils/SkParse.cpp \
|
||||||
src/utils/SkParsePath.cpp \
|
src/utils/SkParsePath.cpp \
|
||||||
src/utils/SkUTF.cpp
|
src/utils/SkUTF.cpp
|
||||||
|
@ -14,6 +14,10 @@ module.exports = function(config) {
|
|||||||
'tests/*.spec.js'
|
'tests/*.spec.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
proxies: {
|
||||||
|
"/pathkit/": "/base/npm-wasm/bin/test/"
|
||||||
|
},
|
||||||
|
|
||||||
// test results reporter to use
|
// test results reporter to use
|
||||||
// possible values: 'dots', 'progress'
|
// possible values: 'dots', 'progress'
|
||||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||||
|
@ -14,6 +14,10 @@ module.exports = function(config) {
|
|||||||
'tests/*.spec.js'
|
'tests/*.spec.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
proxies: {
|
||||||
|
"/pathkit/": "/base/npm-wasm/bin/test/"
|
||||||
|
},
|
||||||
|
|
||||||
// test results reporter to use
|
// test results reporter to use
|
||||||
// possible values: 'dots', 'progress'
|
// possible values: 'dots', 'progress'
|
||||||
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
|
||||||
|
@ -30,6 +30,14 @@
|
|||||||
<canvas class=big id=canvas3></canvas>
|
<canvas class=big id=canvas3></canvas>
|
||||||
<canvas class=big id=canvas4></canvas>
|
<canvas class=big id=canvas4></canvas>
|
||||||
|
|
||||||
|
<h2> Has various Path Effects </h2>
|
||||||
|
<canvas class=big id=canvas5></canvas>
|
||||||
|
<canvas class=big id=canvas6></canvas>
|
||||||
|
<canvas class=big id=canvas7></canvas>
|
||||||
|
<canvas class=big id=canvas8></canvas>
|
||||||
|
<canvas class=big id=canvas9></canvas>
|
||||||
|
<canvas class=big id=canvas10></canvas>
|
||||||
|
|
||||||
<script type="text/javascript" src="/node_modules/experimental-pathkit-wasm/bin/pathkit.js"></script>
|
<script type="text/javascript" src="/node_modules/experimental-pathkit-wasm/bin/pathkit.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" charset="utf-8">
|
<script type="text/javascript" charset="utf-8">
|
||||||
@ -39,6 +47,7 @@
|
|||||||
}).then((PathKit) => {
|
}).then((PathKit) => {
|
||||||
OutputsExample(PathKit);
|
OutputsExample(PathKit);
|
||||||
Path2DExample(PathKit);
|
Path2DExample(PathKit);
|
||||||
|
PathEffectsExample(PathKit);
|
||||||
});
|
});
|
||||||
|
|
||||||
function setCanvasSize(ctx, width, height) {
|
function setCanvasSize(ctx, width, height) {
|
||||||
@ -158,4 +167,73 @@
|
|||||||
objs[1].delete();
|
objs[1].delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see https://fiddle.skia.org/c/@discrete_path
|
||||||
|
function drawStar(path) {
|
||||||
|
let R = 115.2, C = 128.0;
|
||||||
|
path.moveTo(C + R + 22, C);
|
||||||
|
for (let i = 1; i < 8; i++) {
|
||||||
|
let a = 2.6927937 * i;
|
||||||
|
path.lineTo(C + R * Math.cos(a) + 22, C + R * Math.sin(a));
|
||||||
|
}
|
||||||
|
path.closePath();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PathEffectsExample(PathKit) {
|
||||||
|
let transforms = [
|
||||||
|
// no-op
|
||||||
|
(path) => path,
|
||||||
|
// dash
|
||||||
|
(path) => path.dash(10, 3, 0),
|
||||||
|
// trim (takes optional 3rd param for returning the trimmed part
|
||||||
|
// or the complement)
|
||||||
|
(path) => path.trim(0.25, 0.8, false),
|
||||||
|
// simplify
|
||||||
|
(path) => path.simplify(),
|
||||||
|
// stroke
|
||||||
|
(path) => path.stroke(15, PathKit.StrokeJoin.BEVEL, PathKit.StrokeCap.BUTT),
|
||||||
|
// "offset effect", that is, making a border around the shape.
|
||||||
|
(path) => {
|
||||||
|
let temp = path.stroke(10, PathKit.StrokeJoin.ROUND, PathKit.StrokeCap.SQUARE);
|
||||||
|
let ret = temp.op(path, PathKit.PathOp.DIFFERENCE);
|
||||||
|
temp.delete();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let names = ["(plain)", "Dash", "Trim", "Simplify", "Stroke", "Offset"];
|
||||||
|
|
||||||
|
for (let i = 0; i < transforms.length; i++) {
|
||||||
|
let path = PathKit.NewPath();
|
||||||
|
drawStar(path);
|
||||||
|
|
||||||
|
let transformedPath = transforms[i](path);
|
||||||
|
|
||||||
|
let ctx = document.getElementById(`canvas${i+5}`).getContext('2d');
|
||||||
|
setCanvasSize(ctx, 300, 300);
|
||||||
|
ctx.strokeStyle = '#3c597a';
|
||||||
|
ctx.fillStyle = '#3c597a';
|
||||||
|
if (i === 4 || i === 5) {
|
||||||
|
ctx.fill(transformedPath.toPath2D(), transformedPath.getCanvasFillType());
|
||||||
|
if (i === 5) {
|
||||||
|
ctx.fillStyle = "#51d9bb";
|
||||||
|
ctx.fill(path.toPath2D());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.stroke(transformedPath.toPath2D());
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.font = '42px monospace';
|
||||||
|
|
||||||
|
let x = 150-ctx.measureText(names[i]).width/2;
|
||||||
|
ctx.strokeText(names[i], x, 290);
|
||||||
|
|
||||||
|
if (i) {
|
||||||
|
transformedPath.delete();
|
||||||
|
}
|
||||||
|
path.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "experimental-pathkit-wasm",
|
"name": "experimental-pathkit-wasm",
|
||||||
"version": "0.1.4",
|
"version": "0.1.7",
|
||||||
"description": "A WASM version of Skia's PathOps toolkit",
|
"description": "A WASM version of Skia's PathOps toolkit",
|
||||||
"main": "bin/pathkit.js",
|
"main": "bin/pathkit.js",
|
||||||
"homepage": "https://github.com/google/skia/tree/master/experimental/pathkit",
|
"homepage": "https://github.com/google/skia/tree/master/experimental/pathkit",
|
||||||
|
@ -5,14 +5,17 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "SkDashPathEffect.h"
|
||||||
#include "SkFloatBits.h"
|
#include "SkFloatBits.h"
|
||||||
#include "SkFloatingPoint.h"
|
#include "SkFloatingPoint.h"
|
||||||
#include "SkMatrix.h"
|
#include "SkMatrix.h"
|
||||||
|
#include "SkPaint.h"
|
||||||
#include "SkParsePath.h"
|
#include "SkParsePath.h"
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
#include "SkPathOps.h"
|
#include "SkPathOps.h"
|
||||||
#include "SkRect.h"
|
#include "SkRect.h"
|
||||||
#include "SkString.h"
|
#include "SkString.h"
|
||||||
|
#include "SkTrimPathEffect.h"
|
||||||
|
|
||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
#include <emscripten/bind.h>
|
#include <emscripten/bind.h>
|
||||||
@ -22,13 +25,16 @@ using namespace emscripten;
|
|||||||
static const int MOVE = 0;
|
static const int MOVE = 0;
|
||||||
static const int LINE = 1;
|
static const int LINE = 1;
|
||||||
static const int QUAD = 2;
|
static const int QUAD = 2;
|
||||||
|
static const int CONIC = 3;
|
||||||
static const int CUBIC = 4;
|
static const int CUBIC = 4;
|
||||||
static const int CLOSE = 5;
|
static const int CLOSE = 5;
|
||||||
|
|
||||||
// Just for self-documenting purposes where the main thing being returned is an
|
// Just for self-documenting purposes where the main thing being returned is an
|
||||||
// SkPath, but in an error case, something of type val (e.g. null) could also be
|
// SkPath, but in an error case, something of type null (which is val) could also be
|
||||||
// returned;
|
// returned;
|
||||||
using SkPathOrVal = emscripten::val;
|
using SkPathOrNull = emscripten::val;
|
||||||
|
// Self-documenting for when we return a string
|
||||||
|
using JSString = emscripten::val;
|
||||||
|
|
||||||
// =================================================================================
|
// =================================================================================
|
||||||
// Creating/Exporting Paths with cmd arrays
|
// Creating/Exporting Paths with cmd arrays
|
||||||
@ -60,16 +66,9 @@ emscripten::val EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
|
|||||||
cmd.call<void>("push", QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
|
cmd.call<void>("push", QUAD, pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y());
|
||||||
break;
|
break;
|
||||||
case SkPath::kConic_Verb:
|
case SkPath::kConic_Verb:
|
||||||
SkPoint quads[5];
|
cmd.call<void>("push", CONIC,
|
||||||
// approximate with 2^1=2 quads.
|
pts[1].x(), pts[1].y(),
|
||||||
SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
|
pts[2].x(), pts[2].y(), iter.conicWeight());
|
||||||
cmd.call<void>("push", MOVE, quads[0].x(), quads[0].y());
|
|
||||||
cmds.call<void>("push", cmd);
|
|
||||||
cmd = emscripten::val::array();
|
|
||||||
cmd.call<void>("push", QUAD, quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
|
|
||||||
cmds.call<void>("push", cmd);
|
|
||||||
cmd = emscripten::val::array();
|
|
||||||
cmd.call<void>("push", QUAD, quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
|
|
||||||
break;
|
break;
|
||||||
case SkPath::kCubic_Verb:
|
case SkPath::kCubic_Verb:
|
||||||
cmd.call<void>("push", CUBIC,
|
cmd.call<void>("push", CUBIC,
|
||||||
@ -99,7 +98,7 @@ emscripten::val EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
|
|||||||
// in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
|
// in our function type signatures. (this gives an error message like "Cannot call foo due to unbound
|
||||||
// types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
|
// types Pi, Pf"). But, we can just pretend they are numbers and cast them to be pointers and
|
||||||
// the compiler is happy.
|
// the compiler is happy.
|
||||||
SkPathOrVal EMSCRIPTEN_KEEPALIVE FromCmds(uintptr_t /* float* */ cptr, int numCmds) {
|
SkPathOrNull EMSCRIPTEN_KEEPALIVE FromCmds(uintptr_t /* float* */ cptr, int numCmds) {
|
||||||
const auto* cmds = reinterpret_cast<const float*>(cptr);
|
const auto* cmds = reinterpret_cast<const float*>(cptr);
|
||||||
SkPath path;
|
SkPath path;
|
||||||
float x1, y1, x2, y2, x3, y3;
|
float x1, y1, x2, y2, x3, y3;
|
||||||
@ -158,7 +157,7 @@ SkPath EMSCRIPTEN_KEEPALIVE NewPath() {
|
|||||||
// SVG things
|
// SVG things
|
||||||
//========================================================================================
|
//========================================================================================
|
||||||
|
|
||||||
emscripten::val EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
|
JSString EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
|
||||||
SkString s;
|
SkString s;
|
||||||
SkParsePath::ToSVGString(path, &s);
|
SkParsePath::ToSVGString(path, &s);
|
||||||
// Wrapping it in val automatically turns it into a JS string.
|
// Wrapping it in val automatically turns it into a JS string.
|
||||||
@ -169,7 +168,7 @@ emscripten::val EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SkPathOrVal EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str) {
|
SkPathOrNull EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str) {
|
||||||
SkPath path;
|
SkPath path;
|
||||||
if (SkParsePath::FromSVGString(str.c_str(), &path)) {
|
if (SkParsePath::FromSVGString(str.c_str(), &path)) {
|
||||||
return emscripten::val(path);
|
return emscripten::val(path);
|
||||||
@ -181,7 +180,7 @@ SkPathOrVal EMSCRIPTEN_KEEPALIVE FromSVGString(std::string str) {
|
|||||||
// PATHOP things
|
// PATHOP things
|
||||||
//========================================================================================
|
//========================================================================================
|
||||||
|
|
||||||
SkPathOrVal EMSCRIPTEN_KEEPALIVE SimplifyPath(const SkPath& path) {
|
SkPathOrNull EMSCRIPTEN_KEEPALIVE SimplifyPath(const SkPath& path) {
|
||||||
SkPath simple;
|
SkPath simple;
|
||||||
if (Simplify(path, &simple)) {
|
if (Simplify(path, &simple)) {
|
||||||
return emscripten::val(simple);
|
return emscripten::val(simple);
|
||||||
@ -189,7 +188,7 @@ SkPathOrVal EMSCRIPTEN_KEEPALIVE SimplifyPath(const SkPath& path) {
|
|||||||
return emscripten::val::null();
|
return emscripten::val::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPathOrVal EMSCRIPTEN_KEEPALIVE ApplyPathOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
|
SkPathOrNull EMSCRIPTEN_KEEPALIVE ApplyPathOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
|
||||||
SkPath path;
|
SkPath path;
|
||||||
if (Op(pathOne, pathTwo, op, &path)) {
|
if (Op(pathOne, pathTwo, op, &path)) {
|
||||||
return emscripten::val(path);
|
return emscripten::val(path);
|
||||||
@ -197,7 +196,7 @@ SkPathOrVal EMSCRIPTEN_KEEPALIVE ApplyPathOp(const SkPath& pathOne, const SkPath
|
|||||||
return emscripten::val::null();
|
return emscripten::val::null();
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPathOrVal EMSCRIPTEN_KEEPALIVE ResolveBuilder(SkOpBuilder& builder) {
|
SkPathOrNull EMSCRIPTEN_KEEPALIVE ResolveBuilder(SkOpBuilder& builder) {
|
||||||
SkPath path;
|
SkPath path;
|
||||||
if (builder.resolve(&path)) {
|
if (builder.resolve(&path)) {
|
||||||
return emscripten::val(path);
|
return emscripten::val(path);
|
||||||
@ -228,7 +227,6 @@ void EMSCRIPTEN_KEEPALIVE ToCanvas(const SkPath& path, emscripten::val /* Path2D
|
|||||||
SkPoint quads[5];
|
SkPoint quads[5];
|
||||||
// approximate with 2^1=2 quads.
|
// approximate with 2^1=2 quads.
|
||||||
SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
|
SkPath::ConvertConicToQuads(pts[0], pts[1], pts[2], iter.conicWeight(), quads, 1);
|
||||||
ctx.call<void>("moveTo", quads[0].x(), quads[0].y());
|
|
||||||
ctx.call<void>("quadraticCurveTo", quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
|
ctx.call<void>("quadraticCurveTo", quads[1].x(), quads[1].y(), quads[2].x(), quads[2].y());
|
||||||
ctx.call<void>("quadraticCurveTo", quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
|
ctx.call<void>("quadraticCurveTo", quads[3].x(), quads[3].y(), quads[4].x(), quads[4].y());
|
||||||
break;
|
break;
|
||||||
@ -326,6 +324,70 @@ void Path2DAddPath(SkPath& orig, const SkPath& newPath,
|
|||||||
orig.addPath(newPath, m);
|
orig.addPath(newPath, m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSString GetCanvasFillType(const SkPath& path) {
|
||||||
|
if (path.getFillType() == SkPath::FillType::kWinding_FillType) {
|
||||||
|
return emscripten::val("nonzero");
|
||||||
|
} else if (path.getFillType() == SkPath::FillType::kEvenOdd_FillType) {
|
||||||
|
return emscripten::val("evenodd");
|
||||||
|
} else {
|
||||||
|
SkDebugf("warning: can't translate inverted filltype to HTML Canvas\n");
|
||||||
|
return emscripten::val("nonzero"); //Use default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//========================================================================================
|
||||||
|
// Path Effects
|
||||||
|
//========================================================================================
|
||||||
|
|
||||||
|
SkPathOrNull PathEffectDash(const SkPath& path, SkScalar on, SkScalar off, SkScalar phase) {
|
||||||
|
SkPath output;
|
||||||
|
SkScalar intervals[] = { on, off };
|
||||||
|
auto pe = SkDashPathEffect::Make(intervals, 2, phase);
|
||||||
|
if (!pe) {
|
||||||
|
SkDebugf("Invalid args to dash()\n");
|
||||||
|
return emscripten::val::null();
|
||||||
|
}
|
||||||
|
if (pe->filterPath(&output, path, nullptr, nullptr)) {
|
||||||
|
return emscripten::val(output);
|
||||||
|
}
|
||||||
|
SkDebugf("Could not make dashed path\n");
|
||||||
|
return emscripten::val::null();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPathOrNull PathEffectTrim(const SkPath& path, SkScalar startT, SkScalar stopT, bool isComplement) {
|
||||||
|
SkPath output;
|
||||||
|
auto mode = isComplement ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal;
|
||||||
|
auto pe = SkTrimPathEffect::Make(startT, stopT, mode);
|
||||||
|
if (!pe) {
|
||||||
|
SkDebugf("Invalid args to trim(): startT and stopT must be in [0,1]\n");
|
||||||
|
return emscripten::val::null();
|
||||||
|
}
|
||||||
|
if (pe->filterPath(&output, path, nullptr, nullptr)) {
|
||||||
|
return emscripten::val(output);
|
||||||
|
}
|
||||||
|
SkDebugf("Could not trim path\n");
|
||||||
|
return emscripten::val::null();
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPathOrNull PathEffectTrim(const SkPath& path, SkScalar startT, SkScalar stopT) {
|
||||||
|
return PathEffectTrim(path, startT, stopT, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SkPathOrNull PathEffectStroke(const SkPath& path, SkScalar width, SkPaint::Join join, SkPaint::Cap cap) {
|
||||||
|
SkPath output;
|
||||||
|
SkPaint p;
|
||||||
|
p.setStyle(SkPaint::kStroke_Style);
|
||||||
|
p.setStrokeCap(cap);
|
||||||
|
p.setStrokeJoin(join);
|
||||||
|
p.setStrokeWidth(width);
|
||||||
|
|
||||||
|
if (p.getFillPath(path, &output)) {
|
||||||
|
return emscripten::val(output);
|
||||||
|
}
|
||||||
|
SkDebugf("Could not stroke path\n");
|
||||||
|
return emscripten::val::null();
|
||||||
|
}
|
||||||
|
|
||||||
//========================================================================================
|
//========================================================================================
|
||||||
// Testing things
|
// Testing things
|
||||||
//========================================================================================
|
//========================================================================================
|
||||||
@ -384,6 +446,8 @@ EMSCRIPTEN_BINDINGS(skia) {
|
|||||||
.function("addPath",
|
.function("addPath",
|
||||||
select_overload<void(SkPath&, const SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddPath))
|
select_overload<void(SkPath&, const SkPath&, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&Path2DAddPath))
|
||||||
.function("close", &SkPath::close)
|
.function("close", &SkPath::close)
|
||||||
|
.function("conicTo",
|
||||||
|
select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::conicTo))
|
||||||
.function("cubicTo",
|
.function("cubicTo",
|
||||||
select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::cubicTo))
|
select_overload<void(SkScalar, SkScalar, SkScalar, SkScalar, SkScalar, SkScalar)>(&SkPath::cubicTo))
|
||||||
.function("quadTo",
|
.function("quadTo",
|
||||||
@ -392,9 +456,16 @@ EMSCRIPTEN_BINDINGS(skia) {
|
|||||||
// Extra features
|
// Extra features
|
||||||
.function("setFillType", &SkPath::setFillType)
|
.function("setFillType", &SkPath::setFillType)
|
||||||
.function("getFillType", &SkPath::getFillType)
|
.function("getFillType", &SkPath::getFillType)
|
||||||
|
.function("getCanvasFillType", &GetCanvasFillType)
|
||||||
.function("getBounds", &SkPath::getBounds)
|
.function("getBounds", &SkPath::getBounds)
|
||||||
.function("computeTightBounds", &SkPath::computeTightBounds)
|
.function("computeTightBounds", &SkPath::computeTightBounds)
|
||||||
|
|
||||||
|
// PathEffects
|
||||||
|
.function("dash", &PathEffectDash)
|
||||||
|
.function("trim", select_overload<SkPathOrNull(const SkPath&, SkScalar, SkScalar)>(&PathEffectTrim))
|
||||||
|
.function("trim", select_overload<SkPathOrNull(const SkPath&, SkScalar, SkScalar, bool)>(&PathEffectTrim))
|
||||||
|
.function("stroke", &PathEffectStroke)
|
||||||
|
|
||||||
// PathOps
|
// PathOps
|
||||||
.function("simplify", &SimplifyPath)
|
.function("simplify", &SimplifyPath)
|
||||||
.function("op", &ApplyPathOp)
|
.function("op", &ApplyPathOp)
|
||||||
@ -407,6 +478,7 @@ EMSCRIPTEN_BINDINGS(skia) {
|
|||||||
|
|
||||||
#ifdef PATHKIT_TESTING
|
#ifdef PATHKIT_TESTING
|
||||||
.function("dump", select_overload<void() const>(&SkPath::dump))
|
.function("dump", select_overload<void() const>(&SkPath::dump))
|
||||||
|
.function("dumpHex", select_overload<void() const>(&SkPath::dumpHex))
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -444,6 +516,7 @@ EMSCRIPTEN_BINDINGS(skia) {
|
|||||||
constant("MOVE_VERB", MOVE);
|
constant("MOVE_VERB", MOVE);
|
||||||
constant("LINE_VERB", LINE);
|
constant("LINE_VERB", LINE);
|
||||||
constant("QUAD_VERB", QUAD);
|
constant("QUAD_VERB", QUAD);
|
||||||
|
constant("CONIC_VERB", CONIC);
|
||||||
constant("CUBIC_VERB", CUBIC);
|
constant("CUBIC_VERB", CUBIC);
|
||||||
constant("CLOSE_VERB", CLOSE);
|
constant("CLOSE_VERB", CLOSE);
|
||||||
|
|
||||||
@ -458,12 +531,20 @@ EMSCRIPTEN_BINDINGS(skia) {
|
|||||||
|
|
||||||
function("MakeLTRBRect", &SkRect::MakeLTRB);
|
function("MakeLTRBRect", &SkRect::MakeLTRB);
|
||||||
|
|
||||||
// coming soon - Stroke
|
// Stroke
|
||||||
|
enum_<SkPaint::Join>("StrokeJoin")
|
||||||
|
.value("MITER", SkPaint::Join::kMiter_Join)
|
||||||
|
.value("ROUND", SkPaint::Join::kRound_Join)
|
||||||
|
.value("BEVEL", SkPaint::Join::kBevel_Join);
|
||||||
|
|
||||||
|
enum_<SkPaint::Cap>("StrokeCap")
|
||||||
|
.value("BUTT", SkPaint::Cap::kButt_Cap)
|
||||||
|
.value("ROUND", SkPaint::Cap::kRound_Cap)
|
||||||
|
.value("SQUARE", SkPaint::Cap::kSquare_Cap);
|
||||||
|
|
||||||
|
|
||||||
// coming soon - Matrix
|
// coming soon - Matrix
|
||||||
|
|
||||||
// coming soon - Trim
|
|
||||||
|
|
||||||
// Test Utils
|
// Test Utils
|
||||||
function("SkBits2FloatUnsigned", &SkBits2FloatUnsigned);
|
function("SkBits2FloatUnsigned", &SkBits2FloatUnsigned);
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
describe('PathKit\'s Path Behavior', function() {
|
describe('PathKit\'s Path Behavior', function() {
|
||||||
// Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up.
|
// Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up.
|
||||||
var PathKit = null;
|
var PathKit = null;
|
||||||
const LoadPathKit = new Promise(function(resolve, reject){
|
const LoadPathKit = new Promise(function(resolve, reject) {
|
||||||
if (PathKit) {
|
if (PathKit) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
PathKitInit({
|
PathKitInit({
|
||||||
locateFile: (file) => '/base/npm-wasm/bin/test/'+file,
|
locateFile: (file) => '/pathkit/'+file,
|
||||||
}).then((_PathKit) => {
|
}).then((_PathKit) => {
|
||||||
PathKit = _PathKit;
|
PathKit = _PathKit;
|
||||||
resolve();
|
resolve();
|
||||||
@ -31,6 +31,10 @@ describe('PathKit\'s Path Behavior', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function bits2float(str) {
|
||||||
|
return PathKit.SkBits2FloatUnsigned(parseInt(str))
|
||||||
|
}
|
||||||
|
|
||||||
it('has getBounds() and computeTightBounds()', function(done){
|
it('has getBounds() and computeTightBounds()', function(done){
|
||||||
LoadPathKit.then(() => {
|
LoadPathKit.then(() => {
|
||||||
// Based on PathOpsTightBoundsIllBehaved
|
// Based on PathOpsTightBoundsIllBehaved
|
||||||
@ -39,12 +43,36 @@ describe('PathKit\'s Path Behavior', function() {
|
|||||||
path.quadraticCurveTo(4, 3, 2, 2);
|
path.quadraticCurveTo(4, 3, 2, 2);
|
||||||
expect(path.getBounds()).toEqual(PathKit.MakeLTRBRect(1, 1, 4, 3));
|
expect(path.getBounds()).toEqual(PathKit.MakeLTRBRect(1, 1, 4, 3));
|
||||||
expect(path.computeTightBounds()).toEqual(PathKit.MakeLTRBRect(1, 1,
|
expect(path.computeTightBounds()).toEqual(PathKit.MakeLTRBRect(1, 1,
|
||||||
PathKit.SkBits2FloatUnsigned(parseInt("0x40333334")), // 2.8
|
bits2float("0x40333334"), // 2.8
|
||||||
PathKit.SkBits2FloatUnsigned(parseInt("0x40155556")))); // 2.3333333
|
bits2float("0x40155556"))); // 2.3333333
|
||||||
path.delete();
|
path.delete();
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does NOT approximates conics when dumping as toCmds', function(done){
|
||||||
|
LoadPathKit.then(() => {
|
||||||
|
let path = PathKit.NewPath();
|
||||||
|
path.moveTo(20, 120);
|
||||||
|
path.arc(20, 120, 18, 0, 1.75 * Math.PI);
|
||||||
|
path.lineTo(20, 120);
|
||||||
|
|
||||||
|
let expectedCmds = [
|
||||||
|
[PathKit.MOVE_VERB, 20, 120],
|
||||||
|
[PathKit.LINE_VERB, 38, 120],
|
||||||
|
[PathKit.CONIC_VERB, 38, 138, 20, 138, bits2float("0x3f3504f3)")], // 0.707107f
|
||||||
|
[PathKit.CONIC_VERB, 2, 138, 2, 120, bits2float("0x3f3504f3)")], // 0.707107f
|
||||||
|
[PathKit.CONIC_VERB, 2, 102, 20, 102, bits2float("0x3f3504f3)")], // 0.707107f
|
||||||
|
[PathKit.CONIC_VERB, bits2float("0x41dba58e"), 102, bits2float("0x4202e962"), bits2float("0x42d68b4d"), bits2float("0x3f6c8361")], // 27.4558, 102, 32.7279, 107.272, 0.92388
|
||||||
|
[PathKit.LINE_VERB, 20, 120],
|
||||||
|
];
|
||||||
|
let actual = path.toCmds();
|
||||||
|
expect(actual).toEqual(expectedCmds);
|
||||||
|
|
||||||
|
path.delete();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -10,12 +10,12 @@ describe('PathKit\'s Path2D API', function() {
|
|||||||
|
|
||||||
// Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up.
|
// Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up.
|
||||||
var PathKit = null;
|
var PathKit = null;
|
||||||
const LoadPathKit = new Promise(function(resolve, reject){
|
const LoadPathKit = new Promise(function(resolve, reject) {
|
||||||
if (PathKit) {
|
if (PathKit) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
PathKitInit({
|
PathKitInit({
|
||||||
locateFile: (file) => '/base/npm-wasm/bin/test/'+file,
|
locateFile: (file) => '/pathkit/'+file,
|
||||||
}).then((_PathKit) => {
|
}).then((_PathKit) => {
|
||||||
PathKit = _PathKit;
|
PathKit = _PathKit;
|
||||||
resolve();
|
resolve();
|
||||||
@ -23,7 +23,7 @@ describe('PathKit\'s Path2D API', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can do everything in the Path2D API w/o crashing', function(done){
|
it('can do everything in the Path2D API w/o crashing', function(done) {
|
||||||
LoadPathKit.then(() => {
|
LoadPathKit.then(() => {
|
||||||
// This is taken from example.html
|
// This is taken from example.html
|
||||||
let path = PathKit.NewPath();
|
let path = PathKit.NewPath();
|
||||||
@ -79,4 +79,29 @@ describe('PathKit\'s Path2D API', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
it('approximates arcs (conics) with quads', function(done) {
|
||||||
|
LoadPathKit.then(() => {
|
||||||
|
let path = PathKit.NewPath();
|
||||||
|
path.moveTo(20, 120);
|
||||||
|
path.arc(20, 120, 18, 0, 1.75 * Math.PI);
|
||||||
|
path.lineTo(20, 120);
|
||||||
|
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
container.appendChild(canvas);
|
||||||
|
let canvasCtx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
spyOn(canvasCtx, 'quadraticCurveTo');
|
||||||
|
|
||||||
|
canvasCtx.beginPath();
|
||||||
|
path.toCanvas(canvasCtx);
|
||||||
|
canvasCtx.stroke();
|
||||||
|
// No need to check the whole path, as that's more what the
|
||||||
|
// gold correctness tests are for (can account for changes we make
|
||||||
|
// to the approximation algorithms).
|
||||||
|
expect(canvasCtx.quadraticCurveTo).toHaveBeenCalled();
|
||||||
|
path.delete();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
@ -77,12 +77,12 @@ describe('PathKit\'s PathOps Behavior', function() {
|
|||||||
var PathKit = null;
|
var PathKit = null;
|
||||||
var PATHOP_MAP = {};
|
var PATHOP_MAP = {};
|
||||||
var FILLTYPE_MAP = {};
|
var FILLTYPE_MAP = {};
|
||||||
const LoadPathKit = new Promise(function(resolve, reject){
|
const LoadPathKit = new Promise(function(resolve, reject) {
|
||||||
if (PathKit) {
|
if (PathKit) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
PathKitInit({
|
PathKitInit({
|
||||||
locateFile: (file) => '/base/npm-wasm/bin/test/'+file,
|
locateFile: (file) => '/pathkit/'+file,
|
||||||
}).then((_PathKit) => {
|
}).then((_PathKit) => {
|
||||||
PathKit = _PathKit;
|
PathKit = _PathKit;
|
||||||
PATHOP_MAP = {
|
PATHOP_MAP = {
|
||||||
@ -152,6 +152,9 @@ describe('PathKit\'s PathOps Behavior', function() {
|
|||||||
// Do a tolerant match.
|
// Do a tolerant match.
|
||||||
let diff = diffPaths(expected, combined);
|
let diff = diffPaths(expected, combined);
|
||||||
if (test.expectMatch === 'yes'){
|
if (test.expectMatch === 'yes'){
|
||||||
|
// Check fill type
|
||||||
|
expect(combined.getFillType().value).toEqual(getFillType(test.fillTypeOut).value);
|
||||||
|
// diff should be null if the paths are identical (modulo rounding)
|
||||||
if (diff) {
|
if (diff) {
|
||||||
expect(`[${testName}] ${diff}`).toBe('');
|
expect(`[${testName}] ${diff}`).toBe('');
|
||||||
addSVG('[PathOps] ' + testName, expected, combined, diff);
|
addSVG('[PathOps] ' + testName, expected, combined, diff);
|
||||||
@ -202,6 +205,9 @@ describe('PathKit\'s PathOps Behavior', function() {
|
|||||||
// Do a tolerant match.
|
// Do a tolerant match.
|
||||||
let diff = diffPaths(expected, simplified);
|
let diff = diffPaths(expected, simplified);
|
||||||
if (test.expectMatch === 'yes'){
|
if (test.expectMatch === 'yes'){
|
||||||
|
// Check fill type
|
||||||
|
expect(simplified.getFillType().value).toEqual(getFillType(test.fillTypeOut).value);
|
||||||
|
// diff should be null if the paths are identical (modulo rounding)
|
||||||
if (diff) {
|
if (diff) {
|
||||||
expect(`[${testName}] ${diff}`).toBe('');
|
expect(`[${testName}] ${diff}`).toBe('');
|
||||||
addSVG('[Simplify] ' + testName, expected, simplified, diff);
|
addSVG('[Simplify] ' + testName, expected, simplified, diff);
|
||||||
@ -223,4 +229,4 @@ describe('PathKit\'s PathOps Behavior', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
describe('PathKit\'s SVG Behavior', function() {
|
describe('PathKit\'s SVG Behavior', function() {
|
||||||
// Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up.
|
// Note, don't try to print the PathKit object - it can cause Karma/Jasmine to lock up.
|
||||||
var PathKit = null;
|
var PathKit = null;
|
||||||
const LoadPathKit = new Promise(function(resolve, reject){
|
const LoadPathKit = new Promise(function(resolve, reject) {
|
||||||
if (PathKit) {
|
if (PathKit) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
PathKitInit({
|
PathKitInit({
|
||||||
locateFile: (file) => '/base/npm-wasm/bin/test/'+file,
|
locateFile: (file) => '/pathkit/'+file,
|
||||||
}).then((_PathKit) => {
|
}).then((_PathKit) => {
|
||||||
PathKit = _PathKit;
|
PathKit = _PathKit;
|
||||||
resolve();
|
resolve();
|
||||||
@ -15,7 +15,7 @@ describe('PathKit\'s SVG Behavior', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can create a path from an SVG string', function(done){
|
it('can create a path from an SVG string', function(done) {
|
||||||
LoadPathKit.then(() => {
|
LoadPathKit.then(() => {
|
||||||
//.This is a parallelagram from
|
//.This is a parallelagram from
|
||||||
// https://upload.wikimedia.org/wikipedia/commons/e/e7/Simple_parallelogram.svg
|
// https://upload.wikimedia.org/wikipedia/commons/e/e7/Simple_parallelogram.svg
|
||||||
@ -37,7 +37,7 @@ describe('PathKit\'s SVG Behavior', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can create an SVG string from a path', function(done){
|
it('can create an SVG string from a path', function(done) {
|
||||||
LoadPathKit.then(() => {
|
LoadPathKit.then(() => {
|
||||||
let cmds = [[PathKit.MOVE_VERB, 205, 5],
|
let cmds = [[PathKit.MOVE_VERB, 205, 5],
|
||||||
[PathKit.LINE_VERB, 795, 5],
|
[PathKit.LINE_VERB, 795, 5],
|
||||||
@ -56,7 +56,7 @@ describe('PathKit\'s SVG Behavior', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can create an SVG string from hex values', function(done){
|
it('can create an SVG string from hex values', function(done) {
|
||||||
LoadPathKit.then(() => {
|
LoadPathKit.then(() => {
|
||||||
let cmds = [[PathKit.MOVE_VERB, "0x15e80300", "0x400004dc"], // 9.37088e-26f, 2.0003f
|
let cmds = [[PathKit.MOVE_VERB, "0x15e80300", "0x400004dc"], // 9.37088e-26f, 2.0003f
|
||||||
[PathKit.LINE_VERB, 795, 5],
|
[PathKit.LINE_VERB, 795, 5],
|
||||||
@ -74,7 +74,7 @@ describe('PathKit\'s SVG Behavior', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have input and the output be the same', function(done){
|
it('should have input and the output be the same', function(done) {
|
||||||
LoadPathKit.then(() => {
|
LoadPathKit.then(() => {
|
||||||
let testCases = [
|
let testCases = [
|
||||||
'M0 0L1075 0L1075 242L0 242L0 0Z'
|
'M0 0L1075 0L1075 242L0 242L0 0Z'
|
||||||
@ -92,4 +92,20 @@ describe('PathKit\'s SVG Behavior', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('approximates arcs (conics) with quads', function(done) {
|
||||||
|
LoadPathKit.then(() => {
|
||||||
|
let path = PathKit.NewPath();
|
||||||
|
path.moveTo(20, 120);
|
||||||
|
path.arc(20, 120, 18, 0, 1.75 * Math.PI);
|
||||||
|
path.lineTo(20, 120);
|
||||||
|
let svgStr = path.toSVGString();
|
||||||
|
// Q stands for quad. No need to check the whole path, as that's more
|
||||||
|
// what the gold correctness tests are for (can account for changes we make
|
||||||
|
// to the approximation algorithms).
|
||||||
|
expect(svgStr).toContain('Q');
|
||||||
|
path.delete();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -101,6 +101,11 @@ static void report_no_entries(const char* functionName) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
SkFlattenable::Factory SkFlattenable::NameToFactory(const char name[]) {
|
SkFlattenable::Factory SkFlattenable::NameToFactory(const char name[]) {
|
||||||
|
#ifdef WEB_ASSEMBLY
|
||||||
|
// Should not be reachable by WebAssembly Code.
|
||||||
|
SkASSERT(false);
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
InitializeFlattenablesIfNeeded();
|
InitializeFlattenablesIfNeeded();
|
||||||
SkASSERT(std::is_sorted(gEntries, gEntries + gCount, EntryComparator()));
|
SkASSERT(std::is_sorted(gEntries, gEntries + gCount, EntryComparator()));
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
@ -110,9 +115,15 @@ SkFlattenable::Factory SkFlattenable::NameToFactory(const char name[]) {
|
|||||||
if (pair.first == pair.second)
|
if (pair.first == pair.second)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return pair.first->fFactory;
|
return pair.first->fFactory;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkFlattenable::NameToType(const char name[], SkFlattenable::Type* type) {
|
bool SkFlattenable::NameToType(const char name[], SkFlattenable::Type* type) {
|
||||||
|
#ifdef WEB_ASSEMBLY
|
||||||
|
// Should not be reachable by WebAssembly Code.
|
||||||
|
SkASSERT(false);
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
SkASSERT(type);
|
SkASSERT(type);
|
||||||
InitializeFlattenablesIfNeeded();
|
InitializeFlattenablesIfNeeded();
|
||||||
SkASSERT(std::is_sorted(gEntries, gEntries + gCount, EntryComparator()));
|
SkASSERT(std::is_sorted(gEntries, gEntries + gCount, EntryComparator()));
|
||||||
@ -124,9 +135,15 @@ bool SkFlattenable::NameToType(const char name[], SkFlattenable::Type* type) {
|
|||||||
return false;
|
return false;
|
||||||
*type = pair.first->fType;
|
*type = pair.first->fType;
|
||||||
return true;
|
return true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* SkFlattenable::FactoryToName(Factory fact) {
|
const char* SkFlattenable::FactoryToName(Factory fact) {
|
||||||
|
#ifdef WEB_ASSEMBLY
|
||||||
|
// Should not be reachable by WebAssembly Code.
|
||||||
|
SkASSERT(false);
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
InitializeFlattenablesIfNeeded();
|
InitializeFlattenablesIfNeeded();
|
||||||
#ifdef SK_DEBUG
|
#ifdef SK_DEBUG
|
||||||
report_no_entries(__FUNCTION__);
|
report_no_entries(__FUNCTION__);
|
||||||
@ -138,6 +155,7 @@ const char* SkFlattenable::FactoryToName(Factory fact) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -374,6 +374,11 @@ void SkDashImpl::flatten(SkWriteBuffer& buffer) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sk_sp<SkFlattenable> SkDashImpl::CreateProc(SkReadBuffer& buffer) {
|
sk_sp<SkFlattenable> SkDashImpl::CreateProc(SkReadBuffer& buffer) {
|
||||||
|
#ifdef WEB_ASSEMBLY
|
||||||
|
// Should not be reachable by WebAssembly Code.
|
||||||
|
SkASSERT(false);
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
const SkScalar phase = buffer.readScalar();
|
const SkScalar phase = buffer.readScalar();
|
||||||
uint32_t count = buffer.getArrayCount();
|
uint32_t count = buffer.getArrayCount();
|
||||||
|
|
||||||
@ -387,6 +392,7 @@ sk_sp<SkFlattenable> SkDashImpl::CreateProc(SkReadBuffer& buffer) {
|
|||||||
return SkDashPathEffect::Make(intervals.get(), SkToInt(count), phase);
|
return SkDashPathEffect::Make(intervals.get(), SkToInt(count), phase);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -89,12 +89,18 @@ void SkTrimPE::flatten(SkWriteBuffer& buffer) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sk_sp<SkFlattenable> SkTrimPE::CreateProc(SkReadBuffer& buffer) {
|
sk_sp<SkFlattenable> SkTrimPE::CreateProc(SkReadBuffer& buffer) {
|
||||||
|
#ifdef WEB_ASSEMBLY
|
||||||
|
// Should not be reachable by WebAssembly Code.
|
||||||
|
SkASSERT(false);
|
||||||
|
return nullptr;
|
||||||
|
#else
|
||||||
const auto start = buffer.readScalar(),
|
const auto start = buffer.readScalar(),
|
||||||
stop = buffer.readScalar();
|
stop = buffer.readScalar();
|
||||||
const auto mode = buffer.readUInt();
|
const auto mode = buffer.readUInt();
|
||||||
|
|
||||||
return SkTrimPathEffect::Make(start, stop,
|
return SkTrimPathEffect::Make(start, stop,
|
||||||
(mode & 1) ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal);
|
(mode & 1) ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Loading…
Reference in New Issue
Block a user