[canvaskit] Add build flag for pathops
This fixes up some other build flag options: - font-specific js code is correctly omitted when no_font is set - SKP serialization is only compiled in debug (or with flag). Bug: skia:9733 Change-Id: Ifdbd2ddac278cfcefa842f6d4826d5429b6ed64b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/262137 Reviewed-by: Kevin Lubick <kjlubick@google.com>
This commit is contained in:
parent
f1db2661f1
commit
933ea8c301
@ -6,15 +6,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- A "Core" build that removes Fonts, the Skottie animation player, the Particles demo,
|
||||
and PathOps is available in `bin/core/`. It is about half the size of the "CoreWithFonts"
|
||||
build.
|
||||
- Experimental Runtime shader available for custom builds.
|
||||
|
||||
### Fixed
|
||||
- `CanvasKit.SaveLayerInitWithPrevious` and `CanvasKit.SaveLayerF16ColorType` constants.
|
||||
- Some compilation configurations, for example, those with no fonts or just one of particles/skottie.
|
||||
|
||||
### Changed
|
||||
- Small tweaks to compilation settings to reduce code size and linkage time.
|
||||
- JS functions are no longer provided when the underlying c++ calls have been compiled out.
|
||||
|
||||
### Removed
|
||||
- `SkShader.Empty`
|
||||
- `SkShader.Empty`
|
||||
|
||||
### Breaking
|
||||
- In an effort to reduce code size for most clients, npm now contains two CanvasKit builds.
|
||||
In `bin/` there is the "CoreWithFonts" build that contains most functionality from 0.10.0.
|
||||
However, we no longer ship the Skottie animation player, nor the Particles demo. Further,
|
||||
PathOps are removed from this build `MakePathFromOp`, `SkPath.op` and `SkPath.simplify`.
|
||||
Clients who need any of those features are encouraged to create a custom build using
|
||||
`compile.sh`.
|
||||
- `SkPicture.DEBUGONLY_saveAsFile` was accidentally included in release builds. It has been
|
||||
removed. Clients who need this in a release build (e.g. to file a bug report that only
|
||||
reproduces in release) should do a custom build with the `force_serialize_skp` flag given.
|
||||
|
||||
## [0.10.0] - 2019-12-09
|
||||
|
||||
|
@ -16,9 +16,6 @@
|
||||
#include "include/core/SkDrawable.h"
|
||||
#include "include/core/SkEncodedImageFormat.h"
|
||||
#include "include/core/SkFilterQuality.h"
|
||||
#include "include/core/SkFont.h"
|
||||
#include "include/core/SkFontMgr.h"
|
||||
#include "include/core/SkFontTypes.h"
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/core/SkImageFilter.h"
|
||||
#include "include/core/SkImageInfo.h"
|
||||
@ -47,7 +44,6 @@
|
||||
#include "include/effects/SkImageFilters.h"
|
||||
#include "include/effects/SkRuntimeEffect.h"
|
||||
#include "include/effects/SkTrimPathEffect.h"
|
||||
#include "include/pathops/SkPathOps.h"
|
||||
#include "include/utils/SkParsePath.h"
|
||||
#include "include/utils/SkShadowUtils.h"
|
||||
#include "modules/skshaper/include/SkShaper.h"
|
||||
@ -72,9 +68,20 @@
|
||||
#include <emscripten/html5.h>
|
||||
#endif
|
||||
|
||||
#ifndef SK_NO_FONTS
|
||||
#include "include/core/SkFont.h"
|
||||
#include "include/core/SkFontMgr.h"
|
||||
#include "include/core/SkFontTypes.h"
|
||||
#endif
|
||||
|
||||
#ifdef SK_INCLUDE_PARAGRAPH
|
||||
#include "modules/skparagraph/include/Paragraph.h"
|
||||
#endif
|
||||
|
||||
#ifdef SK_INCLUDE_PATHOPS
|
||||
#include "include/pathops/SkPathOps.h"
|
||||
#endif
|
||||
|
||||
// Aliases for less typing
|
||||
using BoneIndices = SkVertices::BoneIndices;
|
||||
using BoneWeights = SkVertices::BoneWeights;
|
||||
@ -314,21 +321,31 @@ void ApplyTransform(SkPath& orig,
|
||||
orig.transform(m);
|
||||
}
|
||||
|
||||
bool EMSCRIPTEN_KEEPALIVE ApplySimplify(SkPath& path) {
|
||||
#ifdef SK_INCLUDE_PATHOPS
|
||||
bool ApplySimplify(SkPath& path) {
|
||||
return Simplify(path, &path);
|
||||
}
|
||||
|
||||
bool EMSCRIPTEN_KEEPALIVE ApplyPathOp(SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
|
||||
bool ApplyPathOp(SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
|
||||
return Op(pathOne, pathTwo, op, &pathOne);
|
||||
}
|
||||
|
||||
JSString EMSCRIPTEN_KEEPALIVE ToSVGString(const SkPath& path) {
|
||||
SkPathOrNull MakePathFromOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
|
||||
SkPath out;
|
||||
if (Op(pathOne, pathTwo, op, &out)) {
|
||||
return emscripten::val(out);
|
||||
}
|
||||
return emscripten::val::null();
|
||||
}
|
||||
#endif
|
||||
|
||||
JSString ToSVGString(const SkPath& path) {
|
||||
SkString s;
|
||||
SkParsePath::ToSVGString(path, &s);
|
||||
return emscripten::val(s.c_str());
|
||||
}
|
||||
|
||||
SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromSVGString(std::string str) {
|
||||
SkPathOrNull MakePathFromSVGString(std::string str) {
|
||||
SkPath path;
|
||||
if (SkParsePath::FromSVGString(str.c_str(), &path)) {
|
||||
return emscripten::val(path);
|
||||
@ -336,20 +353,12 @@ SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromSVGString(std::string str) {
|
||||
return emscripten::val::null();
|
||||
}
|
||||
|
||||
SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromOp(const SkPath& pathOne, const SkPath& pathTwo, SkPathOp op) {
|
||||
SkPath out;
|
||||
if (Op(pathOne, pathTwo, op, &out)) {
|
||||
return emscripten::val(out);
|
||||
}
|
||||
return emscripten::val::null();
|
||||
}
|
||||
|
||||
SkPath EMSCRIPTEN_KEEPALIVE CopyPath(const SkPath& a) {
|
||||
SkPath CopyPath(const SkPath& a) {
|
||||
SkPath copy(a);
|
||||
return copy;
|
||||
}
|
||||
|
||||
bool EMSCRIPTEN_KEEPALIVE Equals(const SkPath& a, const SkPath& b) {
|
||||
bool Equals(const SkPath& a, const SkPath& b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
@ -374,7 +383,7 @@ void VisitPath(const SkPath& p, VisitFunc&& f) {
|
||||
}
|
||||
}
|
||||
|
||||
JSArray EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
|
||||
JSArray ToCmds(const SkPath& path) {
|
||||
JSArray cmds = emscripten::val::array();
|
||||
|
||||
VisitPath(path, [&cmds](SkPath::Verb verb, const SkPoint pts[4], SkPath::RawIter iter) {
|
||||
@ -422,7 +431,7 @@ JSArray EMSCRIPTEN_KEEPALIVE ToCmds(const SkPath& path) {
|
||||
// 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
|
||||
// the compiler is happy.
|
||||
SkPathOrNull EMSCRIPTEN_KEEPALIVE MakePathFromCmds(uintptr_t /* float* */ cptr, int numCmds) {
|
||||
SkPathOrNull MakePathFromCmds(uintptr_t /* float* */ cptr, int numCmds) {
|
||||
const auto* cmds = reinterpret_cast<const float*>(cptr);
|
||||
SkPath path;
|
||||
float x1, y1, x2, y2, x3, y3;
|
||||
@ -737,7 +746,9 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
return SkMaskFilter::MakeBlur(style, sigma, respectCTM);
|
||||
}), allow_raw_pointers());
|
||||
function("_MakePathFromCmds", &MakePathFromCmds);
|
||||
#ifdef SK_INCLUDE_PATHOPS
|
||||
function("MakePathFromOp", &MakePathFromOp);
|
||||
#endif
|
||||
function("MakePathFromSVGString", &MakePathFromSVGString);
|
||||
|
||||
// These won't be called directly, there's a JS helper to deal with typed arrays.
|
||||
@ -1265,10 +1276,11 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.function("_trim", &ApplyTrim)
|
||||
.function("_stroke", &ApplyStroke)
|
||||
|
||||
#ifdef SK_INCLUDE_PATHOPS
|
||||
// PathOps
|
||||
.function("_simplify", &ApplySimplify)
|
||||
.function("_op", &ApplyPathOp)
|
||||
|
||||
#endif
|
||||
// Exporting
|
||||
.function("toSVGString", &ToSVGString)
|
||||
.function("toCmds", &ToCmds)
|
||||
@ -1322,6 +1334,7 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
|
||||
class_<SkPicture>("SkPicture")
|
||||
.smart_ptr<sk_sp<SkPicture>>("sk_sp<SkPicture>")
|
||||
#if defined(SK_DEBUG) || defined(SK_FORCE_SERIALIZE_SKP)
|
||||
// The serialized format of an SkPicture (informally called an "skp"), is not something
|
||||
// that clients should ever rely on. It is useful when filing bug reports, but that's
|
||||
// about it. The format may change at anytime and no promises are made for backwards
|
||||
@ -1330,7 +1343,9 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
// Emscripten doesn't play well with optional arguments, which we don't
|
||||
// want to expose anyway.
|
||||
return self.serialize();
|
||||
}), allow_raw_pointers());
|
||||
}), allow_raw_pointers())
|
||||
#endif
|
||||
;
|
||||
|
||||
class_<SkShader>("SkShader")
|
||||
.smart_ptr<sk_sp<SkShader>>("sk_sp<SkShader>")
|
||||
@ -1549,12 +1564,14 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.value("Stroke", SkPaint::Style::kStroke_Style)
|
||||
.value("StrokeAndFill", SkPaint::Style::kStrokeAndFill_Style);
|
||||
|
||||
#ifdef SK_INCLUDE_PATHOPS
|
||||
enum_<SkPathOp>("PathOp")
|
||||
.value("Difference", SkPathOp::kDifference_SkPathOp)
|
||||
.value("Intersect", SkPathOp::kIntersect_SkPathOp)
|
||||
.value("Union", SkPathOp::kUnion_SkPathOp)
|
||||
.value("XOR", SkPathOp::kXOR_SkPathOp)
|
||||
.value("ReverseDifference", SkPathOp::kReverseDifference_SkPathOp);
|
||||
#endif
|
||||
|
||||
enum_<SkCanvas::PointMode>("PointMode")
|
||||
.value("Points", SkCanvas::PointMode::kPoints_PointMode)
|
||||
|
@ -28,11 +28,13 @@ EMAR=`which emar`
|
||||
RELEASE_CONF="-Oz --closure 1 --llvm-lto 1 -DSK_RELEASE --pre-js $BASE_DIR/release.js \
|
||||
-DGR_GL_CHECK_ALLOC_WITH_GET_ERROR=0"
|
||||
EXTRA_CFLAGS="\"-DSK_RELEASE\", \"-DGR_GL_CHECK_ALLOC_WITH_GET_ERROR=0\","
|
||||
SKP_JS=""
|
||||
if [[ $@ == *debug* ]]; then
|
||||
echo "Building a Debug build"
|
||||
EXTRA_CFLAGS="\"-DSK_DEBUG\""
|
||||
RELEASE_CONF="-O0 --js-opts 0 -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=1 -s GL_ASSERTIONS=1 -g4 \
|
||||
--source-map-base /node_modules/canvaskit/bin/ -DSK_DEBUG --pre-js $BASE_DIR/debug.js"
|
||||
SKP_JS="--pre-js $BASE_DIR/skp.js"
|
||||
BUILD_DIR=${BUILD_DIR:="out/canvaskit_wasm_debug"}
|
||||
elif [[ $@ == *profiling* ]]; then
|
||||
echo "Building a build for profiling"
|
||||
@ -43,6 +45,13 @@ else
|
||||
BUILD_DIR=${BUILD_DIR:="out/canvaskit_wasm"}
|
||||
fi
|
||||
|
||||
# This should only be set by clients who are trying to serialize an
|
||||
# skp to include in a bug report and for whatever reason, it is not
|
||||
# showing up in a debug build.
|
||||
if [[ $@ == *force_serialize_skp* ]] ; then
|
||||
RELEASE_CONF+=" -DSK_FORCE_SERIALIZE_SKP"
|
||||
fi
|
||||
|
||||
mkdir -p $BUILD_DIR
|
||||
# sometimes the .a files keep old symbols around - cleaning them out makes sure
|
||||
# we get a fresh build.
|
||||
@ -98,6 +107,13 @@ if [[ $@ != *no_particles* || $@ != *no_skottie* ]] ; then
|
||||
PARTICLES_BINDINGS+=" modules/skresources/src/SkResources.cpp"
|
||||
fi
|
||||
|
||||
WASM_PATHOPS="-DSK_INCLUDE_PATHOPS"
|
||||
PATHOPS_JS="--pre-js $BASE_DIR/pathops.js"
|
||||
if [[ $@ == *no_pathops* ]] ; then
|
||||
WASM_PATHOPS=""
|
||||
PATHOPS_JS=""
|
||||
fi
|
||||
|
||||
HTML_CANVAS_API="--pre-js $BASE_DIR/htmlcanvas/preamble.js \
|
||||
--pre-js $BASE_DIR/htmlcanvas/util.js \
|
||||
--pre-js $BASE_DIR/htmlcanvas/color.js \
|
||||
@ -118,10 +134,12 @@ fi
|
||||
GN_FONT="skia_enable_fontmgr_empty=false skia_enable_fontmgr_custom_empty=false"
|
||||
FONT_CFLAGS=""
|
||||
BUILTIN_FONT="$BASE_DIR/fonts/NotoMono-Regular.ttf.cpp"
|
||||
FONT_JS="--pre-js $BASE_DIR/font.js"
|
||||
if [[ $@ == *no_font* ]]; then
|
||||
echo "Omitting the built-in font(s), font manager and all code dealing with fonts"
|
||||
BUILTIN_FONT=""
|
||||
FONT_CFLAGS="-DSK_NO_FONTS"
|
||||
FONT_JS=""
|
||||
GN_FONT="skia_enable_fontmgr_empty=true skia_enable_fontmgr_custom_empty=false"
|
||||
elif [[ $@ == *no_embedded_font* ]]; then
|
||||
echo "Omitting the built-in font(s)"
|
||||
@ -243,6 +261,7 @@ ${EMCXX} \
|
||||
-DSK_DISABLE_READBUFFER \
|
||||
-DSK_DISABLE_AAA \
|
||||
$WASM_GPU \
|
||||
$WASM_PATHOPS \
|
||||
$FONT_CFLAGS \
|
||||
-std=c++14 \
|
||||
--bind \
|
||||
@ -252,6 +271,9 @@ ${EMCXX} \
|
||||
$PARAGRAPH_JS \
|
||||
$SKOTTIE_JS \
|
||||
$PARTICLES_JS \
|
||||
$PATHOPS_JS \
|
||||
$FONT_JS \
|
||||
$SKP_JS \
|
||||
$HTML_CANVAS_API \
|
||||
--pre-js $BASE_DIR/postamble.js \
|
||||
--post-js $BASE_DIR/ready.js \
|
||||
|
201
modules/canvaskit/font.js
Normal file
201
modules/canvaskit/font.js
Normal file
@ -0,0 +1,201 @@
|
||||
CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
|
||||
CanvasKit._extraInitializations.push(function() {
|
||||
|
||||
// str can be either a text string or a ShapedText object
|
||||
CanvasKit.SkCanvas.prototype.drawText = function(str, x, y, paint, font) {
|
||||
if (typeof str === 'string') {
|
||||
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
||||
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
var strLen = lengthBytesUTF8(str);
|
||||
// Add 1 for null terminator, which we need when copying/converting, but can ignore
|
||||
// when we call into Skia.
|
||||
var strPtr = CanvasKit._malloc(strLen + 1);
|
||||
stringToUTF8(str, strPtr, strLen + 1);
|
||||
this._drawSimpleText(strPtr, strLen, x, y, font, paint);
|
||||
} else {
|
||||
this._drawShapedText(str, x, y, paint);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns an array of the widths of the glyphs in this string.
|
||||
CanvasKit.SkFont.prototype.getWidths = function(str) {
|
||||
// add 1 for null terminator
|
||||
var codePoints = str.length + 1;
|
||||
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
||||
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
// Add 1 for null terminator
|
||||
var strBytes = lengthBytesUTF8(str) + 1;
|
||||
var strPtr = CanvasKit._malloc(strBytes);
|
||||
stringToUTF8(str, strPtr, strBytes);
|
||||
|
||||
var bytesPerFloat = 4;
|
||||
// allocate widths == numCodePoints
|
||||
var widthPtr = CanvasKit._malloc(codePoints * bytesPerFloat);
|
||||
if (!this._getWidths(strPtr, strBytes, codePoints, widthPtr)) {
|
||||
SkDebug('Could not compute widths');
|
||||
CanvasKit._free(strPtr);
|
||||
CanvasKit._free(widthPtr);
|
||||
return null;
|
||||
}
|
||||
// reminder, this shouldn't copy the data, just is a nice way to
|
||||
// wrap 4 bytes together into a float.
|
||||
var widths = new Float32Array(CanvasKit.buffer, widthPtr, codePoints);
|
||||
// This copies the data so we can free the CanvasKit memory
|
||||
var retVal = Array.from(widths);
|
||||
CanvasKit._free(strPtr);
|
||||
CanvasKit._free(widthPtr);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// arguments should all be arrayBuffers or be an array of arrayBuffers.
|
||||
CanvasKit.SkFontMgr.FromData = function() {
|
||||
if (!arguments.length) {
|
||||
SkDebug('Could not make SkFontMgr from no font sources');
|
||||
return null;
|
||||
}
|
||||
var fonts = arguments;
|
||||
if (fonts.length === 1 && Array.isArray(fonts[0])) {
|
||||
fonts = arguments[0];
|
||||
}
|
||||
if (!fonts.length) {
|
||||
SkDebug('Could not make SkFontMgr from no font sources');
|
||||
return null;
|
||||
}
|
||||
var dPtrs = [];
|
||||
var sizes = [];
|
||||
for (var i = 0; i < fonts.length; i++) {
|
||||
var data = new Uint8Array(fonts[i]);
|
||||
var dptr = copy1dArray(data, CanvasKit.HEAPU8);
|
||||
dPtrs.push(dptr);
|
||||
sizes.push(data.byteLength);
|
||||
}
|
||||
// Pointers are 32 bit unsigned ints
|
||||
var datasPtr = copy1dArray(dPtrs, CanvasKit.HEAPU32);
|
||||
var sizesPtr = copy1dArray(sizes, CanvasKit.HEAPU32);
|
||||
var fm = CanvasKit.SkFontMgr._fromData(datasPtr, sizesPtr, fonts.length);
|
||||
// The SkFontMgr has taken ownership of the bytes we allocated in the for loop.
|
||||
CanvasKit._free(datasPtr);
|
||||
CanvasKit._free(sizesPtr);
|
||||
return fm;
|
||||
}
|
||||
|
||||
// fontData should be an arrayBuffer
|
||||
CanvasKit.SkFontMgr.prototype.MakeTypefaceFromData = function(fontData) {
|
||||
var data = new Uint8Array(fontData);
|
||||
|
||||
var fptr = copy1dArray(data, CanvasKit.HEAPU8);
|
||||
var font = this._makeTypefaceFromData(fptr, data.byteLength);
|
||||
if (!font) {
|
||||
SkDebug('Could not decode font data');
|
||||
// We do not need to free the data since the C++ will do that for us
|
||||
// when the font is deleted (or fails to decode);
|
||||
return null;
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
CanvasKit.SkTextBlob.MakeOnPath = function(str, path, font, initialOffset) {
|
||||
if (!str || !str.length) {
|
||||
SkDebug('ignoring 0 length string');
|
||||
return;
|
||||
}
|
||||
if (!path || !path.countPoints()) {
|
||||
SkDebug('ignoring empty path');
|
||||
return;
|
||||
}
|
||||
if (path.countPoints() === 1) {
|
||||
SkDebug('path has 1 point, returning normal textblob');
|
||||
return this.MakeFromText(str, font);
|
||||
}
|
||||
|
||||
if (!initialOffset) {
|
||||
initialOffset = 0;
|
||||
}
|
||||
|
||||
var widths = font.getWidths(str);
|
||||
|
||||
var rsx = new CanvasKit.RSXFormBuilder();
|
||||
var meas = new CanvasKit.SkPathMeasure(path, false, 1);
|
||||
var dist = initialOffset;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var width = widths[i];
|
||||
dist += width/2;
|
||||
if (dist > meas.getLength()) {
|
||||
// jump to next contour
|
||||
if (!meas.nextContour()) {
|
||||
// We have come to the end of the path - terminate the string
|
||||
// right here.
|
||||
str = str.substring(0, i);
|
||||
break;
|
||||
}
|
||||
dist = width/2;
|
||||
}
|
||||
|
||||
// Gives us the (x, y) coordinates as well as the cos/sin of the tangent
|
||||
// line at that position.
|
||||
var xycs = meas.getPosTan(dist);
|
||||
var cx = xycs[0];
|
||||
var cy = xycs[1];
|
||||
var cosT = xycs[2];
|
||||
var sinT = xycs[3];
|
||||
|
||||
var adjustedX = cx - (width/2 * cosT);
|
||||
var adjustedY = cy - (width/2 * sinT);
|
||||
|
||||
rsx.push(cosT, sinT, adjustedX, adjustedY);
|
||||
dist += width/2;
|
||||
}
|
||||
var retVal = this.MakeFromRSXform(str, rsx, font);
|
||||
rsx.delete();
|
||||
meas.delete();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
CanvasKit.SkTextBlob.MakeFromRSXform = function(str, rsxBuilder, font) {
|
||||
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
||||
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
// Add 1 for null terminator
|
||||
var strLen = lengthBytesUTF8(str) + 1;
|
||||
var strPtr = CanvasKit._malloc(strLen);
|
||||
// Add 1 for the null terminator.
|
||||
stringToUTF8(str, strPtr, strLen);
|
||||
var rptr = rsxBuilder.build();
|
||||
|
||||
var blob = CanvasKit.SkTextBlob._MakeFromRSXform(strPtr, strLen - 1,
|
||||
rptr, font, CanvasKit.TextEncoding.UTF8);
|
||||
if (!blob) {
|
||||
SkDebug('Could not make textblob from string "' + str + '"');
|
||||
return null;
|
||||
}
|
||||
|
||||
var origDelete = blob.delete.bind(blob);
|
||||
blob.delete = function() {
|
||||
CanvasKit._free(strPtr);
|
||||
origDelete();
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
CanvasKit.SkTextBlob.MakeFromText = function(str, font) {
|
||||
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
||||
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
// Add 1 for null terminator
|
||||
var strLen = lengthBytesUTF8(str) + 1;
|
||||
var strPtr = CanvasKit._malloc(strLen);
|
||||
// Add 1 for the null terminator.
|
||||
stringToUTF8(str, strPtr, strLen);
|
||||
|
||||
var blob = CanvasKit.SkTextBlob._MakeFromText(strPtr, strLen - 1, font, CanvasKit.TextEncoding.UTF8);
|
||||
if (!blob) {
|
||||
SkDebug('Could not make textblob from string "' + str + '"');
|
||||
return null;
|
||||
}
|
||||
|
||||
var origDelete = blob.delete.bind(blob);
|
||||
blob.delete = function() {
|
||||
CanvasKit._free(strPtr);
|
||||
origDelete();
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
});
|
@ -428,13 +428,6 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
CanvasKit.SkPath.prototype.op = function(otherPath, op) {
|
||||
if (this._op(otherPath, op)) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
CanvasKit.SkPath.prototype.quadTo = function(cpx, cpy, x, y) {
|
||||
this._quadTo(cpx, cpy, x, y);
|
||||
return this;
|
||||
@ -472,13 +465,6 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
CanvasKit.SkPath.prototype.simplify = function() {
|
||||
if (this._simplify()) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
CanvasKit.SkPath.prototype.stroke = function(opts) {
|
||||
// Fill out any missing values with the default values.
|
||||
/**
|
||||
@ -676,22 +662,6 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
CanvasKit._free(ptr);
|
||||
}
|
||||
|
||||
// str can be either a text string or a ShapedText object
|
||||
CanvasKit.SkCanvas.prototype.drawText = function(str, x, y, paint, font) {
|
||||
if (typeof str === 'string') {
|
||||
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
||||
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
var strLen = lengthBytesUTF8(str);
|
||||
// Add 1 for null terminator, which we need when copying/converting, but can ignore
|
||||
// when we call into Skia.
|
||||
var strPtr = CanvasKit._malloc(strLen + 1);
|
||||
stringToUTF8(str, strPtr, strLen + 1);
|
||||
this._drawSimpleText(strPtr, strLen, x, y, font, paint);
|
||||
} else {
|
||||
this._drawShapedText(str, x, y, paint);
|
||||
}
|
||||
}
|
||||
|
||||
// returns Uint8Array
|
||||
CanvasKit.SkCanvas.prototype.readPixels = function(x, y, w, h, alphaType,
|
||||
colorType, dstRowBytes) {
|
||||
@ -760,98 +730,6 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
return m;
|
||||
}
|
||||
|
||||
// Returns an array of the widths of the glyphs in this string.
|
||||
CanvasKit.SkFont.prototype.getWidths = function(str) {
|
||||
// add 1 for null terminator
|
||||
var codePoints = str.length + 1;
|
||||
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
||||
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
// Add 1 for null terminator
|
||||
var strBytes = lengthBytesUTF8(str) + 1;
|
||||
var strPtr = CanvasKit._malloc(strBytes);
|
||||
stringToUTF8(str, strPtr, strBytes);
|
||||
|
||||
var bytesPerFloat = 4;
|
||||
// allocate widths == numCodePoints
|
||||
var widthPtr = CanvasKit._malloc(codePoints * bytesPerFloat);
|
||||
if (!this._getWidths(strPtr, strBytes, codePoints, widthPtr)) {
|
||||
SkDebug('Could not compute widths');
|
||||
CanvasKit._free(strPtr);
|
||||
CanvasKit._free(widthPtr);
|
||||
return null;
|
||||
}
|
||||
// reminder, this shouldn't copy the data, just is a nice way to
|
||||
// wrap 4 bytes together into a float.
|
||||
var widths = new Float32Array(CanvasKit.buffer, widthPtr, codePoints);
|
||||
// This copies the data so we can free the CanvasKit memory
|
||||
var retVal = Array.from(widths);
|
||||
CanvasKit._free(strPtr);
|
||||
CanvasKit._free(widthPtr);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// arguments should all be arrayBuffers or be an array of arrayBuffers.
|
||||
CanvasKit.SkFontMgr.FromData = function() {
|
||||
if (!arguments.length) {
|
||||
SkDebug('Could not make SkFontMgr from no font sources');
|
||||
return null;
|
||||
}
|
||||
var fonts = arguments;
|
||||
if (fonts.length === 1 && Array.isArray(fonts[0])) {
|
||||
fonts = arguments[0];
|
||||
}
|
||||
if (!fonts.length) {
|
||||
SkDebug('Could not make SkFontMgr from no font sources');
|
||||
return null;
|
||||
}
|
||||
var dPtrs = [];
|
||||
var sizes = [];
|
||||
for (var i = 0; i < fonts.length; i++) {
|
||||
var data = new Uint8Array(fonts[i]);
|
||||
var dptr = copy1dArray(data, CanvasKit.HEAPU8);
|
||||
dPtrs.push(dptr);
|
||||
sizes.push(data.byteLength);
|
||||
}
|
||||
// Pointers are 32 bit unsigned ints
|
||||
var datasPtr = copy1dArray(dPtrs, CanvasKit.HEAPU32);
|
||||
var sizesPtr = copy1dArray(sizes, CanvasKit.HEAPU32);
|
||||
var fm = CanvasKit.SkFontMgr._fromData(datasPtr, sizesPtr, fonts.length);
|
||||
// The SkFontMgr has taken ownership of the bytes we allocated in the for loop.
|
||||
CanvasKit._free(datasPtr);
|
||||
CanvasKit._free(sizesPtr);
|
||||
return fm;
|
||||
}
|
||||
|
||||
// fontData should be an arrayBuffer
|
||||
CanvasKit.SkFontMgr.prototype.MakeTypefaceFromData = function(fontData) {
|
||||
var data = new Uint8Array(fontData);
|
||||
|
||||
var fptr = copy1dArray(data, CanvasKit.HEAPU8);
|
||||
var font = this._makeTypefaceFromData(fptr, data.byteLength);
|
||||
if (!font) {
|
||||
SkDebug('Could not decode font data');
|
||||
// We do not need to free the data since the C++ will do that for us
|
||||
// when the font is deleted (or fails to decode);
|
||||
return null;
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
// The serialized format of an SkPicture (informally called an "skp"), is not something
|
||||
// that clients should ever rely on. It is useful when filing bug reports, but that's
|
||||
// about it. The format may change at anytime and no promises are made for backwards
|
||||
// or forward compatibility.
|
||||
CanvasKit.SkPicture.prototype.DEBUGONLY_saveAsFile = function(skpName) {
|
||||
var data = this.DEBUGONLY_serialize();
|
||||
if (!data) {
|
||||
SkDebug('Could not serialize to skpicture.');
|
||||
return;
|
||||
}
|
||||
var bytes = CanvasKit.getSkDataBytes(data);
|
||||
saveBytesToFile(bytes, skpName);
|
||||
data.delete();
|
||||
}
|
||||
|
||||
CanvasKit.SkShader.Blend = function(mode, dst, src, localMatrix) {
|
||||
if (!localMatrix) {
|
||||
return this._Blend(mode, dst, src);
|
||||
@ -894,111 +772,6 @@ CanvasKit.onRuntimeInitialized = function() {
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
CanvasKit.SkTextBlob.MakeOnPath = function(str, path, font, initialOffset) {
|
||||
if (!str || !str.length) {
|
||||
SkDebug('ignoring 0 length string');
|
||||
return;
|
||||
}
|
||||
if (!path || !path.countPoints()) {
|
||||
SkDebug('ignoring empty path');
|
||||
return;
|
||||
}
|
||||
if (path.countPoints() === 1) {
|
||||
SkDebug('path has 1 point, returning normal textblob');
|
||||
return this.MakeFromText(str, font);
|
||||
}
|
||||
|
||||
if (!initialOffset) {
|
||||
initialOffset = 0;
|
||||
}
|
||||
|
||||
var widths = font.getWidths(str);
|
||||
|
||||
var rsx = new CanvasKit.RSXFormBuilder();
|
||||
var meas = new CanvasKit.SkPathMeasure(path, false, 1);
|
||||
var dist = initialOffset;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var width = widths[i];
|
||||
dist += width/2;
|
||||
if (dist > meas.getLength()) {
|
||||
// jump to next contour
|
||||
if (!meas.nextContour()) {
|
||||
// We have come to the end of the path - terminate the string
|
||||
// right here.
|
||||
str = str.substring(0, i);
|
||||
break;
|
||||
}
|
||||
dist = width/2;
|
||||
}
|
||||
|
||||
// Gives us the (x, y) coordinates as well as the cos/sin of the tangent
|
||||
// line at that position.
|
||||
var xycs = meas.getPosTan(dist);
|
||||
var cx = xycs[0];
|
||||
var cy = xycs[1];
|
||||
var cosT = xycs[2];
|
||||
var sinT = xycs[3];
|
||||
|
||||
var adjustedX = cx - (width/2 * cosT);
|
||||
var adjustedY = cy - (width/2 * sinT);
|
||||
|
||||
rsx.push(cosT, sinT, adjustedX, adjustedY);
|
||||
dist += width/2;
|
||||
}
|
||||
var retVal = this.MakeFromRSXform(str, rsx, font);
|
||||
rsx.delete();
|
||||
meas.delete();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
CanvasKit.SkTextBlob.MakeFromRSXform = function(str, rsxBuilder, font) {
|
||||
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
||||
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
// Add 1 for null terminator
|
||||
var strLen = lengthBytesUTF8(str) + 1;
|
||||
var strPtr = CanvasKit._malloc(strLen);
|
||||
// Add 1 for the null terminator.
|
||||
stringToUTF8(str, strPtr, strLen);
|
||||
var rptr = rsxBuilder.build();
|
||||
|
||||
var blob = CanvasKit.SkTextBlob._MakeFromRSXform(strPtr, strLen - 1,
|
||||
rptr, font, CanvasKit.TextEncoding.UTF8);
|
||||
if (!blob) {
|
||||
SkDebug('Could not make textblob from string "' + str + '"');
|
||||
return null;
|
||||
}
|
||||
|
||||
var origDelete = blob.delete.bind(blob);
|
||||
blob.delete = function() {
|
||||
CanvasKit._free(strPtr);
|
||||
origDelete();
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
CanvasKit.SkTextBlob.MakeFromText = function(str, font) {
|
||||
// lengthBytesUTF8 and stringToUTF8Array are defined in the emscripten
|
||||
// JS. See https://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html#stringToUTF8
|
||||
// Add 1 for null terminator
|
||||
var strLen = lengthBytesUTF8(str) + 1;
|
||||
var strPtr = CanvasKit._malloc(strLen);
|
||||
// Add 1 for the null terminator.
|
||||
stringToUTF8(str, strPtr, strLen);
|
||||
|
||||
var blob = CanvasKit.SkTextBlob._MakeFromText(strPtr, strLen - 1, font, CanvasKit.TextEncoding.UTF8);
|
||||
if (!blob) {
|
||||
SkDebug('Could not make textblob from string "' + str + '"');
|
||||
return null;
|
||||
}
|
||||
|
||||
var origDelete = blob.delete.bind(blob);
|
||||
blob.delete = function() {
|
||||
CanvasKit._free(strPtr);
|
||||
origDelete();
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
// Run through the JS files that are added at compile time.
|
||||
if (CanvasKit._extraInitializations) {
|
||||
CanvasKit._extraInitializations.forEach(function(init) {
|
||||
|
17
modules/canvaskit/pathops.js
Normal file
17
modules/canvaskit/pathops.js
Normal file
@ -0,0 +1,17 @@
|
||||
// Adds in the code to use pathops with SkPath
|
||||
CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
|
||||
CanvasKit._extraInitializations.push(function() {
|
||||
CanvasKit.SkPath.prototype.op = function(otherPath, op) {
|
||||
if (this._op(otherPath, op)) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
CanvasKit.SkPath.prototype.simplify = function() {
|
||||
if (this._simplify()) {
|
||||
return this;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
});
|
17
modules/canvaskit/skp.js
Normal file
17
modules/canvaskit/skp.js
Normal file
@ -0,0 +1,17 @@
|
||||
CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
|
||||
CanvasKit._extraInitializations.push(function() {
|
||||
// The serialized format of an SkPicture (informally called an "skp"), is not something
|
||||
// that clients should ever rely on. It is useful when filing bug reports, but that's
|
||||
// about it. The format may change at anytime and no promises are made for backwards
|
||||
// or forward compatibility.
|
||||
CanvasKit.SkPicture.prototype.DEBUGONLY_saveAsFile = function(skpName) {
|
||||
var data = this.DEBUGONLY_serialize();
|
||||
if (!data) {
|
||||
SkDebug('Could not serialize to skpicture.');
|
||||
return;
|
||||
}
|
||||
var bytes = CanvasKit.getSkDataBytes(data);
|
||||
saveBytesToFile(bytes, skpName);
|
||||
data.delete();
|
||||
}
|
||||
});
|
@ -15,17 +15,17 @@ describe('Skottie behavior', function() {
|
||||
});
|
||||
|
||||
it('can draw one with an animated gif', function(done) {
|
||||
if (!CanvasKit.skottie || !CanvasKit.managed_skottie) {
|
||||
console.warn('Skipping test because not compiled with skottie');
|
||||
done();
|
||||
return;
|
||||
}
|
||||
const imgPromise = fetch('/assets/flightAnim.gif')
|
||||
.then((response) => response.arrayBuffer());
|
||||
const jsonPromise = fetch('/assets/animated_gif.json')
|
||||
.then((response) => response.text());
|
||||
|
||||
Promise.all([imgPromise, jsonPromise, LoadCanvasKit]).then((values) => {
|
||||
if (!CanvasKit.managed_skottie) {
|
||||
console.warn('Skipping test because not compiled with skottie')
|
||||
done();
|
||||
return;
|
||||
}
|
||||
catchException(done, () => {
|
||||
const imgBuffer = values[0];
|
||||
expect(imgBuffer).toBeTruthy();
|
||||
|
Loading…
Reference in New Issue
Block a user