var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
import { l as lodash, X as Promise$2 } from "./index.js";
import { e as editorDefaults, P as utils, x as createCanvas, a3 as fitText } from "./watermark.js";
import { E as ElementModel, h as hexaToRgba, u as useEffects, g as getEffectedTextEffects, b as getUpdateFontsSubset } from "./background.js";
import { i as inherit, B as BaseElement$1, P as Promise$1 } from "./base-element.js";
import { t as textBase } from "./index21.js";
import { l as load } from "./opentype.js";
import { g as getLines, a as getWords } from "./get-lines.js";
import "vue";
import "./v4.js";
import "./index18.js";
import "./dom.js";
import "./clone.js";
import "./flattenDeep.js";
import "./defaults.js";
import "./index15.js";
import "./gif-utils.js";
import "./gif-apng.worker.js";
import "./upng.js";
import "./api-service.js";
var methods = {
  convertEffectTextToText(element, layout = this.currentLayout) {
    element = this.getElement(element);
    if (!element) {
      return;
    }
    const defaultElement = editorDefaults.element;
    const defaultTextElement = editorDefaults.textElement;
    const props = [].concat(Object.keys(defaultTextElement)).concat(Object.keys(defaultElement));
    const data = lodash.exports.pick(element, props);
    data.type = "text";
    data.version = editorDefaults.version;
    data.resize = 5;
    data.width = element.typoWidthRatio * element.width;
    data.height = element.typoHeightRatio * element.height;
    data.left += (element.width - data.width) / 2;
    data.top += (element.height - data.height) / 2;
    const newElement = this.replaceElement(element, data, layout);
    this.focusElement(newElement);
    return newElement;
  }
};
class EffectTextModel extends ElementModel {
  constructor(data) {
    super(data);
    lodash.exports.defaultsDeep(this, editorDefaults.effectTextElement);
    if (!this.typoWidthRatio || !this.typoHeightRatio || this.typoWidthRatio === 1 && this.typoHeightRatio === 1) {
      this.typoWidthRatio = this.baseWidthRatio || this.baseWidth / this.width || 1;
      this.typoHeightRatio = this.baseHeightRatio || this.baseHeight / this.height || 1;
    }
    ["baseWidth", "baseHeight", "baseWidthRatio", "baseHeightRatio"].forEach((attr) => {
      if (this[attr] !== void 0) {
        delete this[attr];
      }
    });
    this.$typoWidth = this.width * this.typoWidthRatio;
    this.$typoHeight = this.height * this.typoHeightRatio;
    this.resize = 1;
    if (this.backgroundColor) {
      this.backgroundColor = hexaToRgba(this.backgroundColor);
    }
    if (this.color) {
      this.color = hexaToRgba(this.color);
    }
    if (this.textShadow) {
      const shadow = this.textShadow;
      shadow.color = hexaToRgba(shadow.color);
    }
    useEffects("text", this, true);
    if (this.textEffects && this.textEffects.length) {
      this.textEffects.forEach((effect) => {
        if (effect.stroke) {
          effect.stroke.color = hexaToRgba(effect.stroke.color);
        }
        if (effect.shadow) {
          effect.shadow.color = hexaToRgba(effect.shadow.color);
        }
        if (effect.filling) {
          effect.filling.color = hexaToRgba(effect.filling.color);
          if (effect.filling.gradient) {
            effect.filling.gradient.stops.forEach((stopPoint) => {
              stopPoint.color = hexaToRgba(stopPoint.color);
            });
          }
        }
      });
    }
  }
}
var EffectTextModel$1 = EffectTextModel;
var template = `<div
    class="editor-element"
    :class="[
        'editor-element-' + model.type,
        model.lock ? 'editor-element-lock' : '',
        model.hidden ? 'editor-element-hidden' : '',
        model.frozen ? 'editor-element-frozen' : '',
        model.$loaded ? '' : 'editor-element-loading',
        model.$selected ? 'editor-element-selected' : '',
        model.$editing ? 'editor-element-editing' : '',
        linkSelected ? 'editor-element-link-selected' : ''
    ]"
    :style="baseStyle"
>
    <div
        class="element-inner"
        :style="{
            textAlign: model.textAlign,
            lineHeight: model.lineHeight,
            letterSpacing: model.letterSpacing + 'px',

            width: model.$typoWidth + 'px',
            height: model.$typoHeight + 'px',
            transform: 'scale(' + global.zoom + ')',
        }"
    >
        <div
            ref="textInner"
            class="elment-inner-content"
            :class="isVertical ? 'middle-v' : 'middle-h'"
            :style="{padding: textPadding, opacity: 0}"
        >
            <div class="element-main" :style="textStyle" ref="textNode" v-html="contentsHTML"></div>
        </div>
    </div>
    <img
        v-if="showWithImg"
        class="effect-text-img"
        crossorigin="anonymous"
        :src="model.imageUrl"
        ref="img"
    />
    <div v-else class="canvas-container">
        <canvas class="effect-text-area" :style="canvasStyle" ref="clickAreaCanvas" />
        <canvas class="effect-text-result" :style="canvasStyle" ref="canvas" />
    </div>

    <div class="element-tips-loading" v-if="showLoading">
        <i class="fa fa-spin fa-spinner"></i>
    </div>

    <ElementCommon
        :element="model"
        :options="options"
        :global="global"
        :editor="editor"
        :layout="editor.currentLayout"
        :hideBlink="hideBlink"
        :isShowBlink="isShowBlink"
        :bgNinePatch="bgNinePatch"
    />
</div>
`;
const TextBaseElement = inherit(BaseElement$1, __spreadProps(__spreadValues({}, textBase), { events: {} }));
var BaseElement = inherit(TextBaseElement, {
  template,
  data() {
    return {
      ratio: 1
    };
  },
  computed: {
    cssStyle() {
      const { rect, model } = this;
      return {
        height: rect.height + "px",
        width: rect.width + "px",
        transform: this.transform.toString(),
        left: rect.left + "px",
        top: rect.top + "px",
        opacity: this.opacity,
        overflow: model.resize === 7 ? "hidden" : "visible"
      };
    }
  },
  methods: {
    loadFont(name) {
      const superMethods = textBase.methods;
      return superMethods.load.call(this, name);
    },
    updateRect() {
      const { model } = this;
      const { zoom } = this.global;
      const rect = this.getRect();
      const height = rect.height / zoom;
      const width = rect.width / zoom;
      if (!(height > 0 && width > 0) || !this.$refs.textInner)
        return;
      if (Math.abs(width - model.$typoWidth) > 0.1) {
        model.$typoWidth = width;
      }
      if (Math.abs(height - model.$typoHeight) > 0.1) {
        model.$typoHeight = height;
      }
      if (model.$editing) {
        model.width = width;
        model.height = height;
      }
    }
  }
});
function toRadian(angle) {
  return angle / 180 * Math.PI;
}
function drawPath(ctx, commands, options) {
  options = Object.assign({ strokeWidth: 1 }, options);
  ctx.beginPath();
  for (let i = 0; i < commands.length; i++) {
    const cmd = commands[i];
    switch (cmd.type) {
      case "M":
        ctx.moveTo(cmd.x, cmd.y);
        break;
      case "L":
        ctx.lineTo(cmd.x, cmd.y);
        break;
      case "C":
        ctx.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y);
        break;
      case "Q":
        ctx.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y);
        break;
      case "Z":
        ctx.closePath();
    }
  }
  if (!options.isOnlyStorke) {
    ctx.fillStyle = options.fillStyle;
    ctx.fill();
  }
  if (options.strokeWidth) {
    ctx.lineWidth = options.strokeWidth;
    ctx.strokeStyle = options.strokeStyle || options.color;
    ctx.stroke();
  }
}
function getGsubVrtrCharMap(font) {
  if (!lodash.exports.get(font, "tables.gsub.features") || !lodash.exports.get(font, "tables.gsub.lookups"))
    return {};
  const gsub = font.tables.gsub;
  const { features, lookups } = gsub;
  let vrt2Features = [];
  let vertFeatures = [];
  const resultsMap = {};
  features.forEach((item) => {
    if (item && item.tag === "vrt2") {
      vrt2Features = vrt2Features.concat(item.feature);
    } else if (item && item.tag === "vert" && !window.safari) {
      vertFeatures = vertFeatures.concat(item.feature);
    }
  });
  const fn = (verts) => {
    const lookupListIndexes = lodash.exports.uniq(verts.reduce((r, item) => {
      return r.concat(...item.lookupListIndexes);
    }, []));
    lookupListIndexes.forEach((i) => {
      const subtables = lookups[i].subtables;
      subtables.forEach(({ coverage, substitute }) => {
        if (!coverage || !substitute)
          return;
        if (coverage.format === 1 && coverage.glyphs) {
          coverage.glyphs.forEach((code, i2) => {
            resultsMap[code] = substitute[i2];
          });
        } else if (coverage.format === 2 && coverage.ranges) {
          coverage.ranges.forEach(({ start, end, index: index2 }) => {
            for (let i2 = start; i2 < end + 1; i2++) {
              resultsMap[i2] = substitute[index2];
              index2 = index2 + 1;
            }
          });
        }
      });
    });
  };
  fn(vertFeatures);
  fn(vrt2Features);
  return resultsMap;
}
function drawCanvas({ ctx, word, path, fontWeight = 400 }) {
  drawPath(ctx, path.commands, {
    strokeWidth: fontWeight > 400 ? 0 : word.fontWeight === 700 ? (word.fontSize * 3 / 100).toFixed(1) - 0 : 0
  });
  if (word.textDecoration === "line-through") {
    drawPath(ctx, path.lineThroughCommands);
  }
  if (word.textDecoration === "underline") {
    drawPath(ctx, path.underlineCommands);
  }
}
function getEffectExpand(effects, rect) {
  const { width, height, min } = rect;
  const totalPoleArray = [0, width, 0, height];
  effects.forEach((effect) => {
    const { offset, stroke, shadow, skew } = effect;
    const points = [
      { x: 0, y: 0 },
      { x: width, y: 0 },
      { x: 0, y: height },
      { x: width, y: height }
    ];
    if (skew && skew.enable) {
      points.forEach((point) => {
        const x = point.x + point.y * Math.tan(toRadian(skew.x));
        const y = point.y + point.x * Math.tan(toRadian(skew.y));
        point.x = x;
        point.y = y;
      });
    }
    const poleArray = [0, 0, 0, 0];
    points.forEach((point) => {
      poleArray[0] = Math.min(poleArray[0], point.x);
      poleArray[1] = Math.max(poleArray[1], point.x);
      poleArray[2] = Math.min(poleArray[2], point.y);
      poleArray[3] = Math.max(poleArray[3], point.y);
    });
    if (offset) {
      poleArray.forEach((val, i, arr) => {
        arr[i] = val + (i < 2 ? offset.x : offset.y);
      });
    }
    let newPoleArray1 = null;
    if (stroke && stroke.enable) {
      const strokeExpand = stroke.width;
      newPoleArray1 = poleArray.map((val, i) => {
        return val + Math.pow(-1, i + 1) * strokeExpand;
      });
    }
    let newPoleArray2 = null;
    if (shadow && shadow.enable) {
      const { offsetX, offsetY, blur } = shadow;
      newPoleArray2 = poleArray.map((val, i) => {
        return val + Math.pow(-1, i + 1) * blur + (i < 2 ? offsetX || 0 : offsetY || 0);
      });
    }
    poleArray.forEach((val, i) => {
      const func = i % 2 ? Math.max : Math.min;
      totalPoleArray[i] = func((newPoleArray1 || poleArray)[i], (newPoleArray2 || poleArray)[i], totalPoleArray[i]);
    });
  });
  return {
    width: totalPoleArray[1] - totalPoleArray[0],
    height: totalPoleArray[3] - totalPoleArray[2],
    min: {
      x: totalPoleArray[0] + min.x,
      y: totalPoleArray[2] + min.y
    }
  };
}
const cache = {};
const CN_WHILE_LIST = ["\u2014", "\u2026", "\u201C", "\u201D", "\uFE4F", "\uFE4B", "\uFE4C", "\u2018", "\u2019", "\u02DC"];
const EN_BLACK_LIST = ["\xA9", "\xAE", "\xF7"];
class FontPath {
  constructor(fontData, model) {
    this.font = null;
    this.model = model;
    this.fontData = fontData;
    return new Proxy(this, {
      get(target, property) {
        if (target.font) {
          return target.font["$" + property] || target.font[property] || target[property];
        } else {
          return target[property];
        }
      }
    });
  }
  load() {
    const fontData = this.fontData;
    if (cache[fontData.name])
      return cache[fontData.name];
    cache[fontData.name] = new Promise$1((resolve, reject) => {
      load(fontData.woff || fontData.ttf, (err, font) => {
        if (err) {
          reject(err);
          return;
        }
        this._initMethods(font);
        resolve(font);
      });
    }).then((font) => {
      this.font = font;
      return this;
    }).catch((e) => {
      delete cache[fontData.name];
      throw e;
    });
    return cache[fontData.name];
  }
  _initMethods(font) {
    const { fontData, model } = this;
    const vertialGlyphIndexMap = getGsubVrtrCharMap(font);
    const getIsVertical = () => {
      return model.writingMode.includes("vertical");
    };
    font.name = fontData.name;
    font.typoDescender = lodash.exports.get(font, "tables.os2.sTypoDescender");
    font.typoAscender = lodash.exports.get(font, "tables.os2.sTypoAscender");
    font.typoLinegap = lodash.exports.get(font, "tables.os2.sTypoLineGap");
    font.usWinAscent = font.ascender;
    font.usWinDescent = font.descender;
    font.$getInfo = function(word) {
      const { content, fontSize } = word;
      const { usWinAscent, usWinDescent, unitsPerEm, tables } = this;
      const fontSizePx = (usWinAscent + Math.abs(usWinDescent)) / unitsPerEm * fontSize;
      const baseLine = usWinAscent / unitsPerEm * fontSize;
      const yStrikeoutPosition = usWinAscent - tables.os2.yStrikeoutPosition;
      const yStrikeoutPositionPx = yStrikeoutPosition / unitsPerEm * fontSize;
      const yStrikeoutSize = tables.os2.yStrikeoutSize;
      const yStrikeoutSizePx = yStrikeoutSize / unitsPerEm * fontSize;
      const underlinePosition = usWinAscent - tables.post.underlinePosition;
      const underlinePositionPx = underlinePosition / unitsPerEm * fontSize;
      const underlineThickness = tables.post.underlineThickness;
      const underlineThicknessPx = underlineThickness / unitsPerEm * fontSize;
      const advanceWidthPx = font.getAdvanceWidth(content, fontSize);
      return {
        boxHeight: fontSizePx,
        boxWidth: advanceWidthPx,
        underlinePosition: underlinePositionPx,
        underlineThickness: underlineThicknessPx,
        yStrikeoutPosition: yStrikeoutPositionPx,
        yStrikeoutSize: yStrikeoutSizePx,
        baseLine
      };
    };
    font.$setItalic = function(path, word, basePoint) {
      if (fontData.style === "italic")
        return;
      const { content, left, top, fontSize } = word;
      const { baseLine, boxWidth } = font.$getInfo({ fontSize, content });
      const base = basePoint || {
        y: top + baseLine,
        x: left + boxWidth / 2
      };
      path.commands.forEach((item) => {
        ["", "1", "2"].forEach((key) => {
          if (item["x" + key]) {
            const point = utils.getSkewPoint({
              x: item["x" + key],
              y: item["y" + key]
            }, base, -0.24, 0);
            item["x" + key] = point.x;
            item["y" + key] = point.y;
          }
        });
      });
    };
    font.$setTextDecoration = function(path, word) {
      const isVertical = getIsVertical();
      const { content, left, top, width, height, fontSize } = word;
      const { yStrikeoutPosition, underlinePosition, boxHeight } = font.$getInfo({
        fontSize,
        content
      });
      const lineWidth = 0.1 * fontSize;
      const fnX = (y, lineWidth2) => {
        return [
          {
            type: "M",
            x: left,
            y
          },
          {
            type: "L",
            x: left + width,
            y
          },
          {
            type: "L",
            x: left + width,
            y: y + lineWidth2
          },
          {
            type: "L",
            x: left,
            y: y + lineWidth2
          },
          {
            type: "Z"
          }
        ];
      };
      const fnY = (x, lineWidth2) => {
        return [
          {
            type: "M",
            x,
            y: top
          },
          {
            type: "L",
            x,
            y: top + height
          },
          {
            type: "L",
            x: x + lineWidth2,
            y: top + height
          },
          {
            type: "L",
            x: x + lineWidth2,
            y: top
          },
          {
            type: "Z"
          }
        ];
      };
      if (isVertical) {
        path.lineThroughCommands = fnY(Math.max(left + width / 2, 1), lineWidth);
        path.underlineCommands = fnY(Math.max(left, 1), lineWidth);
        path.clickAreaCommands = fnY(Math.max(left, 1), boxHeight);
      } else {
        path.lineThroughCommands = fnX(Math.max(top + yStrikeoutPosition, 1), lineWidth);
        path.underlineCommands = fnX(Math.max(top + underlinePosition, 1), lineWidth);
        path.clickAreaCommands = fnX(Math.max(top, 1), boxHeight);
      }
    };
    font.$getPathByData = function(word) {
      const { content, left, top, fontSize, textWidth, textHeight } = word;
      const { baseLine, boxHeight, boxWidth } = font.$getInfo({ fontSize, content });
      const isVertical = getIsVertical();
      const vertialIndex = isVertical && vertialGlyphIndexMap[font.charToGlyphIndex(content)];
      const dx = isVertical ? boxHeight - boxWidth : 0;
      const dy = isVertical && Math.abs(textWidth - textHeight) > 0.1 ? (this.usWinAscent - this.typoAscender) / (this.usWinAscent + Math.abs(this.usWinDescent)) * boxHeight : 0;
      const x = left + dx / 2;
      const y = top + baseLine - dy;
      let path;
      if (isVertical && (!EN_BLACK_LIST.includes(content) && content.charCodeAt() <= 256 || CN_WHILE_LIST.includes(content))) {
        path = font.getPath(content, x, top + baseLine - (boxHeight - boxWidth) / 2, fontSize);
        const base = {
          y: top - (boxHeight - boxWidth) / 2 + boxHeight / 2,
          x: x + boxWidth / 2
        };
        if (word.fontStyle === "italic") {
          this.$setItalic(path, word, isVertical ? {
            y: top - (boxHeight - boxWidth) / 2 + baseLine,
            x: base.x
          } : null);
        }
        path.commands.forEach((item) => {
          ["", "1", "2"].forEach((key) => {
            if (item["x" + key]) {
              const point = utils.getPointPosition({
                x: item["x" + key],
                y: item["y" + key]
              }, base, 90);
              item["x" + key] = point.x;
              item["y" + key] = point.y;
            }
          });
        });
      } else if (vertialIndex) {
        path = font.glyphs.glyphs[vertialIndex].getPath(x, y, fontSize);
        if (word.fontStyle === "italic") {
          this.$setItalic(path, word, isVertical ? {
            y: top + this.typoAscender / (this.usWinAscent + Math.abs(this.usWinDescent)) * boxHeight,
            x: x + boxWidth / 2
          } : null);
        }
      } else {
        path = font.getPath(content, x, y, fontSize);
        if (word.fontStyle === "italic") {
          this.$setItalic(path, word, isVertical ? {
            y,
            x: x + boxHeight / 2
          } : null);
        }
      }
      this.$setTextDecoration(path, word);
      return path;
    };
  }
}
let transformBase;
const getTransformEngine = async () => {
  transformBase = await import(
    /* webpackChunkName: "three-font-parser" */
    "./three-font-parser.esm.js"
  );
};
async function transformPath(paths, model, pathOptions) {
  const { deformation = { enable: true } } = model;
  if (deformation.enable) {
    if (!transformBase) {
      await getTransformEngine();
    }
    const { ShapePath, BendForPaths, FFDForPaths, VerbatimForPaths } = transformBase;
    const shapePaths = [];
    const tagDatas = [];
    for (let i = 0; i < paths.length; i++) {
      const { commands, lineThroughCommands, underlineCommands, clickAreaCommands } = paths[i];
      const shapePath = new ShapePath();
      const tagData = [];
      pathsToShapePaths(commands, shapePath);
      tagData.push(shapePath.subPaths.length);
      pathsToShapePaths(lineThroughCommands, shapePath);
      tagData.push(shapePath.subPaths.length);
      pathsToShapePaths(underlineCommands, shapePath);
      tagData.push(shapePath.subPaths.length);
      pathsToShapePaths(clickAreaCommands, shapePath);
      tagData.push(shapePath.subPaths.length);
      shapePaths.push(shapePath);
      tagDatas.push(tagData);
    }
    let boundingBox = {};
    let transformEngine;
    if (/^bend/.test(deformation.type) || deformation.type === "archCurve") {
      transformEngine = new BendForPaths();
    } else if (/-byWord$/.test(deformation.type)) {
      transformEngine = new VerbatimForPaths();
    } else {
      transformEngine = new FFDForPaths();
    }
    const options = Object.assign(pathOptions, deformation);
    if (transformEngine) {
      boundingBox = transformEngine.transform(shapePaths, options);
    }
    for (let i = 0; i < shapePaths.length; i++) {
      const shapePath = shapePaths[i];
      const tagData = tagDatas[i];
      const newCommands = [];
      const newLineThroughCommands = [];
      const newUnderlineCommands = [];
      const newClickAreaCommands = [];
      const { subPaths } = shapePath;
      for (let j = 0; j < subPaths.length; j++) {
        const { curves } = subPaths[j];
        let currentCommands;
        if (j < tagData[0]) {
          currentCommands = newCommands;
        } else if (j < tagData[1]) {
          currentCommands = newLineThroughCommands;
        } else if (j < tagData[2]) {
          currentCommands = newUnderlineCommands;
        } else if (j < tagData[3]) {
          currentCommands = newClickAreaCommands;
        }
        const startPoint = curves[0].type === "LineCurve" ? curves[0].v1 : curves[0].v0;
        currentCommands.push({
          type: "M",
          x: startPoint.x,
          y: startPoint.y
        });
        for (let k = 0, l = curves.length; k < l; k++) {
          const curve = curves[k];
          let command;
          const { v1, v2, v3 } = curve;
          switch (curve.type) {
            case "LineCurve":
              command = k === l - 1 ? {
                type: "Z"
              } : {
                type: "L",
                x: v2.x,
                y: v2.y
              };
              break;
            case "QuadraticBezierCurve":
              command = {
                type: "Q",
                x1: v1.x,
                y1: v1.y,
                x: v2.x,
                y: v2.y
              };
              break;
            case "CubicBezierCurve":
              command = {
                type: "C",
                x1: v1.x,
                y1: v1.y,
                x2: v2.x,
                y2: v2.y,
                x: v3.x,
                y: v3.y
              };
          }
          currentCommands.push(command);
        }
      }
      paths[i].commands = newCommands;
      paths[i].lineThroughCommands = newLineThroughCommands;
      paths[i].underlineCommands = newUnderlineCommands;
      paths[i].clickAreaCommands = newClickAreaCommands;
    }
    return boundingBox;
  } else {
    let xMin = Infinity;
    let xMax = -Infinity;
    let yMin = Infinity;
    let yMax = -Infinity;
    for (let i = 0; i < paths.length; i++) {
      const { clickAreaCommands } = paths[i];
      for (let j = 0; j < clickAreaCommands.length; j++) {
        const command = clickAreaCommands[j];
        if (command.x) {
          xMin = Math.min(xMin, command.x);
          xMax = Math.max(xMax, command.x);
          yMin = Math.min(yMin, command.y);
          yMax = Math.max(yMax, command.y);
        }
      }
    }
    return {
      width: xMax - xMin,
      height: yMax - yMin,
      min: { x: xMin, y: yMin },
      max: { x: xMax, y: yMax }
    };
  }
}
function pathsToShapePaths(commands, shapePath) {
  let startX, startY;
  for (let j = 0, l = commands.length; j < l; j++) {
    const coord = commands[j];
    switch (coord.type) {
      case "M":
        startX = coord.x;
        startY = coord.y;
        shapePath.moveTo(coord.x, coord.y);
        break;
      case "L":
        shapePath.lineTo(coord.x, coord.y);
        break;
      case "C":
        shapePath.bezierCurveTo(coord.x1, coord.y1, coord.x2, coord.y2, coord.x, coord.y);
        break;
      case "Q":
        shapePath.quadraticCurveTo(coord.x1, coord.y1, coord.x, coord.y);
        break;
      case "Z":
        shapePath.lineTo(startX, startY);
        break;
      default:
        console.info(coord.type, coord, "kuake is sb");
    }
  }
}
const createTimeoutPromise = (time) => {
  return new Promise$2((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("timeout"));
    }, time);
  });
};
function createPromiseQueue(options = {}) {
  const store = /* @__PURE__ */ new Map();
  const queue = [];
  let isRunning = false;
  const exec = async () => {
    isRunning = true;
    const id = queue.shift();
    const idQueue = store.get(id);
    const { createPromise, resolve, reject } = idQueue.pop();
    const withTimeout = [createPromise()].concat(options.timeout ? [createTimeoutPromise(options.timeout)] : []);
    try {
      const result = await Promise$2.race(withTimeout);
      resolve(result);
    } catch (err) {
      reject(err);
    }
    if (queue.length) {
      await exec();
    }
    isRunning = false;
  };
  const promiseQueue2 = {
    async run(id, createPromise) {
      if (!store.get(id)) {
        store.set(id, []);
      }
      if (!queue.includes(id)) {
        queue.push(id);
      }
      const promise = new Promise$2((resolve, reject) => {
        store.get(id).push({
          createPromise,
          resolve,
          reject
        });
      });
      if (!isRunning) {
        if (options.wait) {
          isRunning = true;
          await Promise$2.delay(options.wait);
        }
        exec();
      }
      return promise;
    },
    clear() {
      queue.splice(0, queue.length);
      store.clear();
      isRunning = null;
    }
  };
  return promiseQueue2;
}
const canvas1 = createCanvas();
const canvas2 = createCanvas();
const canvas3 = createCanvas();
const timeOut = 2e4;
const promiseQueue = createPromiseQueue({
  timeout: timeOut
});
class FontEffect {
  constructor({
    inputCtx,
    outputCtx,
    effectedTextEffects,
    paths,
    pathOffset,
    model,
    mode = "design",
    devicePixelRatio = window.devicePixelRatio
  }) {
    this.paths = paths;
    this.effectedTextEffects = effectedTextEffects;
    this.pathOffset = pathOffset;
    this.inputCtx = inputCtx;
    this.inputCanvas = inputCtx.canvas;
    this.outputCtx = outputCtx;
    this.outputCanvas = outputCtx.canvas;
    this.offCanvas = canvas1;
    this.effectCanvas = canvas2;
    this.temCanvas = canvas3;
    this.model = model;
    this.id = model.$id + mode;
    this.devicePixelRatio = devicePixelRatio;
    this.offCtx = this.offCanvas.getContext("2d");
    this.effectCtx = this.effectCanvas.getContext("2d");
    this.temCtx = this.temCanvas.getContext("2d");
  }
  init() {
    this.width = this.inputCanvas.width;
    this.height = this.inputCanvas.height;
    this.outputCanvas.width = this.temCanvas.width = this.offCanvas.width = this.effectCanvas.width = this.width;
    this.outputCanvas.height = this.temCanvas.height = this.offCanvas.height = this.effectCanvas.height = this.height;
  }
  load() {
    const urls = [];
    this._imgsMap = {};
    this.effectedTextEffects.forEach((effect) => {
      const url = effect.filling && effect.filling.enable && effect.filling.type === 1 && effect.filling.imageContent.image;
      url && urls.push(url);
    });
    return Promise$1.map(urls, utils.loadImage).then((imgs) => {
      imgs.forEach((img, i) => {
        this._imgsMap[urls[i]] = img;
      });
    });
  }
  async draw() {
    const keys = ["shadow", "filling", "stroke"];
    await this.load();
    this.init();
    this.effectedTextEffects.forEach((effect) => {
      effect.enable !== false && keys.forEach((key) => {
        const item = effect[key];
        if (item && item.enable && this[key]) {
          this[key](item);
          this.offCtx.drawImage(this.effectCanvas, 0, 0);
          this._clearRect(this.effectCtx);
        }
        if (item && key === "filling" && !item.enable) {
          this.offCtx.drawImage(this.inputCanvas, 0, 0);
        }
      });
      this.transform(effect);
      this._clearRect(this.offCtx);
    });
  }
  async render() {
    return promiseQueue.run(this.id, this.draw.bind(this));
  }
  transform(effect) {
    const ctx = this.outputCtx;
    const { skew = { x: 0, y: 0 }, offset = { x: 0, y: 0 } } = effect;
    ctx.save();
    ctx.setTransform(1, Math.tan(toRadian(skew.y)), Math.tan(toRadian(skew.x)), 1, offset.x * this.devicePixelRatio, offset.y * this.devicePixelRatio);
    ctx.drawImage(this.offCanvas, 0, 0);
    ctx.restore();
  }
  stroke({ width, color }) {
    const ctx = this.temCtx;
    this._clearRect(ctx);
    ctx.save();
    ctx.translate(this.pathOffset.x, this.pathOffset.y);
    ctx.scale(this.devicePixelRatio, this.devicePixelRatio);
    ctx.miterLimit = 4 * this.devicePixelRatio;
    this.paths.forEach((path) => {
      drawPath(ctx, path.commands, {
        strokeWidth: Math.round(width),
        strokeStyle: color,
        isOnlyStorke: true,
        offset: this.pathOffset
      });
    });
    ctx.restore();
    this.effectCtx.drawImage(this.temCanvas, 0, 0);
  }
  shadow(option) {
    const ctx = this.temCtx;
    this._clearRect(ctx);
    ctx.save();
    ctx.shadowColor = option.color;
    ctx.shadowBlur = option.blur;
    ctx.shadowOffsetX = option.offsetX * this.devicePixelRatio + 1e4;
    ctx.shadowOffsetY = option.offsetY * this.devicePixelRatio;
    ctx.drawImage(this.inputCanvas, -1e4, 0);
    ctx.restore();
    this.effectCtx.drawImage(this.temCanvas, 0, 0);
  }
  filling(option) {
    const ctx = this.temCtx;
    this._clearRect(ctx);
    ctx.drawImage(this.inputCanvas, 0, 0);
    ctx.save();
    ctx.globalCompositeOperation = "source-in";
    if (option.type === 0) {
      this.fillingColor(ctx, option);
    }
    if (option.type === 1) {
      this.fillingImage(ctx, option);
    }
    if (option.type === 2) {
      this.fillingGradient(ctx, option);
    }
    ctx.restore();
    this.effectCtx.drawImage(this.temCanvas, 0, 0);
  }
  fillingColor(ctx, option) {
    ctx.fillStyle = option.color;
    this._fillRect(ctx);
  }
  fillingGradient(ctx, option) {
    const w = this.width / 2;
    const h = this.height / 2;
    const radian = -toRadian(option.gradient.angle);
    const r = Math.abs(w * Math.sin(radian)) + Math.abs(h * Math.cos(radian));
    const linegrad = ctx.createLinearGradient(w - r * Math.cos(radian), h - r * Math.sin(radian), w + r * Math.cos(radian), h + r * Math.sin(radian));
    for (const colorSet of option.gradient.stops) {
      linegrad.addColorStop(colorSet.offset, colorSet.color);
    }
    ctx.fillStyle = linegrad;
    this._fillRect(ctx);
  }
  fillingImage(ctx, option) {
    if (!option.imageContent.image) {
      return Promise$1.resolve();
    }
    const ptrn = ctx.createPattern(this._imgsMap[option.imageContent.image], "repeat");
    ctx.fillStyle = ptrn;
    const { scaleX, scaleY } = option.imageContent;
    ctx.scale(scaleX, scaleY);
    this._fillRect(ctx, scaleX, scaleY);
  }
  _fillRect(ctx, scaleX = 1, scaleY = 1) {
    ctx.fillRect(0, 0, ctx.canvas.width / scaleX, ctx.canvas.height / scaleY);
  }
  _clearRect(ctx) {
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  }
}
var EffectTextElement = inherit(BaseElement, {
  name: "effect-text-element",
  template,
  data() {
    return {
      isRendering: false,
      isRenderInit: false
    };
  },
  computed: {
    canvasStyle() {
      const { zoom = 1 } = this.global;
      const { ratio = 1 } = this;
      return {
        transform: `scale(${zoom * ratio / window.devicePixelRatio})`
      };
    },
    isMirrorMode() {
      return this.options.mode === "mirror" && this.model.imageUrl;
    },
    linkSelected() {
      const element = this.editor.currentSubElement || this.editor.currentElement || {};
      return this.isLinkWith(element);
    },
    showWithImg() {
      if (!this.isRenderInit && !this.model.imageUrl) {
        this.lazyRender();
      }
      return !this.isRenderInit;
    },
    showLoading() {
      return this.isRendering && this.isDesignMode;
    }
  },
  events: {
    "element.loaded"(model) {
      if (model === this.model) {
        this.syncRect();
      }
    },
    "element.transformStart"(model, { action }) {
      if (this.isModelRelative(model) && action === "resize") {
        const { width, height } = this.rect;
        this.$textResizeMeta = {
          width,
          height,
          letterSpacing: this.model.letterSpacing,
          fontSize: this.model.fontSize,
          contents: lodash.exports.cloneDeep(this.model.contents)
        };
      }
    },
    "element.transformEnd"(model, drag, { action }) {
      if (this.isModelRelative(model) && action === "resize") {
        model === this.model && this.syncRectPos(drag.dir.length > 1);
        this.$nextTick(() => this.lazyRender());
      }
    },
    "element.transformResize"(drag, model) {
      if (this.isModelRelative(model)) {
        const isHorizontal = this.model.writingMode === "horizontal-tb";
        const { dir } = drag;
        if (isHorizontal && (dir === "n" || dir === "s") || !isHorizontal && (dir === "w" || dir === "e")) {
          return;
        }
        if (dir.length > 1) {
          const currRect = this.rect;
          const baseText = this.$textResizeMeta;
          this.ratio = isHorizontal ? currRect.width / (baseText.width || 1) : currRect.height / (baseText.height || 1);
        } else {
          this.syncRect();
        }
      }
    },
    "element.change"(model, propName) {
      if (propName === "contents" && this.isLinkWith(model)) {
        const content = model.contents.reduce((list, content2) => {
          list.push(content2.content);
          return list;
        }, []).join("");
        this.editor.changeElement({
          contents: [{ content }],
          content
        }, this.model, false);
        this.syncRect();
      }
    },
    "model.fontSize"(val, oldVal) {
      if (!this.isDesignMode || this.model.$resizeApi)
        return;
      this.scaleEffect(val / oldVal || 1);
      this.lazyRender();
    }
  },
  methods: {
    async load() {
      if (this.isDesignMode) {
        this.loadFont();
      }
      if (this.model.imageUrl) {
        await utils.loadImage(this.model.imageUrl, this.options.fitCrossOrigin);
      } else {
        await this.render(true);
      }
    },
    async loadFontPath() {
      const vm = this;
      const names = await this.loadFont();
      return Promise$1.map(names, (name) => {
        const fontData = vm.getFontData(name);
        return new FontPath(fontData, this.model).load();
      }).then((fonts) => {
        const result = {};
        fonts.forEach((item) => {
          result[item.name] = item;
        });
        return result;
      });
    },
    getWords() {
      const lines = getLines(this.$refs.textNode, this.$refs.textInner);
      const types = [
        "ellipse-byWord",
        "triangle-byWord",
        "rectangular-byWord",
        "pentagon-byWord"
      ];
      if (!types.some((type) => type === this.model.deformation.type)) {
        lines.forEach((line) => {
          line.forEach((word) => {
            word.width -= this.model.letterSpacing;
          });
        });
      }
      const words = getWords(lines, this.model);
      return words;
    },
    getFontData(fontFamily) {
      const { options } = this;
      return options.fontsMap[fontFamily] || options.fontsMap[this.model.fontFamily] || options.defaultFont;
    },
    getPaths(fontPaths) {
      const initPaths = [];
      this.words = this.getWords();
      const charPosDatas = [];
      let maxFontSize = 0;
      this.words.forEach((word) => {
        if (word.fontSize < 12) {
          word.fontSize = 12 * this.fontSizeScale;
        }
        const fontData = this.getFontData(word.fontFamily);
        const fontPath = fontPaths[fontData.name];
        const path = fontPath.getPathByData(word);
        initPaths.push(path);
        const x = word.left + 0.5 * word.width;
        const y = word.top + 0.5 * word.height;
        const fontBox = fontPath.$getInfo(word);
        charPosDatas.push({
          rowNum: word.lineIndex,
          columnNum: word.wordIndex,
          fontSize: word.fontSize,
          centerPos: { x, y },
          centerDiviation: 0.5 * word.height - fontBox.baseLine
        });
        maxFontSize = Math.max(maxFontSize, word.fontSize);
      });
      this.pathOptions = {
        charPosDatas,
        writingMode: this.model.writingMode,
        maxFontSize
      };
      return initPaths;
    },
    draw() {
      if (this.model.$editing || this.editor.global.$draging || !this.initBBox || !this.initPaths[0])
        return;
      if (this.getTextEffectsEnable()) {
        this.effectedTextEffects = getEffectedTextEffects(this.model);
        this.boundingBox = getEffectExpand(this.effectedTextEffects, this.initBBox);
      }
      if (!this.checkBoundingBox)
        return;
      this.resizeCanvas(this.boundingBox);
      const { width, height, min = { x: 0, y: 0 } } = this.boundingBox;
      this.clickAreaCanvas.width = width;
      this.clickAreaCanvas.height = height;
      this.cacheCtx.save();
      this.clickAreaCtx.save();
      this.cacheCtx.translate(-min.x, -min.y);
      this.clickAreaCtx.translate(-min.x, -min.y);
      this.clickAreaCtx.fillStyle = "#00ff00";
      this.words.forEach((word, i) => {
        const fontData = this.getFontData(word.fontFamily);
        this.cacheCtx.fillStyle = word.color;
        this.cacheCtx.strokeStyle = word.color;
        drawCanvas({
          ctx: this.cacheCtx,
          word,
          path: this.paths[i],
          fontWeight: fontData.weight
        });
        drawPath(this.clickAreaCtx, this.paths[i].clickAreaCommands);
      });
      this.cacheCtx.restore();
      this.clickAreaCtx.restore();
      this.doTextEffects();
    },
    async doTransform() {
      if (this.model.$editing || this.editor.global.$draging)
        return;
      if (this.initPaths && this.initPaths[0]) {
        this.paths = lodash.exports.cloneDeep(this.initPaths);
        this.boundingBox = await transformPath(this.paths, this.model, this.pathOptions);
        this.initBBox = this.boundingBox;
        this.draw();
      }
    },
    async doTextEffects() {
      if (this.model.$editing || this.editor.global.$draging)
        return;
      if (this.getTextEffectsEnable()) {
        const { min = { x: 0, y: 0 } } = this.boundingBox;
        const fe = new FontEffect({
          inputCtx: this.cacheCtx,
          outputCtx: this.ctx,
          model: this.model,
          mode: this.options.mode,
          paths: this.paths,
          effectedTextEffects: this.effectedTextEffects || [],
          pathOffset: {
            x: -min.x * window.devicePixelRatio,
            y: -min.y * window.devicePixelRatio
          }
        });
        await fe.render();
      } else {
        this.canvas.width = this.cacheCanvas.width;
        this.canvas.height = this.cacheCanvas.height;
        this.ctx.drawImage(this.cacheCanvas, 0, 0);
      }
      this.ratio = 1;
      this.model.imageUrl = null;
      this.editor.lazyUpdatePicker();
    },
    async initRenderer() {
      this.isRenderInit = true;
      this.cacheCanvas = createCanvas();
      this.cacheCtx = this.cacheCanvas.getContext("2d");
      await this.$nextTick();
      this.canvas = this.$refs.canvas;
      this.clickAreaCanvas = this.$refs.clickAreaCanvas;
      this.ctx = this.canvas.getContext("2d");
      this.clickAreaCtx = this.clickAreaCanvas.getContext("2d");
    },
    async render(isForce) {
      if (!this.$refs.textInner || (this.model.$editing || this.editor.global.$draging) && isForce !== true)
        return;
      this.isRendering = true;
      this.syncRect();
      await this.$nextTick();
      const fontPaths = await this.loadFontPath();
      if (this.$refs.textInner) {
        this.initPaths = this.getPaths(fontPaths);
        if (this.initPaths && this.initPaths[0]) {
          if (!this.isRenderInit) {
            await this.initRenderer();
          }
          await this.doTransform();
        }
      }
      this.isRendering = false;
    },
    lazyRender(arg) {
      if (!this._lazyRender) {
        this._lazyRender = lodash.exports.throttle(async (arg2) => {
          this.scaleRatio = 1;
          await this.render(arg2);
        }, 100);
      }
      this._lazyRender(arg);
    },
    resizeCanvas({ width, height }) {
      this.cacheCanvas.width = Math.ceil(width * window.devicePixelRatio);
      this.cacheCanvas.height = Math.ceil(height * window.devicePixelRatio);
      this.cacheCtx.restore();
      this.cacheCtx.save();
      this.cacheCtx.scale(window.devicePixelRatio, window.devicePixelRatio);
      const { model } = this;
      const dw = width - model.width;
      const dh = height - model.height;
      if (this.isDesignMode) {
        model.left += (model.width - width) / 2;
        model.top += (model.height - height) / 2;
      }
      this.model.typoWidthRatio = model.$typoWidth / width;
      this.model.typoHeightRatio = model.$typoHeight / height;
      model.width = width;
      model.height = height;
      if (Math.abs(dw) + Math.abs(dh) > 0.1) {
        const groups = this.editor.getParentGroups(this.model);
        for (let i = groups.length - 1; i >= 0; i--) {
          this.$events.$emit("group.boundingReset", groups[i]);
        }
      }
    },
    checkBoundingBox() {
      const { width = 0, height = 0 } = this.boundingBox;
      return width > 1 && height > 1;
    },
    getTextEffectsEnable() {
      return this.model.textEffects && this.model.textEffects.some((effect) => {
        const {
          offset = {},
          filling = {},
          stroke = {},
          shadow = {},
          skew = {}
        } = effect;
        const effectEnable = effect.enable && (offset.enable || filling.enable || stroke.enable || shadow.enable || skew.enable);
        return effectEnable;
      });
    },
    syncRectPos(isScale = false) {
      const baseText = this.$textResizeMeta;
      const { ratio = 1, rect, global } = this;
      const { zoom = 1 } = global;
      this.model.width = rect.width / zoom;
      this.model.height = rect.height / zoom;
      this.model.top = rect.top / zoom;
      this.model.left = rect.left / zoom;
      if (isScale) {
        fitText(this.model, baseText, ratio);
      }
      delete this.$textResizeMeta;
      if (!this.isDesignMode) {
        this.ratio = 1;
      }
    },
    checkLoadFullFont() {
      const { model, options } = this;
      const fontData = getUpdateFontsSubset([{ elements: [model] }], options);
      if (fontData) {
        Object.keys(fontData).forEach((name) => {
          const fontSubset = options.fontSubsetsMap[name];
          if (fontSubset) {
            fontSubset.loadType = "all";
          }
        });
        this.checkLoad();
      }
    }
  },
  mounted() {
    this.checkLoadFullFont();
    this.syncRect();
  },
  watch: {
    "model.width"(val) {
      this.model.$typoWidth = val * (this.model.$editing ? 1 : this.model.typoWidthRatio);
    },
    "model.height"(val) {
      this.model.$typoHeight = val * (this.model.$editing ? 1 : this.model.typoHeightRatio);
    },
    "model.$editing"(val) {
      if (this.isDesignMode) {
        const { model } = this;
        if (val) {
          model.resize = this.isVertical ? 3 : 5;
          model.left += model.width * (1 - model.typoWidthRatio) / 2;
          model.top += model.height * (1 - model.typoHeightRatio) / 2;
          model.width = model.$typoWidth;
          model.height = model.$typoHeight;
        } else {
          model.resize = 1;
          model.width = model.$typoWidth / model.typoWidthRatio;
          model.height = model.$typoHeight / model.typoHeightRatio;
          model.top += (model.$typoHeight - model.height) / 2;
          model.left += (model.$typoWidth - model.width) / 2;
        }
      }
      if (!val) {
        this.lazyRender();
        return;
      }
      let needCheckLoad;
      this.model.contents.forEach((item) => {
        const font = this.options.fontsMap[item.fontFamily || this.model.fontFamily] || this.options.defaultFont;
        const fontSubset = this.options.fontSubsetsMap[font.name];
        if (fontSubset && fontSubset.loadType !== "all") {
          fontSubset.loadType = "all";
          needCheckLoad = true;
        }
      });
      if (needCheckLoad) {
        this.checkLoad();
      }
    },
    "model.writingMode"() {
      if (!this.isDesignMode) {
        return;
      }
      const { model } = this;
      const newResize = {
        2: 4,
        4: 2,
        5: 3,
        3: 5
      }[model.editingResize];
      if (newResize) {
        model.editingResize = newResize;
      }
      [model.width, model.height] = [model.height, model.width];
      [model.typoWidthRatio, model.typoHeightRatio] = [
        model.typoHeightRatio,
        model.typoWidthRatio
      ];
      this.lazyRender();
    },
    "model.contents": {
      deep: true,
      handler() {
        if (!this.model.$editing && !this.model.$draging) {
          this.checkLoadFullFont();
        }
        this.syncRect();
        this.lazyRender();
      }
    },
    "model.textAlign": "lazyRender",
    "model.letterSpacing": "lazyRender",
    "model.lineHeight": "lazyRender",
    "model.padding": "lazyRender",
    "model.deformation": {
      deep: true,
      handler() {
        if (this.model.$needSpeedUp && this.initPaths) {
          this.doTransform();
          this.model.$needSpeedUp = false;
        } else {
          this.lazyRender();
        }
      }
    },
    "model.textEffects": {
      deep: true,
      handler() {
        if (this.isRenderInit) {
          this.draw();
        } else {
          this.lazyRender();
        }
      }
    }
  }
});
var index = {
  model: EffectTextModel$1,
  methods,
  layoutComponent: EffectTextElement
};
export { index as default };
