Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions MIGRATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ Affected APIs:
- `Buffer.serialize` now takes a single options object: `{ font, start, end, format, flags }` (all optional). The previous positional signature is gone.
- `shape` and `shapeWithTrace` now take `Feature[]` instead of a comma-separated string. Use the new `Feature` class (e.g. `new Feature("liga", 0)` or `Feature.fromString("-liga")`).
- `Font.setVariations` now takes `Variation[]` instead of `Record<string, number>`. Use the new `Variation` class (e.g. `font.setVariations([new Variation("wght", 700)])` or `Variation.fromString("wght=700")`).
- `Buffer.setLanguage`, `Face.getName`, `Face.listNames`, and `otTagToLanguage` now use the new `Language` class instead of plain BCP 47 strings (e.g. `buffer.setLanguage(new Language("en"))`).
- `Buffer.setScript` and `otTagToScript` now use the new `Script` class instead of plain ISO 15924 tag strings (e.g. `buffer.setScript(new Script("Latn"))` or, for the predefined ISO 15924 scripts, `buffer.setScript(Script.LATIN)`).
- `Direction` is now a class with `INVALID`/`LTR`/`RTL`/`TTB`/`BTT` static instances and a string constructor. `Buffer.setDirection` takes a `Direction` instance; the call form `buffer.setDirection(Direction.RTL)` shown in the v0 → v1 table above keeps working.
- `Buffer.addText` / `Buffer.addCodePoints`: `itemLength` accepts `undefined` (or omission), instead of `null`.
- `Face.getFeatureNameIds`: returns `undefined` on failure, instead of `null`.
- `Font.glyphHOrigin` / `glyphVOrigin` / `glyphExtents` / `glyphFromName`: return `undefined` on failure, instead of `null`.
Expand Down
2 changes: 2 additions & 0 deletions harfbuzz.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ _hb_buffer_get_content_type
_hb_buffer_guess_segment_properties
_hb_buffer_set_cluster_level
_hb_buffer_set_direction
_hb_direction_from_string
_hb_direction_to_string
_hb_buffer_set_flags
_hb_buffer_set_language
_hb_buffer_set_script
Expand Down
39 changes: 11 additions & 28 deletions src/buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import {
track,
hb_tag,
utf8_ptr_to_string,
string_to_ascii_ptr,
string_to_utf16_ptr,
type ValueOf,
} from "./helpers";
import type { GlyphInfo, GlyphPosition } from "./types";
import { Font } from "./font";
import type { Language } from "./language";
import type { Script } from "./script";
import type { Direction } from "./direction";

export const BufferContentType = {
INVALID: 0,
Expand Down Expand Up @@ -44,15 +46,6 @@ export const BufferFlag = {
} as const;
export type BufferFlag = ValueOf<typeof BufferFlag>;

export const Direction = {
INVALID: 0,
LTR: 4,
RTL: 5,
TTB: 6,
BTT: 7,
} as const;
export type Direction = ValueOf<typeof Direction>;

export const ClusterLevel = {
MONOTONE_GRAPHEMES: 0,
MONOTONE_CHARACTERS: 1,
Expand Down Expand Up @@ -161,10 +154,10 @@ export class Buffer {

/**
* Set buffer direction explicitly.
* @param dir A {@link Direction} value.
* @param dir The buffer direction.
*/
setDirection(dir: Direction): void {
exports.hb_buffer_set_direction(this.ptr, dir);
exports.hb_buffer_set_direction(this.ptr, dir.value);
}

/**
Expand All @@ -177,28 +170,18 @@ export class Buffer {

/**
* Set buffer language explicitly.
* @param language The buffer language
* @param language The buffer language.
*/
setLanguage(language: string): void {
const str = string_to_ascii_ptr(language);
exports.hb_buffer_set_language(
this.ptr,
exports.hb_language_from_string(str.ptr, -1),
);
str.free();
setLanguage(language: Language): void {
exports.hb_buffer_set_language(this.ptr, language.ptr);
}

/**
* Set buffer script explicitly.
* @param script The buffer script
* @param script The buffer script.
*/
setScript(script: string): void {
const str = string_to_ascii_ptr(script);
exports.hb_buffer_set_script(
this.ptr,
exports.hb_script_from_string(str.ptr, -1),
);
str.free();
setScript(script: Script): void {
exports.hb_buffer_set_script(this.ptr, script.value);
}

/**
Expand Down
49 changes: 49 additions & 0 deletions src/direction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { exports, string_to_ascii_ptr, utf8_ptr_to_string } from "./helpers";

/**
* The direction of a text segment or buffer.
*
* A segment can also be tested for horizontal or vertical orientation
* (irrespective of specific direction).
*/
export class Direction {
/** Initial, unset direction. */
static readonly INVALID = new Direction(0);
/** Text is set horizontally from left to right. */
static readonly LTR = new Direction(4);
/** Text is set horizontally from right to left. */
static readonly RTL = new Direction(5);
/** Text is set vertically from top to bottom. */
static readonly TTB = new Direction(6);
/** Text is set vertically from bottom to top. */
static readonly BTT = new Direction(7);

readonly value: number;

/**
* Converts a string to a Direction. Matching is loose and case-insensitive;
* the first letter determines the direction (`l`/`L`: LTR, `r`/`R`: RTL,
* `t`/`T`: TTB, `b`/`B`: BTT). Other strings yield `Direction.INVALID`.
* @param name A string like `"ltr"`, `"rtl"`, `"ttb"`, or `"btt"`.
*/
constructor(name: string);
/** @internal Wrap an existing hb_direction_t. */
constructor(existingValue: number);
constructor(arg: string | number) {
if (typeof arg === "number") {
this.value = arg;
} else {
const strPtr = string_to_ascii_ptr(arg);
this.value = exports.hb_direction_from_string(strPtr.ptr, -1);
strPtr.free();
}
}

/**
* Converts the Direction to a string.
* @returns A string like `"ltr"`, `"rtl"`, `"ttb"`, `"btt"`, or `"invalid"`.
*/
toString(): string {
return utf8_ptr_to_string(exports.hb_direction_to_string(this.value));
}
}
14 changes: 5 additions & 9 deletions src/face.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import {
hb_tag,
hb_untag,
utf16_ptr_to_string,
language_to_string,
language_from_string,
typed_array_from_set,
type ValueOf,
} from "./helpers";
import type { AxisInfo, NameEntry, FeatureNameIds } from "./types";
import type { Blob } from "./blob";
import { Language } from "./language";

const HB_OT_NAME_ID_INVALID = 0xffff;

Expand Down Expand Up @@ -266,9 +265,7 @@ export class Face {
for (let i = 0; i < numEntries; i++) {
entries.push({
nameId: Module.HEAPU32[entriesPtr / 4 + i * 3],
language: language_to_string(
Module.HEAPU32[entriesPtr / 4 + i * 3 + 2],
),
language: new Language(Module.HEAPU32[entriesPtr / 4 + i * 3 + 2]),
});
}
Module.stackRestore(sp);
Expand All @@ -281,18 +278,17 @@ export class Face {
* @param language The language of the name to get.
* @returns The name string.
*/
getName(nameId: number, language: string): string {
getName(nameId: number, language: Language): string {
const sp = Module.stackSave();
const languagePtr = language_from_string(language);
const nameLen =
exports.hb_ot_name_get_utf16(this.ptr, nameId, languagePtr, 0, 0) + 1;
exports.hb_ot_name_get_utf16(this.ptr, nameId, language.ptr, 0, 0) + 1;
const textSizePtr = Module.stackAlloc(4);
const textPtr = exports.malloc(nameLen * 2);
Module.HEAPU32[textSizePtr / 4] = nameLen;
exports.hb_ot_name_get_utf16(
this.ptr,
nameId,
languagePtr,
language.ptr,
textSizePtr,
textPtr,
);
Expand Down
12 changes: 0 additions & 12 deletions src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,18 +119,6 @@ export function string_to_utf16_ptr(text: string): StringPtr {
};
}

export function language_to_string(language: number): string {
const ptr = exports.hb_language_to_string(language);
return utf8_ptr_to_string(ptr);
}

export function language_from_string(str: string): number {
const languageStr = string_to_ascii_ptr(str);
const languagePtr = exports.hb_language_from_string(languageStr.ptr, -1);
languageStr.free();
return languagePtr;
}

/**
* Return the typed array of HarfBuzz set contents.
* @param setPtr Pointer of set
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export * from "./font-funcs";
export * from "./buffer";
export * from "./feature";
export * from "./variation";
export * from "./language";
export * from "./script";
export * from "./direction";
export * from "./shape";

init(await createHarfBuzz());
36 changes: 36 additions & 0 deletions src/language.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { exports, string_to_ascii_ptr, utf8_ptr_to_string } from "./helpers";

/**
* A {@link https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-language-t | HarfBuzz language}.
*
* Data type for languages. Each Language corresponds to a BCP 47 language tag.
*/
export class Language {
readonly ptr: number;

/**
* Converts `tag` representing a BCP 47 language tag to the corresponding
* Language.
* @param tag A string representing a BCP 47 language tag.
*/
constructor(tag: string);
/** @internal Wrap an existing hb_language_t. */
constructor(existingPtr: number);
constructor(arg: string | number) {
if (typeof arg === "number") {
this.ptr = arg;
} else {
const strPtr = string_to_ascii_ptr(arg);
this.ptr = exports.hb_language_from_string(strPtr.ptr, -1);
strPtr.free();
}
}

/**
* Converts the language to a string.
* @returns A string representing the language.
*/
toString(): string {
return utf8_ptr_to_string(exports.hb_language_to_string(this.ptr));
}
}
Loading