"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CffDrawCall = exports.CffDrawCallRaw = exports.CffBlendPrimitive = exports.CffDrawCallRawT = void 0;
const errors_1 = require("@ot-builder/errors");
const variance_1 = require("@ot-builder/variance");
const operator_1 = require("../../interp/operator");
const mir_1 = require("./mir");
class CffDrawCallRawT {
    constructor(args, operator, flags) {
        this.args = args;
        this.operator = operator;
        this.flags = flags;
    }
}
exports.CffDrawCallRawT = CffDrawCallRawT;
class CffBlendPrimitive {
    constructor(ivd, origin, deltas) {
        this.ivd = ivd;
        this.origin = origin;
        this.deltas = deltas;
    }
    isZero() {
        if (this.origin !== 0)
            return false;
        if (this.ivd) {
            for (const delta of this.deltas)
                if (delta)
                    return false;
        }
        return true;
    }
}
exports.CffBlendPrimitive = CffBlendPrimitive;
class CffDrawCallRaw extends CffDrawCallRawT {
}
exports.CffDrawCallRaw = CffDrawCallRaw;
class CffDrawCall extends CffDrawCallRawT {
    constructor(ivd, args, operator, flags) {
        super(args, operator, flags);
        this.ivd = ivd;
        let sp = 0, sr = 0;
        for (const arg of args) {
            if (typeof arg === "number") {
                sr = Math.max(sp + 1, sr);
            }
            else {
                sr = Math.max(sp + 1, sp + arg.deltas.length + 1, sr);
            }
            sp += 1;
        }
        this.stackRidge = sr;
        this.stackRise = sp;
    }
    get masterCount() {
        return this.ivd ? this.ivd.masterIDs.length : 0;
    }
    // Raw to DC conversion
    static seqFromRawSeqImpl(ctx, eo, from) {
        const to = [];
        const { ivd, intermediate } = CffDrawCall.intermediateSeqFromRawSeqImpl(ctx, from);
        for (const dci of intermediate) {
            const args = CffDrawCall.convertCallArgs(dci, ivd, eo);
            to.push(new CffDrawCall(ivd, args, dci.operator, dci.flags));
        }
        // Always emitting a VxIndex operator since we don't know what is the corresponded PD's
        // inherited VS index. The global optimizer should hide most of them into subroutines.
        if (ivd)
            to.unshift(new CffDrawCall(ivd, [ivd.outerIndex], eo.vsIndexOperator));
        return to;
    }
    static intermediateSeqFromRawSeqImpl(ctx, from) {
        const intermediate = [];
        const col = ctx.ivs ? ctx.ivs.createCollector() : null;
        for (const dc of from) {
            const args = [];
            for (const arg of dc.args) {
                if (!col || variance_1.OtVar.Ops.isConstant(arg)) {
                    args.push(variance_1.OtVar.Ops.evaluate(arg, null));
                }
                else {
                    args.push(col.collect(arg));
                }
            }
            intermediate.push(new CffDrawCallRawT(args, dc.operator, dc.flags));
        }
        const ivd = col ? col.getIVD(false, 1) : null;
        return { ivd, intermediate };
    }
    static convertCallArgs(dci, ivd, eo) {
        const args = [];
        let hasBlend = false;
        for (const arg of dci.args) {
            if (typeof arg === "number") {
                args.push(arg);
            }
            else if (!ivd) {
                throw errors_1.Errors.Unreachable();
            }
            else {
                args.push(new CffBlendPrimitive(ivd, arg.origin, arg.resolve()));
                hasBlend = true;
            }
        }
        if (hasBlend && ivd && eo.forceBlendToPleaseTtx) {
            for (let aid = 0; aid < args.length; aid++) {
                const arg = args[aid];
                if (typeof arg === "number") {
                    args[aid] = new CffBlendPrimitive(ivd, arg, new Array(ivd.masterIDs.length).fill(0));
                }
            }
        }
        return args;
    }
    static charStringSeqFromRawSeq(ctx, from) {
        const eo = {
            ...ctx.getLimits(),
            vsIndexOperator: operator_1.CharStringOperator.VsIndex,
            blendOperator: operator_1.CharStringOperator.Blend
        };
        return this.seqFromRawSeqImpl(ctx, eo, from);
    }
    static dictStringSeqFromRawSeq(ctx, from) {
        const eo = {
            ...ctx.getLimits(),
            forceBlendToPleaseTtx: true,
            vsIndexOperator: operator_1.CffOperator.VsIndex,
            blendOperator: operator_1.CffOperator.Blend
        };
        return this.seqFromRawSeqImpl(ctx, eo, from);
    }
    // DC to Mir conversion
    toMirImpl(eo, mirSeq) {
        const converter = new MirArgConverter(mirSeq, eo);
        for (const arg of this.args)
            converter.push(arg);
        converter.flush();
        mirSeq.push({
            type: mir_1.MirType.Operator,
            opCode: this.operator,
            flags: this.flags,
            stackRidge: 0,
            stackRise: -converter.sp
        });
    }
    static charStringSeqToMir(ctx, dcSeq) {
        const mirSeq = [];
        const eo = {
            ...ctx.getLimits(),
            vsIndexOperator: operator_1.CharStringOperator.VsIndex,
            blendOperator: operator_1.CharStringOperator.Blend
        };
        for (const dc of dcSeq)
            dc.toMirImpl(eo, mirSeq);
        return mirSeq;
    }
    static dictSeqToMir(ctx, dcSeq) {
        const mirSeq = [];
        const eo = {
            ...ctx.getLimits(),
            vsIndexOperator: operator_1.CffOperator.VsIndex,
            blendOperator: operator_1.CffOperator.Blend
        };
        for (const dc of dcSeq)
            dc.toMirImpl(eo, mirSeq);
        return mirSeq;
    }
}
exports.CffDrawCall = CffDrawCall;
class MirArgConverter {
    constructor(to, eo) {
        this.to = to;
        this.eo = eo;
        this.sp = 0;
        this.pendingBlendOrigins = [];
        this.pendingBlendDeltas = [];
    }
    push(x) {
        if (typeof x === "number") {
            this.flush();
            this.sp += 1;
            this.to.push(mir_1.Mir.operand(x));
        }
        else {
            if (this.willOverflow(x))
                this.flush();
            this.pendingBlendOrigins.push(x.origin);
            for (const d of x.deltas)
                this.pendingBlendDeltas.push(d);
        }
    }
    willOverflow(x) {
        return (this.sp +
            1 +
            this.pendingBlendDeltas.length +
            this.pendingBlendOrigins.length +
            1 +
            x.deltas.length >=
            this.eo.maxStack);
    }
    flush() {
        if (this.pendingBlendOrigins.length) {
            for (const x of this.pendingBlendOrigins)
                this.to.push(mir_1.Mir.operand(x));
            for (const x of this.pendingBlendDeltas)
                this.to.push(mir_1.Mir.operand(x));
            this.to.push(mir_1.Mir.operand(this.pendingBlendOrigins.length));
            this.to.push({
                type: mir_1.MirType.Operator,
                opCode: this.eo.blendOperator,
                flags: undefined,
                stackRidge: 0,
                stackRise: this.pendingBlendOrigins.length -
                    (1 + this.pendingBlendOrigins.length + this.pendingBlendDeltas.length)
            });
            this.sp += this.pendingBlendOrigins.length;
            this.pendingBlendOrigins.length = 0;
            this.pendingBlendDeltas.length = 0;
        }
    }
}
//# sourceMappingURL=draw-call.js.map