{"version":3,"file":"Text.min.mjs","sources":["../../../../src/shapes/Text/Text.ts"],"sourcesContent":["import { cache } from '../../cache';\nimport { DEFAULT_SVG_FONT_SIZE, FILL, STROKE } from '../../constants';\nimport type { ObjectEvents } from '../../EventTypeDefs';\nimport type {\n  CompleteTextStyleDeclaration,\n  TextStyle,\n  TextStyleDeclaration,\n} from './StyledText';\nimport { StyledText } from './StyledText';\nimport { SHARED_ATTRIBUTES } from '../../parser/attributes';\nimport { parseAttributes } from '../../parser/parseAttributes';\nimport type {\n  Abortable,\n  TCacheCanvasDimensions,\n  TClassProperties,\n  TFiller,\n  TOptions,\n} from '../../typedefs';\nimport { classRegistry } from '../../ClassRegistry';\nimport { graphemeSplit } from '../../util/lang_string';\nimport { createCanvasElementFor } from '../../util/misc/dom';\nimport type { TextStyleArray } from '../../util/misc/textStyles';\nimport {\n  hasStyleChanged,\n  stylesFromArray,\n  stylesToArray,\n} from '../../util/misc/textStyles';\nimport { getPathSegmentsInfo, getPointOnPath } from '../../util/path';\nimport { cacheProperties } from '../Object/FabricObject';\nimport { Path } from '../Path';\nimport { TextSVGExportMixin } from './TextSVGExportMixin';\nimport { applyMixins } from '../../util/applyMixins';\nimport type { FabricObjectProps, SerializedObjectProps } from '../Object/types';\nimport type { StylePropertiesType } from './constants';\nimport {\n  additionalProps,\n  textDefaultValues,\n  textLayoutProperties,\n  JUSTIFY,\n  JUSTIFY_CENTER,\n  JUSTIFY_LEFT,\n  JUSTIFY_RIGHT,\n  TEXT_DECORATION_THICKNESS,\n} from './constants';\nimport { CENTER, LEFT, RIGHT, TOP, BOTTOM } from '../../constants';\nimport { isFiller } from '../../util/typeAssertions';\nimport type { Gradient } from '../../gradient/Gradient';\nimport type { Pattern } from '../../Pattern';\nimport type { CSSRules } from '../../parser/typedefs';\nimport { renderCircleControl, renderSquareControl } from '../../controls';\nimport { ITextProps } from '../IText/IText';\n\nlet measuringContext: CanvasRenderingContext2D | null;\n\n/**\n * Return a context for measurement of text string.\n * if created it gets stored for reuse\n */\nfunction getMeasuringContext() {\n  if (!measuringContext) {\n    const canvas = createCanvasElementFor({\n      width: 0,\n      height: 0,\n    });\n    measuringContext = canvas.getContext('2d');\n  }\n  return measuringContext;\n}\n\nexport type TPathSide = 'left' | 'right';\n\nexport type TPathAlign = 'baseline' | 'center' | 'ascender' | 'descender';\n\nexport type TextLinesInfo = {\n  lines: string[];\n  graphemeLines: string[][];\n  graphemeText: string[];\n  _unwrappedLines: string[][];\n};\n\n/**\n * Measure and return the info of a single grapheme.\n * needs the the info of previous graphemes already filled\n * Override to customize measuring\n */\nexport type GraphemeBBox = {\n  width: number;\n  height: number;\n  kernedWidth: number;\n  left: number;\n  deltaY: number;\n  renderLeft?: number;\n  renderTop?: number;\n  angle?: number;\n  // James modified\n  visible?: boolean;\n};\n\n// @TODO this is not complete\ninterface UniqueTextProps {\n  charSpacing: number;\n  lineHeight: number;\n  fontSize: number;\n  fontWeight: string | number;\n  fontFamily: string;\n  fontStyle: string;\n  pathSide: TPathSide;\n  pathAlign: TPathAlign;\n  underline: boolean;\n  overline: boolean;\n  linethrough: boolean;\n  textAlign: string;\n  direction: CanvasDirection;\n  path?: Path;\n  textDecorationThickness: number;\n}\n\nexport interface SerializedTextProps\n  extends SerializedObjectProps,\n    UniqueTextProps {\n  styles: TextStyleArray | TextStyle;\n}\n\nexport interface TextProps extends FabricObjectProps, UniqueTextProps {\n  styles: TextStyle;\n}\n\n/**\n * Text class\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#text}\n */\nexport class FabricText<\n    Props extends TOptions<TextProps> = Partial<TextProps>,\n    SProps extends SerializedTextProps = SerializedTextProps,\n    EventSpec extends ObjectEvents = ObjectEvents,\n  >\n  extends StyledText<Props, SProps, EventSpec>\n  implements UniqueTextProps\n{\n  /**\n   * Properties that requires a text layout recalculation when changed\n   * @type string[]\n   * @protected\n   */\n  static textLayoutProperties: string[] = textLayoutProperties;\n\n  /**\n   * @private\n   */\n  declare _reNewline: RegExp;\n\n  /**\n   * Use this regular expression to filter for whitespaces that is not a new line.\n   * Mostly used when text is 'justify' aligned.\n   * @private\n   */\n  declare _reSpacesAndTabs: RegExp;\n\n  /**\n   * Use this regular expression to filter for whitespace that is not a new line.\n   * Mostly used when text is 'justify' aligned.\n   * @private\n   */\n  declare _reSpaceAndTab: RegExp;\n\n  /**\n   * Use this regular expression to filter consecutive groups of non spaces.\n   * Mostly used when text is 'justify' aligned.\n   * @private\n   */\n  declare _reWords: RegExp;\n\n  declare text: string;\n\n  /**\n   * Font size (in pixels)\n   * @type Number\n   * @default\n   */\n  declare fontSize: number;\n\n  /**\n   * Font weight (e.g. bold, normal, 400, 600, 800)\n   * @type {(Number|String)}\n   * @default\n   */\n  declare fontWeight: string | number;\n\n  /**\n   * Font family\n   * @type String\n   * @default\n   */\n  declare fontFamily: string;\n\n  /**\n   * Text decoration underline.\n   * @type Boolean\n   * @default\n   */\n  declare underline: boolean;\n\n  /**\n   * Text decoration overline.\n   * @type Boolean\n   * @default\n   */\n  declare overline: boolean;\n\n  /**\n   * Text decoration linethrough.\n   * @type Boolean\n   * @default\n   */\n  declare linethrough: boolean;\n\n  /**\n   * Text alignment. Possible values: \"left\", \"center\", \"right\", \"justify\",\n   * \"justify-left\", \"justify-center\" or \"justify-right\".\n   * @type String\n   * @default\n   */\n  declare textAlign: string;\n\n  /**\n   * Font style . Possible values: \"\", \"normal\", \"italic\" or \"oblique\".\n   * @type String\n   * @default\n   */\n  declare fontStyle: string;\n\n  /**\n   * Line height\n   * @type Number\n   * @default\n   */\n  declare lineHeight: number;\n\n  /**\n   * Superscript schema object (minimum overlap)\n   */\n  declare superscript: {\n    /**\n     * fontSize factor\n     * @default 0.6\n     */\n    size: number;\n    /**\n     * baseline-shift factor (upwards)\n     * @default -0.35\n     */\n    baseline: number;\n  };\n\n  /**\n   * Subscript schema object (minimum overlap)\n   */\n  declare subscript: {\n    /**\n     * fontSize factor\n     * @default 0.6\n     */\n    size: number;\n    /**\n     * baseline-shift factor (downwards)\n     * @default 0.11\n     */\n    baseline: number;\n  };\n\n  /**\n   * Background color of text lines\n   * @type String\n   * @default\n   */\n  declare textBackgroundColor: string;\n\n  declare styles: TextStyle;\n\n  /**\n   * Path that the text should follow.\n   * since 4.6.0 the path will be drawn automatically.\n   * if you want to make the path visible, give it a stroke and strokeWidth or fill value\n   * if you want it to be hidden, assign visible = false to the path.\n   * This feature is in BETA, and SVG import/export is not yet supported.\n   * @type Path\n   * @example\n   * const textPath = new Text('Text on a path', {\n   *     top: 150,\n   *     left: 150,\n   *     textAlign: 'center',\n   *     charSpacing: -50,\n   *     path: new Path('M 0 0 C 50 -100 150 -100 200 0', {\n   *         strokeWidth: 1,\n   *         visible: false\n   *     }),\n   *     pathSide: 'left',\n   *     pathStartOffset: 0\n   * });\n   * @default\n   */\n  declare path?: Path;\n\n  /**\n   * The text decoration tickness for underline, overline and strikethrough\n   * The tickness is expressed in thousandths of fontSize ( em ).\n   * The original value was 1/15 that translates to 66.6667 thousandths.\n   * The choice of unit of measure is to align with charSpacing.\n   * You can slim the tickness without issues, while large underline or overline may end up\n   * outside the bounding box of the text. In order to fix that a bigger refactor of the code\n   * is needed and is out of scope for now. If you need such large overline on the first line\n   * of text or large underline on the last line of text, consider disabling caching as a\n   * workaround\n   * @default 66.667\n   */\n  declare textDecorationThickness: number;\n\n  /**\n   * Offset amount for text path starting position\n   * Only used when text has a path\n   * @default\n   */\n  declare pathStartOffset: number;\n\n  /**\n   * Which side of the path the text should be drawn on.\n   * Only used when text has a path\n   * @type {TPathSide} 'left|right'\n   * @default\n   */\n  declare pathSide: TPathSide;\n\n  /**\n   * How text is aligned to the path. This property determines\n   * the perpendicular position of each character relative to the path.\n   * (one of \"baseline\", \"center\", \"ascender\", \"descender\")\n   * This feature is in BETA, and its behavior may change\n   * @type TPathAlign\n   * @default\n   */\n  declare pathAlign: TPathAlign;\n\n  /**\n   * @private\n   */\n  declare _fontSizeFraction: number;\n\n  /**\n   * @private\n   */\n  declare offsets: { underline: number; linethrough: number; overline: number };\n\n  /**\n   * Text Line proportion to font Size (in pixels)\n   * @type Number\n   * @default\n   */\n  declare _fontSizeMult: number;\n\n  /**\n   * additional space between characters\n   * expressed in thousands of em unit\n   * @type Number\n   * @default\n   */\n  declare charSpacing: number;\n\n  /**\n   * Baseline shift, styles only, keep at 0 for the main text object\n   * @type {Number}\n   * @default\n   */\n  declare deltaY: number;\n\n  /**\n   * WARNING: EXPERIMENTAL. NOT SUPPORTED YET\n   * determine the direction of the text.\n   * This has to be set manually together with textAlign and originX for proper\n   * experience.\n   * some interesting link for the future\n   * https://www.w3.org/International/questions/qa-bidi-unicode-controls\n   * @since 4.5.0\n   * @type {CanvasDirection} 'ltr|rtl'\n   * @default\n   */\n  declare direction: CanvasDirection;\n\n  /**\n   * contains characters bounding boxes\n   * This variable is considered to be protected.\n   * But for how mixins are implemented right now, we can't leave it private\n   * @protected\n   */\n  __charBounds: GraphemeBBox[][] = [];\n\n  /**\n   * use this size when measuring text. To avoid IE11 rounding errors\n   * @type {Number}\n   * @default\n   * @readonly\n   * @private\n   */\n  declare CACHE_FONT_SIZE: number;\n\n  /**\n   * contains the min text width to avoid getting 0\n   * @type {Number}\n   * @default\n   */\n  declare MIN_TEXT_WIDTH: number;\n\n  /**\n   * contains the the text of the object, divided in lines as they are displayed\n   * on screen. Wrapping will divide the text independently of line breaks\n   * @type {string[]}\n   * @default\n   */\n  declare textLines: string[];\n\n  /**\n   * same as textlines, but each line is an array of graphemes as split by splitByGrapheme\n   * @type {string[]}\n   * @default\n   */\n  declare _textLines: string[][];\n\n  declare _unwrappedTextLines: string[][];\n  declare _text: string[];\n  declare cursorWidth: number;\n  declare __lineHeights: number[];\n  declare __lineWidths: number[];\n  declare initialized?: true;\n\n  static cacheProperties = [...cacheProperties, ...additionalProps];\n\n  static ownDefaults = textDefaultValues;\n\n  /**\n   * James add\n   * Indicates whether text is in editing mode\n   * @type Boolean\n   * @default\n   */\n  declare isEditing: boolean;\n  /**\n   * James add\n   * 是否有隐藏文字\n   */\n  declare hasHideText: boolean;\n\n  /**\n   * James add\n   * 是否启用计算文字高度\n   */\n  static enableCalcTextHeight: boolean;\n\n  static type = 'Text';\n\n  static getDefaults(): Record<string, any> {\n    return { ...super.getDefaults(), ...FabricText.ownDefaults };\n  }\n\n  constructor(text: string, options?: Props) {\n    super();\n    Object.assign(this, FabricText.ownDefaults);\n    this.setOptions(options);\n    if (!this.styles) {\n      this.styles = {};\n    }\n    this.text = text;\n    this.initialized = true;\n    if (this.path) {\n      this.setPathInfo();\n    }\n    this.initDimensions();\n    this.setCoords();\n  }\n\n  /**\n   * If text has a path, it will add the extra information needed\n   * for path and text calculations\n   */\n  setPathInfo() {\n    const path = this.path;\n    if (path) {\n      path.segmentsInfo = getPathSegmentsInfo(path.path);\n\n      // James modified 检查空路径的话，设置path为空\n      if (!path.width && !path.height) {\n        console.log(this, 'text path empty');\n        this.path = undefined;\n      }\n    }\n  }\n\n  /**\n   * @private\n   * Divides text into lines of text and lines of graphemes.\n   */\n  _splitText(): TextLinesInfo {\n    const newLines = this._splitTextIntoLines(this.text);\n    this.textLines = newLines.lines;\n    this._textLines = newLines.graphemeLines;\n    this._unwrappedTextLines = newLines._unwrappedLines;\n    this._text = newLines.graphemeText;\n    return newLines;\n  }\n\n  /**\n   * Initialize or update text dimensions.\n   * Updates this.width and this.height with the proper values.\n   * Does not return dimensions.\n   */\n  initDimensions() {\n    this._splitText();\n    this._clearCache();\n    this.dirty = true;\n    if (this.path) {\n      this.width = this.path.width;\n      this.height = this.path.height;\n    } else {\n      this.width =\n        this.calcTextWidth() || this.cursorWidth || this.MIN_TEXT_WIDTH;\n      this.height = this.calcTextHeight();\n    }\n    if (this.textAlign.includes(JUSTIFY)) {\n      // once text is measured we need to make space fatter to make justified text.\n      this.enlargeSpaces();\n    }\n  }\n\n  /**\n   * Enlarge space boxes and shift the others\n   */\n  enlargeSpaces() {\n    let diffSpace,\n      currentLineWidth,\n      numberOfSpaces,\n      accumulatedSpace,\n      line,\n      charBound,\n      spaces;\n    for (let i = 0, len = this._textLines.length; i < len; i++) {\n      if (\n        this.textAlign !== JUSTIFY &&\n        (i === len - 1 || this.isEndOfWrapping(i))\n      ) {\n        continue;\n      }\n      accumulatedSpace = 0;\n      line = this._textLines[i];\n      currentLineWidth = this.getLineWidth(i);\n      if (\n        currentLineWidth < this.width &&\n        (spaces = this.textLines[i].match(this._reSpacesAndTabs))\n      ) {\n        numberOfSpaces = spaces.length;\n        diffSpace = (this.width - currentLineWidth) / numberOfSpaces;\n        for (let j = 0; j <= line.length; j++) {\n          charBound = this.__charBounds[i][j];\n          if (this._reSpaceAndTab.test(line[j])) {\n            charBound.width += diffSpace;\n            charBound.kernedWidth += diffSpace;\n            charBound.left += accumulatedSpace;\n            accumulatedSpace += diffSpace;\n          } else {\n            charBound.left += accumulatedSpace;\n          }\n        }\n      }\n    }\n  }\n\n  /**\n   * Detect if the text line is ended with an hard break\n   * text and itext do not have wrapping, return false\n   * @return {Boolean}\n   */\n  isEndOfWrapping(lineIndex: number): boolean {\n    return lineIndex === this._textLines.length - 1;\n  }\n\n  /**\n   * Detect if a line has a linebreak and so we need to account for it when moving\n   * and counting style.\n   * It return always 1 for text and Itext. Textbox has its own implementation\n   * @return Number\n   */\n  missingNewlineOffset(lineIndex: number, skipWrapping?: boolean): 0 | 1;\n  missingNewlineOffset(_lineIndex: number): 1 {\n    return 1;\n  }\n\n  /**\n   * Returns 2d representation (lineIndex and charIndex) of cursor\n   * @param {Number} selectionStart\n   * @param {Boolean} [skipWrapping] consider the location for unwrapped lines. useful to manage styles.\n   */\n  get2DCursorLocation(selectionStart: number, skipWrapping?: boolean) {\n    const lines = skipWrapping ? this._unwrappedTextLines : this._textLines;\n    let i: number;\n    for (i = 0; i < lines.length; i++) {\n      if (selectionStart <= lines[i].length) {\n        return {\n          lineIndex: i,\n          charIndex: selectionStart,\n        };\n      }\n      selectionStart -=\n        lines[i].length + this.missingNewlineOffset(i, skipWrapping);\n    }\n    return {\n      lineIndex: i - 1,\n      charIndex:\n        lines[i - 1].length < selectionStart\n          ? lines[i - 1].length\n          : selectionStart,\n    };\n  }\n\n  /**\n   * Returns string representation of an instance\n   * @return {String} String representation of text object\n   */\n  toString(): string {\n    return `#<Text (${this.complexity()}): { \"text\": \"${\n      this.text\n    }\", \"fontFamily\": \"${this.fontFamily}\" }>`;\n  }\n\n  /**\n   * Return the dimension and the zoom level needed to create a cache canvas\n   * big enough to host the object to be cached.\n   * @private\n   * @param {Object} dim.x width of object to be cached\n   * @param {Object} dim.y height of object to be cached\n   * @return {Object}.width width of canvas\n   * @return {Object}.height height of canvas\n   * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n   * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n   */\n  _getCacheCanvasDimensions(): TCacheCanvasDimensions {\n    const dims = super._getCacheCanvasDimensions();\n    const fontSize = this.fontSize;\n    dims.width += fontSize * dims.zoomX * 2;\n    dims.height += fontSize * dims.zoomY * 2;\n    return dims;\n  }\n\n  /**\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   */\n  _render(ctx: CanvasRenderingContext2D) {\n    const path = this.path;\n    path && !path.isNotVisible() && path._render(ctx);\n    this._setTextStyles(ctx);\n    this._renderTextLinesBackground(ctx);\n    this._renderTextDecoration(ctx, 'underline');\n    this._renderText(ctx);\n    this._renderTextDecoration(ctx, 'overline');\n    this._renderTextDecoration(ctx, 'linethrough');\n  }\n\n  /**\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   */\n  _renderText(ctx: CanvasRenderingContext2D) {\n    if (this.paintFirst === STROKE) {\n      this._renderTextStroke(ctx);\n      this._renderTextFill(ctx);\n    } else {\n      this._renderTextFill(ctx);\n      this._renderTextStroke(ctx);\n    }\n  }\n\n  /**\n   * Set the font parameter of the context with the object properties or with charStyle\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   * @param {Object} [charStyle] object with font style properties\n   * @param {String} [charStyle.fontFamily] Font Family\n   * @param {Number} [charStyle.fontSize] Font size in pixels. ( without px suffix )\n   * @param {String} [charStyle.fontWeight] Font weight\n   * @param {String} [charStyle.fontStyle] Font style (italic|normal)\n   */\n  _setTextStyles(\n    ctx: CanvasRenderingContext2D,\n    charStyle?: any,\n    forMeasuring?: boolean,\n  ) {\n    ctx.textBaseline = 'alphabetic';\n    if (this.path) {\n      switch (this.pathAlign) {\n        case CENTER:\n          ctx.textBaseline = 'middle';\n          break;\n        case 'ascender':\n          ctx.textBaseline = TOP;\n          break;\n        case 'descender':\n          ctx.textBaseline = BOTTOM;\n          break;\n      }\n    }\n    ctx.font = this._getFontDeclaration(charStyle, forMeasuring);\n  }\n\n  /**\n   * calculate and return the text Width measuring each line.\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   * @return {Number} Maximum width of Text object\n   */\n  calcTextWidth(): number {\n    let maxWidth = this.getLineWidth(0);\n\n    for (let i = 1, len = this._textLines.length; i < len; i++) {\n      const currentLineWidth = this.getLineWidth(i);\n      if (currentLineWidth > maxWidth) {\n        maxWidth = currentLineWidth;\n      }\n    }\n    return maxWidth;\n  }\n\n  /**\n   * @private\n   * @param {String} method Method name (\"fillText\" or \"strokeText\")\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   * @param {String} line Text to render\n   * @param {Number} left Left position of text\n   * @param {Number} top Top position of text\n   * @param {Number} lineIndex Index of a line in a text\n   */\n  _renderTextLine(\n    method: 'fillText' | 'strokeText',\n    ctx: CanvasRenderingContext2D,\n    line: string[],\n    left: number,\n    top: number,\n    lineIndex: number,\n  ) {\n    this._renderChars(method, ctx, line, left, top, lineIndex);\n  }\n\n  /**\n   * Renders the text background for lines, taking care of style\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   */\n  _renderTextLinesBackground(ctx: CanvasRenderingContext2D) {\n    if (!this.textBackgroundColor && !this.styleHas('textBackgroundColor')) {\n      return;\n    }\n    const originalFill = ctx.fillStyle,\n      leftOffset = this._getLeftOffset();\n    let lineTopOffset = this._getTopOffset();\n\n    for (let i = 0, len = this._textLines.length; i < len; i++) {\n      const heightOfLine = this.getHeightOfLine(i);\n      if (\n        !this.textBackgroundColor &&\n        !this.styleHas('textBackgroundColor', i)\n      ) {\n        lineTopOffset += heightOfLine;\n        continue;\n      }\n      const jlen = this._textLines[i].length;\n      const lineLeftOffset = this._getLineLeftOffset(i);\n      let boxWidth = 0;\n      let boxStart = 0;\n      let drawStart;\n      let currentColor;\n      let lastColor = this.getValueOfPropertyAt(i, 0, 'textBackgroundColor');\n      for (let j = 0; j < jlen; j++) {\n        // at this point charbox are either standard or full with pathInfo if there is a path.\n        const charBox = this.__charBounds[i][j] as Required<GraphemeBBox>;\n        currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');\n        // James modified\n        if (this.path && !this.isEditing) {\n          ctx.save();\n          ctx.translate(charBox.renderLeft, charBox.renderTop);\n          ctx.rotate(charBox.angle);\n          ctx.fillStyle = currentColor;\n          currentColor &&\n            ctx.fillRect(\n              -charBox.width / 2,\n              (-heightOfLine / this.lineHeight) * (1 - this._fontSizeFraction),\n              charBox.width,\n              heightOfLine / this.lineHeight,\n            );\n          ctx.restore();\n        } else if (currentColor !== lastColor) {\n          drawStart = leftOffset + lineLeftOffset + boxStart;\n          if (this.direction === 'rtl') {\n            drawStart = this.width - drawStart - boxWidth;\n          }\n          ctx.fillStyle = lastColor;\n          lastColor &&\n            ctx.fillRect(\n              drawStart,\n              lineTopOffset,\n              boxWidth,\n              heightOfLine / this.lineHeight,\n            );\n          boxStart = charBox.left;\n          boxWidth = charBox.width;\n          lastColor = currentColor;\n        } else {\n          boxWidth += charBox.kernedWidth;\n        }\n      }\n      if (currentColor && !this.path) {\n        drawStart = leftOffset + lineLeftOffset + boxStart;\n        if (this.direction === 'rtl') {\n          drawStart = this.width - drawStart - boxWidth;\n        }\n        ctx.fillStyle = currentColor;\n        ctx.fillRect(\n          drawStart,\n          lineTopOffset,\n          boxWidth,\n          heightOfLine / this.lineHeight,\n        );\n      }\n      lineTopOffset += heightOfLine;\n    }\n    ctx.fillStyle = originalFill;\n    // if there is text background color no\n    // other shadows should be casted\n    this._removeShadow(ctx);\n  }\n\n  /**\n   * measure and return the width of a single character.\n   * possibly overridden to accommodate different measure logic or\n   * to hook some external lib for character measurement\n   * @private\n   * @param {String} _char, char to be measured\n   * @param {Object} charStyle style of char to be measured\n   * @param {String} [previousChar] previous char\n   * @param {Object} [prevCharStyle] style of previous char\n   */\n  _measureChar(\n    _char: string,\n    charStyle: CompleteTextStyleDeclaration,\n    previousChar: string | undefined,\n    prevCharStyle: CompleteTextStyleDeclaration | Record<string, never>,\n  ) {\n    const fontCache = cache.getFontCache(charStyle),\n      fontDeclaration = this._getFontDeclaration(charStyle),\n      couple = previousChar + _char,\n      stylesAreEqual =\n        previousChar &&\n        fontDeclaration === this._getFontDeclaration(prevCharStyle),\n      fontMultiplier = charStyle.fontSize / this.CACHE_FONT_SIZE;\n    let width: number | undefined,\n      coupleWidth: number | undefined,\n      previousWidth: number | undefined,\n      kernedWidth: number | undefined;\n\n    if (previousChar && fontCache[previousChar] !== undefined) {\n      previousWidth = fontCache[previousChar];\n    }\n    if (fontCache[_char] !== undefined) {\n      kernedWidth = width = fontCache[_char];\n    }\n    if (stylesAreEqual && fontCache[couple] !== undefined) {\n      coupleWidth = fontCache[couple];\n      kernedWidth = coupleWidth - previousWidth!;\n    }\n    if (\n      width === undefined ||\n      previousWidth === undefined ||\n      coupleWidth === undefined\n    ) {\n      const ctx = getMeasuringContext()!;\n      // send a TRUE to specify measuring font size CACHE_FONT_SIZE\n      this._setTextStyles(ctx, charStyle, true);\n      if (width === undefined) {\n        kernedWidth = width = ctx.measureText(_char).width;\n        fontCache[_char] = width;\n      }\n      if (previousWidth === undefined && stylesAreEqual && previousChar) {\n        previousWidth = ctx.measureText(previousChar).width;\n        fontCache[previousChar] = previousWidth;\n      }\n      if (stylesAreEqual && coupleWidth === undefined) {\n        // we can measure the kerning couple and subtract the width of the previous character\n        coupleWidth = ctx.measureText(couple).width;\n        fontCache[couple] = coupleWidth;\n        // safe to use the non-null since if undefined we defined it before.\n        kernedWidth = coupleWidth - previousWidth!;\n      }\n    }\n    return {\n      width: width * fontMultiplier,\n      kernedWidth: kernedWidth! * fontMultiplier,\n    };\n  }\n\n  /**\n   * Computes height of character at given position\n   * @param {Number} line the line index number\n   * @param {Number} _char the character index number\n   * @return {Number} fontSize of the character\n   */\n  getHeightOfChar(line: number, _char: number): number {\n    return this.getValueOfPropertyAt(line, _char, 'fontSize');\n  }\n\n  /**\n   * measure a text line measuring all characters.\n   * @param {Number} lineIndex line number\n   */\n  measureLine(lineIndex: number) {\n    const lineInfo = this._measureLine(lineIndex);\n    if (this.charSpacing !== 0) {\n      lineInfo.width -= this._getWidthOfCharSpacing();\n    }\n    if (lineInfo.width < 0) {\n      lineInfo.width = 0;\n    }\n    return lineInfo;\n  }\n\n  /**\n   * measure every grapheme of a line, populating __charBounds\n   * @param {Number} lineIndex\n   * @return {Object} object.width total width of characters\n   * @return {Object} object.numOfSpaces length of chars that match this._reSpacesAndTabs\n   */\n  _measureLine(lineIndex: number) {\n    let width = 0,\n      prevGrapheme: string | undefined,\n      graphemeInfo: GraphemeBBox | undefined;\n\n    const reverse = this.pathSide === RIGHT,\n      path = this.path,\n      line = this._textLines[lineIndex],\n      llength = line.length,\n      lineBounds = new Array<GraphemeBBox>(llength);\n\n    this.__charBounds[lineIndex] = lineBounds;\n    for (let i = 0; i < llength; i++) {\n      const grapheme = line[i];\n      graphemeInfo = this._getGraphemeBox(grapheme, lineIndex, i, prevGrapheme);\n      lineBounds[i] = graphemeInfo;\n      width += graphemeInfo.kernedWidth;\n      prevGrapheme = grapheme;\n    }\n    // this latest bound box represent the last character of the line\n    // to simplify cursor handling in interactive mode.\n    lineBounds[llength] = {\n      left: graphemeInfo ? graphemeInfo.left + graphemeInfo.width : 0,\n      width: 0,\n      kernedWidth: 0,\n      height: this.fontSize,\n      deltaY: 0,\n    } as GraphemeBBox;\n    if (path && path.segmentsInfo) {\n      let positionInPath = 0;\n      const totalPathLength =\n        path.segmentsInfo[path.segmentsInfo.length - 1].length;\n      switch (this.textAlign) {\n        case LEFT:\n          positionInPath = reverse ? totalPathLength - width : 0;\n          break;\n        case CENTER:\n          positionInPath = (totalPathLength - width) / 2;\n          break;\n        case RIGHT:\n          positionInPath = reverse ? 0 : totalPathLength - width;\n          break;\n        //todo - add support for justify\n      }\n      positionInPath += this.pathStartOffset * (reverse ? -1 : 1);\n      for (\n        let i = reverse ? llength - 1 : 0;\n        reverse ? i >= 0 : i < llength;\n        reverse ? i-- : i++\n      ) {\n        graphemeInfo = lineBounds[i];\n\n        // James modified\n        /* if (positionInPath > totalPathLength) {\n          positionInPath %= totalPathLength;\n        } else if (positionInPath < 0) {\n          positionInPath += totalPathLength;\n        } */\n        // 超过路径范围外不显示\n        var visible = false;\n        var tolerance = 2;\n        if (\n          positionInPath >= 0 - tolerance &&\n          positionInPath + graphemeInfo.kernedWidth <=\n            totalPathLength + tolerance\n        ) {\n          visible = true;\n        }\n        if (visible) {\n          // it would probably much faster to send all the grapheme position for a line\n          // and calculate path position/angle at once.\n          this._setGraphemeOnPath(positionInPath, graphemeInfo);\n        }\n        positionInPath += graphemeInfo.kernedWidth;\n        graphemeInfo.visible = visible;\n      }\n    }\n    return { width: width, numOfSpaces: 0 };\n  }\n\n  /**\n   * Calculate the angle  and the left,top position of the char that follow a path.\n   * It appends it to graphemeInfo to be reused later at rendering\n   * @private\n   * @param {Number} positionInPath to be measured\n   * @param {GraphemeBBox} graphemeInfo current grapheme box information\n   * @param {Object} startingPoint position of the point\n   */\n  _setGraphemeOnPath(positionInPath: number, graphemeInfo: GraphemeBBox) {\n    const centerPosition = positionInPath + graphemeInfo.kernedWidth / 2,\n      path = this.path!;\n\n    // we are at currentPositionOnPath. we want to know what point on the path is.\n    const info = getPointOnPath(path.path, centerPosition, path.segmentsInfo)!;\n    graphemeInfo.renderLeft = info.x - path.pathOffset.x;\n    graphemeInfo.renderTop = info.y - path.pathOffset.y;\n    graphemeInfo.angle = info.angle + (this.pathSide === RIGHT ? Math.PI : 0);\n  }\n\n  /**\n   *\n   * @param {String} grapheme to be measured\n   * @param {Number} lineIndex index of the line where the char is\n   * @param {Number} charIndex position in the line\n   * @param {String} [prevGrapheme] character preceding the one to be measured\n   * @returns {GraphemeBBox} grapheme bbox\n   */\n  _getGraphemeBox(\n    grapheme: string,\n    lineIndex: number,\n    charIndex: number,\n    prevGrapheme?: string,\n    skipLeft?: boolean,\n  ): GraphemeBBox {\n    const style = this.getCompleteStyleDeclaration(lineIndex, charIndex),\n      prevStyle = prevGrapheme\n        ? this.getCompleteStyleDeclaration(lineIndex, charIndex - 1)\n        : {},\n      info = this._measureChar(grapheme, style, prevGrapheme, prevStyle);\n    let kernedWidth = info.kernedWidth,\n      width = info.width,\n      charSpacing;\n\n    if (this.charSpacing !== 0) {\n      charSpacing = this._getWidthOfCharSpacing();\n      width += charSpacing;\n      kernedWidth += charSpacing;\n    }\n\n    const box: GraphemeBBox = {\n      width,\n      left: 0,\n      height: style.fontSize,\n      kernedWidth,\n      deltaY: style.deltaY,\n    };\n    if (charIndex > 0 && !skipLeft) {\n      const previousBox = this.__charBounds[lineIndex][charIndex - 1];\n      box.left =\n        previousBox.left + previousBox.width + info.kernedWidth - info.width;\n    }\n    return box;\n  }\n\n  /**\n   * Calculate height of line at 'lineIndex'\n   * @param {Number} lineIndex index of line to calculate\n   * @return {Number}\n   */\n  getHeightOfLine(lineIndex: number): number {\n    if (this.__lineHeights[lineIndex]) {\n      return this.__lineHeights[lineIndex];\n    }\n\n    // char 0 is measured before the line cycle because it needs to char\n    // emptylines\n    let maxHeight = this.getHeightOfChar(lineIndex, 0);\n    for (let i = 1, len = this._textLines[lineIndex].length; i < len; i++) {\n      maxHeight = Math.max(this.getHeightOfChar(lineIndex, i), maxHeight);\n    }\n\n    return (this.__lineHeights[lineIndex] =\n      maxHeight * this.lineHeight * this._fontSizeMult);\n  }\n\n  /**\n   * Calculate text box height\n   */\n  calcTextHeight() {\n    let lineHeight,\n      height = 0;\n    for (let i = 0, len = this._textLines.length; i < len; i++) {\n      lineHeight = this.getHeightOfLine(i);\n      height += i === len - 1 ? lineHeight / this.lineHeight : lineHeight;\n    }\n    return height;\n  }\n\n  /**\n   * @private\n   * @return {Number} Left offset\n   */\n  _getLeftOffset(): number {\n    return this.direction === 'ltr' ? -this.width / 2 : this.width / 2;\n  }\n\n  /**\n   * @private\n   * @return {Number} Top offset\n   */\n  _getTopOffset(): number {\n    return -this.height / 2;\n  }\n\n  /**\n   * James add\n   * 是否应该按行隐藏文字\n   * @returns\n   */\n  _shouldHideTextLine() {\n    return !this.isEditing && !this.path;\n  }\n\n  /**\n   * James modified\n   * 框子外的文字不绘制\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   * @param {String} method Method name (\"fillText\" or \"strokeText\")\n   */\n  _renderTextCommon(\n    ctx: CanvasRenderingContext2D,\n    method: 'fillText' | 'strokeText',\n  ) {\n    ctx.save();\n    let lineHeights = 0;\n    const left = this._getLeftOffset(),\n      top = this._getTopOffset();\n\n    // 存在隐藏文字\n    this.hasHideText = false;\n    for (let i = 0, len = this._textLines.length; i < len; i++) {\n      const heightOfLine = this.getHeightOfLine(i),\n        maxHeight = heightOfLine / this.lineHeight,\n        leftOffset = this._getLineLeftOffset(i);\n\n      // 非编辑状态超过box 不显示\n      if (\n        this._shouldHideTextLine() &&\n        lineHeights + maxHeight * 0.8 > this.height\n      ) {\n        this.hasHideText = true;\n        break;\n      }\n\n      this._renderTextLine(\n        method,\n        ctx,\n        this._textLines[i],\n        left + leftOffset,\n        top + lineHeights + maxHeight,\n        i,\n      );\n      lineHeights += heightOfLine;\n    }\n    ctx.restore();\n  }\n\n  /**\n   * James add\n   * 增加隐藏文字图标\n   */\n  showHideTextIcon() {\n    const control = this.controls?.['mb'];\n    if (control) {\n      control.render = (ctx, left, top, styleOverride, fabricObject) => {\n        styleOverride = styleOverride || {};\n        if (this.hasHideText) {\n          styleOverride = {\n            ...styleOverride,\n            cornerStrokeColor: '#FF0000',\n            cornerSize: 10,\n          };\n        }\n        switch (styleOverride.cornerStyle || fabricObject.cornerStyle) {\n          case 'circle':\n            renderCircleControl.call(\n              control,\n              ctx,\n              left,\n              top,\n              styleOverride,\n              fabricObject,\n            );\n            break;\n          default:\n            renderSquareControl.call(\n              control,\n              ctx,\n              left,\n              top,\n              styleOverride,\n              fabricObject,\n            );\n        }\n      };\n    }\n  }\n\n  /**\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   */\n  _renderTextFill(ctx: CanvasRenderingContext2D) {\n    if (!this.fill && !this.styleHas(FILL)) {\n      return;\n    }\n\n    this._renderTextCommon(ctx, 'fillText');\n  }\n\n  /**\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   */\n  _renderTextStroke(ctx: CanvasRenderingContext2D) {\n    if ((!this.stroke || this.strokeWidth === 0) && this.isEmptyStyles()) {\n      return;\n    }\n\n    if (this.shadow && !this.shadow.affectStroke) {\n      this._removeShadow(ctx);\n    }\n\n    ctx.save();\n    this._setLineDash(ctx, this.strokeDashArray);\n    ctx.beginPath();\n    this._renderTextCommon(ctx, 'strokeText');\n    ctx.closePath();\n    ctx.restore();\n  }\n\n  /**\n   * @private\n   * @param {String} method fillText or strokeText.\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   * @param {Array} line Content of the line, splitted in an array by grapheme\n   * @param {Number} left\n   * @param {Number} top\n   * @param {Number} lineIndex\n   */\n  _renderChars(\n    method: 'fillText' | 'strokeText',\n    ctx: CanvasRenderingContext2D,\n    line: Array<any>,\n    left: number,\n    top: number,\n    lineIndex: number,\n  ) {\n    const lineHeight = this.getHeightOfLine(lineIndex),\n      isJustify = this.textAlign.includes(JUSTIFY),\n      path = this.path,\n      shortCut =\n        !isJustify &&\n        this.charSpacing === 0 &&\n        this.isEmptyStyles(lineIndex) &&\n        !path,\n      isLtr = this.direction === 'ltr',\n      sign = this.direction === 'ltr' ? 1 : -1,\n      // James modified\n      // 修改为之前绘制 direction rtl的方式，5.3.0版本的绘制方式显示有问题\n      // this was changed in the PR #7674\n      // currentDirection = ctx.canvas.getAttribute('dir');\n      currentDirection = ctx.direction;\n\n    let actualStyle,\n      nextStyle,\n      charsToRender = '',\n      charBox,\n      boxWidth = 0,\n      timeToRender,\n      drawingLeft;\n\n    ctx.save();\n    if (currentDirection !== this.direction) {\n      ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');\n      // James modified\n      ctx.direction = isLtr ? 'ltr' : 'rtl';\n      ctx.textAlign = isLtr ? LEFT : RIGHT;\n    }\n    top -= (lineHeight * this._fontSizeFraction) / this.lineHeight;\n    if (shortCut) {\n      // render all the line in one pass without checking\n      // drawingLeft = isLtr ? left : left - this.getLineWidth(lineIndex);\n      // James modified\n      this._renderChar(method, ctx, lineIndex, 0, line.join(''), left, top);\n      ctx.restore();\n      return;\n    }\n    for (let i = 0, len = line.length - 1; i <= len; i++) {\n      timeToRender = i === len || this.charSpacing || path;\n      charsToRender += line[i];\n      charBox = this.__charBounds[lineIndex][i] as Required<GraphemeBBox>;\n      if (boxWidth === 0) {\n        left += sign * (charBox.kernedWidth - charBox.width);\n        boxWidth += charBox.width;\n      } else {\n        boxWidth += charBox.kernedWidth;\n      }\n      if (isJustify && !timeToRender) {\n        if (this._reSpaceAndTab.test(line[i])) {\n          timeToRender = true;\n        }\n      }\n      if (!timeToRender) {\n        // if we have charSpacing, we render char by char\n        actualStyle =\n          actualStyle || this.getCompleteStyleDeclaration(lineIndex, i);\n        nextStyle = this.getCompleteStyleDeclaration(lineIndex, i + 1);\n        timeToRender = hasStyleChanged(actualStyle, nextStyle, false);\n      }\n      if (timeToRender) {\n        // James modified\n        if (path && !this.isEditing) {\n          if (charBox.visible) {\n            ctx.save();\n            ctx.translate(charBox.renderLeft, charBox.renderTop);\n            ctx.rotate(charBox.angle);\n            this._renderChar(\n              method,\n              ctx,\n              lineIndex,\n              i,\n              charsToRender,\n              -boxWidth / 2,\n              0,\n            );\n            ctx.restore();\n          }\n        } else {\n          drawingLeft = left;\n          this._renderChar(\n            method,\n            ctx,\n            lineIndex,\n            i,\n            charsToRender,\n            drawingLeft,\n            top,\n          );\n        }\n        charsToRender = '';\n        actualStyle = nextStyle;\n        left += sign * boxWidth;\n        boxWidth = 0;\n      }\n    }\n    ctx.restore();\n  }\n\n  /**\n   * This function try to patch the missing gradientTransform on canvas gradients.\n   * transforming a context to transform the gradient, is going to transform the stroke too.\n   * we want to transform the gradient but not the stroke operation, so we create\n   * a transformed gradient on a pattern and then we use the pattern instead of the gradient.\n   * this method has drawbacks: is slow, is in low resolution, needs a patch for when the size\n   * is limited.\n   * @private\n   * @param {TFiller} filler a fabric gradient instance\n   * @return {CanvasPattern} a pattern to use as fill/stroke style\n   */\n  _applyPatternGradientTransformText(filler: TFiller) {\n    // TODO: verify compatibility with strokeUniform\n    const width = this.width + this.strokeWidth,\n      height = this.height + this.strokeWidth,\n      pCanvas = createCanvasElementFor({\n        width,\n        height,\n      }),\n      pCtx = pCanvas.getContext('2d')!;\n    pCanvas.width = width;\n    pCanvas.height = height;\n    pCtx.beginPath();\n    pCtx.moveTo(0, 0);\n    pCtx.lineTo(width, 0);\n    pCtx.lineTo(width, height);\n    pCtx.lineTo(0, height);\n    pCtx.closePath();\n    pCtx.translate(width / 2, height / 2);\n    pCtx.fillStyle = filler.toLive(pCtx)!;\n    this._applyPatternGradientTransform(pCtx, filler);\n    pCtx.fill();\n    return pCtx.createPattern(pCanvas, 'no-repeat')!;\n  }\n\n  handleFiller<T extends 'fill' | 'stroke'>(\n    ctx: CanvasRenderingContext2D,\n    property: `${T}Style`,\n    filler: TFiller | string,\n  ): { offsetX: number; offsetY: number } {\n    let offsetX: number, offsetY: number;\n    if (isFiller(filler)) {\n      if (\n        (filler as Gradient<'linear'>).gradientUnits === 'percentage' ||\n        (filler as Gradient<'linear'>).gradientTransform ||\n        (filler as Pattern).patternTransform\n      ) {\n        // need to transform gradient in a pattern.\n        // this is a slow process. If you are hitting this codepath, and the object\n        // is not using caching, you should consider switching it on.\n        // we need a canvas as big as the current object caching canvas.\n        offsetX = -this.width / 2;\n        offsetY = -this.height / 2;\n        ctx.translate(offsetX, offsetY);\n        ctx[property] = this._applyPatternGradientTransformText(filler);\n        return { offsetX, offsetY };\n      } else {\n        // is a simple gradient or pattern\n        ctx[property] = filler.toLive(ctx)!;\n        return this._applyPatternGradientTransform(ctx, filler);\n      }\n    } else {\n      // is a color\n      ctx[property] = filler;\n    }\n    return { offsetX: 0, offsetY: 0 };\n  }\n\n  /**\n   * This function prepare the canvas for a stroke style, and stroke and strokeWidth\n   * need to be sent in as defined\n   * @param {CanvasRenderingContext2D} ctx\n   * @param {CompleteTextStyleDeclaration} style with stroke and strokeWidth defined\n   * @returns\n   */\n  _setStrokeStyles(\n    ctx: CanvasRenderingContext2D,\n    {\n      stroke,\n      strokeWidth,\n    }: Pick<CompleteTextStyleDeclaration, 'stroke' | 'strokeWidth'>,\n  ) {\n    ctx.lineWidth = strokeWidth;\n    ctx.lineCap = this.strokeLineCap;\n    ctx.lineDashOffset = this.strokeDashOffset;\n    ctx.lineJoin = this.strokeLineJoin;\n    ctx.miterLimit = this.strokeMiterLimit;\n    return this.handleFiller(ctx, 'strokeStyle', stroke!);\n  }\n\n  /**\n   * This function prepare the canvas for a ill style, and fill\n   * need to be sent in as defined\n   * @param {CanvasRenderingContext2D} ctx\n   * @param {CompleteTextStyleDeclaration} style with ill defined\n   * @returns\n   */\n  _setFillStyles(ctx: CanvasRenderingContext2D, { fill }: Pick<this, 'fill'>) {\n    return this.handleFiller(ctx, 'fillStyle', fill!);\n  }\n\n  /**\n   * @private\n   * @param {String} method\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   * @param {Number} lineIndex\n   * @param {Number} charIndex\n   * @param {String} _char\n   * @param {Number} left Left coordinate\n   * @param {Number} top Top coordinate\n   * @param {Number} lineHeight Height of the line\n   */\n  _renderChar(\n    method: 'fillText' | 'strokeText',\n    ctx: CanvasRenderingContext2D,\n    lineIndex: number,\n    charIndex: number,\n    _char: string,\n    left: number,\n    top: number,\n  ) {\n    const decl = this._getStyleDeclaration(lineIndex, charIndex),\n      fullDecl = this.getCompleteStyleDeclaration(lineIndex, charIndex),\n      shouldFill = method === 'fillText' && fullDecl.fill,\n      shouldStroke =\n        method === 'strokeText' && fullDecl.stroke && fullDecl.strokeWidth;\n\n    if (!shouldStroke && !shouldFill) {\n      return;\n    }\n    ctx.save();\n\n    ctx.font = this._getFontDeclaration(fullDecl);\n\n    if (decl.textBackgroundColor) {\n      this._removeShadow(ctx);\n    }\n    if (decl.deltaY) {\n      top += decl.deltaY;\n    }\n\n    if (shouldFill) {\n      const fillOffsets = this._setFillStyles(ctx, fullDecl);\n      ctx.fillText(\n        _char,\n        left - fillOffsets.offsetX,\n        top - fillOffsets.offsetY,\n      );\n    }\n\n    if (shouldStroke) {\n      const strokeOffsets = this._setStrokeStyles(ctx, fullDecl);\n      ctx.strokeText(\n        _char,\n        left - strokeOffsets.offsetX,\n        top - strokeOffsets.offsetY,\n      );\n    }\n\n    ctx.restore();\n  }\n\n  /**\n   * Turns the character into a 'superior figure' (i.e. 'superscript')\n   * @param {Number} start selection start\n   * @param {Number} end selection end\n   */\n  setSuperscript(start: number, end: number) {\n    this._setScript(start, end, this.superscript);\n  }\n\n  /**\n   * Turns the character into an 'inferior figure' (i.e. 'subscript')\n   * @param {Number} start selection start\n   * @param {Number} end selection end\n   */\n  setSubscript(start: number, end: number) {\n    this._setScript(start, end, this.subscript);\n  }\n\n  /**\n   * Applies 'schema' at given position\n   * @private\n   * @param {Number} start selection start\n   * @param {Number} end selection end\n   * @param {Number} schema\n   */\n  protected _setScript(\n    start: number,\n    end: number,\n    schema: {\n      size: number;\n      baseline: number;\n    },\n  ) {\n    const loc = this.get2DCursorLocation(start, true),\n      fontSize = this.getValueOfPropertyAt(\n        loc.lineIndex,\n        loc.charIndex,\n        'fontSize',\n      ),\n      dy = this.getValueOfPropertyAt(loc.lineIndex, loc.charIndex, 'deltaY'),\n      style = {\n        fontSize: fontSize * schema.size,\n        deltaY: dy + fontSize * schema.baseline,\n      };\n    this.setSelectionStyles(style, start, end);\n  }\n\n  /**\n   * @private\n   * @param {Number} lineIndex index text line\n   * @return {Number} Line left offset\n   */\n  _getLineLeftOffset(lineIndex: number): number {\n    const lineWidth = this.getLineWidth(lineIndex),\n      lineDiff = this.width - lineWidth,\n      textAlign = this.textAlign,\n      direction = this.direction,\n      isEndOfWrapping = this.isEndOfWrapping(lineIndex);\n    let leftOffset = 0;\n    if (\n      textAlign === JUSTIFY ||\n      (textAlign === JUSTIFY_CENTER && !isEndOfWrapping) ||\n      (textAlign === JUSTIFY_RIGHT && !isEndOfWrapping) ||\n      (textAlign === JUSTIFY_LEFT && !isEndOfWrapping)\n    ) {\n      return 0;\n    }\n    if (textAlign === CENTER) {\n      leftOffset = lineDiff / 2;\n    }\n    if (textAlign === RIGHT) {\n      leftOffset = lineDiff;\n    }\n    if (textAlign === JUSTIFY_CENTER) {\n      leftOffset = lineDiff / 2;\n    }\n    if (textAlign === JUSTIFY_RIGHT) {\n      leftOffset = lineDiff;\n    }\n    if (direction === 'rtl') {\n      if (\n        textAlign === RIGHT ||\n        textAlign === JUSTIFY ||\n        textAlign === JUSTIFY_RIGHT\n      ) {\n        leftOffset = 0;\n      } else if (textAlign === LEFT || textAlign === JUSTIFY_LEFT) {\n        leftOffset = -lineDiff;\n      } else if (textAlign === CENTER || textAlign === JUSTIFY_CENTER) {\n        leftOffset = -lineDiff / 2;\n      }\n    }\n    return leftOffset;\n  }\n\n  /**\n   * @private\n   */\n  _clearCache() {\n    this._forceClearCache = false;\n    this.__lineWidths = [];\n    this.__lineHeights = [];\n    this.__charBounds = [];\n  }\n\n  /**\n   * Measure a single line given its index. Used to calculate the initial\n   * text bounding box. The values are calculated and stored in __lineWidths cache.\n   * @private\n   * @param {Number} lineIndex line number\n   * @return {Number} Line width\n   */\n  getLineWidth(lineIndex: number): number {\n    if (this.__lineWidths[lineIndex] !== undefined) {\n      return this.__lineWidths[lineIndex];\n    }\n\n    const { width } = this.measureLine(lineIndex);\n    this.__lineWidths[lineIndex] = width;\n    return width;\n  }\n\n  _getWidthOfCharSpacing() {\n    if (this.charSpacing !== 0) {\n      return (this.fontSize * this.charSpacing) / 1000;\n    }\n    return 0;\n  }\n\n  /**\n   * Retrieves the value of property at given character position\n   * @param {Number} lineIndex the line number\n   * @param {Number} charIndex the character number\n   * @param {String} property the property name\n   * @returns the value of 'property'\n   */\n  getValueOfPropertyAt<T extends StylePropertiesType>(\n    lineIndex: number,\n    charIndex: number,\n    property: T,\n  ): this[T] {\n    const charStyle = this._getStyleDeclaration(lineIndex, charIndex);\n    return (charStyle[property] ?? this[property]) as this[T];\n  }\n\n  /**\n   * @private\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   */\n  _renderTextDecoration(\n    ctx: CanvasRenderingContext2D,\n    type: 'underline' | 'linethrough' | 'overline',\n  ) {\n    if (!this[type] && !this.styleHas(type)) {\n      return;\n    }\n    let topOffset = this._getTopOffset();\n    const leftOffset = this._getLeftOffset(),\n      path = this.path,\n      charSpacing = this._getWidthOfCharSpacing(),\n      offsetAligner =\n        type === 'linethrough' ? 0.5 : type === 'overline' ? 1 : 0,\n      offsetY = this.offsets[type];\n    for (let i = 0, len = this._textLines.length; i < len; i++) {\n      const heightOfLine = this.getHeightOfLine(i);\n      if (!this[type] && !this.styleHas(type, i)) {\n        topOffset += heightOfLine;\n        continue;\n      }\n      const line = this._textLines[i];\n      const maxHeight = heightOfLine / this.lineHeight;\n      const lineLeftOffset = this._getLineLeftOffset(i);\n      let boxStart = 0;\n      let boxWidth = 0;\n      let lastDecoration = this.getValueOfPropertyAt(i, 0, type);\n      let lastFill = this.getValueOfPropertyAt(i, 0, FILL);\n      let lastTickness = this.getValueOfPropertyAt(\n        i,\n        0,\n        TEXT_DECORATION_THICKNESS,\n      );\n      let currentDecoration = lastDecoration;\n      let currentFill = lastFill;\n      let currentTickness = lastTickness;\n      const top = topOffset + maxHeight * (1 - this._fontSizeFraction);\n      let size = this.getHeightOfChar(i, 0);\n      let dy = this.getValueOfPropertyAt(i, 0, 'deltaY');\n      for (let j = 0, jlen = line.length; j < jlen; j++) {\n        const charBox = this.__charBounds[i][j] as Required<GraphemeBBox>;\n        currentDecoration = this.getValueOfPropertyAt(i, j, type);\n        currentFill = this.getValueOfPropertyAt(i, j, FILL);\n        currentTickness = this.getValueOfPropertyAt(\n          i,\n          j,\n          TEXT_DECORATION_THICKNESS,\n        );\n        const currentSize = this.getHeightOfChar(i, j);\n        const currentDy = this.getValueOfPropertyAt(i, j, 'deltaY');\n        if (path && currentDecoration && currentFill) {\n          const finalTickness = (this.fontSize * currentTickness) / 1000;\n          ctx.save();\n          // bug? verify lastFill is a valid fill here.\n          ctx.fillStyle = lastFill as string;\n          ctx.translate(charBox.renderLeft, charBox.renderTop);\n          ctx.rotate(charBox.angle);\n          ctx.fillRect(\n            -charBox.kernedWidth / 2,\n            offsetY * currentSize + currentDy - offsetAligner * finalTickness,\n            charBox.kernedWidth,\n            finalTickness,\n          );\n          ctx.restore();\n        } else if (\n          (currentDecoration !== lastDecoration ||\n            currentFill !== lastFill ||\n            currentSize !== size ||\n            currentTickness !== lastTickness ||\n            currentDy !== dy) &&\n          boxWidth > 0\n        ) {\n          const finalTickness = (this.fontSize * lastTickness) / 1000;\n          let drawStart = leftOffset + lineLeftOffset + boxStart;\n          if (this.direction === 'rtl') {\n            drawStart = this.width - drawStart - boxWidth;\n          }\n          if (lastDecoration && lastFill && lastTickness) {\n            // bug? verify lastFill is a valid fill here.\n            ctx.fillStyle = lastFill as string;\n            ctx.fillRect(\n              drawStart,\n              top + offsetY * size + dy - offsetAligner * finalTickness,\n              boxWidth,\n              finalTickness,\n            );\n          }\n          boxStart = charBox.left;\n          boxWidth = charBox.width;\n          lastDecoration = currentDecoration;\n          lastTickness = currentTickness;\n          lastFill = currentFill;\n          size = currentSize;\n          dy = currentDy;\n        } else {\n          boxWidth += charBox.kernedWidth;\n        }\n      }\n      let drawStart = leftOffset + lineLeftOffset + boxStart;\n      if (this.direction === 'rtl') {\n        drawStart = this.width - drawStart - boxWidth;\n      }\n      ctx.fillStyle = currentFill as string;\n      const finalTickness = (this.fontSize * currentTickness) / 1000;\n      currentDecoration &&\n        currentFill &&\n        currentTickness &&\n        ctx.fillRect(\n          drawStart,\n          top + offsetY * size + dy - offsetAligner * finalTickness,\n          boxWidth - charSpacing,\n          finalTickness,\n        );\n      topOffset += heightOfLine;\n    }\n    // if there is text background color no\n    // other shadows should be casted\n    this._removeShadow(ctx);\n  }\n\n  /**\n   * return font declaration string for canvas context\n   * @param {Object} [styleObject] object\n   * @returns {String} font declaration formatted for canvas context.\n   */\n  _getFontDeclaration(\n    {\n      fontFamily = this.fontFamily,\n      fontStyle = this.fontStyle,\n      fontWeight = this.fontWeight,\n      fontSize = this.fontSize,\n    }: Partial<\n      Pick<\n        TextStyleDeclaration,\n        'fontFamily' | 'fontStyle' | 'fontWeight' | 'fontSize'\n      >\n    > = {},\n    forMeasuring?: boolean,\n  ): string {\n    const parsedFontFamily =\n      fontFamily.includes(\"'\") ||\n      fontFamily.includes('\"') ||\n      fontFamily.includes(',') ||\n      FabricText.genericFonts.includes(fontFamily.toLowerCase())\n        ? fontFamily\n        : `\"${fontFamily}\"`;\n    return [\n      fontStyle,\n      fontWeight,\n      `${forMeasuring ? this.CACHE_FONT_SIZE : fontSize}px`,\n      parsedFontFamily,\n    ].join(' ');\n  }\n\n  /**\n   * Renders text instance on a specified context\n   * @param {CanvasRenderingContext2D} ctx Context to render on\n   */\n  render(ctx: CanvasRenderingContext2D) {\n    if (!this.visible) {\n      return;\n    }\n    if (\n      this.canvas &&\n      this.canvas.skipOffscreen &&\n      !this.group &&\n      !this.isOnScreen()\n    ) {\n      return;\n    }\n    if (this._forceClearCache) {\n      this.initDimensions();\n    }\n    super.render(ctx);\n  }\n\n  /**\n   * Override this method to customize grapheme splitting\n   * @todo the util `graphemeSplit` needs to be injectable in some way.\n   * is more comfortable to inject the correct util rather than having to override text\n   * in the middle of the prototype chain\n   * @param {string} value\n   * @returns {string[]} array of graphemes\n   */\n  graphemeSplit(value: string): string[] {\n    return graphemeSplit(value);\n  }\n\n  /**\n   * Returns the text as an array of lines.\n   * @param {String} text text to split\n   * @returns  Lines in the text\n   */\n  _splitTextIntoLines(text: string): TextLinesInfo {\n    // James modified 生成换行数据， 如果是path则不进行换行(删除换行字符)\n    text = this.path ? text.replaceAll(/\\r?\\n/g, '') : text;\n    const lines = text.split(this._reNewline),\n      newLines = new Array<string[]>(lines.length),\n      newLine = ['\\n'];\n    let newText: string[] = [];\n    for (let i = 0; i < lines.length; i++) {\n      newLines[i] = this.graphemeSplit(lines[i]);\n      newText = newText.concat(newLines[i], newLine);\n    }\n    newText.pop();\n    return {\n      _unwrappedLines: newLines,\n      lines: lines,\n      graphemeText: newText,\n      graphemeLines: newLines,\n    };\n  }\n\n  /**\n   * Returns object representation of an instance\n   * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n   * @return {Object} Object representation of an instance\n   */\n  toObject<\n    T extends Omit<Props & TClassProperties<this>, keyof SProps>,\n    K extends keyof T = never,\n  >(propertiesToInclude: K[] = []): Pick<T, K> & SProps {\n    return {\n      ...super.toObject([...additionalProps, ...propertiesToInclude] as K[]),\n      styles: stylesToArray(this.styles, this.text),\n      ...(this.path ? { path: this.path.toObject() } : {}),\n    };\n  }\n\n  set(key: string | any, value?: any) {\n    const { textLayoutProperties } = this.constructor as typeof FabricText;\n    super.set(key, value);\n    let needsDims = false;\n    let isAddingPath = false;\n    if (typeof key === 'object') {\n      for (const _key in key) {\n        if (_key === 'path') {\n          this.setPathInfo();\n        }\n        needsDims = needsDims || textLayoutProperties.includes(_key);\n        isAddingPath = isAddingPath || _key === 'path';\n      }\n    } else {\n      needsDims = textLayoutProperties.includes(key);\n      isAddingPath = key === 'path';\n    }\n    if (isAddingPath) {\n      this.setPathInfo();\n    }\n    if (needsDims && this.initialized) {\n      this.initDimensions();\n      this.setCoords();\n    }\n    return this;\n  }\n\n  /**\n   * Returns complexity of an instance\n   * @return {Number} complexity\n   */\n  complexity(): number {\n    return 1;\n  }\n\n  /**\n   * List of generic font families\n   * @see https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#generic-name\n   */\n  static genericFonts = [\n    'serif',\n    'sans-serif',\n    'monospace',\n    'cursive',\n    'fantasy',\n    'system-ui',\n    'ui-serif',\n    'ui-sans-serif',\n    'ui-monospace',\n    'ui-rounded',\n    'math',\n    'emoji',\n    'fangsong',\n  ];\n\n  /* _FROM_SVG_START_ */\n\n  /**\n   * List of attribute names to account for when parsing SVG element (used by {@link FabricText.fromElement})\n   * @static\n   * @memberOf Text\n   * @see: http://www.w3.org/TR/SVG/text.html#TextElement\n   */\n  static ATTRIBUTE_NAMES = SHARED_ATTRIBUTES.concat(\n    'x',\n    'y',\n    'dx',\n    'dy',\n    'font-family',\n    'font-style',\n    'font-weight',\n    'font-size',\n    'letter-spacing',\n    'text-decoration',\n    'text-anchor',\n  );\n\n  /* _FROM_SVG_END_ */\n\n  /**\n   * Returns FabricText instance from an object representation\n   * @param {Object} object plain js Object to create an instance from\n   * @returns {Promise<FabricText>}\n   */\n  static fromObject<\n    T extends TOptions<SerializedTextProps>,\n    S extends FabricText,\n  >(object: T) {\n    return this._fromObject<S>(\n      {\n        ...object,\n        styles: stylesFromArray(object.styles || {}, object.text),\n      },\n      {\n        extraParam: 'text',\n      },\n    );\n  }\n}\n\napplyMixins(FabricText, [TextSVGExportMixin]);\nclassRegistry.setClass(FabricText);\n"],"names":["measuringContext","FabricText","StyledText","getDefaults","super","ownDefaults","constructor","text","options","_defineProperty","Object","assign","this","setOptions","styles","initialized","path","setPathInfo","initDimensions","setCoords","segmentsInfo","getPathSegmentsInfo","width","height","console","log","undefined","_splitText","newLines","_splitTextIntoLines","textLines","lines","_textLines","graphemeLines","_unwrappedTextLines","_unwrappedLines","_text","graphemeText","_clearCache","dirty","calcTextWidth","cursorWidth","MIN_TEXT_WIDTH","calcTextHeight","textAlign","includes","JUSTIFY","enlargeSpaces","diffSpace","currentLineWidth","numberOfSpaces","accumulatedSpace","line","charBound","spaces","i","len","length","isEndOfWrapping","getLineWidth","match","_reSpacesAndTabs","j","__charBounds","_reSpaceAndTab","test","kernedWidth","left","lineIndex","missingNewlineOffset","_lineIndex","get2DCursorLocation","selectionStart","skipWrapping","charIndex","toString","complexity","fontFamily","_getCacheCanvasDimensions","dims","fontSize","zoomX","zoomY","_render","ctx","isNotVisible","_setTextStyles","_renderTextLinesBackground","_renderTextDecoration","_renderText","paintFirst","STROKE","_renderTextStroke","_renderTextFill","charStyle","forMeasuring","textBaseline","pathAlign","CENTER","TOP","BOTTOM","font","_getFontDeclaration","maxWidth","_renderTextLine","method","top","_renderChars","textBackgroundColor","styleHas","originalFill","fillStyle","leftOffset","_getLeftOffset","lineTopOffset","_getTopOffset","heightOfLine","getHeightOfLine","jlen","lineLeftOffset","_getLineLeftOffset","drawStart","currentColor","boxWidth","boxStart","lastColor","getValueOfPropertyAt","charBox","isEditing","save","translate","renderLeft","renderTop","rotate","angle","fillRect","lineHeight","_fontSizeFraction","restore","direction","_removeShadow","_measureChar","_char","previousChar","prevCharStyle","fontCache","cache","getFontCache","fontDeclaration","couple","stylesAreEqual","fontMultiplier","CACHE_FONT_SIZE","coupleWidth","previousWidth","canvas","createCanvasElementFor","getContext","getMeasuringContext","measureText","getHeightOfChar","measureLine","lineInfo","_measureLine","charSpacing","_getWidthOfCharSpacing","prevGrapheme","graphemeInfo","reverse","pathSide","RIGHT","llength","lineBounds","Array","grapheme","_getGraphemeBox","deltaY","positionInPath","totalPathLength","LEFT","pathStartOffset","visible","_setGraphemeOnPath","numOfSpaces","centerPosition","info","getPointOnPath","x","pathOffset","y","Math","PI","skipLeft","style","getCompleteStyleDeclaration","prevStyle","box","previousBox","__lineHeights","maxHeight","max","_fontSizeMult","_shouldHideTextLine","_renderTextCommon","lineHeights","hasHideText","showHideTextIcon","_this$controls","control","controls","render","styleOverride","fabricObject","cornerStrokeColor","cornerSize","cornerStyle","renderCircleControl","call","renderSquareControl","fill","FILL","stroke","strokeWidth","isEmptyStyles","shadow","affectStroke","_setLineDash","strokeDashArray","beginPath","closePath","isJustify","shortCut","isLtr","sign","currentDirection","actualStyle","nextStyle","timeToRender","drawingLeft","charsToRender","setAttribute","_renderChar","join","hasStyleChanged","_applyPatternGradientTransformText","filler","pCanvas","pCtx","moveTo","lineTo","toLive","_applyPatternGradientTransform","createPattern","handleFiller","property","offsetX","offsetY","isFiller","gradientUnits","gradientTransform","patternTransform","_setStrokeStyles","_ref","lineWidth","lineCap","strokeLineCap","lineDashOffset","strokeDashOffset","lineJoin","strokeLineJoin","miterLimit","strokeMiterLimit","_setFillStyles","_ref2","decl","_getStyleDeclaration","fullDecl","shouldFill","shouldStroke","fillOffsets","fillText","strokeOffsets","strokeText","setSuperscript","start","end","_setScript","superscript","setSubscript","subscript","schema","loc","dy","size","baseline","setSelectionStyles","lineDiff","JUSTIFY_CENTER","JUSTIFY_RIGHT","JUSTIFY_LEFT","_forceClearCache","__lineWidths","_charStyle$property","type","topOffset","offsetAligner","offsets","lastDecoration","lastFill","lastTickness","TEXT_DECORATION_THICKNESS","currentDecoration","currentFill","currentTickness","currentSize","currentDy","finalTickness","fontStyle","fontWeight","arguments","parsedFontFamily","genericFonts","toLowerCase","skipOffscreen","group","isOnScreen","graphemeSplit","value","replaceAll","split","_reNewline","newLine","newText","concat","pop","toObject","propertiesToInclude","additionalProps","stylesToArray","set","key","textLayoutProperties","needsDims","isAddingPath","_key","fromObject","object","_fromObject","stylesFromArray","extraParam","cacheProperties","textDefaultValues","SHARED_ATTRIBUTES","applyMixins","TextSVGExportMixin","classRegistry","setClass"],"mappings":"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"}