dropflow
Version:
A small CSS2 document renderer built from specifications
127 lines (126 loc) • 5.73 kB
JavaScript
import wasm from './wasm.js';
import { onWasmMemoryResized } from './wasm-env.js';
let heapu32 = new Uint32Array(wasm.instance.exports.memory.buffer);
onWasmMemoryResized(() => {
heapu32 = new Uint32Array(wasm.instance.exports.memory.buffer);
});
// Based on unicode-trie from Devon Govett, which is based on Utrie2 from the
// ICU project.
//
// The unicode-trie port is a direct code translation without much understanding
// of the original source. I have removed several features that are only used
// for collation and handling encoding errors, making the index tables and data
// block layout much easier to understand. The result is a codepoint-only trie.
//
// I've also removed gzip since it's another dependency and redundant since
// browsers already do that
//
// Copyright 2018 Devon Govett
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
/** Shift size for getting the index-1 table offset. */
export const SHIFT_1 = 6 + 5;
/** Shift size for getting the index-2 table offset. */
export const SHIFT_2 = 5;
/**
* Difference between the two shift sizes;
* for getting an index-1 offset from an index-2 offset. 6=11-5
*/
export const SHIFT_1_2 = SHIFT_1 - SHIFT_2;
/**
* Number of index-1 entries for the BMP. 32=0x20
* This part of the index-1 table is omitted from the serialized form.
*/
export const OMITTED_BMP_INDEX_1_LENGTH = 0x10000 >> SHIFT_1;
/** Number of code points per index-1 table entry. 2048=0x800 */
export const CP_PER_INDEX_1_ENTRY = 1 << SHIFT_1;
/** Number of entries in an index-2 block. 64=0x40 */
export const INDEX_2_BLOCK_LENGTH = 1 << SHIFT_1_2;
/** Mask for getting the lower bits for the in-index-2-block offset. */
export const INDEX_2_MASK = INDEX_2_BLOCK_LENGTH - 1;
/** Number of entries in a data block. 32=0x20 */
export const DATA_BLOCK_LENGTH = 1 << SHIFT_2;
/** Mask for getting the lower bits for the in-data-block offset. */
export const DATA_MASK = DATA_BLOCK_LENGTH - 1;
/**
* Shift size for shifting left the index array values.
* Increases possible data size with 16-bit index values at the cost
* of compactability.
* This requires data blocks to be aligned by DATA_GRANULARITY.
*/
export const INDEX_SHIFT = 2;
/** The alignment size of a data block. Also the granularity for compaction. */
export const DATA_GRANULARITY = 1 << INDEX_SHIFT;
/* Fixed layout of the first part of the index array. ------------------- */
/**
* The BMP part of the index-2 table is fixed and linear and starts at offset 0.
*/
export const INDEX_2_OFFSET = 0;
/**
* Length=2048=0x800=0x10000>>SHIFT_2.
*/
export const INDEX_2_BMP_LENGTH = 0x10000 >> SHIFT_2;
/**
* The index-1 table, only used for supplementary code points, at offset 2048=0x800.
* Variable length, for code points up to highStart, where the last single-value range starts.
* Maximum length 512=0x200=0x100000>>SHIFT_1.
* (For 0x100000 supplementary code points U+10000..U+10ffff.)
*
* The part of the index-2 table for supplementary code points starts
* after this index-1 table.
*
* Both the index-1 table and the following part of the index-2 table
* are omitted completely if there is only BMP data.
*/
export const INDEX_1_OFFSET = INDEX_2_BMP_LENGTH;
export const MAX_INDEX_1_LENGTH = 0x100000 >> SHIFT_1;
export default class UnicodeTrie {
highStart;
errorValue;
dataPtr32;
dataLength;
constructor(dataPtr) {
const dataPtr32 = dataPtr >> 2;
this.highStart = heapu32[dataPtr32 + 1];
this.errorValue = heapu32[dataPtr32 + 2];
this.dataPtr32 = dataPtr32 + 3;
this.dataLength = heapu32[dataPtr32];
}
get(codePoint) {
let index;
if (codePoint < 0 || codePoint > 0x10ffff) {
return this.errorValue;
}
if (codePoint <= 0xffff) {
// Ordinary BMP code point, excluding leading surrogates.
// BMP uses a single level lookup. BMP index starts at offset 0 in the index.
// data is stored in the index array itself.
index = (heapu32[this.dataPtr32 + (codePoint >> SHIFT_2)] << INDEX_SHIFT) + (codePoint & DATA_MASK);
return heapu32[this.dataPtr32 + index];
}
if (codePoint < this.highStart) {
// Supplemental code point, use two-level lookup.
index = heapu32[this.dataPtr32 + (INDEX_1_OFFSET - OMITTED_BMP_INDEX_1_LENGTH) + (codePoint >> SHIFT_1)];
index = heapu32[this.dataPtr32 + index + ((codePoint >> SHIFT_2) & INDEX_2_MASK)];
index = (index << INDEX_SHIFT) + (codePoint & DATA_MASK);
return heapu32[this.dataPtr32 + index];
}
return heapu32[this.dataPtr32 + this.dataLength - DATA_GRANULARITY];
}
}