123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670 |
- /**
- * @licstart The following is the entire license notice for the
- * Javascript code in this page
- *
- * Copyright 2022 Mozilla Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * @licend The above is the entire license notice for the
- * Javascript code in this page
- */
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.GlyfTable = void 0;
- const ON_CURVE_POINT = 1 << 0;
- const X_SHORT_VECTOR = 1 << 1;
- const Y_SHORT_VECTOR = 1 << 2;
- const REPEAT_FLAG = 1 << 3;
- const X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR = 1 << 4;
- const Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR = 1 << 5;
- const OVERLAP_SIMPLE = 1 << 6;
- const ARG_1_AND_2_ARE_WORDS = 1 << 0;
- const ARGS_ARE_XY_VALUES = 1 << 1;
- const WE_HAVE_A_SCALE = 1 << 3;
- const MORE_COMPONENTS = 1 << 5;
- const WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
- const WE_HAVE_A_TWO_BY_TWO = 1 << 7;
- const WE_HAVE_INSTRUCTIONS = 1 << 8;
- class GlyfTable {
- constructor({
- glyfTable,
- isGlyphLocationsLong,
- locaTable,
- numGlyphs
- }) {
- this.glyphs = [];
- const loca = new DataView(locaTable.buffer, locaTable.byteOffset, locaTable.byteLength);
- const glyf = new DataView(glyfTable.buffer, glyfTable.byteOffset, glyfTable.byteLength);
- const offsetSize = isGlyphLocationsLong ? 4 : 2;
- let prev = isGlyphLocationsLong ? loca.getUint32(0) : 2 * loca.getUint16(0);
- let pos = 0;
- for (let i = 0; i < numGlyphs; i++) {
- pos += offsetSize;
- const next = isGlyphLocationsLong ? loca.getUint32(pos) : 2 * loca.getUint16(pos);
- if (next === prev) {
- this.glyphs.push(new Glyph({}));
- continue;
- }
- const glyph = Glyph.parse(prev, glyf);
- this.glyphs.push(glyph);
- prev = next;
- }
- }
- getSize() {
- return this.glyphs.reduce((a, g) => {
- const size = g.getSize();
- return a + (size + 3 & ~3);
- }, 0);
- }
- write() {
- const totalSize = this.getSize();
- const glyfTable = new DataView(new ArrayBuffer(totalSize));
- const isLocationLong = totalSize > 0x1fffe;
- const offsetSize = isLocationLong ? 4 : 2;
- const locaTable = new DataView(new ArrayBuffer((this.glyphs.length + 1) * offsetSize));
- if (isLocationLong) {
- locaTable.setUint32(0, 0);
- } else {
- locaTable.setUint16(0, 0);
- }
- let pos = 0;
- let locaIndex = 0;
- for (const glyph of this.glyphs) {
- pos += glyph.write(pos, glyfTable);
- pos = pos + 3 & ~3;
- locaIndex += offsetSize;
- if (isLocationLong) {
- locaTable.setUint32(locaIndex, pos);
- } else {
- locaTable.setUint16(locaIndex, pos >> 1);
- }
- }
- return {
- isLocationLong,
- loca: new Uint8Array(locaTable.buffer),
- glyf: new Uint8Array(glyfTable.buffer)
- };
- }
- scale(factors) {
- for (let i = 0, ii = this.glyphs.length; i < ii; i++) {
- this.glyphs[i].scale(factors[i]);
- }
- }
- }
- exports.GlyfTable = GlyfTable;
- class Glyph {
- constructor({
- header = null,
- simple = null,
- composites = null
- }) {
- this.header = header;
- this.simple = simple;
- this.composites = composites;
- }
- static parse(pos, glyf) {
- const [read, header] = GlyphHeader.parse(pos, glyf);
- pos += read;
- if (header.numberOfContours < 0) {
- const composites = [];
- while (true) {
- const [n, composite] = CompositeGlyph.parse(pos, glyf);
- pos += n;
- composites.push(composite);
- if (!(composite.flags & MORE_COMPONENTS)) {
- break;
- }
- }
- return new Glyph({
- header,
- composites
- });
- }
- const simple = SimpleGlyph.parse(pos, glyf, header.numberOfContours);
- return new Glyph({
- header,
- simple
- });
- }
- getSize() {
- if (!this.header) {
- return 0;
- }
- const size = this.simple ? this.simple.getSize() : this.composites.reduce((a, c) => a + c.getSize(), 0);
- return this.header.getSize() + size;
- }
- write(pos, buf) {
- if (!this.header) {
- return 0;
- }
- const spos = pos;
- pos += this.header.write(pos, buf);
- if (this.simple) {
- pos += this.simple.write(pos, buf);
- } else {
- for (const composite of this.composites) {
- pos += composite.write(pos, buf);
- }
- }
- return pos - spos;
- }
- scale(factor) {
- if (!this.header) {
- return;
- }
- const xMiddle = (this.header.xMin + this.header.xMax) / 2;
- this.header.scale(xMiddle, factor);
- if (this.simple) {
- this.simple.scale(xMiddle, factor);
- } else {
- for (const composite of this.composites) {
- composite.scale(xMiddle, factor);
- }
- }
- }
- }
- class GlyphHeader {
- constructor({
- numberOfContours,
- xMin,
- yMin,
- xMax,
- yMax
- }) {
- this.numberOfContours = numberOfContours;
- this.xMin = xMin;
- this.yMin = yMin;
- this.xMax = xMax;
- this.yMax = yMax;
- }
- static parse(pos, glyf) {
- return [10, new GlyphHeader({
- numberOfContours: glyf.getInt16(pos),
- xMin: glyf.getInt16(pos + 2),
- yMin: glyf.getInt16(pos + 4),
- xMax: glyf.getInt16(pos + 6),
- yMax: glyf.getInt16(pos + 8)
- })];
- }
- getSize() {
- return 10;
- }
- write(pos, buf) {
- buf.setInt16(pos, this.numberOfContours);
- buf.setInt16(pos + 2, this.xMin);
- buf.setInt16(pos + 4, this.yMin);
- buf.setInt16(pos + 6, this.xMax);
- buf.setInt16(pos + 8, this.yMax);
- return 10;
- }
- scale(x, factor) {
- this.xMin = Math.round(x + (this.xMin - x) * factor);
- this.xMax = Math.round(x + (this.xMax - x) * factor);
- }
- }
- class Contour {
- constructor({
- flags,
- xCoordinates,
- yCoordinates
- }) {
- this.xCoordinates = xCoordinates;
- this.yCoordinates = yCoordinates;
- this.flags = flags;
- }
- }
- class SimpleGlyph {
- constructor({
- contours,
- instructions
- }) {
- this.contours = contours;
- this.instructions = instructions;
- }
- static parse(pos, glyf, numberOfContours) {
- const endPtsOfContours = [];
- for (let i = 0; i < numberOfContours; i++) {
- const endPt = glyf.getUint16(pos);
- pos += 2;
- endPtsOfContours.push(endPt);
- }
- const numberOfPt = endPtsOfContours[numberOfContours - 1] + 1;
- const instructionLength = glyf.getUint16(pos);
- pos += 2;
- const instructions = new Uint8Array(glyf).slice(pos, pos + instructionLength);
- pos += instructionLength;
- const flags = [];
- for (let i = 0; i < numberOfPt; pos++, i++) {
- let flag = glyf.getUint8(pos);
- flags.push(flag);
- if (flag & REPEAT_FLAG) {
- const count = glyf.getUint8(++pos);
- flag ^= REPEAT_FLAG;
- for (let m = 0; m < count; m++) {
- flags.push(flag);
- }
- i += count;
- }
- }
- const allXCoordinates = [];
- let xCoordinates = [];
- let yCoordinates = [];
- let pointFlags = [];
- const contours = [];
- let endPtsOfContoursIndex = 0;
- let lastCoordinate = 0;
- for (let i = 0; i < numberOfPt; i++) {
- const flag = flags[i];
- if (flag & X_SHORT_VECTOR) {
- const x = glyf.getUint8(pos++);
- lastCoordinate += flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR ? x : -x;
- xCoordinates.push(lastCoordinate);
- } else if (flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) {
- xCoordinates.push(lastCoordinate);
- } else {
- lastCoordinate += glyf.getInt16(pos);
- pos += 2;
- xCoordinates.push(lastCoordinate);
- }
- if (endPtsOfContours[endPtsOfContoursIndex] === i) {
- endPtsOfContoursIndex++;
- allXCoordinates.push(xCoordinates);
- xCoordinates = [];
- }
- }
- lastCoordinate = 0;
- endPtsOfContoursIndex = 0;
- for (let i = 0; i < numberOfPt; i++) {
- const flag = flags[i];
- if (flag & Y_SHORT_VECTOR) {
- const y = glyf.getUint8(pos++);
- lastCoordinate += flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR ? y : -y;
- yCoordinates.push(lastCoordinate);
- } else if (flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) {
- yCoordinates.push(lastCoordinate);
- } else {
- lastCoordinate += glyf.getInt16(pos);
- pos += 2;
- yCoordinates.push(lastCoordinate);
- }
- pointFlags.push(flag & ON_CURVE_POINT | flag & OVERLAP_SIMPLE);
- if (endPtsOfContours[endPtsOfContoursIndex] === i) {
- xCoordinates = allXCoordinates[endPtsOfContoursIndex];
- endPtsOfContoursIndex++;
- contours.push(new Contour({
- flags: pointFlags,
- xCoordinates,
- yCoordinates
- }));
- yCoordinates = [];
- pointFlags = [];
- }
- }
- return new SimpleGlyph({
- contours,
- instructions
- });
- }
- getSize() {
- let size = this.contours.length * 2 + 2 + this.instructions.length;
- let lastX = 0;
- let lastY = 0;
- for (const contour of this.contours) {
- size += contour.flags.length;
- for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
- const x = contour.xCoordinates[i];
- const y = contour.yCoordinates[i];
- let abs = Math.abs(x - lastX);
- if (abs > 255) {
- size += 2;
- } else if (abs > 0) {
- size += 1;
- }
- lastX = x;
- abs = Math.abs(y - lastY);
- if (abs > 255) {
- size += 2;
- } else if (abs > 0) {
- size += 1;
- }
- lastY = y;
- }
- }
- return size;
- }
- write(pos, buf) {
- const spos = pos;
- const xCoordinates = [];
- const yCoordinates = [];
- const flags = [];
- let lastX = 0;
- let lastY = 0;
- for (const contour of this.contours) {
- for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
- let flag = contour.flags[i];
- const x = contour.xCoordinates[i];
- let delta = x - lastX;
- if (delta === 0) {
- flag |= X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR;
- xCoordinates.push(0);
- } else {
- const abs = Math.abs(delta);
- if (abs <= 255) {
- flag |= delta >= 0 ? X_SHORT_VECTOR | X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR : X_SHORT_VECTOR;
- xCoordinates.push(abs);
- } else {
- xCoordinates.push(delta);
- }
- }
- lastX = x;
- const y = contour.yCoordinates[i];
- delta = y - lastY;
- if (delta === 0) {
- flag |= Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR;
- yCoordinates.push(0);
- } else {
- const abs = Math.abs(delta);
- if (abs <= 255) {
- flag |= delta >= 0 ? Y_SHORT_VECTOR | Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR : Y_SHORT_VECTOR;
- yCoordinates.push(abs);
- } else {
- yCoordinates.push(delta);
- }
- }
- lastY = y;
- flags.push(flag);
- }
- buf.setUint16(pos, xCoordinates.length - 1);
- pos += 2;
- }
- buf.setUint16(pos, this.instructions.length);
- pos += 2;
- if (this.instructions.length) {
- new Uint8Array(buf.buffer, 0, buf.buffer.byteLength).set(this.instructions, pos);
- pos += this.instructions.length;
- }
- for (const flag of flags) {
- buf.setUint8(pos++, flag);
- }
- for (let i = 0, ii = xCoordinates.length; i < ii; i++) {
- const x = xCoordinates[i];
- const flag = flags[i];
- if (flag & X_SHORT_VECTOR) {
- buf.setUint8(pos++, x);
- } else if (!(flag & X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR)) {
- buf.setInt16(pos, x);
- pos += 2;
- }
- }
- for (let i = 0, ii = yCoordinates.length; i < ii; i++) {
- const y = yCoordinates[i];
- const flag = flags[i];
- if (flag & Y_SHORT_VECTOR) {
- buf.setUint8(pos++, y);
- } else if (!(flag & Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR)) {
- buf.setInt16(pos, y);
- pos += 2;
- }
- }
- return pos - spos;
- }
- scale(x, factor) {
- for (const contour of this.contours) {
- if (contour.xCoordinates.length === 0) {
- continue;
- }
- for (let i = 0, ii = contour.xCoordinates.length; i < ii; i++) {
- contour.xCoordinates[i] = Math.round(x + (contour.xCoordinates[i] - x) * factor);
- }
- }
- }
- }
- class CompositeGlyph {
- constructor({
- flags,
- glyphIndex,
- argument1,
- argument2,
- transf,
- instructions
- }) {
- this.flags = flags;
- this.glyphIndex = glyphIndex;
- this.argument1 = argument1;
- this.argument2 = argument2;
- this.transf = transf;
- this.instructions = instructions;
- }
- static parse(pos, glyf) {
- const spos = pos;
- const transf = [];
- let flags = glyf.getUint16(pos);
- const glyphIndex = glyf.getUint16(pos + 2);
- pos += 4;
- let argument1, argument2;
- if (flags & ARG_1_AND_2_ARE_WORDS) {
- if (flags & ARGS_ARE_XY_VALUES) {
- argument1 = glyf.getInt16(pos);
- argument2 = glyf.getInt16(pos + 2);
- } else {
- argument1 = glyf.getUint16(pos);
- argument2 = glyf.getUint16(pos + 2);
- }
- pos += 4;
- flags ^= ARG_1_AND_2_ARE_WORDS;
- } else {
- if (flags & ARGS_ARE_XY_VALUES) {
- argument1 = glyf.getInt8(pos);
- argument2 = glyf.getInt8(pos + 1);
- } else {
- argument1 = glyf.getUint8(pos);
- argument2 = glyf.getUint8(pos + 1);
- }
- pos += 2;
- }
- if (flags & WE_HAVE_A_SCALE) {
- transf.push(glyf.getUint16(pos));
- pos += 2;
- } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
- transf.push(glyf.getUint16(pos), glyf.getUint16(pos + 2));
- pos += 4;
- } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
- transf.push(glyf.getUint16(pos), glyf.getUint16(pos + 2), glyf.getUint16(pos + 4), glyf.getUint16(pos + 6));
- pos += 8;
- }
- let instructions = null;
- if (flags & WE_HAVE_INSTRUCTIONS) {
- const instructionLength = glyf.getUint16(pos);
- pos += 2;
- instructions = new Uint8Array(glyf).slice(pos, pos + instructionLength);
- pos += instructionLength;
- }
- return [pos - spos, new CompositeGlyph({
- flags,
- glyphIndex,
- argument1,
- argument2,
- transf,
- instructions
- })];
- }
- getSize() {
- let size = 2 + 2 + this.transf.length * 2;
- if (this.flags & WE_HAVE_INSTRUCTIONS) {
- size += 2 + this.instructions.length;
- }
- size += 2;
- if (this.flags & 2) {
- if (!(this.argument1 >= -128 && this.argument1 <= 127 && this.argument2 >= -128 && this.argument2 <= 127)) {
- size += 2;
- }
- } else {
- if (!(this.argument1 >= 0 && this.argument1 <= 255 && this.argument2 >= 0 && this.argument2 <= 255)) {
- size += 2;
- }
- }
- return size;
- }
- write(pos, buf) {
- const spos = pos;
- if (this.flags & ARGS_ARE_XY_VALUES) {
- if (!(this.argument1 >= -128 && this.argument1 <= 127 && this.argument2 >= -128 && this.argument2 <= 127)) {
- this.flags |= ARG_1_AND_2_ARE_WORDS;
- }
- } else {
- if (!(this.argument1 >= 0 && this.argument1 <= 255 && this.argument2 >= 0 && this.argument2 <= 255)) {
- this.flags |= ARG_1_AND_2_ARE_WORDS;
- }
- }
- buf.setUint16(pos, this.flags);
- buf.setUint16(pos + 2, this.glyphIndex);
- pos += 4;
- if (this.flags & ARG_1_AND_2_ARE_WORDS) {
- if (this.flags & ARGS_ARE_XY_VALUES) {
- buf.setInt16(pos, this.argument1);
- buf.setInt16(pos + 2, this.argument2);
- } else {
- buf.setUint16(pos, this.argument1);
- buf.setUint16(pos + 2, this.argument2);
- }
- pos += 4;
- } else {
- buf.setUint8(pos, this.argument1);
- buf.setUint8(pos + 1, this.argument2);
- pos += 2;
- }
- if (this.flags & WE_HAVE_INSTRUCTIONS) {
- buf.setUint16(pos, this.instructions.length);
- pos += 2;
- if (this.instructions.length) {
- new Uint8Array(buf.buffer, 0, buf.buffer.byteLength).set(this.instructions, pos);
- pos += this.instructions.length;
- }
- }
- return pos - spos;
- }
- scale(x, factor) {}
- }
|