"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readCffCommon = readCffCommon;
exports.cffCleanupUnusedData = cffCleanupUnusedData;
exports.applyBuildResults = applyBuildResults;
exports.buildCharStrings = buildCharStrings;
exports.getRevFdSelect = getRevFdSelect;
const errors_1 = require("@ot-builder/errors");
const ot_glyphs_1 = require("@ot-builder/ot-glyphs");
const interpret_state_1 = require("../char-string/read/interpret-state");
const interpreter_1 = require("../char-string/read/interpreter");
const shape_building_1 = require("../char-string/read/shape-building");
const subroutine_index_1 = require("../char-string/read/subroutine-index");
const draw_call_1 = require("../char-string/write/draw-call");
const draw_call_gen_1 = require("../char-string/write/draw-call-gen");
const draw_call_optimize_1 = require("../char-string/write/draw-call-optimize");
const general_1 = require("../char-string/write/draw-call-optimize/general");
const empty_impl_1 = require("../char-string/write/global-optimize/empty-impl");
const subroutine_analyze_1 = require("../char-string/write/global-optimize/subroutine-analyze");
const glyph_data_sink_1 = require("../charset/glyph-data-sink");
const io_1 = require("../charset/io");
const font_dict_1 = require("../dict/font-dict");
const glyph_data_sink_2 = require("../fd-select/glyph-data-sink");
const io_2 = require("../fd-select/io");
const cff2_ivs_1 = require("../structs/cff2-ivs");
function getCorrespondedPd(cff, fdId) {
    const fd = cff.fdArray ? cff.fdArray[fdId] || cff.topDict : cff.topDict;
    return fd.privateDict;
}
function readCffCommon(cff, gOrd, topDict, ctx, gSubrs, designSpace) {
    cff.topDict = topDict.fd;
    if (topDict.cidROS)
        cff.cid = topDict.cidROS;
    if (designSpace && topDict.vVarStore)
        ctx.ivs = topDict.vVarStore.next(cff2_ivs_1.Cff2IVS, designSpace);
    if (topDict.vFDArray)
        cff.fdArray = topDict.vFDArray.next(font_dict_1.CffFdArrayIo, ctx);
    if (topDict.vFDSelect) {
        cff.fdSelect = new Map();
        topDict.vFDSelect.next(io_2.CffFdSelect, ctx, new glyph_data_sink_2.CffGlyphFdSelectSink(gOrd, cff.fdSelect));
    }
    if (topDict.vCharSet) {
        let charSetSink;
        if (cff.cid) {
            cff.cid.mapping = new Map();
            charSetSink = new glyph_data_sink_1.CffCidCharsetSink(gOrd, ctx.naming, cff.cid.mapping);
        }
        else {
            charSetSink = new glyph_data_sink_1.CffGlyphNameCharsetSink(gOrd, ctx.naming, ctx);
        }
        topDict.vCharSet.next(io_1.CffCharSet, ctx, charSetSink);
    }
    if (topDict.vCharStrings) {
        const charStrings = topDict.vCharStrings.next(subroutine_index_1.CffSubroutineIndex, ctx);
        for (let gid = 0; gid < gOrd.length; gid++) {
            const glyph = gOrd.at(gid);
            readGlyph(ctx, cff, gid, glyph, charStrings, gSubrs);
        }
    }
}
function readGlyph(ctx, cff, gid, glyph, charStrings, gSubrs) {
    const fdId = cff.fdSelect ? cff.fdSelect.get(glyph) || 0 : 0;
    const pd = getCorrespondedPd(cff, fdId);
    if (!pd)
        throw errors_1.Errors.Cff.MissingPrivateDict(fdId);
    const localSubrs = pd.localSubroutines || [];
    // Interpret charString
    const gb = new shape_building_1.CffGlyphBuilder(glyph);
    const st = new interpret_state_1.CffCharStringInterpStateImpl(ctx.ivs);
    // Private dicts have inherited VS index, we should take this into consideration
    // cf. https://docs.microsoft.com/en-us/typography/opentype/spec/cff2charstr#syntax-for-font-variations-support-operators
    if (ctx.ivs)
        st.setVsIndex(pd.inheritedVsIndex);
    gb.setWidth(pd.defaultWidthX);
    (0, interpreter_1.interpretCharString)(charStrings[gid], st, {
        global: gSubrs,
        local: localSubrs,
        defaultWidthX: pd.defaultWidthX,
        nominalWidthX: pd.nominalWidthX
    }, gb);
    gb.endChar();
    // Apply coStat data
    const hMet = ctx.coStat.getHMetric(gid, null);
    if (hMet)
        glyph.horizontal = hMet;
    const vMet = ctx.coStat.getVMetric(gid, null);
    if (vMet)
        glyph.vertical = vMet;
}
function cffCleanupUnusedData(cff) {
    if (cff.topDict && cff.topDict.privateDict) {
        cff.topDict.privateDict.localSubroutines = null;
    }
    if (cff.fdArray) {
        for (const fd of cff.fdArray)
            if (fd.privateDict)
                fd.privateDict.localSubroutines = null;
    }
}
function setLocalSubrForFd(fd, lSubrs) {
    if (!lSubrs.length)
        return;
    if (!fd.privateDict)
        fd.privateDict = new ot_glyphs_1.Cff.PrivateDict();
    fd.privateDict.localSubroutines = lSubrs;
}
function applyBuildResults(cff, results) {
    if (cff.fdArray && cff.fdArray.length) {
        for (let fdId = 0; fdId < cff.fdArray.length; fdId++) {
            const fd = cff.fdArray[fdId];
            const lSubrs = results.localSubroutines[fdId] || [];
            setLocalSubrForFd(fd, lSubrs);
        }
    }
    else {
        setLocalSubrForFd(cff.topDict, results.localSubroutines[0] || []);
    }
}
function getOptimizer(cfg, ctx, fdCount) {
    if (cfg.cff.doGlobalOptimization) {
        return subroutine_analyze_1.CharStringGlobalOptSubrFactory.createOptimizer(ctx, fdCount);
    }
    else {
        return empty_impl_1.CharStringGlobalOptEmptyImplFactory.createOptimizer(ctx, fdCount);
    }
}
function getLocalOptimizers(cfg, ctx) {
    if (cfg.cff.doLocalOptimization) {
        return (0, draw_call_optimize_1.StandardDrawCallOptimizers)(ctx);
    }
    else {
        return (0, draw_call_optimize_1.MinimalDrawCallOptimizers)(ctx);
    }
}
function buildCharStrings(cff, cfg, gOrd, ctx) {
    const fdCount = cff.fdArray ? cff.fdArray.length : 1;
    const optimizer = getOptimizer(cfg, ctx, fdCount);
    ctx.stat.setNumGlyphs(gOrd.length);
    for (let gid = 0; gid < gOrd.length; gid++) {
        const glyph = gOrd.at(gid);
        const fdId = cff.fdSelect ? cff.fdSelect.get(glyph) || 0 : 0;
        if (fdId >= fdCount)
            throw errors_1.Errors.Cff.FdIdOverflow(fdId, fdCount);
        const pd = getCorrespondedPd(cff, fdId);
        if (!pd)
            throw errors_1.Errors.Cff.MissingPrivateDict(fdId);
        const rawDrawCalls = (0, draw_call_gen_1.codeGenGlyph)(ctx, gid, glyph, pd);
        const drawCalls = [...(0, general_1.cffOptimizeDrawCall)(rawDrawCalls, getLocalOptimizers(cfg, ctx))];
        optimizer.addCharString(gid, fdId, draw_call_1.CffDrawCall.charStringSeqToMir(ctx, drawCalls));
    }
    const results = optimizer.getResults();
    ctx.stat.settle();
    applyBuildResults(cff, results);
    return results;
}
function getRevFdSelect(cff, gOrd) {
    if (!cff.fdSelect)
        return [];
    const results = [];
    for (let gid = 0; gid < gOrd.length; gid++) {
        const fdId = cff.fdSelect.get(gOrd.at(gid)) || 0;
        results[gid] = fdId;
    }
    return results;
}
//# sourceMappingURL=shared.js.map