"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GvarTableWrite = void 0;
const bin_util_1 = require("@ot-builder/bin-util");
const ot_glyphs_1 = require("@ot-builder/ot-glyphs");
const primitive_1 = require("@ot-builder/primitive");
const var_store_1 = require("@ot-builder/var-store");
const shared_1 = require("./shared");
exports.GvarTableWrite = (0, bin_util_1.Write)((frag, gOrd, cfg, designSpace, acEmpty) => {
    const ta = new var_store_1.TupleAllocator();
    const context = {
        designSpace: designSpace,
        tupleAllocator: ta,
        iupTolerance: cfg.ttf.gvarOptimizeTolerance
    };
    const gvarBody = new bin_util_1.Frag();
    let hasMeaningfulData = false;
    const gvarOffsets = [];
    for (let gid = 0; gid < gOrd.length; gid++) {
        let tvd = var_store_1.TupleVariationWriteOpt.writeOpt(new GlyphTupleVariationSource(gOrd.at(gid)), context);
        if (!tvd && cfg.ttf.gvarForceProduceGVD) {
            tvd = bin_util_1.Frag.uint16(0).uint16(4).uint32(0);
        }
        if (tvd) {
            hasMeaningfulData = true;
            const tvdBuffer = (0, bin_util_1.alignBufferSize)(bin_util_1.Frag.pack(tvd), shared_1.GvarOffsetAlign);
            gvarOffsets.push(gvarBody.size);
            gvarBody.bytes(tvdBuffer);
            if (cfg.ttf.gvarForceZeroGapsBetweenGVD)
                gvarBody.uint32(0);
        }
        else {
            gvarOffsets.push(gvarBody.size);
        }
    }
    gvarOffsets.push(gvarBody.size);
    if (acEmpty)
        acEmpty.set(!hasMeaningfulData);
    const sharedTuples = [...ta.storage()];
    const bSharedTuples = new bin_util_1.Frag();
    for (const tuple of sharedTuples) {
        for (let aid = 0; aid < designSpace.length; aid++) {
            bSharedTuples.push(primitive_1.F2D14, tuple[aid] || 0);
        }
    }
    // Entire table
    frag.uint16(1)
        .uint16(0)
        .uint16(designSpace.length)
        .uint16(sharedTuples.length)
        .ptr32(bSharedTuples)
        .uint16(gOrd.length);
    if (gvarBody.size < primitive_1.UInt16.max * 2) {
        frag.uint16(0);
        frag.ptr32(gvarBody);
        for (let gid = 0; gid <= gOrd.length; gid++) {
            frag.uint16(gvarOffsets[gid] / 2);
        }
    }
    else {
        frag.uint16(shared_1.GvarFlag.LongOffsets);
        frag.ptr32(gvarBody);
        for (let gid = 0; gid <= gOrd.length; gid++) {
            frag.uint32(gvarOffsets[gid]);
        }
    }
});
class GlyphTupleVariationSource {
    constructor(glyph) {
        this.dimensions = 2;
        this.data = [
            ...(glyph.geometry ? new GeomVarCollector().process(glyph.geometry) : []),
            [glyph.horizontal.start, 0],
            [glyph.horizontal.end, 0],
            [0, glyph.vertical.start],
            [0, glyph.vertical.end]
        ];
    }
}
class GeomVarCollector {
    process(geom) {
        switch (geom.type) {
            case ot_glyphs_1.OtGlyph.GeometryType.ContourSet:
                return this.contourSet(geom);
            case ot_glyphs_1.OtGlyph.GeometryType.TtReference:
                return this.ttReference(geom);
            case ot_glyphs_1.OtGlyph.GeometryType.GeometryList:
                return this.geometryList(geom);
        }
    }
    contourSet(cs) {
        const collected = [];
        for (const c of cs.contours) {
            const items = [];
            for (const z of c) {
                items.push(z.x, z.y);
            }
            collected.push(items);
        }
        return collected;
    }
    geometryList(geom) {
        const collected = [];
        for (const entry of geom.items) {
            const sub = this.process(entry);
            for (const x of sub)
                collected.push(x);
        }
        return collected;
    }
    ttReference(ref) {
        return [[ref.transform.dx, ref.transform.dy]];
    }
}
//# sourceMappingURL=write.js.map