[canvaskit] Use textblob
Removes old API and replaces with new version. drawText now requires SkFont and other changes. Bug: skia: Change-Id: Ie42a5243629542934c761223ed2e8dc6685d3572 Reviewed-on: https://skia-review.googlesource.com/c/183389 Reviewed-by: Mike Reed <reed@google.com>
This commit is contained in:
parent
9f810c2da4
commit
ec4903d515
@ -11,6 +11,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `SkCanvas.drawArc`, `SkCanvas.drawLine`, `SkCanvas.drawOval`, `SkCanvas.drawRoundRect` exposed.
|
||||
- Can import/export a SkPath to an array of commands. See `CanvasKit.MakePathFromCmds` and
|
||||
`SkPath.toCmds`.
|
||||
- `SkCanvas.drawTextBlob()` and `SkCanvas.SkTextBlob.MakeFromText()` to draw text to a canvas.
|
||||
- `CanvasKit.TextEncoding` enum. For use with `SkTextBlob`.
|
||||
|
||||
### Changed
|
||||
- `SkCanvas.drawText()` now requires an `SkFont` object.
|
||||
|
||||
### Removed
|
||||
- `SkPaint.setTextSize()`, `SkPaint.getTextSize()`, `SkPaint.setTypeface()`
|
||||
which should be replaced by using `SkFont`.
|
||||
|
||||
|
||||
### Fixed
|
||||
- Potential bug in `ready()` if already loaded.
|
||||
|
@ -156,9 +156,9 @@
|
||||
|
||||
const textPaint = new CanvasKit.SkPaint();
|
||||
textPaint.setColor(CanvasKit.RED);
|
||||
textPaint.setTextSize(30);
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setTypeface(roboto);
|
||||
|
||||
const textFont = new CanvasKit.SkFont(roboto, 30);
|
||||
|
||||
let i = 0;
|
||||
|
||||
@ -183,7 +183,7 @@
|
||||
canvas.clear(CanvasKit.TRANSPARENT);
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
canvas.drawText('Try Clicking!', 10, 280, textPaint);
|
||||
canvas.drawText('Try Clicking!', 10, 280, textFont, textPaint);
|
||||
|
||||
surface.flush();
|
||||
|
||||
@ -205,7 +205,9 @@
|
||||
document.getElementById('patheffect').addEventListener('pointerdown', interact);
|
||||
preventScrolling(document.getElementById('patheffect'));
|
||||
// A client would need to delete this if it didn't go on for ever.
|
||||
//paint.delete();
|
||||
// paint.delete();
|
||||
// textPaint.delete();
|
||||
// textFont.delete();
|
||||
}
|
||||
|
||||
function PathExample(CanvasKit) {
|
||||
@ -1067,8 +1069,13 @@
|
||||
pos, CanvasKit.TileMode.Mirror, transform);
|
||||
|
||||
paint.setShader(shader);
|
||||
paint.setTextSize(75);
|
||||
canvas.drawText('Radial', 10, 200, paint);
|
||||
const textFont = new CanvasKit.SkFont(null, 75);
|
||||
const textBlob = CanvasKit.SkTextBlob.MakeFromText('Radial', textFont);
|
||||
|
||||
canvas.drawTextBlob(textBlob, 10, 200, paint);
|
||||
paint.delete()
|
||||
textFont.delete();
|
||||
textBlob.delete();
|
||||
surface.flush();
|
||||
}
|
||||
</script>
|
||||
|
@ -41,9 +41,10 @@ CanvasKitInit({
|
||||
ctx.drawImage(img, 100, 150, 400, 350, 10, 200, 150, 100);
|
||||
|
||||
console.log('<img src="' + canvas.toDataURL() + '" />');
|
||||
|
||||
fancyAPI(CanvasKit);
|
||||
});
|
||||
|
||||
// Not currently called
|
||||
function fancyAPI(CanvasKit) {
|
||||
let surface = CanvasKit.MakeSurface(300, 300);
|
||||
const canvas = surface.getCanvas();
|
||||
@ -56,9 +57,9 @@ function fancyAPI(CanvasKit) {
|
||||
|
||||
const textPaint = new CanvasKit.SkPaint();
|
||||
textPaint.setColor(CanvasKit.Color(40, 0, 0));
|
||||
textPaint.setTextSize(30);
|
||||
textPaint.setAntiAlias(true);
|
||||
textPaint.setTypeface(roboto);
|
||||
|
||||
const textFont = new CanvasKit.SkFont(roboto, 30);
|
||||
|
||||
const skpath = starPath(CanvasKit);
|
||||
const dpe = CanvasKit.MakeSkDashPathEffect([15, 5, 5, 10], 1);
|
||||
@ -72,7 +73,7 @@ function fancyAPI(CanvasKit) {
|
||||
canvas.clear(CanvasKit.Color(255, 255, 255, 1.0));
|
||||
|
||||
canvas.drawPath(skpath, paint);
|
||||
canvas.drawText('Try Clicking!', 10, 280, textPaint);
|
||||
canvas.drawText('Try Clicking!', 10, 280, textFont, textPaint);
|
||||
|
||||
surface.flush();
|
||||
|
||||
@ -97,6 +98,7 @@ function fancyAPI(CanvasKit) {
|
||||
textPaint.delete();
|
||||
paint.delete();
|
||||
roboto.delete();
|
||||
textFont.delete();
|
||||
|
||||
surface.dispose();
|
||||
}
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "SkStrokeRec.h"
|
||||
#include "SkSurface.h"
|
||||
#include "SkSurfaceProps.h"
|
||||
#include "SkTextBlob.h"
|
||||
#include "SkTrimPathEffect.h"
|
||||
#include "SkTypeface.h"
|
||||
#include "SkTypes.h"
|
||||
@ -479,6 +480,10 @@ namespace emscripten {
|
||||
template<>
|
||||
void raw_destructor<SkVertices>(SkVertices *ptr) {
|
||||
}
|
||||
|
||||
template<>
|
||||
void raw_destructor<SkTextBlob>(SkTextBlob *ptr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -685,13 +690,15 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
SkShadowUtils::DrawShadow(&self, path, zPlaneParams, lightPos, lightRadius,
|
||||
SkColor(ambientColor), SkColor(spotColor), flags);
|
||||
}))
|
||||
.function("drawText", optional_override([](SkCanvas& self, std::string text, SkScalar x,
|
||||
SkScalar y, const SkPaint& p) {
|
||||
// TODO(kjlubick): This does not work well for non-ascii
|
||||
// Need to maybe add a helper in interface.js that supports UTF-8
|
||||
// Otherwise, go with std::wstring and set UTF-32 encoding.
|
||||
self.drawText(text.c_str(), text.length(), x, y, p);
|
||||
.function("_drawSimpleText", optional_override([](SkCanvas& self, uintptr_t /* char* */ sptr,
|
||||
size_t len, SkScalar x, SkScalar y, const SkFont& font,
|
||||
const SkPaint& paint) {
|
||||
// See comment above for uintptr_t explanation
|
||||
const char* str = reinterpret_cast<const char*>(sptr);
|
||||
|
||||
self.drawSimpleText(str, len, SkTextEncoding::kUTF8, x, y, font, paint);
|
||||
}))
|
||||
.function("drawTextBlob", select_overload<void (const sk_sp<SkTextBlob>&, SkScalar, SkScalar, const SkPaint&)>(&SkCanvas::drawTextBlob))
|
||||
.function("drawVertices", select_overload<void (const sk_sp<SkVertices>&, SkBlendMode, const SkPaint&)>(&SkCanvas::drawVertices))
|
||||
.function("flush", &SkCanvas::flush)
|
||||
.function("getTotalMatrix", optional_override([](const SkCanvas& self)->SimpleMatrix {
|
||||
@ -798,7 +805,6 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.function("getStrokeJoin", &SkPaint::getStrokeJoin)
|
||||
.function("getStrokeMiter", &SkPaint::getStrokeMiter)
|
||||
.function("getStrokeWidth", &SkPaint::getStrokeWidth)
|
||||
.function("getTextSize", &SkPaint::getTextSize)
|
||||
.function("setAntiAlias", &SkPaint::setAntiAlias)
|
||||
.function("setBlendMode", &SkPaint::setBlendMode)
|
||||
.function("setColor", optional_override([](SkPaint& self, JSColor color)->void {
|
||||
@ -814,9 +820,7 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.function("setStrokeJoin", &SkPaint::setStrokeJoin)
|
||||
.function("setStrokeMiter", &SkPaint::setStrokeMiter)
|
||||
.function("setStrokeWidth", &SkPaint::setStrokeWidth)
|
||||
.function("setStyle", &SkPaint::setStyle)
|
||||
.function("setTypeface", &SkPaint::setTypeface)
|
||||
.function("setTextSize", &SkPaint::setTextSize);
|
||||
.function("setStyle", &SkPaint::setStyle);
|
||||
|
||||
class_<SkPathEffect>("SkPathEffect")
|
||||
.smart_ptr<sk_sp<SkPathEffect>>("sk_sp<SkPathEffect>");
|
||||
@ -886,6 +890,17 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.function("makeImageSnapshot", select_overload<sk_sp<SkImage>(const SkIRect& bounds)>(&SkSurface::makeImageSnapshot))
|
||||
.function("getCanvas", &SkSurface::getCanvas, allow_raw_pointers());
|
||||
|
||||
class_<SkTextBlob>("SkTextBlob")
|
||||
.smart_ptr<sk_sp<SkTextBlob>>("sk_sp<SkTextBlob>>")
|
||||
.class_function("_MakeFromText",optional_override([](uintptr_t /* char* */ sptr,
|
||||
size_t len, const SkFont& font,
|
||||
SkTextEncoding encoding)->sk_sp<SkTextBlob> {
|
||||
// See comment above for uintptr_t explanation
|
||||
const char* str = reinterpret_cast<const char*>(sptr);
|
||||
return SkTextBlob::MakeFromText(str, len, font, encoding);
|
||||
}), allow_raw_pointers());
|
||||
|
||||
|
||||
class_<SkTypeface>("SkTypeface")
|
||||
.smart_ptr<sk_sp<SkTypeface>>("sk_sp<SkTypeface>");
|
||||
|
||||
@ -1006,12 +1021,11 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.value("Round", SkPaint::Join::kRound_Join)
|
||||
.value("Bevel", SkPaint::Join::kBevel_Join);
|
||||
|
||||
value_object<StrokeOpts>("StrokeOpts")
|
||||
.field("width", &StrokeOpts::width)
|
||||
.field("miter_limit", &StrokeOpts::miter_limit)
|
||||
.field("join", &StrokeOpts::join)
|
||||
.field("cap", &StrokeOpts::cap)
|
||||
.field("precision", &StrokeOpts::precision);
|
||||
enum_<SkTextEncoding>("TextEncoding")
|
||||
.value("UTF8", SkTextEncoding::kUTF8)
|
||||
.value("UTF16", SkTextEncoding::kUTF16)
|
||||
.value("UTF32", SkTextEncoding::kUTF32)
|
||||
.value("GlyphID", SkTextEncoding::kGlyphID);
|
||||
|
||||
enum_<SkShader::TileMode>("TileMode")
|
||||
.value("Clamp", SkShader::TileMode::kClamp_TileMode)
|
||||
@ -1067,6 +1081,13 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.field("w", &SkISize::fWidth)
|
||||
.field("h", &SkISize::fHeight);
|
||||
|
||||
value_object<StrokeOpts>("StrokeOpts")
|
||||
.field("width", &StrokeOpts::width)
|
||||
.field("miter_limit", &StrokeOpts::miter_limit)
|
||||
.field("join", &StrokeOpts::join)
|
||||
.field("cap", &StrokeOpts::cap)
|
||||
.field("precision", &StrokeOpts::precision);
|
||||
|
||||
// Allows clients to supply a 1D array of 9 elements and the bindings
|
||||
// will automatically turn it into a 3x3 2D matrix.
|
||||
// e.g. path.transform([0,1,2,3,4,5,6,7,8])
|
||||
|
@ -94,6 +94,7 @@ var CanvasKit = {
|
||||
drawRoundRect: function() {},
|
||||
drawShadow: function() {},
|
||||
drawText: function() {},
|
||||
drawTextBlob: function() {},
|
||||
drawVertices: function() {},
|
||||
flush: function() {},
|
||||
getTotalMatrix: function() {},
|
||||
@ -105,6 +106,7 @@ var CanvasKit = {
|
||||
translate: function() {},
|
||||
|
||||
// private API
|
||||
_drawSimpleText: function() {},
|
||||
_readPixels: function() {},
|
||||
_writePixels: function() {},
|
||||
delete: function() {},
|
||||
@ -162,7 +164,6 @@ var CanvasKit = {
|
||||
getStrokeJoin: function() {},
|
||||
getStrokeMiter: function() {},
|
||||
getStrokeWidth: function() {},
|
||||
getTextSize: function() {},
|
||||
setAntiAlias: function() {},
|
||||
setBlendMode: function() {},
|
||||
setColor: function() {},
|
||||
@ -175,8 +176,6 @@ var CanvasKit = {
|
||||
setStrokeMiter: function() {},
|
||||
setStrokeWidth: function() {},
|
||||
setStyle: function() {},
|
||||
setTextSize: function() {},
|
||||
setTypeface: function() {},
|
||||
|
||||
//private API
|
||||
delete: function() {},
|
||||
@ -246,6 +245,11 @@ var CanvasKit = {
|
||||
delete: function() {},
|
||||
},
|
||||
|
||||
SkTextBlob: {
|
||||
MakeFromText: function() {},
|
||||
_MakeFromText: function() {},
|
||||
},
|
||||
|
||||
SkVertices: {
|
||||
// public API (from C++ bindings)
|
||||
bounds: function() {},
|
||||
@ -386,6 +390,13 @@ var CanvasKit = {
|
||||
Bevel: {},
|
||||
},
|
||||
|
||||
TextEncoding: {
|
||||
UTF8: {},
|
||||
UTF16: {},
|
||||
UTF32: {},
|
||||
GlyphID: {},
|
||||
},
|
||||
|
||||
TileMode: {
|
||||
Clamp: {},
|
||||
Repeat: {},
|
||||
@ -458,6 +469,7 @@ CanvasKit.SkVertices.prototype.applyBones = function() {};
|
||||
|
||||
CanvasKit.SkImage.prototype.encodeToData = function() {};
|
||||
|
||||
CanvasKit.SkCanvas.prototype.drawText = function() {};
|
||||
/** @return {Uint8Array} */
|
||||
CanvasKit.SkCanvas.prototype.readPixels = function() {};
|
||||
CanvasKit.SkCanvas.prototype.writePixels = function() {};
|
||||
|
@ -6,11 +6,9 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
this._paint.setStrokeMiter(10);
|
||||
this._paint.setStrokeCap(CanvasKit.StrokeCap.Butt);
|
||||
this._paint.setStrokeJoin(CanvasKit.StrokeJoin.Miter);
|
||||
this._paint.setTextSize(10);
|
||||
this._paint.setTypeface(null);
|
||||
this._fontString = '10px monospace';
|
||||
|
||||
this._font = new CanvasKit.SkFont();
|
||||
this._font = new CanvasKit.SkFont(null, 10);
|
||||
|
||||
this._strokeStyle = CanvasKit.BLACK;
|
||||
this._fillStyle = CanvasKit.BLACK;
|
||||
@ -106,8 +104,6 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
// tf is a "dict" according to closure, that is, the field
|
||||
// names are not minified. Thus, we need to access it via
|
||||
// bracket notation to tell closure not to minify these names.
|
||||
this._paint.setTextSize(tf['sizePx']);
|
||||
this._paint.setTypeface(tf['typeface']);
|
||||
this._font.setSize(tf['sizePx']);
|
||||
this._font.setTypeface(tf['typeface']);
|
||||
this._fontString = newFont;
|
||||
@ -694,16 +690,19 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
|
||||
this.fillText = function(text, x, y, maxWidth) {
|
||||
// TODO do something with maxWidth, probably involving measure
|
||||
var fillPaint = this._fillPaint()
|
||||
var fillPaint = this._fillPaint();
|
||||
var blob = CanvasKit.SkTextBlob.MakeFromText(text, this._font);
|
||||
|
||||
var shadowPaint = this._shadowPaint(fillPaint);
|
||||
if (shadowPaint) {
|
||||
this._canvas.save();
|
||||
this._canvas.concat(this._shadowOffsetMatrix());
|
||||
this._canvas.drawText(text, x, y, shadowPaint);
|
||||
this._canvas.drawTextBlob(blob, x, y, shadowPaint);
|
||||
this._canvas.restore();
|
||||
shadowPaint.dispose();
|
||||
}
|
||||
this._canvas.drawText(text, x, y, fillPaint);
|
||||
this._canvas.drawTextBlob(blob, x, y, fillPaint);
|
||||
blob.delete();
|
||||
fillPaint.dispose();
|
||||
}
|
||||
|
||||
@ -1085,16 +1084,18 @@ function CanvasRenderingContext2D(skcanvas) {
|
||||
this.strokeText = function(text, x, y, maxWidth) {
|
||||
// TODO do something with maxWidth, probably involving measure
|
||||
var strokePaint = this._strokePaint();
|
||||
var blob = CanvasKit.SkTextBlob.MakeFromText(text, this._font);
|
||||
|
||||
var shadowPaint = this._shadowPaint(strokePaint);
|
||||
if (shadowPaint) {
|
||||
this._canvas.save();
|
||||
this._canvas.concat(this._shadowOffsetMatrix());
|
||||
this._canvas.drawText(text, x, y, shadowPaint);
|
||||
this._canvas.drawTextBlob(blob, x, y, shadowPaint);
|
||||
this._canvas.restore();
|
||||
shadowPaint.dispose();
|
||||
}
|
||||
this._canvas.drawText(text, x, y, strokePaint);
|
||||
this._canvas.drawTextBlob(blob, x, y, strokePaint);
|
||||
blob.delete();
|
||||
strokePaint.dispose();
|
||||
}
|
||||
|
||||
|
@ -382,6 +382,17 @@
|
||||
throw 'encodeToData expected to take 0 or 2 arguments. Got ' + arguments.length;
|
||||
}
|
||||
|
||||
CanvasKit.SkCanvas.prototype.drawText = function(str, x, y, font, paint) {
|
||||
// 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);
|
||||
this._drawSimpleText(strPtr, strLen, x, y, font, paint);
|
||||
}
|
||||
|
||||
// returns Uint8Array
|
||||
CanvasKit.SkCanvas.prototype.readPixels = function(x, y, w, h, alphaType,
|
||||
colorType, dstRowBytes) {
|
||||
@ -453,6 +464,29 @@
|
||||
return font;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -133,13 +133,15 @@ describe('CanvasKit\'s Path Behavior', function() {
|
||||
|
||||
canvas.drawArc(CanvasKit.LTRBRect(55, 35, 95, 80), 15, 270, true, paint);
|
||||
|
||||
paint.setTextSize(20);
|
||||
canvas.drawText('this is ascii text', 5, 100, paint);
|
||||
const font = new CanvasKit.SkFont(null, 20);
|
||||
canvas.drawText('this is ascii text', 5, 100, font, paint);
|
||||
|
||||
canvas.drawText('Unicode chars 💩 é É ص', 5, 130, paint);
|
||||
const blob = CanvasKit.SkTextBlob.MakeFromText('Unicode chars 💩 é É ص', font);
|
||||
canvas.drawTextBlob(blob, 5, 130, paint);
|
||||
|
||||
surface.flush();
|
||||
|
||||
font.delete();
|
||||
blob.delete();
|
||||
paint.delete();
|
||||
|
||||
reportSurface(surface, 'canvas_api_example', done);
|
||||
@ -172,9 +174,10 @@ describe('CanvasKit\'s Path Behavior', function() {
|
||||
|
||||
const textPaint = new CanvasKit.SkPaint();
|
||||
textPaint.setColor(CanvasKit.Color(40, 0, 0, 1.0));
|
||||
textPaint.setTextSize(30);
|
||||
textPaint.setAntiAlias(true);
|
||||
|
||||
const textFont = new CanvasKit.SkFont(null, 30);
|
||||
|
||||
const dpe = CanvasKit.MakeSkDashPathEffect([15, 5, 5, 10], 1);
|
||||
|
||||
paint.setPathEffect(dpe);
|
||||
@ -186,7 +189,7 @@ describe('CanvasKit\'s Path Behavior', function() {
|
||||
canvas.clear(CanvasKit.Color(255, 255, 255, 1.0));
|
||||
|
||||
canvas.drawPath(path, paint);
|
||||
canvas.drawText('This is text', 10, 280, textPaint);
|
||||
canvas.drawText('This is text', 10, 280, textFont, textPaint);
|
||||
surface.flush();
|
||||
dpe.delete();
|
||||
path.delete();
|
||||
|
Loading…
Reference in New Issue
Block a user