Skip to content

Commit

Permalink
Merge pull request #320 from Brooooooklyn/register-font-family
Browse files Browse the repository at this point in the history
Register font family
  • Loading branch information
Brooooooklyn authored Jul 30, 2021
2 parents a051192 + 2e934a5 commit b77f45d
Show file tree
Hide file tree
Showing 19 changed files with 308 additions and 92 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ crate-type = ["cdylib"]
anyhow = "1.0"
base64 = "0.13"
cssparser = "0.28"
napi = "1"
napi = {version = "1", features = ["serde-json"]}
napi-derive = "1"
once_cell = "1.8"
regex = "1.5"
serde = "1"
serde_derive = "1"
serde_json = "1"
thiserror = "1.0"

[target.'cfg(all(target_arch = "x86_64", not(target_env = "musl")))'.dependencies]
Expand Down
Binary file added __test__/fonts-dir/iosevka-curly-heavy.woff2
Binary file not shown.
Binary file added __test__/fonts-dir/iosevka-curly-italic.woff2
Binary file not shown.
Binary file added __test__/fonts-dir/iosevka-curly-regular.woff2
Binary file not shown.
Binary file added __test__/fonts/Cascadia.woff2
Binary file not shown.
Binary file added __test__/fonts/Virgil.woff2
Binary file not shown.
14 changes: 14 additions & 0 deletions __test__/global-fonts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,17 @@ test('multiple identical fonts should only exist within one font family', (t) =>
test('return false if font path not existed', (t) => {
t.false(GlobalFonts.register(Buffer.from('whatever')))
})

test('should be able to register font with name alias', (t) => {
const fontAliasName = 'Cascadia-skr-canvas-test'
t.true(GlobalFonts.registerFromPath(join(__dirname, 'fonts', 'Cascadia.woff2'), fontAliasName))
const styleSet = GlobalFonts.families.find(({ family }) => family === fontAliasName)
t.deepEqual(styleSet, {
family: 'Cascadia-skr-canvas-test',
styles: [{ weight: 400, width: 'normal', style: 'normal' }],
})
})

test('should be able to register fonts from dir', (t) => {
t.is(GlobalFonts.loadFontsFromDir(join(__dirname, 'fonts-dir')), 3)
})
5 changes: 2 additions & 3 deletions example/draw-text-with-baseline.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
const { readFileSync, writeFileSync } = require('fs')
const { writeFileSync } = require('fs')
const { join } = require('path')

const { createCanvas, GlobalFonts } = require('../index.js')

const fontPath = join(__dirname, '..', '__test__', 'fonts', 'iosevka-slab-regular.ttf')
const fontData = readFileSync(fontPath)

console.info(GlobalFonts.families)

GlobalFonts.register(fontData)
GlobalFonts.registerFromPath(fontPath)

console.info(GlobalFonts.families)

Expand Down
3 changes: 3 additions & 0 deletions example/draw-text.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ const { createCanvas, GlobalFonts } = require('../index.js')
const fontPath = join(__dirname, '..', '__test__', 'fonts', 'iosevka-slab-regular.ttf')
const fontData = readFileSync(fontPath)

const WoffFontPath = join(__dirname, '..', '__test__', 'fonts', 'Virgil.woff2')

console.info(GlobalFonts.families)

GlobalFonts.register(fontData)
GlobalFonts.registerFromPath(WoffFontPath, 'Virgil')

console.info(GlobalFonts.families)

Expand Down
15 changes: 11 additions & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,13 +297,20 @@ export interface Canvas {
export function createCanvas(width: number, height: number): Canvas

interface IGlobalFonts {
readonly families: string[]
readonly families: {
family: string
styles: {
weight: number
width: string
style: string
}[]
}[]
// return true if succeeded
register(font: Buffer): boolean
register(font: Buffer, nameAlias?: string): boolean
// absolute path
registerFromPath(path: string): boolean
registerFromPath(path: string, nameAlias?: string): boolean
has(name: string): boolean
loadSystemFonts(): number
loadFontsFromDir(path: string): number
}

export const GlobalFonts: IGlobalFonts
Expand Down
34 changes: 25 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,16 @@ const FillType = {
}

const GlobalFontsSingleton = new GlobalFonts()
let FamilyNamesMap = GlobalFontsSingleton._families
let FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)

// eslint-disable-next-line sonarjs/no-unused-collection
const Fonts = []

Object.defineProperty(GlobalFontsSingleton, 'register', {
value: function register(path) {
const result = GlobalFontsSingleton._register(path)
FamilyNamesMap = GlobalFontsSingleton._families
value: function register(fontData, nameAlias = '') {
const result = GlobalFontsSingleton._register(fontData, nameAlias)
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
Fonts.push(fontData)
return result
},
configurable: false,
Expand All @@ -58,9 +62,20 @@ Object.defineProperty(GlobalFontsSingleton, 'register', {
})

Object.defineProperty(GlobalFontsSingleton, 'registerFromPath', {
value: function register(path) {
const result = GlobalFontsSingleton._registerFromPath(path)
FamilyNamesMap = GlobalFontsSingleton._families
value: function registerFromPath(path, nameAlias = '') {
const result = GlobalFontsSingleton._registerFromPath(path, nameAlias)
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
return result
},
configurable: false,
enumerable: false,
writable: false,
})

Object.defineProperty(GlobalFontsSingleton, 'loadFontsFromDir', {
value: function loadFontsFromDir(path) {
const result = GlobalFontsSingleton._loadFontsFromDir(path)
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
return result
},
configurable: false,
Expand All @@ -70,13 +85,13 @@ Object.defineProperty(GlobalFontsSingleton, 'registerFromPath', {

Object.defineProperty(GlobalFontsSingleton, 'families', {
get: function () {
return Object.keys(GlobalFontsSingleton._families)
return FamilyNamesSet
},
})

Object.defineProperty(GlobalFontsSingleton, 'has', {
value: function has(name) {
return !!FamilyNamesMap[name]
return !!FamilyNamesSet.find(({ family }) => family === name)
},
configurable: false,
enumerable: false,
Expand Down Expand Up @@ -169,6 +184,7 @@ function createCanvas(width, height) {

if (!process.env.DISABLE_SYSTEM_FONTS_LOAD) {
GlobalFontsSingleton.loadSystemFonts()
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
}

module.exports = {
Expand Down
3 changes: 1 addition & 2 deletions scripts/build-skia.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ const GN_ARGS = [
`skia_enable_skshaper=true`,
`skia_enable_tools=false`,
`skia_enable_svg=true`,
`skia_enable_ccpr=true`,
`skia_enable_nga=false`,
`skia_use_expat=true`,
`skia_use_gl=false`,
`skia_use_harfbuzz=true`,
Expand All @@ -61,6 +59,7 @@ const GN_ARGS = [
`skia_use_libwebp_decode=true`,
`skia_use_libwebp_encode=true`,
`skia_use_freetype=true`,
`skia_use_freetype_woff2=true`,
`skia_use_fontconfig=false`,
`skia_use_system_freetype2=false`,
`skia_use_system_libjpeg_turbo=false`,
Expand Down
2 changes: 1 addition & 1 deletion skia
Submodule skia updated 2041 files
75 changes: 50 additions & 25 deletions skia-c/skia_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ extern "C"
}

SkPaint paint;
paint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
paint.setAlpha(SK_AlphaOPAQUE);

const auto sampling = SkSamplingOptions(SkFilterQuality::kLow_SkFilterQuality);
// The original surface draws itself to the copy's canvas.
SURFACE_CAST->draw(copy->getCanvas(), -(SkScalar)x, -(SkScalar)y, &paint);
SURFACE_CAST->draw(copy->getCanvas(), -(SkScalar)x, -(SkScalar)y, sampling, &paint);

return reinterpret_cast<skiac_surface *>(copy);
}
Expand Down Expand Up @@ -261,10 +261,9 @@ extern "C"
{
auto image = SURFACE_CAST->makeImageSnapshot();
SkPaint paint;
paint.setFilterQuality((SkFilterQuality)filter_quality);
paint.setAlpha(alpha);
paint.setBlendMode((SkBlendMode)blend_mode);
const auto sampling = SkSamplingOptions();
const auto sampling = SkSamplingOptions((SkFilterQuality)filter_quality);
CANVAS_CAST->drawImage(image, left, top, sampling, &paint);
}

Expand All @@ -276,10 +275,9 @@ extern "C"
{
auto image = SURFACE_CAST->makeImageSnapshot();
SkPaint paint;
paint.setFilterQuality((SkFilterQuality)filter_quality);
auto src = SkRect::MakeXYWH(0, 0, image->width(), image->height());
auto dst = SkRect::MakeXYWH(x, y, w, h);
const auto sampling = SkSamplingOptions();
const auto sampling = SkSamplingOptions((SkFilterQuality)filter_quality);
CANVAS_CAST->drawImageRect(image, src, dst, sampling, &paint, SkCanvas::kFast_SrcRectConstraint);
}

Expand All @@ -304,9 +302,15 @@ extern "C"
{
auto font_collection = c_collection->collection;
auto font_style = SkFontStyle(weight, stretch, (SkFontStyle::Slant)slant);
const std::vector<SkString> families = {SkString(font_family)};
SkTArray<SkString> families;
SkStrSplit(font_family, ",", &families);
TextStyle text_style;
text_style.setFontFamilies(families);
std::vector<SkString> families_vec;
for (auto family : families)
{
families_vec.emplace_back(family);
}
text_style.setFontFamilies(families_vec);
text_style.setFontSize(font_size);
text_style.setWordSpacing(0);
text_style.setHeight(1);
Expand All @@ -322,14 +326,12 @@ extern "C"
paragraph_style.setTextStyle(text_style);
paragraph_style.setTextAlign((TextAlign)align);
paragraph_style.setTextDirection((TextDirection)direction);

auto builder = ParagraphBuilder::make(paragraph_style, font_collection);
builder->addText(text, text_len);

auto paragraph = reinterpret_cast<ParagraphImpl *>(builder->Build().release());
ParagraphBuilderImpl builder(paragraph_style, font_collection);
builder.addText(text, text_len);
auto paragraph = static_cast<ParagraphImpl *>(builder.Build().release());
paragraph->layout(MAX_LAYOUT_WIDTH);

auto metrics_vec = std::vector<LineMetrics>();
std::vector<LineMetrics> metrics_vec;
paragraph->getLineMetrics(metrics_vec);
auto line_metrics = metrics_vec[0];
auto run = paragraph->run(0);
Expand Down Expand Up @@ -360,18 +362,18 @@ extern "C"
switch (css_baseline)
{
case CssBaseline::Top:
baseline_offset = font_metrics.fAscent - ascent;
baseline_offset = -alphabetic_baseline - font_metrics.fAscent;
break;
case CssBaseline::Hanging:
// https://github1s.com/chromium/chromium/blob/HEAD/third_party/blink/renderer/core/html/canvas/text_metrics.cc#L21-L24
// According to
// http://wiki.apache.org/xmlgraphics-fop/LineLayout/AlignmentHandling
// "FOP (Formatting Objects Processor) puts the hanging baseline at 80% of
// the ascender height"
baseline_offset = font_metrics.fAscent - (ascent - descent) * HANGING_AS_PERCENT_OF_ASCENT / 100.0;
baseline_offset = -alphabetic_baseline - (font_metrics.fAscent - font_metrics.fDescent) * HANGING_AS_PERCENT_OF_ASCENT / 100.0;
break;
case CssBaseline::Middle:
baseline_offset = (font_metrics.fAscent - font_metrics.fDescent) / 2;
baseline_offset = -paragraph->getHeight() / 2;
break;
case CssBaseline::Alphabetic:
baseline_offset = -alphabetic_baseline;
Expand Down Expand Up @@ -412,7 +414,6 @@ extern "C"
c_line_metrics->font_ascent = line_metrics.fAscent + offset;
c_line_metrics->font_descent = line_metrics.fDescent - offset;
}
delete paragraph;
}

void skiac_canvas_reset_transform(skiac_canvas *c_canvas)
Expand Down Expand Up @@ -507,7 +508,7 @@ extern "C"

int skiac_paint_get_blend_mode(skiac_paint *c_paint)
{
return (int)PAINT_CAST->getBlendMode();
return (int)PAINT_CAST->getBlendMode_or(SkBlendMode::kSrcOver);
}

void skiac_paint_set_shader(skiac_paint *c_paint, skiac_shader *c_shader)
Expand Down Expand Up @@ -1164,26 +1165,50 @@ extern "C"
return c_font_collection->assets->countFamilies();
}

void skiac_font_collection_get_family(skiac_font_collection *c_font_collection, uint32_t i, skiac_string *c_string)
void skiac_font_collection_get_family(skiac_font_collection *c_font_collection, uint32_t i, skiac_string *c_string, void *on_get_style_rust, skiac_on_match_font_style on_match_font_style)
{
auto name = new SkString();
c_font_collection->assets->getFamilyName(i, name);
auto font_style_set = c_font_collection->assets->matchFamily(name->c_str());
auto style_count = font_style_set->count();
for (auto i = 0; i < style_count; i++)
{
SkFontStyle style;
font_style_set->getStyle(i, &style, nullptr);
if (on_match_font_style)
{
on_match_font_style(style.width(), style.weight(), (int)style.slant(), on_get_style_rust);
}
}
font_style_set->unref();
c_string->length = name->size();
c_string->ptr = name->c_str();
c_string->sk_string = name;
}

size_t skiac_font_collection_register(skiac_font_collection *c_font_collection, const uint8_t *font, size_t length)
size_t skiac_font_collection_register(skiac_font_collection *c_font_collection, const uint8_t *font, size_t length, const char *name_alias)
{
auto typeface_data = SkData::MakeWithCopy(font, length);
auto typeface_data = SkData::MakeWithoutCopy(font, length);
auto typeface = c_font_collection->font_mgr->makeFromData(typeface_data);
return c_font_collection->assets->registerTypeface(typeface);
auto result = c_font_collection->assets->registerTypeface(typeface);
if (name_alias)
{
auto alias = SkString(name_alias);
c_font_collection->assets->registerTypeface(typeface, alias);
};
return result;
}

size_t skiac_font_collection_register_from_path(skiac_font_collection *c_font_collection, const char *font_path)
size_t skiac_font_collection_register_from_path(skiac_font_collection *c_font_collection, const char *font_path, const char *name_alias)
{
auto typeface = c_font_collection->font_mgr->makeFromFile(font_path);
return c_font_collection->assets->registerTypeface(typeface);
auto result = c_font_collection->assets->registerTypeface(typeface);
if (name_alias)
{
auto alias = SkString(name_alias);
c_font_collection->assets->registerTypeface(typeface, alias);
}
return result;
}

void skiac_font_collection_destroy(skiac_font_collection *c_font_collection)
Expand Down
16 changes: 6 additions & 10 deletions skia-c/skia_c.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <modules/skparagraph/include/TypefaceFontProvider.h>
#include <modules/svg/include/SkSVGDOM.h>
#include <src/ports/SkFontMgr_custom.h>
#include <src/core/SkFontDescriptor.h>

#include <stdint.h>

Expand Down Expand Up @@ -126,6 +127,8 @@ struct skiac_string
SkString *sk_string;
};

typedef void (*skiac_on_match_font_style)(int width, int weight, int slant, void *skiac_on_match_font_style_rust);

struct skiac_sk_data
{
uint8_t *ptr;
Expand Down Expand Up @@ -349,19 +352,12 @@ extern "C"
// SkString
void skiac_delete_sk_string(skiac_sk_string *c_sk_string);

// TypefaceFontProvider
skiac_typeface_font_provider *skiac_typeface_font_provider_create();
size_t skiac_typeface_font_provider_register(skiac_typeface_font_provider *c_typeface_font_provider, skiac_font_mgr *c_font_mgr, uint8_t *font, size_t length);
size_t skiac_typeface_font_provider_register_from_file(skiac_typeface_font_provider *c_typeface_font_provider, skiac_font_mgr *c_font_mgr, const char *font_path);
void skiac_typeface_font_provider_ref(skiac_typeface_font_provider *c_typeface_font_provider);
void skiac_typeface_font_provider_unref(skiac_typeface_font_provider *c_typeface_font_provider);

// FontCollection
skiac_font_collection *skiac_font_collection_create();
uint32_t skiac_font_collection_get_default_fonts_count(skiac_font_collection *c_font_collection);
void skiac_font_collection_get_family(skiac_font_collection *c_font_collection, uint32_t i, skiac_string *c_string);
size_t skiac_font_collection_register(skiac_font_collection *c_font_collection, const uint8_t *font, size_t length);
size_t skiac_font_collection_register_from_path(skiac_font_collection *c_font_collection, const char *font_path);
void skiac_font_collection_get_family(skiac_font_collection *c_font_collection, uint32_t i, skiac_string *c_string, void *on_get_style_rust, skiac_on_match_font_style on_match_font_style);
size_t skiac_font_collection_register(skiac_font_collection *c_font_collection, const uint8_t *font, size_t length, const char *name_alias);
size_t skiac_font_collection_register_from_path(skiac_font_collection *c_font_collection, const char *font_path, const char *name_alias);
void skiac_font_collection_destroy(skiac_font_collection *c_font_collection);
}

Expand Down
Loading

0 comments on commit b77f45d

Please sign in to comment.