Add hollow letters and digits (#2189)
This commit is contained in:
parent
8e7bd0a0bc
commit
cfac37ddf0
9 changed files with 318 additions and 65 deletions
10
package-lock.json
generated
10
package-lock.json
generated
|
@ -3665,9 +3665,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/typo-geom": {
|
||||
"version": "0.13.2",
|
||||
"resolved": "https://registry.npmjs.org/typo-geom/-/typo-geom-0.13.2.tgz",
|
||||
"integrity": "sha512-0xEeNX/bQl/qx1+jgMy7ObtyUK9SmdhZALCNTs2dHyTTCCpHRNHL1nPw+Us0ZmxbLRi9gy5GpINJ3tynE8K6Pw==",
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/typo-geom/-/typo-geom-0.14.0.tgz",
|
||||
"integrity": "sha512-h3KmTEdKHrD+VWrR/Oqfr/NAPyTNaEKqhcIMhpbotNiHyXTrv113NCY//o0sUswwDEpHcTxcagxdG3dm/J9hlA==",
|
||||
"dependencies": {
|
||||
"clipper-lib": "^6.4.2",
|
||||
"tslib": "^2.6.2"
|
||||
|
@ -3994,7 +3994,7 @@
|
|||
"@iosevka/geometry-cache": "28.0.7",
|
||||
"@iosevka/glyph": "28.0.7",
|
||||
"@iosevka/util": "28.0.7",
|
||||
"typo-geom": "^0.13.2"
|
||||
"typo-geom": "^0.14.0"
|
||||
}
|
||||
},
|
||||
"packages/font-kits": {
|
||||
|
@ -4021,7 +4021,7 @@
|
|||
"dependencies": {
|
||||
"@iosevka/util": "28.0.7",
|
||||
"spiro": "^3.0.0",
|
||||
"typo-geom": "^0.13.2"
|
||||
"typo-geom": "^0.14.0"
|
||||
}
|
||||
},
|
||||
"packages/geometry-cache": {
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
{
|
||||
"name": "@iosevka/font-glyphs",
|
||||
"version": "28.0.7",
|
||||
"private": true,
|
||||
"exports": {
|
||||
".": "./src/index.mjs",
|
||||
"./aesthetics": "./src/meta/aesthetics.mjs",
|
||||
"./unicode-knowledge": "./src/meta/unicode-knowledge.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iosevka/font-kits": "28.0.7",
|
||||
"@iosevka/geometry": "28.0.7",
|
||||
"@iosevka/geometry-cache": "28.0.7",
|
||||
"@iosevka/glyph": "28.0.7",
|
||||
"@iosevka/util": "28.0.7",
|
||||
"typo-geom": "^0.13.2"
|
||||
}
|
||||
"name": "@iosevka/font-glyphs",
|
||||
"version": "28.0.7",
|
||||
"private": true,
|
||||
"exports": {
|
||||
".": "./src/index.mjs",
|
||||
"./aesthetics": "./src/meta/aesthetics.mjs",
|
||||
"./unicode-knowledge": "./src/meta/unicode-knowledge.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iosevka/font-kits": "28.0.7",
|
||||
"@iosevka/geometry": "28.0.7",
|
||||
"@iosevka/geometry-cache": "28.0.7",
|
||||
"@iosevka/glyph": "28.0.7",
|
||||
"@iosevka/util": "28.0.7",
|
||||
"typo-geom": "^0.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ $$include '../meta/macros.ptl'
|
|||
import [linreg clamp mix fallback] from "@iosevka/util"
|
||||
import [getGrTree IsSuperscript IsSubscript AnyCv DotlessOrNot] from "@iosevka/glyph/relation"
|
||||
import [AnyLocalizedForm CvDecompose MathSansSerif Texture] from "@iosevka/glyph/relation"
|
||||
import [BooleanGeometry StrokeGeometry] from "@iosevka/geometry"
|
||||
import [NumeratorForm DenominatorForm] from "@iosevka/glyph/relation"
|
||||
import [Transform] from "@iosevka/geometry/transform"
|
||||
extern Map
|
||||
|
@ -775,14 +776,13 @@ glyph-block Autobuild-Transformed-Texture : begin
|
|||
createTextureDerivatives Texture.ShrR 0 SHRINK [jobs 0xF400]
|
||||
createTextureDerivatives Texture.ShrLR SHRINK SHRINK [jobs 0xF500]
|
||||
|
||||
|
||||
glyph-block Autobuild-Transformed-Mathematical : begin
|
||||
glyph-block-import CommonShapes
|
||||
glyph-block-import Common-Derivatives
|
||||
glyph-block-import Recursive-Build : Fork
|
||||
glyph-block-import Autobuild-Transformed-Shared : extendRelatedGlyphs link-relations wrapName
|
||||
|
||||
define [createMathDerivedSeriesImpl groupName tfm _records] : begin
|
||||
define [createMathDerivedSeriesImpl groupName tfm _records postProcessing] : begin
|
||||
local { records relSets targetNameMap } : extendRelatedGlyphs groupName _records
|
||||
local pendingGlyphs : records.map : [record] => record.1
|
||||
local forkedPara : para.createFork tfm
|
||||
|
@ -793,6 +793,7 @@ glyph-block Autobuild-Transformed-Mathematical : begin
|
|||
if [not glyphT] : console.log glyphid
|
||||
include glyphT AS_BASE ALSO_METRICS
|
||||
set currentGlyph.gizmo glyphT.gizmo
|
||||
if postProcessing : include : postProcessing para forkedPara
|
||||
|
||||
link-relations relSets
|
||||
|
||||
|
@ -822,7 +823,7 @@ glyph-block Autobuild-Transformed-Mathematical : begin
|
|||
define Greek2 : Array.from 'Ϝϝ'
|
||||
define ObliqueBlackboardBolds : Array.from '𝔻𝕕𝕖𝕚𝕛'
|
||||
|
||||
define [CreateMathDerivatives groupName tfm gr base letters overrides] : begin
|
||||
define [CreateMathDerivatives groupName tfm gr base letters overrides postProcessing] : begin
|
||||
local jobs {}
|
||||
local overrideMap : new Map (overrides || {})
|
||||
foreach j [range 0 letters.length] : begin
|
||||
|
@ -832,7 +833,7 @@ glyph-block Autobuild-Transformed-Mathematical : begin
|
|||
local dst : base + j
|
||||
if [overrideMap.has letter] : set dst [overrideMap.get letter]
|
||||
if source : jobs.push { dst source }
|
||||
createMathDerivedSeriesImpl groupName tfm jobs
|
||||
createMathDerivedSeriesImpl groupName tfm jobs postProcessing
|
||||
|
||||
define [CreateMathAliasableImpl groupName altGroupName tfm gr base letters overrides] : begin
|
||||
local overrideMap : new Map (overrides || {})
|
||||
|
@ -902,6 +903,16 @@ glyph-block Autobuild-Transformed-Mathematical : begin
|
|||
# Italic blackboard bold
|
||||
CreateMathDerivatives 'mathit' tfItalic null 0x2145 ObliqueBlackboardBolds
|
||||
|
||||
# Outlined letters and digits -- for Symbols for Legacy Computing Supplement
|
||||
define [TfOutline para forkedPara] : glyph-proc
|
||||
local g currentGlyph.geometry
|
||||
local sw : forkedPara.stroke / 4
|
||||
local gizmo : currentGlyph.gizmo || GlobalTransform
|
||||
set currentGlyph.geometry : new StrokeGeometry g gizmo sw HVContrast true
|
||||
|
||||
CreateMathDerivatives 'legacyComputingOutlined' tfBold null 0x1CCD6 UpperLatin null TfOutline
|
||||
CreateMathDerivatives 'legacyComputingOutlined' tfBold null 0x1CCF0 Digits null TfOutline
|
||||
|
||||
glyph-block Autobuild-Rhotic : begin
|
||||
glyph-block-import Mark-Shared-Metrics : markFine markstroke
|
||||
glyph-block-import CommonShapes
|
||||
|
|
|
@ -4,7 +4,7 @@ import zlib from "zlib";
|
|||
import * as CurveUtil from "@iosevka/geometry/curve-util";
|
||||
import { encode, decode } from "@msgpack/msgpack";
|
||||
|
||||
const Edition = 32;
|
||||
const Edition = 33;
|
||||
const MAX_AGE = 16;
|
||||
class GfEntry {
|
||||
constructor(age, value) {
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
{
|
||||
"name": "@iosevka/geometry",
|
||||
"version": "28.0.7",
|
||||
"private": true,
|
||||
"exports": {
|
||||
".": "./src/index.mjs",
|
||||
"./anchor": "./src/anchor.mjs",
|
||||
"./box": "./src/box.mjs",
|
||||
"./segment": "./src/segment.mjs",
|
||||
"./curve-util": "./src/curve-util.mjs",
|
||||
"./point": "./src/point.mjs",
|
||||
"./transform": "./src/transform.mjs",
|
||||
"./spiro-control": "./src/spiro-control.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iosevka/util": "28.0.7",
|
||||
"spiro": "^3.0.0",
|
||||
"typo-geom": "^0.13.2"
|
||||
}
|
||||
"name": "@iosevka/geometry",
|
||||
"version": "28.0.7",
|
||||
"private": true,
|
||||
"exports": {
|
||||
".": "./src/index.mjs",
|
||||
"./anchor": "./src/anchor.mjs",
|
||||
"./box": "./src/box.mjs",
|
||||
"./segment": "./src/segment.mjs",
|
||||
"./curve-util": "./src/curve-util.mjs",
|
||||
"./point": "./src/point.mjs",
|
||||
"./transform": "./src/transform.mjs",
|
||||
"./spiro-control": "./src/spiro-control.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@iosevka/util": "28.0.7",
|
||||
"spiro": "^3.0.0",
|
||||
"typo-geom": "^0.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import * as TypoGeom from "typo-geom";
|
||||
|
||||
import { Point } from "./point.mjs";
|
||||
import { Point, Vec2 } from "./point.mjs";
|
||||
import { Transform } from "./transform.mjs";
|
||||
import { mix } from "@iosevka/util";
|
||||
|
||||
function contourToRep(contour) {
|
||||
let c = [];
|
||||
|
@ -71,6 +72,26 @@ export const OCCURRENT_PRECISION = 1 / 16;
|
|||
export const GEOMETRY_PRECISION = 1 / 4;
|
||||
export const BOOLE_RESOLUTION = 0x4000;
|
||||
|
||||
export function derivativeFromFiniteDifference(c, t) {
|
||||
const DELTA = 1 / 0x10000;
|
||||
const forward2 = c.eval(t + 2 * DELTA);
|
||||
const forward1 = c.eval(t + DELTA);
|
||||
const backward1 = c.eval(t - DELTA);
|
||||
const backward2 = c.eval(t - 2 * DELTA);
|
||||
return new Vec2(
|
||||
((1 / 12) * backward2.x -
|
||||
(2 / 3) * backward1.x +
|
||||
(2 / 3) * forward1.x -
|
||||
(1 / 12) * forward2.x) /
|
||||
DELTA,
|
||||
((1 / 12) * backward2.y -
|
||||
(2 / 3) * backward1.y +
|
||||
(2 / 3) * forward1.y -
|
||||
(1 / 12) * forward2.y) /
|
||||
DELTA
|
||||
);
|
||||
}
|
||||
|
||||
export class OffsetCurve {
|
||||
constructor(bone, offset, contrast) {
|
||||
this.bone = bone;
|
||||
|
@ -87,25 +108,7 @@ export class OffsetCurve {
|
|||
};
|
||||
}
|
||||
derivative(t) {
|
||||
const DELTA = 1 / 0x10000;
|
||||
const forward = this.eval(t + DELTA);
|
||||
const backward = this.eval(t - DELTA);
|
||||
return {
|
||||
x: (forward.x - backward.x) / (2 * DELTA),
|
||||
y: (forward.y - backward.y) / (2 * DELTA)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class ReverseCurve {
|
||||
constructor(original) {
|
||||
this.m_original = original;
|
||||
}
|
||||
eval(t) {
|
||||
return this.m_original.eval(1 - t);
|
||||
}
|
||||
derivative(t) {
|
||||
return -this.m_original.derivative(1 - t);
|
||||
return derivativeFromFiniteDifference(this, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,3 +152,49 @@ export class BezToContoursSink {
|
|||
this.lastContour.push(Point.transformedXY(this.gizmo, Point.Type.Corner, x, y));
|
||||
}
|
||||
}
|
||||
|
||||
export function Bez3FromHermite(zStart, dStart, zEnd, dEnd) {
|
||||
const a = zStart,
|
||||
d = zEnd;
|
||||
const b = new Vec2(a.x + dStart.x / 3, a.y + dStart.y / 3);
|
||||
const c = new Vec2(d.x - dEnd.x / 3, d.y - dEnd.y / 3);
|
||||
return new TypoGeom.Arcs.Bez3(a, b, c, d);
|
||||
}
|
||||
|
||||
export class RoundCapCurve {
|
||||
constructor(side, contrast, center0, point0, center1, point1) {
|
||||
this.contrast = contrast;
|
||||
this.center0 = center0;
|
||||
this.center1 = center1;
|
||||
|
||||
const theta0 = Math.atan2(point0.y - center0.y, (point0.x - center0.x) / contrast);
|
||||
let theta1 = Math.atan2(point1.y - center1.y, (point1.x - center1.x) / contrast);
|
||||
if (side) {
|
||||
while (theta1 < theta0) theta1 += 2 * Math.PI;
|
||||
} else {
|
||||
while (theta1 > theta0) theta1 -= 2 * Math.PI;
|
||||
}
|
||||
this.theta0 = theta0;
|
||||
this.theta1 = theta1;
|
||||
|
||||
this.r0 = Math.hypot(center0.y - point0.y, (center0.x - point0.x) / contrast);
|
||||
this.r1 = Math.hypot(center1.y - point1.y, (center1.x - point1.x) / contrast);
|
||||
}
|
||||
|
||||
eval(t) {
|
||||
const centerX = mix(this.center0.x, this.center1.x, t);
|
||||
const centerY = mix(this.center0.y, this.center1.y, t);
|
||||
const r = mix(this.r0, this.r1, t);
|
||||
const theta = mix(this.theta0, this.theta1, t);
|
||||
|
||||
return {
|
||||
x: centerX + r * Math.cos(theta) * this.contrast,
|
||||
y: centerY + r * Math.sin(theta)
|
||||
};
|
||||
}
|
||||
|
||||
derivative(t) {
|
||||
// TODO: calculate an exact form instead of using finite difference
|
||||
return derivativeFromFiniteDifference(this, t);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import { Point } from "./point.mjs";
|
|||
import { QuadifySink } from "./quadify.mjs";
|
||||
import { SpiroExpander } from "./spiro-expand.mjs";
|
||||
import { Transform } from "./transform.mjs";
|
||||
import { strokeArcs } from "./stroke.mjs";
|
||||
|
||||
export const CPLX_NON_EMPTY = 0x01; // A geometry tree that is not empty
|
||||
export const CPLX_NON_SIMPLE = 0x02; // A geometry tree that contains non-simple contours
|
||||
|
@ -533,6 +534,83 @@ export class BooleanGeometry extends GeometryBase {
|
|||
}
|
||||
}
|
||||
|
||||
export class StrokeGeometry extends GeometryBase {
|
||||
constructor(geom, gizmo, radius, contrast, fInside) {
|
||||
super();
|
||||
this.m_geom = geom;
|
||||
this.m_gizmo = gizmo;
|
||||
this.m_radius = radius;
|
||||
this.m_contrast = contrast;
|
||||
this.m_fInside = fInside;
|
||||
}
|
||||
|
||||
asContours() {
|
||||
// Produce simplified arcs
|
||||
const nonTransformedGeometry = new TransformedGeometry(this.m_geom, this.m_gizmo.inverse());
|
||||
let arcs = TypoGeom.Boolean.removeOverlap(
|
||||
CurveUtil.convertShapeToArcs(nonTransformedGeometry.asContours()),
|
||||
TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||
CurveUtil.BOOLE_RESOLUTION
|
||||
);
|
||||
|
||||
// Fairize to get get some arcs that are simple enough
|
||||
const fairizedArcs = TypoGeom.Fairize.fairizeBezierShape(arcs);
|
||||
|
||||
// Stroke the arcs
|
||||
const strokedArcs = strokeArcs(
|
||||
fairizedArcs,
|
||||
this.m_radius,
|
||||
this.m_contrast,
|
||||
this.m_fInside
|
||||
);
|
||||
|
||||
// Convert to Iosevka format
|
||||
let sink = new CurveUtil.BezToContoursSink(this.m_gizmo);
|
||||
TypoGeom.ShapeConv.transferBezArcShape(strokedArcs, sink, CurveUtil.GEOMETRY_PRECISION);
|
||||
|
||||
return sink.contours;
|
||||
}
|
||||
asReferences() {
|
||||
return null;
|
||||
}
|
||||
getDependencies() {
|
||||
return this.m_geom.getDependencies();
|
||||
}
|
||||
unlinkReferences() {
|
||||
return new StrokeGeometry(
|
||||
this.m_geom.unlinkReferences(),
|
||||
this.m_gizmo,
|
||||
this.m_radius,
|
||||
this.m_contrast,
|
||||
this.m_fInside
|
||||
);
|
||||
}
|
||||
filterTag(fn) {
|
||||
return new StrokeGeometry(
|
||||
this.m_geom.filterTag(fn),
|
||||
this.m_gizmo,
|
||||
this.m_radius,
|
||||
this.m_contrast,
|
||||
this.m_fInside
|
||||
);
|
||||
}
|
||||
measureComplexity() {
|
||||
return this.m_geom.measureComplexity() | CPLX_NON_SIMPLE;
|
||||
}
|
||||
toShapeStringOrNull() {
|
||||
const sTarget = this.m_geom.unlinkReferences().toShapeStringOrNull();
|
||||
if (!sTarget) return null;
|
||||
return Format.struct(
|
||||
`StrokeGeometry`,
|
||||
sTarget,
|
||||
Format.gizmo(this.m_gizmo),
|
||||
Format.n(this.m_radius),
|
||||
Format.n(this.m_contrast),
|
||||
this.m_fInside
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// This special geometry type is used in the finalization phase to create TTF contours.
|
||||
export class SimplifyGeometry extends GeometryBase {
|
||||
constructor(g) {
|
||||
|
|
114
packages/geometry/src/stroke.mjs
Normal file
114
packages/geometry/src/stroke.mjs
Normal file
|
@ -0,0 +1,114 @@
|
|||
import * as TypoGeom from "typo-geom";
|
||||
import {
|
||||
BOOLE_RESOLUTION,
|
||||
Bez3FromHermite,
|
||||
GEOMETRY_PRECISION,
|
||||
OCCURRENT_PRECISION,
|
||||
OffsetCurve,
|
||||
RoundCapCurve
|
||||
} from "./curve-util.mjs";
|
||||
|
||||
export function strokeArcs(arcs, radius, contrast, fInside) {
|
||||
let currentArcs = null;
|
||||
for (const contour of arcs) {
|
||||
let leftSide = offsetContour(contour, -radius, contrast);
|
||||
let rightSide = offsetContour(contour, radius, contrast);
|
||||
let bezs = TypoGeom.ShapeConv.convertShapeToBez3([leftSide, rightSide], GEOMETRY_PRECISION);
|
||||
|
||||
if (!currentArcs) {
|
||||
currentArcs = bezs;
|
||||
} else {
|
||||
currentArcs = TypoGeom.Boolean.combine(
|
||||
TypoGeom.Boolean.ClipType.ctUnion,
|
||||
currentArcs,
|
||||
bezs,
|
||||
TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||
TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||
BOOLE_RESOLUTION
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentArcs) {
|
||||
if (fInside) {
|
||||
return TypoGeom.Boolean.combine(
|
||||
TypoGeom.Boolean.ClipType.ctIntersection,
|
||||
TypoGeom.ShapeConv.convertShapeToBez3(arcs, GEOMETRY_PRECISION),
|
||||
currentArcs,
|
||||
TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||
TypoGeom.Boolean.PolyFillType.pftNonZero,
|
||||
BOOLE_RESOLUTION
|
||||
);
|
||||
} else {
|
||||
return currentArcs;
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function offsetContour(arcs, distance, contrast) {
|
||||
// The arcs here are guaranteed to be simple, i.e. no self-intersections.
|
||||
const fReverse = distance < 0;
|
||||
let offsetArcs = [];
|
||||
let prevOffsetedArc = new OffsetCurve(arcs[arcs.length - 1], distance, contrast);
|
||||
for (let i = 0; i < arcs.length; i++) {
|
||||
const current = arcs[i];
|
||||
const currentOffsetedArc = new OffsetCurve(current, distance, contrast);
|
||||
|
||||
// Evaluate the previous' end and the current's start, determine whether they are close enough
|
||||
const prevEnd = prevOffsetedArc.eval(1);
|
||||
const currentStart = currentOffsetedArc.eval(0);
|
||||
if (
|
||||
Math.abs(prevEnd.x - currentStart.x) > OCCURRENT_PRECISION ||
|
||||
Math.abs(prevEnd.y - currentStart.y) > OCCURRENT_PRECISION
|
||||
) {
|
||||
offsetArcs.push(
|
||||
createCap(
|
||||
distance < 0,
|
||||
contrast,
|
||||
prevOffsetedArc.bone.eval(1),
|
||||
prevEnd,
|
||||
prevOffsetedArc.derivative(1),
|
||||
currentOffsetedArc.bone.eval(0),
|
||||
currentStart,
|
||||
currentOffsetedArc.derivative(0)
|
||||
)
|
||||
);
|
||||
// offsetArcs.push(Bez3FromHermite(prevEnd, dPrevEnd, currentStart, dCurrentStart));
|
||||
}
|
||||
|
||||
// Push the current arc
|
||||
offsetArcs.push(currentOffsetedArc);
|
||||
|
||||
prevOffsetedArc = currentOffsetedArc;
|
||||
}
|
||||
|
||||
if (fReverse) {
|
||||
offsetArcs.reverse();
|
||||
for (let i = 0; i < offsetArcs.length; i++) {
|
||||
offsetArcs[i] = new TypoGeom.Arcs.Reverted(offsetArcs[i]);
|
||||
}
|
||||
}
|
||||
return offsetArcs;
|
||||
}
|
||||
|
||||
function createCap(
|
||||
side,
|
||||
contrast,
|
||||
prevEndNoOffset, // Previous non-offseted curve's end point
|
||||
prevEnd, // Previous offseted curve's end point
|
||||
dPrevEnd, // Previous offseted curve's end point's derivative
|
||||
currentStartNoOffset, // Current non-offseted curve's start point
|
||||
currentStart, // Current offseted curve's start point
|
||||
dCurrentStart // Current offseted curve's start point's derivative
|
||||
) {
|
||||
return new RoundCapCurve(
|
||||
side,
|
||||
contrast,
|
||||
prevEndNoOffset,
|
||||
prevEnd,
|
||||
currentStartNoOffset,
|
||||
currentStart
|
||||
);
|
||||
}
|
|
@ -4,7 +4,8 @@ export async function collectBlockData() {
|
|||
const BlockData = [
|
||||
[[0xe0a0, 0xe0df], "Private Use Area — Powerline"],
|
||||
[[0xee00, 0xee0f], "Private Use Area — Progress Bar"],
|
||||
[[0xef10, 0xef1f], "Private Use Area — Iosevka Private Dingbats"]
|
||||
[[0xef10, 0xef1f], "Private Use Area — Iosevka Private Dingbats"],
|
||||
[[0x1cc00, 0x1ceaf], "Symbols for Legacy Computing Supplement"]
|
||||
];
|
||||
|
||||
for (const id of UnicodeDataIndex.Block) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue