Repository: motion-canvas/motion-canvas
File: packages/2d/src/components/Txt.ts (TypeScript)

Code before:
    if (this.lineWidth() <= 0) {
      context.fillText(text, box.x, y);
    } else if (this.strokeFirst()) {
      context.strokeText(text, box.x, y);
      context.fillText(text, box.x, y);
    } else {
      context.fillText(text, box.x, y);
      context.strokeText(text, box.x, y);
    }

    context.restore();
  }

  protected override getCacheBBox(): BBox {
    const cache = super.getCacheBBox();

    if (!this.element.hasChildNodes) return cache;

    const size = this.computedSize();
    const range = document.createRange();
    range.selectNodeContents(this.element);
    const bbox = range.getBoundingClientRect();

    const lineWidth = this.lineWidth();
    // We take the default value of the miterLimit as 10.
    const miterLimitCoefficient = 0.5 * 10;

    return new BBox(
      -size.width / 2,
      -size.height / 2,
      bbox.width,
      bbox.height,
    ).expand(lineWidth * miterLimitCoefficient);
  }

  @computed()
  protected formattedText() {
    Txt.formatter.innerText = this.text();
    return Txt.formatter.innerText;
  }

  protected override updateLayout() {
    this.applyFont();
    this.applyFlex();

    // Make sure the text is aligned correctly even if the text is smaller than
    // the container.
    if (this.justifyContent.isInitial()) {
      this.element.style.justifyContent =
        this.styles.getPropertyValue('text-align');
    }

Review comment (performance):
Also, this coefficient should only be used if `this.lineJoin()` is set to `miter`.
For both `bevel` and `round`, the coefficient can be just `0.5`
```suggestion
    const miterLimitCoefficient = this.lineJoin() === 'miter' ? 0.5 * 10 : 0.5;
```

Code after:
    if (this.lineWidth() <= 0) {
      context.fillText(text, box.x, y);
    } else if (this.strokeFirst()) {
      context.strokeText(text, box.x, y);
      context.fillText(text, box.x, y);
    } else {
      context.fillText(text, box.x, y);
      context.strokeText(text, box.x, y);
    }

    context.restore();
  }

  protected override getCacheBBox(): BBox {
    const size = this.computedSize();
    const range = document.createRange();
    range.selectNodeContents(this.element);
    const bbox = range.getBoundingClientRect();

    const lineWidth = this.lineWidth();
    // We take the default value of the miterLimit as 10.
    const miterLimitCoefficient = this.lineJoin() === 'miter' ? 0.5 * 10 : 0.5;

    return new BBox(
      -size.width / 2,
      -size.height / 2,
      bbox.width,
      bbox.height,
    ).expand(lineWidth * miterLimitCoefficient);
  }

  @computed()
  protected formattedText() {
    Txt.formatter.innerText = this.text();
    return Txt.formatter.innerText;
  }

  protected override updateLayout() {
    this.applyFont();
    this.applyFlex();

    // Make sure the text is aligned correctly even if the text is smaller than
    // the container.
    if (this.justifyContent.isInitial()) {
      this.element.style.justifyContent =
        this.styles.getPropertyValue('text-align');
    }

    const wrap =
      this.styles.whiteSpace !== 'nowrap' && this.styles.whiteSpace !== 'pre';