text-shaper 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,17 +5,33 @@
5
5
 
6
6
  Pure TypeScript text shaping engine with OpenType layout, TrueType hinting, and FreeType-style rasterization. Works in browsers and Bun/Node.js with zero dependencies.
7
7
 
8
+ ## Performance
9
+
10
+ text-shaper outperforms harfbuzzjs (WebAssembly) and opentype.js across all benchmarks:
11
+
12
+ | Category | vs harfbuzzjs | vs opentype.js |
13
+ |----------|---------------|----------------|
14
+ | Path Extraction | 16x faster | 10x faster |
15
+ | Text to SVG | 1.2-1.5x faster | 4-6x faster |
16
+ | Latin Shaping | 1.5x faster | 22x faster |
17
+ | Arabic Shaping | 1.2x faster | 86x faster |
18
+ | Hebrew Shaping | 1.6x faster | 33x faster |
19
+ | Hindi Shaping | 3.6x faster | 11x faster |
20
+ | Myanmar Shaping | 10.5x faster | 17x faster |
21
+ | CJK Shaping | 1.3-1.5x faster | 11-13x faster |
22
+
8
23
  ## Features
9
24
 
10
25
  - **OpenType Layout**: Full GSUB (substitution) and GPOS (positioning) support
11
26
  - **Complex Scripts**: Arabic, Indic, USE (Universal Shaping Engine) shapers
12
27
  - **Variable Fonts**: fvar, gvar, avar, HVAR, VVAR, MVAR tables
13
28
  - **AAT Support**: morx, kerx, trak tables for Apple fonts
14
- - **Color Fonts**: SVG, sbix, CBDT/CBLC tables
29
+ - **Color Fonts**: SVG, sbix, CBDT/CBLC, COLR/CPAL tables
15
30
  - **BiDi**: UAX #9 bidirectional text algorithm
16
31
  - **Rasterization**: FreeType-style grayscale, LCD subpixel, and monochrome rendering
17
32
  - **TrueType Hinting**: Full bytecode interpreter (150+ opcodes)
18
33
  - **Texture Atlas**: GPU-ready glyph atlas generation with shelf packing
34
+ - **SDF/MSDF**: Signed distance field rendering for scalable text
19
35
  - **Zero Dependencies**: Pure TypeScript, works in browser and Node.js
20
36
 
21
37
  ## Installation
@@ -28,16 +44,18 @@ bun add text-shaper
28
44
 
29
45
  ## Usage
30
46
 
47
+ ### Basic Shaping
48
+
31
49
  ```typescript
32
50
  import { Font, shape, UnicodeBuffer } from "text-shaper";
33
51
 
34
52
  // Load a font
35
- const fontData = await Bun.file("path/to/font.ttf").arrayBuffer();
36
- const font = new Font(fontData);
53
+ const fontData = await fetch("path/to/font.ttf").then(r => r.arrayBuffer());
54
+ const font = Font.load(fontData);
37
55
 
38
56
  // Create a buffer with text
39
57
  const buffer = new UnicodeBuffer();
40
- buffer.addString("Hello, World!");
58
+ buffer.addStr("Hello, World!");
41
59
 
42
60
  // Shape the text
43
61
  const glyphBuffer = shape(font, buffer);
@@ -46,21 +64,49 @@ const glyphBuffer = shape(font, buffer);
46
64
  for (let i = 0; i < glyphBuffer.length; i++) {
47
65
  const info = glyphBuffer.info[i];
48
66
  const pos = glyphBuffer.pos[i];
49
- console.log(`Glyph ${info.glyphId}: advance=${pos.xAdvance}, offset=(${pos.xOffset}, ${pos.yOffset})`);
67
+ console.log(`Glyph ${info.glyphId}: advance=${pos.xAdvance}`);
68
+ }
69
+ ```
70
+
71
+ ### High-Performance Shaping
72
+
73
+ For best performance, reuse buffers with `shapeInto`:
74
+
75
+ ```typescript
76
+ import { Font, shapeInto, UnicodeBuffer, GlyphBuffer } from "text-shaper";
77
+
78
+ const font = Font.load(fontData);
79
+ const uBuffer = new UnicodeBuffer();
80
+ const gBuffer = GlyphBuffer.withCapacity(128);
81
+
82
+ // Shape multiple strings efficiently
83
+ for (const text of texts) {
84
+ uBuffer.clear();
85
+ uBuffer.addStr(text);
86
+ gBuffer.reset();
87
+ shapeInto(font, uBuffer, gBuffer);
88
+ // Process gBuffer...
50
89
  }
51
90
  ```
52
91
 
53
92
  ### With Features
54
93
 
55
94
  ```typescript
56
- import { Font, shape, UnicodeBuffer, feature, features } from "text-shaper";
95
+ import { Font, shape, UnicodeBuffer, feature } from "text-shaper";
96
+
97
+ const glyphBuffer = shape(font, buffer, {
98
+ features: [
99
+ feature("smcp"), // Small caps
100
+ feature("liga"), // Ligatures
101
+ feature("kern"), // Kerning
102
+ ],
103
+ });
104
+
105
+ // Or use convenience helpers
106
+ import { smallCaps, standardLigatures, kerning, combineFeatures } from "text-shaper";
57
107
 
58
108
  const glyphBuffer = shape(font, buffer, {
59
- features: features(
60
- feature("smcp", 1), // Small caps
61
- feature("liga", 1), // Ligatures
62
- feature("kern", 1), // Kerning
63
- ),
109
+ features: combineFeatures(smallCaps(), standardLigatures(), kerning()),
64
110
  });
65
111
  ```
66
112
 
@@ -80,42 +126,26 @@ const glyphBuffer = shape(font, buffer, {
80
126
  ### Rendering to SVG
81
127
 
82
128
  ```typescript
83
- import { Font, shape, UnicodeBuffer, shapedTextToSVG } from "text-shaper";
129
+ import {
130
+ Font, shape, UnicodeBuffer,
131
+ glyphBufferToShapedGlyphs, shapedTextToSVG
132
+ } from "text-shaper";
84
133
 
85
134
  const buffer = new UnicodeBuffer();
86
- buffer.addString("Hello");
135
+ buffer.addStr("Hello");
87
136
 
88
137
  const glyphBuffer = shape(font, buffer);
89
- const svg = shapedTextToSVG(font, glyphBuffer, { fontSize: 48 });
138
+ const shapedGlyphs = glyphBufferToShapedGlyphs(glyphBuffer);
139
+ const svg = shapedTextToSVG(font, shapedGlyphs, { fontSize: 48 });
90
140
  ```
91
141
 
92
- ## API
93
-
94
- ### Core Classes
95
-
96
- - `Font` - Load and parse OpenType/TrueType fonts
97
- - `Face` - Font face with variation coordinates applied
98
- - `UnicodeBuffer` - Input buffer for text to shape
99
- - `GlyphBuffer` - Output buffer containing shaped glyphs
100
-
101
- ### Shaping
102
-
103
- - `shape(font, buffer, options?)` - Shape text in a buffer
104
- - `createShapePlan(font, options)` - Create a reusable shape plan
105
-
106
- ### Rendering
107
-
108
- - `getGlyphPath(font, glyphId)` - Get glyph outline as path commands
109
- - `shapedTextToSVG(font, buffer, options)` - Render shaped text to SVG
110
- - `renderShapedText(ctx, font, buffer, options)` - Render to Canvas 2D context
111
-
112
142
  ### Rasterization
113
143
 
114
144
  ```typescript
115
145
  import { Font, rasterizeGlyph, buildAtlas, PixelMode } from "text-shaper";
116
146
 
117
147
  // Rasterize a single glyph
118
- const glyph = rasterizeGlyph(font, glyphId, 48, {
148
+ const bitmap = rasterizeGlyph(font, glyphId, 48, {
119
149
  pixelMode: PixelMode.Gray, // Gray, Mono, or LCD
120
150
  hinting: true, // Enable TrueType hinting
121
151
  });
@@ -129,6 +159,342 @@ const atlas = buildAtlas(font, glyphIds, {
129
159
  });
130
160
  ```
131
161
 
162
+ ### SDF/MSDF Rendering
163
+
164
+ ```typescript
165
+ import {
166
+ Font, getGlyphPath, renderSdf, renderMsdf, buildMsdfAtlas
167
+ } from "text-shaper";
168
+
169
+ // Single glyph SDF
170
+ const path = getGlyphPath(font, glyphId);
171
+ if (path) {
172
+ const sdf = renderSdf(path, {
173
+ width: 64,
174
+ height: 64,
175
+ scale: 1,
176
+ spread: 8,
177
+ });
178
+ }
179
+
180
+ // MSDF atlas for GPU text rendering (handles font internally)
181
+ const msdfAtlas = buildMsdfAtlas(font, glyphIds, {
182
+ fontSize: 32,
183
+ spread: 4,
184
+ });
185
+ ```
186
+
187
+ ### Fluent API
188
+
189
+ Two composition styles for glyph manipulation and rendering:
190
+
191
+ #### Builder Pattern (Method Chaining)
192
+
193
+ ```typescript
194
+ import { Font, glyph, char, glyphVar, combine, PixelMode } from "text-shaper";
195
+
196
+ // From glyph ID
197
+ const rgba = glyph(font, glyphId)
198
+ ?.scale(2)
199
+ .rotateDeg(15)
200
+ .rasterizeAuto({ padding: 2 })
201
+ .blur(5)
202
+ .toRGBA();
203
+
204
+ // From character
205
+ const svg = char(font, "A")
206
+ ?.scale(3)
207
+ .italic(12)
208
+ .toSVG({ width: 100, height: 100 });
209
+
210
+ // Variable fonts
211
+ const bitmap = glyphVar(font, glyphId, [700, 100]) // wght=700, wdth=100
212
+ ?.embolden(50)
213
+ .rasterize({ pixelMode: PixelMode.Gray, scale: 2 })
214
+ .toBitmap();
215
+
216
+ // Combine multiple glyphs
217
+ const h = glyph(font, hGlyphId)?.translate(0, 0);
218
+ const i = glyph(font, iGlyphId)?.translate(100, 0);
219
+ if (h && i) {
220
+ const combined = combine(h, i).scale(2).rasterizeAuto().toRGBA();
221
+ }
222
+ ```
223
+
224
+ #### PathBuilder Methods
225
+
226
+ ```typescript
227
+ // Transforms (lazy - accumulated as matrix)
228
+ .scale(sx, sy?) // Scale uniformly or non-uniformly
229
+ .translate(dx, dy) // Translate by offset
230
+ .rotate(radians) // Rotate by angle in radians
231
+ .rotateDeg(degrees) // Rotate by angle in degrees
232
+ .shear(shearX, shearY) // Shear transform
233
+ .italic(degrees) // Italic slant (convenience for shear)
234
+ .matrix(m) // Apply custom 2D matrix
235
+ .perspective(m) // Apply 3D perspective matrix
236
+ .resetTransform() // Reset accumulated transforms
237
+ .apply() // Apply accumulated transforms to path
238
+
239
+ // Path effects (immediate - modifies path)
240
+ .embolden(strength) // Make strokes thicker
241
+ .condense(factor) // Horizontal compression
242
+ .oblique(slant) // Oblique slant effect
243
+ .stroke(width, cap?, join?) // Convert to stroked outline
244
+ .strokeAsymmetric(opts) // Independent x/y stroke widths
245
+
246
+ // Output
247
+ .rasterize(options) // Rasterize to BitmapBuilder
248
+ .rasterizeAuto(options?) // Auto-sized rasterization
249
+ .toSdf(options) // Render to SDF bitmap
250
+ .toMsdf(options) // Render to MSDF bitmap
251
+ .toSVG(options?) // Export as SVG string
252
+ .toSVGElement(options?) // Export as SVG path element
253
+ .toCanvas(ctx, options?) // Draw to Canvas 2D context
254
+ .toPath() // Get raw GlyphPath
255
+ .clone() // Clone the builder
256
+ ```
257
+
258
+ #### BitmapBuilder Methods
259
+
260
+ ```typescript
261
+ // Blur effects
262
+ .blur(radius) // Gaussian blur
263
+ .boxBlur(radius) // Box blur (faster)
264
+ .fastBlur(radius) // Fast approximated blur
265
+ .cascadeBlur(rx, ry?) // Cascade blur for large radii
266
+ .adaptiveBlur(rx, ry?) // Adaptive quality blur
267
+
268
+ // Modifications
269
+ .embolden(xStrength, yStrength?) // Expand bitmap
270
+ .shift(dx, dy) // Shift bitmap contents
271
+ .resize(width, height) // Resize (nearest neighbor)
272
+ .resizeBilinear(w, h) // Resize with bilinear filtering
273
+ .pad(left, top, right, bottom) // Add padding
274
+ .convert(pixelMode) // Convert pixel format
275
+
276
+ // Output
277
+ .toRGBA() // Export as RGBA Uint8Array
278
+ .toGray() // Export as grayscale Uint8Array
279
+ .toBitmap() // Get Bitmap object
280
+ .toRasterizedGlyph() // Get RasterizedGlyph with metrics
281
+ .clone() // Clone the builder
282
+ ```
283
+
284
+ #### Pipe Pattern (Functional)
285
+
286
+ ```typescript
287
+ import {
288
+ pipe, glyph,
289
+ $scale, $rotate, $embolden,
290
+ $rasterize, $blur, $toRGBA
291
+ } from "text-shaper";
292
+
293
+ // Compose operations functionally
294
+ const rgba = pipe(
295
+ glyph(font, glyphId),
296
+ $scale(2),
297
+ $rotate(Math.PI / 12),
298
+ $embolden(30),
299
+ $rasterize({ pixelMode: PixelMode.Gray }),
300
+ $blur(3),
301
+ $toRGBA()
302
+ );
303
+ ```
304
+
305
+ ### Line Breaking & Justification
306
+
307
+ ```typescript
308
+ import { breakIntoLines, justify, JustifyMode } from "text-shaper";
309
+
310
+ // Break text into lines
311
+ const lines = breakIntoLines(glyphBuffer, font, maxWidth);
312
+
313
+ // Justify a line
314
+ const justified = justify(line, targetWidth, {
315
+ mode: JustifyMode.Distribute,
316
+ });
317
+ ```
318
+
319
+ ### Text Segmentation
320
+
321
+ ```typescript
322
+ import { countGraphemes, splitGraphemes, splitWords } from "text-shaper";
323
+
324
+ // Count grapheme clusters (visual characters)
325
+ const count = countGraphemes("👨‍👩‍👧‍👦Hello"); // 6 (family emoji = 1)
326
+
327
+ // Split into graphemes
328
+ const graphemes = splitGraphemes("नमस्ते"); // Devanagari clusters
329
+
330
+ // Split into words
331
+ const words = splitWords("Hello World"); // ["Hello", " ", "World"]
332
+ ```
333
+
334
+ ### Canvas Rendering
335
+
336
+ ```typescript
337
+ import {
338
+ Font, shape, UnicodeBuffer,
339
+ glyphBufferToShapedGlyphs, renderShapedText
340
+ } from "text-shaper";
341
+
342
+ const canvas = document.getElementById("canvas") as HTMLCanvasElement;
343
+ const ctx = canvas.getContext("2d")!;
344
+
345
+ const buffer = new UnicodeBuffer();
346
+ buffer.addStr("Hello Canvas!");
347
+
348
+ const glyphBuffer = shape(font, buffer);
349
+ const shapedGlyphs = glyphBufferToShapedGlyphs(glyphBuffer);
350
+
351
+ renderShapedText(ctx, font, shapedGlyphs, {
352
+ x: 50,
353
+ y: 100,
354
+ fontSize: 48,
355
+ });
356
+ ```
357
+
358
+ ### BiDi & RTL Text
359
+
360
+ ```typescript
361
+ import {
362
+ Font, shape, UnicodeBuffer,
363
+ processBidi, reorderGlyphs, detectDirection
364
+ } from "text-shaper";
365
+
366
+ // Automatic RTL detection and reordering
367
+ const buffer = new UnicodeBuffer();
368
+ buffer.addStr("Hello שלום World"); // Mixed LTR/RTL
369
+
370
+ const glyphBuffer = shape(font, buffer);
371
+ // Glyphs are automatically reordered for visual display
372
+
373
+ // Manual BiDi processing
374
+ const bidiResult = processBidi("مرحبا Hello");
375
+ console.log(bidiResult.direction); // "rtl"
376
+ console.log(bidiResult.levels); // Embedding levels per character
377
+
378
+ // Detect text direction
379
+ const dir = detectDirection("שלום"); // "rtl"
380
+ ```
381
+
382
+ ### Color Fonts
383
+
384
+ ```typescript
385
+ import {
386
+ Font,
387
+ hasColorGlyph, getColorPaint, getColorLayers, // COLR
388
+ hasSvgGlyph, getSvgDocument, // SVG
389
+ hasColorBitmap, getBitmapGlyph, // CBDT/sbix
390
+ } from "text-shaper";
391
+
392
+ // Check for color glyph support
393
+ const glyphId = font.glyphId("😀".codePointAt(0)!);
394
+
395
+ // COLR/CPAL (vector color)
396
+ if (hasColorGlyph(font, glyphId)) {
397
+ const paint = getColorPaint(font, glyphId);
398
+ // Render paint tree...
399
+ }
400
+
401
+ // SVG color glyphs
402
+ if (hasSvgGlyph(font, glyphId)) {
403
+ const svgDoc = getSvgDocument(font, glyphId);
404
+ // Use SVG document directly
405
+ }
406
+
407
+ // Bitmap color glyphs (sbix, CBDT)
408
+ if (hasColorBitmap(font, glyphId)) {
409
+ const bitmap = getBitmapGlyph(font, glyphId, 128); // ppem=128
410
+ // bitmap.data contains PNG/JPEG data
411
+ }
412
+ ```
413
+
414
+ ### Texture Atlas (WebGL/GPU)
415
+
416
+ ```typescript
417
+ import {
418
+ Font, buildAtlas, buildStringAtlas, buildMsdfAtlas,
419
+ atlasToRGBA, getGlyphUV, PixelMode
420
+ } from "text-shaper";
421
+
422
+ // Build atlas from glyph IDs
423
+ const atlas = buildAtlas(font, glyphIds, {
424
+ fontSize: 32,
425
+ padding: 2,
426
+ pixelMode: PixelMode.Gray,
427
+ });
428
+
429
+ // Build atlas from string (auto-extracts unique glyphs)
430
+ const textAtlas = buildStringAtlas(font, "Hello World!", {
431
+ fontSize: 48,
432
+ padding: 1,
433
+ });
434
+
435
+ // Convert to RGBA for WebGL texture
436
+ const rgba = atlasToRGBA(atlas);
437
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, atlas.width, atlas.height,
438
+ 0, gl.RGBA, gl.UNSIGNED_BYTE, rgba);
439
+
440
+ // Get UV coordinates for rendering
441
+ const uv = getGlyphUV(atlas, glyphId);
442
+ // uv = { u0, v0, u1, v1, ... }
443
+
444
+ // MSDF atlas for scalable GPU text
445
+ const msdfAtlas = buildMsdfAtlas(font, glyphIds, {
446
+ fontSize: 32,
447
+ spread: 4,
448
+ });
449
+ ```
450
+
451
+ ### Browser Usage
452
+
453
+ ```typescript
454
+ // Fetch font from URL
455
+ const fontData = await fetch("/fonts/MyFont.ttf").then(r => r.arrayBuffer());
456
+ const font = Font.load(fontData);
457
+
458
+ // Or from File input
459
+ const file = input.files[0];
460
+ const buffer = await file.arrayBuffer();
461
+ const font = Font.load(buffer);
462
+
463
+ // Works with any ArrayBuffer source
464
+ ```
465
+
466
+ ## API Reference
467
+
468
+ ### Core Classes
469
+
470
+ | Class | Description |
471
+ |-------|-------------|
472
+ | `Font` | Load and parse OpenType/TrueType fonts |
473
+ | `Face` | Font face with variation coordinates applied |
474
+ | `UnicodeBuffer` | Input buffer for text to shape |
475
+ | `GlyphBuffer` | Output buffer containing shaped glyphs |
476
+
477
+ ### Shaping Functions
478
+
479
+ | Function | Description |
480
+ |----------|-------------|
481
+ | `shape(font, buffer, options?)` | Shape text, returns new GlyphBuffer |
482
+ | `shapeInto(font, buffer, glyphBuffer, options?)` | Shape into existing buffer (faster) |
483
+ | `createShapePlan(font, options)` | Create reusable shape plan |
484
+ | `getOrCreateShapePlan(font, options)` | Get cached or create shape plan |
485
+
486
+ ### Rendering Functions
487
+
488
+ | Function | Description |
489
+ |----------|-------------|
490
+ | `getGlyphPath(font, glyphId)` | Get glyph outline as path commands |
491
+ | `shapedTextToSVG(font, shapedGlyphs, options)` | Render shaped text to SVG string |
492
+ | `renderShapedText(ctx, font, shapedGlyphs, options)` | Render to Canvas 2D context |
493
+ | `glyphBufferToShapedGlyphs(buffer)` | Convert GlyphBuffer to ShapedGlyph[] |
494
+ | `rasterizeGlyph(font, glyphId, size, options)` | Rasterize glyph to bitmap |
495
+ | `rasterizePath(path, options)` | Rasterize path commands to bitmap |
496
+ | `buildAtlas(font, glyphIds, options)` | Build texture atlas |
497
+
132
498
  ### Feature Helpers
133
499
 
134
500
  ```typescript
@@ -152,10 +518,19 @@ proportionalFigures() // pnum
152
518
  stylisticSet(n) // ss01-ss20
153
519
  characterVariant(n) // cv01-cv99
154
520
  swash() // swsh
155
-
156
- // And many more...
157
521
  ```
158
522
 
523
+ ### Unicode Utilities
524
+
525
+ | Function | Description |
526
+ |----------|-------------|
527
+ | `processBidi(text)` | Process bidirectional text (UAX #9) |
528
+ | `getScript(codepoint)` | Get Unicode script for codepoint |
529
+ | `getScriptRuns(text)` | Split text into script runs |
530
+ | `countGraphemes(text)` | Count grapheme clusters |
531
+ | `splitGraphemes(text)` | Split into grapheme clusters |
532
+ | `analyzeLineBreaks(text)` | Find line break opportunities (UAX #14) |
533
+
159
534
  ## Supported Tables
160
535
 
161
536
  ### Required
@@ -171,7 +546,7 @@ CFF, CFF2
171
546
  fvar, gvar, avar, HVAR, VVAR, MVAR, STAT
172
547
 
173
548
  ### AAT (Apple)
174
- morx, kerx, kern, trak
549
+ morx, kerx, kern, trak, feat
175
550
 
176
551
  ### Color
177
552
  COLR, CPAL, SVG, sbix, CBDT, CBLC
@@ -185,4 +560,3 @@ fpgm, prep, cvt, gasp
185
560
  ## License
186
561
 
187
562
  [MIT](LICENSE)
188
-
@@ -23,10 +23,10 @@ export declare class GlyphBuffer {
23
23
  private _infoPool;
24
24
  /** Pre-allocated position pool for reuse */
25
25
  private _posPool;
26
+ /** Pre-allocated capacity hint */
27
+ private _capacity;
26
28
  /** Create buffer with pre-allocated capacity (lazy object creation) */
27
29
  static withCapacity(capacity: number): GlyphBuffer;
28
- /** Hint for initial capacity (used for lazy allocation) */
29
- private _capacity;
30
30
  /** Number of glyphs */
31
31
  get length(): number;
32
32
  /** Reset buffer for reuse - reuses existing object pool */
@@ -3,7 +3,49 @@
3
3
  * Based on the brotli.js reference implementation (MIT License)
4
4
  * https://github.com/devongovett/brotli.js
5
5
  */
6
+ interface HuffmanCode {
7
+ bits: number;
8
+ value: number;
9
+ }
10
+ declare class BitReader {
11
+ private data;
12
+ private buf;
13
+ private pos;
14
+ private val;
15
+ private bitPos;
16
+ private bitEndPos;
17
+ private eos;
18
+ constructor(data: Uint8Array);
19
+ private fillBuffer;
20
+ readMoreInput(): void;
21
+ fillBitWindow(): void;
22
+ readBits(n: number): number;
23
+ get currentBitPos(): number;
24
+ set currentBitPos(v: number);
25
+ get currentVal(): number;
26
+ }
27
+ declare function buildHuffmanTable(rootTable: HuffmanCode[], tableOffset: number, rootBits: number, codeLengths: Uint8Array, codeLengthsSize: number): number;
28
+ declare function getNextKey(key: number, len: number): number;
29
+ declare function replicateValue(table: HuffmanCode[], offset: number, step: number, end: number, code: HuffmanCode): void;
30
+ declare function nextTableBitSize(count: Int32Array, len: number, rootBits: number): number;
31
+ declare function readHuffmanCodeLengths(codeLengthCodeLengths: Uint8Array, numSymbols: number, codeLengths: Uint8Array, br: BitReader): void;
32
+ declare function readBlockLength(table: HuffmanCode[], tableOffset: number, br: BitReader): number;
6
33
  /**
7
34
  * Decompress Brotli-compressed data
8
35
  */
9
36
  export declare function decompress(data: Uint8Array): Uint8Array;
37
+ export declare const __testing: {
38
+ getNextKey: typeof getNextKey;
39
+ replicateValue: typeof replicateValue;
40
+ nextTableBitSize: typeof nextTableBitSize;
41
+ buildHuffmanTable: typeof buildHuffmanTable;
42
+ readBlockLength: typeof readBlockLength;
43
+ readHuffmanCodeLengths: typeof readHuffmanCodeLengths;
44
+ BitReader: typeof BitReader;
45
+ HuffmanCode: {
46
+ bits: number;
47
+ value: number;
48
+ };
49
+ CODE_LENGTH_CODES: number;
50
+ };
51
+ export {};
@@ -79,7 +79,70 @@ export interface ItemVariationData {
79
79
  * Parse CFF2 table
80
80
  */
81
81
  export declare function parseCff2(reader: Reader): Cff2Table;
82
+ /**
83
+ * Parse CFF2 INDEX structure (uses 32-bit count)
84
+ */
85
+ declare function parseIndex(reader: Reader): Uint8Array[];
86
+ /**
87
+ * Read offset of given size
88
+ */
89
+ declare function readOffset(reader: Reader, offSize: number): number;
90
+ /**
91
+ * Parse a CFF2 DICT structure
92
+ */
93
+ declare function parseDict(reader: Reader): Map<number, number[]>;
94
+ /**
95
+ * Parse real number
96
+ */
97
+ declare function parseReal(reader: Reader): number;
98
+ /**
99
+ * Parse CFF2 Top DICT
100
+ */
101
+ declare function parseCff2TopDict(reader: Reader): Cff2TopDict;
102
+ /**
103
+ * Parse CFF2 FD DICT
104
+ */
105
+ declare function parseCff2FDDict(reader: Reader): Cff2FDDict;
106
+ /**
107
+ * Parse CFF2 Private DICT
108
+ */
109
+ declare function parseCff2PrivateDict(reader: Reader): Cff2PrivateDict;
110
+ /**
111
+ * Convert delta-encoded values to absolute
112
+ */
113
+ declare function deltaToAbsolute(deltas: number[]): number[];
114
+ /**
115
+ * Parse FDSelect structure
116
+ */
117
+ declare function parseFDSelect(reader: Reader, numGlyphs: number): Cff2FDSelect;
118
+ /**
119
+ * Parse ItemVariationStore
120
+ */
121
+ declare function parseItemVariationStore(reader: Reader): ItemVariationStore;
122
+ /**
123
+ * Parse VariationRegionList
124
+ */
125
+ declare function parseVariationRegionList(reader: Reader): VariationRegionList;
126
+ /**
127
+ * Parse ItemVariationData
128
+ */
129
+ declare function parseItemVariationData(reader: Reader): ItemVariationData;
82
130
  /**
83
131
  * Calculate variation delta for given coordinates
84
132
  */
85
133
  export declare function calculateVariationDelta(vstore: ItemVariationStore, outerIndex: number, innerIndex: number, normalizedCoords: number[]): number;
134
+ export declare const __testing: {
135
+ parseIndex: typeof parseIndex;
136
+ readOffset: typeof readOffset;
137
+ parseDict: typeof parseDict;
138
+ parseReal: typeof parseReal;
139
+ parseCff2TopDict: typeof parseCff2TopDict;
140
+ parseCff2FDDict: typeof parseCff2FDDict;
141
+ parseCff2PrivateDict: typeof parseCff2PrivateDict;
142
+ deltaToAbsolute: typeof deltaToAbsolute;
143
+ parseFDSelect: typeof parseFDSelect;
144
+ parseItemVariationStore: typeof parseItemVariationStore;
145
+ parseVariationRegionList: typeof parseVariationRegionList;
146
+ parseItemVariationData: typeof parseItemVariationData;
147
+ };
148
+ export {};
@@ -134,6 +134,14 @@ export interface GposTable {
134
134
  }
135
135
  export type { Anchor, MarkArray } from "./gpos-mark.ts";
136
136
  export declare function parseGpos(reader: Reader): GposTable;
137
+ declare function parseGposLookup(reader: Reader): AnyGposLookup | null;
138
+ declare function parseValueRecord(reader: Reader, valueFormat: uint16, subtableReader?: Reader): ValueRecord;
139
+ declare function parseSinglePos(reader: Reader, subtableOffsets: number[]): SinglePosSubtable[];
140
+ declare function parsePairPos(reader: Reader, subtableOffsets: number[]): PairPosSubtable[];
141
+ declare function parseExtensionLookup(reader: Reader, subtableOffsets: number[], baseProps: {
142
+ flag: uint16;
143
+ markFilteringSet?: uint16;
144
+ }): AnyGposLookup | null;
137
145
  export declare function getKerning(lookup: PairPosLookup, firstGlyph: GlyphId, secondGlyph: GlyphId): {
138
146
  xAdvance1: number;
139
147
  xAdvance2: number;
@@ -143,3 +151,10 @@ export declare function getKerning(lookup: PairPosLookup, firstGlyph: GlyphId, s
143
151
  * Returns true if kerning was applied, false otherwise.
144
152
  */
145
153
  export declare function applyKerningDirect(lookup: PairPosLookup, firstGlyph: GlyphId, secondGlyph: GlyphId, pos1: GlyphPosition, pos2: GlyphPosition): boolean;
154
+ export declare const __testing: {
155
+ parseGposLookup: typeof parseGposLookup;
156
+ parseExtensionLookup: typeof parseExtensionLookup;
157
+ parseSinglePos: typeof parseSinglePos;
158
+ parsePairPos: typeof parsePairPos;
159
+ parseValueRecord: typeof parseValueRecord;
160
+ };