@postermywall/fabricjs-2 7.1.0-pmw-69 → 7.4.0-pmw-70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vitest-attachments/babbd13e5ebd8c87d4f680401cd695e6d9726cc4.png +0 -0
- package/.vitest-attachments/cf8464e8a89ae803d8259877182f41cb2ace5cbb.png +0 -0
- package/.vitest-attachments/d76689b557e9557f6d3c9a7f0763e94eb8eceb76.png +0 -0
- package/CHANGELOG.md +1 -0
- package/dist/index.js +78 -18
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +4 -4
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +4 -4
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +78 -18
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +76 -17
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +76 -17
- package/dist/index.node.mjs.map +1 -1
- package/dist/package.min.mjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/src/shapes/Text/Text.d.ts +26 -2
- package/dist/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist/src/shapes/Text/Text.min.mjs +1 -1
- package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.mjs +41 -16
- package/dist/src/shapes/Text/Text.mjs.map +1 -1
- package/dist/src/shapes/Text/TextSVGExportMixin.d.ts +12 -0
- package/dist/src/shapes/Text/TextSVGExportMixin.d.ts.map +1 -1
- package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs +2 -2
- package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs.map +1 -1
- package/dist/src/shapes/Text/TextSVGExportMixin.mjs +37 -1
- package/dist/src/shapes/Text/TextSVGExportMixin.mjs.map +1 -1
- package/dist-extensions/src/shapes/Text/Text.d.ts +26 -2
- package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Text/TextSVGExportMixin.d.ts +12 -0
- package/dist-extensions/src/shapes/Text/TextSVGExportMixin.d.ts.map +1 -1
- package/package.json +1 -1
- package/postermywall-fabricjs-2-7.4.0-pmw-70.tgz +0 -0
- package/src/shapes/Text/Text.ts +78 -34
- package/src/shapes/Text/TextSVGExportMixin.ts +62 -1
- package/src/shapes/Text/__screenshots__/TextSVGExportMixin.spec.ts/TextSvgExport-toSVG-toSVG-1.png +0 -0
- package/src/shapes/Text/__screenshots__/TextSVGExportMixin.spec.ts/TextSvgExport-toSVG-toSVG-justified-1.png +0 -0
- package/src/shapes/Text/__screenshots__/TextSVGExportMixin.spec.ts/TextSvgExport-toSVG-toSVG-with-deltaY-1.png +0 -0
- package/src/shapes/Text/__screenshots__/TextSVGExportMixin.spec.ts/TextSvgExport-toSVG-toSVG-with-font-1.png +0 -0
- package/src/shapes/Text/__screenshots__/TextSVGExportMixin.spec.ts/TextSvgExport-toSVG-toSVG-with-font-and-origins-1.png +0 -0
- package/src/shapes/Text/__screenshots__/TextSVGExportMixin.spec.ts/TextSvgExport-toSVG-toSVG-with-multiple-spaces-1.png +0 -0
- package/src/shapes/Text/__screenshots__/TextSVGExportMixin.spec.ts/TextSvgExport-toSVG-toSVG-with-text-as-a-clipPath-1.png +0 -0
- package/src/shapes/Text/glyphOverhang.spec.ts +14 -0
- package/src/shapes/Text/svgListMarkers.spec.ts +116 -0
- /package/.vitest-attachments/{0b71b97b594519eb09336f957db6701e064f1e6b.png → 1629802dbea5d4ab7edf7e6f65edc8c84e892e6e.png} +0 -0
- /package/.vitest-attachments/{2f7310caa5815d4e4ed35964597101936fcb397f.png → 23857cd0ba8b7c015d07ea8d7ce12e83dd88818d.png} +0 -0
- /package/{src/shapes/Text/__screenshots__/glyphOverhang.spec.ts/glyph-overhang-widens-a-group-cache-that-caters-for-text-children-by-the-same-reach-1.png → .vitest-attachments/a9d6ab42d2436605fb54e5a753e00e9a55fd6d98.png} +0 -0
- /package/{src/shapes/Text/__screenshots__/glyphOverhang.spec.ts/glyph-overhang-widens-the-text-cache-canvas-by-twice-the-reach-once-it-exceeds-the-font-size-floor-1.png → .vitest-attachments/b895abca787d674e9796cc7d12648978cac129d5.png} +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## [next]
|
|
4
4
|
|
|
5
|
+
- feat(text): export list markers as SVG spans where the canvas draws them, write the gradient definitions of per-character fills, and read a right-to-left line's glyph reach by each glyph's own ink (pmw-70)
|
|
5
6
|
- feat(text): measure each glyph's ink reach and size the text and group caches from it, so swashes and descenders of any font are not cut (pmw-69)
|
|
6
7
|
- Upgrade 7.4.0 [#4](https://github.com/fabricjs/fabric.js/pull/4)
|
|
7
8
|
|
package/dist/index.js
CHANGED
|
@@ -452,7 +452,7 @@
|
|
|
452
452
|
const cache = new Cache();
|
|
453
453
|
//#endregion
|
|
454
454
|
//#region src/constants.ts
|
|
455
|
-
const VERSION = "7.
|
|
455
|
+
const VERSION = "7.4.0-pmw-70";
|
|
456
456
|
function noop() {}
|
|
457
457
|
const halfPI = Math.PI / 2;
|
|
458
458
|
const quarterPI = Math.PI / 4;
|
|
@@ -15862,7 +15862,26 @@
|
|
|
15862
15862
|
var TextSVGExportMixin = class extends FabricObjectSVGExportMixin {
|
|
15863
15863
|
_toSVG() {
|
|
15864
15864
|
const offsets = this._getSVGLeftTopOffsets(), textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);
|
|
15865
|
-
return this._wrapSVGTextAndBg(textAndBg);
|
|
15865
|
+
return [...this._getStyledCharFillerMarkup(), ...this._wrapSVGTextAndBg(textAndBg)];
|
|
15866
|
+
}
|
|
15867
|
+
/**
|
|
15868
|
+
* *PMW* The gradient definitions of per-character fills. The object-level fill is written by
|
|
15869
|
+
* _createBaseSVGMarkup, but a styled character's gradient only ever appeared as a `url(#id)`
|
|
15870
|
+
* reference, so the text rendered black in any SVG consumer.
|
|
15871
|
+
*/
|
|
15872
|
+
_getStyledCharFillerMarkup() {
|
|
15873
|
+
const seen = /* @__PURE__ */ new Set(), markup = [];
|
|
15874
|
+
Object.values(this.styles).forEach((line) => {
|
|
15875
|
+
Object.values(line).forEach((declaration) => {
|
|
15876
|
+
var _declaration$fill;
|
|
15877
|
+
const fill = (_declaration$fill = declaration.fill) !== null && _declaration$fill !== void 0 ? _declaration$fill : null;
|
|
15878
|
+
if (isFiller(fill) && !seen.has(String(fill.id))) {
|
|
15879
|
+
seen.add(String(fill.id));
|
|
15880
|
+
markup.push(fill.toSVG(this));
|
|
15881
|
+
}
|
|
15882
|
+
});
|
|
15883
|
+
});
|
|
15884
|
+
return markup;
|
|
15866
15885
|
}
|
|
15867
15886
|
toSVG(reviver) {
|
|
15868
15887
|
const textSvg = this._createBaseSVGMarkup(this._toSVG(), {
|
|
@@ -15918,6 +15937,7 @@
|
|
|
15918
15937
|
lineOffset = this._getLineLeftOffset(i);
|
|
15919
15938
|
if (this.direction === "rtl") lineOffset += this.width;
|
|
15920
15939
|
if (this.textBackgroundColor || this.styleHas("textBackgroundColor", i)) this._setSVGTextLineBg(textBgRects, i, textLeftOffset + lineOffset, height);
|
|
15940
|
+
this._setSVGListMarker(textSpans, i, textLeftOffset + lineOffset, height);
|
|
15921
15941
|
this._setSVGTextLineText(textSpans, i, textLeftOffset + lineOffset, height);
|
|
15922
15942
|
height += this.getHeightOfLine(i);
|
|
15923
15943
|
}
|
|
@@ -15942,6 +15962,21 @@
|
|
|
15942
15962
|
}
|
|
15943
15963
|
return `<tspan x="${toFixed(left, numFractionDigit)}" y="${toFixed(top, numFractionDigit)}" ${dySpan}${angleAttr}${fillStyles}>${escapeXml(char)}</tspan>`;
|
|
15944
15964
|
}
|
|
15965
|
+
/**
|
|
15966
|
+
* *PMW* The list marker of a visual row as its own span, placed exactly where the canvas
|
|
15967
|
+
* render draws it ({@link FabricText#_getListMarkerPlacement}): the row's text start is the
|
|
15968
|
+
* span's left offset and the row's bottom is its top offset plus the line height.
|
|
15969
|
+
*/
|
|
15970
|
+
_setSVGListMarker(textSpans, lineIndex, textLeftOffset, textTopOffset) {
|
|
15971
|
+
const placed = this._getListMarkerPlacement(lineIndex, textLeftOffset, textTopOffset + this.getHeightOfLineImpl(lineIndex));
|
|
15972
|
+
if (!placed) return;
|
|
15973
|
+
const styleProps = this.getSvgSpanStyles({
|
|
15974
|
+
fontFamily: placed.fontFamily,
|
|
15975
|
+
fontSize: placed.fontSize,
|
|
15976
|
+
fill: placed.fill
|
|
15977
|
+
}, true);
|
|
15978
|
+
textSpans.push(`<tspan x="${toFixed(placed.left, config.NUM_FRACTION_DIGITS)}" y="${toFixed(placed.baseline, config.NUM_FRACTION_DIGITS)}" style="${styleProps}">${escapeXml(placed.marker)}</tspan>`);
|
|
15979
|
+
}
|
|
15945
15980
|
_setSVGTextLineText(textSpans, lineIndex, textLeftOffset, textTopOffset) {
|
|
15946
15981
|
const lineHeight = this.getHeightOfLine(lineIndex), isJustify = this.textAlign.includes(JUSTIFY), line = this._textLines[lineIndex];
|
|
15947
15982
|
let actualStyle, nextStyle, charsToRender = "", charBox, style, boxWidth = 0, timeToRender;
|
|
@@ -16293,7 +16328,8 @@
|
|
|
16293
16328
|
/**
|
|
16294
16329
|
* *PMW* Walks every measured grapheme: horizontally, its ink left of the line start and
|
|
16295
16330
|
* right of the box edge, both after the line's alignment offset (a right-to-left line lays
|
|
16296
|
-
* its graphemes out mirrored, so it
|
|
16331
|
+
* its graphemes out mirrored, so it counts each glyph's reach past its own advance box
|
|
16332
|
+
* instead, with no alignment credit, and reads conservatively);
|
|
16297
16333
|
* vertically, the first line's ink above its baseline and the last line's ink below the
|
|
16298
16334
|
* box bottom. A stroke paints half its width outside the outline on every side.
|
|
16299
16335
|
* @private
|
|
@@ -16307,11 +16343,11 @@
|
|
|
16307
16343
|
let horizontal = 0, vertical = 0, lineTop = 0;
|
|
16308
16344
|
for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {
|
|
16309
16345
|
this.getLineWidth(lineIndex);
|
|
16310
|
-
const bounds = this.__charBounds[lineIndex], isRtl = this.direction === "rtl", leftOffset =
|
|
16346
|
+
const bounds = this.__charBounds[lineIndex], isRtl = this.direction === "rtl", leftOffset = this._getLineLeftOffset(lineIndex), rightEdge = this.width - leftOffset, baselineFromTop = lineTop + this.getHeightOfLineImpl(lineIndex) * (1 - this._fontSizeFraction), roomBelowBaseline = this.height - baselineFromTop;
|
|
16311
16347
|
for (let charIndex = 0; bounds && charIndex < this._textLines[lineIndex].length; charIndex++) {
|
|
16312
16348
|
const box = bounds[charIndex], ink = box.ink;
|
|
16313
16349
|
if (!ink) continue;
|
|
16314
|
-
horizontal = Math.max(horizontal, ink.left - box.left - leftOffset, box.left + ink.right - rightEdge);
|
|
16350
|
+
horizontal = isRtl ? Math.max(horizontal, ink.left, ink.right - box.width) : Math.max(horizontal, ink.left - box.left - leftOffset, box.left + ink.right - rightEdge);
|
|
16315
16351
|
if (lineIndex === 0) vertical = Math.max(vertical, ink.ascent - box.deltaY - baselineFromTop);
|
|
16316
16352
|
if (lineIndex === lineCount - 1) vertical = Math.max(vertical, ink.descent + box.deltaY - roomBelowBaseline);
|
|
16317
16353
|
}
|
|
@@ -16651,6 +16687,7 @@
|
|
|
16651
16687
|
* @param {Number} lineIndex index of line to calculate
|
|
16652
16688
|
* @return {Number}
|
|
16653
16689
|
*/
|
|
16690
|
+
/** *PMW* also read by the SVG export mixin, which is a separate class */
|
|
16654
16691
|
getHeightOfLineImpl(lineIndex) {
|
|
16655
16692
|
const lh = this.__lineHeights;
|
|
16656
16693
|
if (lh[lineIndex]) return lh[lineIndex];
|
|
@@ -17056,27 +17093,50 @@
|
|
|
17056
17093
|
* @private
|
|
17057
17094
|
*/
|
|
17058
17095
|
_renderListMarker(ctx, visualLineIndex, lineDrawLeft, lineDrawTop) {
|
|
17059
|
-
|
|
17060
|
-
if (!
|
|
17061
|
-
const realLineIndex = this._getRealLineIndex(visualLineIndex);
|
|
17062
|
-
const marker = (_this$lineStyles$real2 = this.lineStyles[realLineIndex]) === null || _this$lineStyles$real2 === void 0 ? void 0 : _this$lineStyles$real2.listMarker;
|
|
17063
|
-
if (!marker) return;
|
|
17064
|
-
const { fontSize, fontFamily, fill } = this._getListMarkerStyle(realLineIndex);
|
|
17065
|
-
const gap = LIST_MARKER_GAP_FACTOR * fontSize;
|
|
17066
|
-
const markerLeft = this.direction === "rtl" ? lineDrawLeft + gap : lineDrawLeft - gap - this._measureListMarkerWidth(realLineIndex);
|
|
17096
|
+
const placed = this._getListMarkerPlacement(visualLineIndex, lineDrawLeft, lineDrawTop);
|
|
17097
|
+
if (!placed) return;
|
|
17067
17098
|
ctx.save();
|
|
17068
17099
|
ctx.direction = "ltr";
|
|
17069
17100
|
ctx.textAlign = LEFT;
|
|
17070
17101
|
ctx.font = this._getFontDeclaration({
|
|
17071
|
-
fontSize,
|
|
17072
|
-
fontFamily
|
|
17102
|
+
fontSize: placed.fontSize,
|
|
17103
|
+
fontFamily: placed.fontFamily
|
|
17073
17104
|
});
|
|
17074
|
-
ctx.fillStyle = fill;
|
|
17075
|
-
|
|
17076
|
-
ctx.fillText(String(marker), markerLeft, lineDrawTop - this.getHeightOfLineImpl(visualLineIndex) * this._fontSizeFraction - unorderedMarkerRaise);
|
|
17105
|
+
ctx.fillStyle = placed.fill;
|
|
17106
|
+
ctx.fillText(placed.marker, placed.left, placed.baseline);
|
|
17077
17107
|
ctx.restore();
|
|
17078
17108
|
}
|
|
17079
17109
|
/**
|
|
17110
|
+
* *PMW* Where a visual row's list marker is drawn, in text units, given the row's own draw
|
|
17111
|
+
* anchors (`lineDrawLeft` is the row's text start, `lineDrawTop` its bottom). Shared by the
|
|
17112
|
+
* canvas render and the SVG export so both put the marker in the same place. Null when the
|
|
17113
|
+
* row does not start a listed real line.
|
|
17114
|
+
*
|
|
17115
|
+
* LTR: right-aligned in the LEFT gutter (like the legacy bullets textbox) — the marker's
|
|
17116
|
+
* right edge sits a fixed gap from the text column, so ordinal periods line up and digits
|
|
17117
|
+
* grow left. RTL mirrors: the gutter (and the marker) sit RIGHT of the text, whose draw
|
|
17118
|
+
* anchor is its right edge there. An unordered glyph is raised a little above the baseline.
|
|
17119
|
+
* @private
|
|
17120
|
+
*/
|
|
17121
|
+
_getListMarkerPlacement(visualLineIndex, lineDrawLeft, lineDrawTop) {
|
|
17122
|
+
var _this$lineStyles$real2, _this$lineStyles$real3;
|
|
17123
|
+
if (!this._isStartOfRealLine(visualLineIndex)) return null;
|
|
17124
|
+
const realLineIndex = this._getRealLineIndex(visualLineIndex);
|
|
17125
|
+
const marker = (_this$lineStyles$real2 = this.lineStyles[realLineIndex]) === null || _this$lineStyles$real2 === void 0 ? void 0 : _this$lineStyles$real2.listMarker;
|
|
17126
|
+
if (!marker) return null;
|
|
17127
|
+
const { fontSize, fontFamily, fill } = this._getListMarkerStyle(realLineIndex);
|
|
17128
|
+
const gap = LIST_MARKER_GAP_FACTOR * fontSize;
|
|
17129
|
+
const unorderedMarkerRaise = ((_this$lineStyles$real3 = this.lineStyles[realLineIndex]) === null || _this$lineStyles$real3 === void 0 ? void 0 : _this$lineStyles$real3.listMarkerFontFamily) ? fontSize / UNORDERED_MARKER_RAISE_FACTOR : 0;
|
|
17130
|
+
return {
|
|
17131
|
+
marker: String(marker),
|
|
17132
|
+
fontSize,
|
|
17133
|
+
fontFamily,
|
|
17134
|
+
fill,
|
|
17135
|
+
left: this.direction === "rtl" ? lineDrawLeft + gap : lineDrawLeft - gap - this._measureListMarkerWidth(realLineIndex),
|
|
17136
|
+
baseline: lineDrawTop - this.getHeightOfLineImpl(visualLineIndex) * this._fontSizeFraction - unorderedMarkerRaise
|
|
17137
|
+
};
|
|
17138
|
+
}
|
|
17139
|
+
/**
|
|
17080
17140
|
* *PMW* Sets or clears (align undefined) one real line's alignment override.
|
|
17081
17141
|
*/
|
|
17082
17142
|
setLineAlignment(realLineIndex, align) {
|