Skip to content

Commit

Permalink
feat: support register font with family name alias
Browse files Browse the repository at this point in the history
  • Loading branch information
Brooooooklyn committed Jul 29, 2021
1 parent aae2628 commit 4860c80
Show file tree
Hide file tree
Showing 14 changed files with 277 additions and 67 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.
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)
})
2 changes: 1 addition & 1 deletion example/draw-text.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const WoffFontPath = join(__dirname, '..', '__test__', 'fonts', 'Virgil.woff2')
console.info(GlobalFonts.families)

GlobalFonts.register(fontData)
GlobalFonts.registerFromPath(WoffFontPath)
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
30 changes: 21 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,15 @@ 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(fontData) {
const result = GlobalFontsSingleton._register(fontData)
FamilyNamesMap = GlobalFontsSingleton._families
value: function register(fontData, nameAlias = '') {
const result = GlobalFontsSingleton._register(fontData, nameAlias)
FamilyNamesSet = JSON.parse(GlobalFontsSingleton._families)
Fonts.push(fontData)
return result
},
Expand All @@ -62,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 @@ -74,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 @@ -173,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
34 changes: 29 additions & 5 deletions skia-c/skia_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1159,26 +1159,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::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
48 changes: 48 additions & 0 deletions src/font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,21 @@ pub enum FontStyle {
Oblique,
}

impl FontStyle {
#[inline]
pub fn as_str(&self) -> &str {
match *self {
Self::Italic => "italic",
Self::Normal => "normal",
Self::Oblique => "oblique",
}
}
}

impl FromStr for FontStyle {
type Err = ParseError;

#[inline]
fn from_str(s: &str) -> Result<FontStyle, ParseError> {
match s {
"normal" => Ok(Self::Normal),
Expand All @@ -166,6 +178,7 @@ pub enum FontVariant {
impl FromStr for FontVariant {
type Err = ParseError;

#[inline]
fn from_str(s: &str) -> Result<FontVariant, ParseError> {
match s {
"normal" => Ok(Self::Normal),
Expand All @@ -189,6 +202,41 @@ pub enum FontStretch {
UltraExpanded = 9,
}

impl From<i32> for FontStretch {
#[inline]
fn from(value: i32) -> Self {
match value {
1 => FontStretch::UltraCondensed,
2 => FontStretch::ExtraCondensed,
3 => FontStretch::Condensed,
4 => FontStretch::SemiCondensed,
5 => FontStretch::Normal,
6 => FontStretch::SemiExpanded,
7 => FontStretch::Expanded,
8 => FontStretch::ExtraExpanded,
9 => FontStretch::UltraExpanded,
_ => unreachable!(),
}
}
}

impl FontStretch {
#[inline]
pub fn as_str(&self) -> &str {
match *self {
FontStretch::UltraCondensed => "ultra-condensed",
FontStretch::ExtraCondensed => "extra-condensed",
FontStretch::Condensed => "condensed",
FontStretch::SemiCondensed => "semi-condensed",
FontStretch::Normal => "normal",
FontStretch::SemiExpanded => "semi-expanded",
FontStretch::Expanded => "expanded",
FontStretch::ExtraExpanded => "extra-expanded",
FontStretch::UltraExpanded => "ultra-expanded",
}
}
}

#[inline]
// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight
fn parse_font_weight(weight: &str) -> Option<u32> {
Expand Down
Loading

1 comment on commit 4860c80

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 4860c80 Previous: a051192 Ratio
Draw house#skia-canvas 23 ops/sec (±0.13%) 20.5 ops/sec (±0.5%) 0.89
Draw house#node-canvas 18 ops/sec (±0.33%) 21.9 ops/sec (±0.69%) 1.22
Draw house#@napi-rs/skia 21 ops/sec (±0.26%) 22 ops/sec (±1.26%) 1.05
Draw gradient#skia-canvas 23 ops/sec (±0.42%) 19.7 ops/sec (±0.45%) 0.86
Draw gradient#node-canvas 17 ops/sec (±0.49%) 20.5 ops/sec (±1.11%) 1.21
Draw gradient#@napi-rs/skia 20 ops/sec (±0.39%) 21.2 ops/sec (±0.76%) 1.06

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.