@nasser-sw/fabric 7.0.0-beta1 → 7.0.1-beta10
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/0 +0 -0
- package/debug/{konva → konva-master}/CHANGELOG.md +2 -1
- package/debug/{konva → konva-master}/README.md +7 -3
- package/debug/{konva → konva-master}/package.json +1 -1
- package/debug/{konva → konva-master}/release.sh +1 -4
- package/debug/{konva → konva-master}/src/Canvas.ts +37 -0
- package/debug/{konva → konva-master}/src/shapes/Text.ts +2 -2
- package/dist/index.js +2198 -272
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +2198 -272
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +2198 -272
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +2198 -272
- package/dist/index.node.mjs.map +1 -1
- package/dist/package.json.min.mjs +1 -1
- package/dist/package.json.mjs +1 -1
- package/dist/src/shapes/Line.d.ts +33 -86
- package/dist/src/shapes/Line.d.ts.map +1 -1
- package/dist/src/shapes/Line.min.mjs +1 -1
- package/dist/src/shapes/Line.min.mjs.map +1 -1
- package/dist/src/shapes/Line.mjs +405 -159
- package/dist/src/shapes/Line.mjs.map +1 -1
- package/dist/src/shapes/Polyline.d.ts +7 -0
- package/dist/src/shapes/Polyline.d.ts.map +1 -1
- package/dist/src/shapes/Polyline.min.mjs +1 -1
- package/dist/src/shapes/Polyline.min.mjs.map +1 -1
- package/dist/src/shapes/Polyline.mjs +48 -16
- package/dist/src/shapes/Polyline.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.d.ts +19 -0
- 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 +302 -16
- package/dist/src/shapes/Text/Text.mjs.map +1 -1
- package/dist/src/shapes/Textbox.d.ts +56 -1
- package/dist/src/shapes/Textbox.d.ts.map +1 -1
- package/dist/src/shapes/Textbox.min.mjs +1 -1
- package/dist/src/shapes/Textbox.min.mjs.map +1 -1
- package/dist/src/shapes/Textbox.mjs +633 -11
- package/dist/src/shapes/Textbox.mjs.map +1 -1
- package/dist/src/shapes/Triangle.d.ts +27 -2
- package/dist/src/shapes/Triangle.d.ts.map +1 -1
- package/dist/src/shapes/Triangle.min.mjs +1 -1
- package/dist/src/shapes/Triangle.min.mjs.map +1 -1
- package/dist/src/shapes/Triangle.mjs +72 -12
- package/dist/src/shapes/Triangle.mjs.map +1 -1
- package/dist/src/text/examples/arabicTextExample.d.ts +60 -0
- package/dist/src/text/examples/arabicTextExample.d.ts.map +1 -0
- package/dist/src/text/measure.d.ts +9 -0
- package/dist/src/text/measure.d.ts.map +1 -1
- package/dist/src/text/measure.min.mjs +1 -1
- package/dist/src/text/measure.min.mjs.map +1 -1
- package/dist/src/text/measure.mjs +175 -4
- package/dist/src/text/measure.mjs.map +1 -1
- package/dist/src/text/overlayEditor.d.ts +8 -0
- package/dist/src/text/overlayEditor.d.ts.map +1 -1
- package/dist/src/text/overlayEditor.min.mjs +1 -1
- package/dist/src/text/overlayEditor.min.mjs.map +1 -1
- package/dist/src/text/overlayEditor.mjs +395 -56
- package/dist/src/text/overlayEditor.mjs.map +1 -1
- package/dist/src/text/scriptUtils.d.ts +142 -0
- package/dist/src/text/scriptUtils.d.ts.map +1 -0
- package/dist/src/text/scriptUtils.min.mjs +2 -0
- package/dist/src/text/scriptUtils.min.mjs.map +1 -0
- package/dist/src/text/scriptUtils.mjs +212 -0
- package/dist/src/text/scriptUtils.mjs.map +1 -0
- package/dist/src/util/misc/cornerRadius.d.ts +70 -0
- package/dist/src/util/misc/cornerRadius.d.ts.map +1 -0
- package/dist/src/util/misc/cornerRadius.min.mjs +2 -0
- package/dist/src/util/misc/cornerRadius.min.mjs.map +1 -0
- package/dist/src/util/misc/cornerRadius.mjs +181 -0
- package/dist/src/util/misc/cornerRadius.mjs.map +1 -0
- package/dist-extensions/src/shapes/CustomLine.d.ts +10 -0
- package/dist-extensions/src/shapes/CustomLine.d.ts.map +1 -0
- package/dist-extensions/src/shapes/Line.d.ts +33 -86
- package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Polyline.d.ts +7 -0
- package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Text/Text.d.ts +19 -0
- package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Textbox.d.ts +56 -1
- package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Triangle.d.ts +27 -2
- package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
- package/dist-extensions/src/text/measure.d.ts +9 -0
- package/dist-extensions/src/text/measure.d.ts.map +1 -1
- package/dist-extensions/src/text/overlayEditor.d.ts +8 -0
- package/dist-extensions/src/text/overlayEditor.d.ts.map +1 -1
- package/dist-extensions/src/text/scriptUtils.d.ts +142 -0
- package/dist-extensions/src/text/scriptUtils.d.ts.map +1 -0
- package/dist-extensions/src/util/misc/cornerRadius.d.ts +70 -0
- package/dist-extensions/src/util/misc/cornerRadius.d.ts.map +1 -0
- package/fabric-test-editor.html +3552 -0
- package/fabric-test2.html +647 -0
- package/fabric.ts +182 -182
- package/fonts/STV Bold.ttf +0 -0
- package/fonts/STV Light.ttf +0 -0
- package/fonts/STV Regular.ttf +0 -0
- package/package.json +164 -164
- package/src/shapes/Line.ts +484 -157
- package/src/shapes/Polyline.ts +70 -29
- package/src/shapes/Text/Text.ts +317 -19
- package/src/shapes/Textbox.ts +663 -12
- package/src/shapes/Triangle.spec.ts +76 -0
- package/src/shapes/Triangle.ts +85 -15
- package/src/text/measure.ts +200 -50
- package/src/text/overlayEditor.ts +504 -94
- package/src/util/misc/cornerRadius.spec.ts +141 -0
- package/src/util/misc/cornerRadius.ts +269 -0
- /package/debug/{konva → konva-master}/LICENSE +0 -0
- /package/debug/{konva → konva-master}/gulpfile.mjs +0 -0
- /package/debug/{konva → konva-master}/resources/doc-includes/ContainerParams.txt +0 -0
- /package/debug/{konva → konva-master}/resources/doc-includes/NodeParams.txt +0 -0
- /package/debug/{konva → konva-master}/resources/doc-includes/ShapeParams.txt +0 -0
- /package/debug/{konva → konva-master}/resources/jsdoc.conf.json +0 -0
- /package/debug/{konva → konva-master}/rollup.config.mjs +0 -0
- /package/debug/{konva → konva-master}/src/Animation.ts +0 -0
- /package/debug/{konva → konva-master}/src/BezierFunctions.ts +0 -0
- /package/debug/{konva → konva-master}/src/Container.ts +0 -0
- /package/debug/{konva → konva-master}/src/Context.ts +0 -0
- /package/debug/{konva → konva-master}/src/Core.ts +0 -0
- /package/debug/{konva → konva-master}/src/DragAndDrop.ts +0 -0
- /package/debug/{konva → konva-master}/src/Factory.ts +0 -0
- /package/debug/{konva → konva-master}/src/FastLayer.ts +0 -0
- /package/debug/{konva → konva-master}/src/Global.ts +0 -0
- /package/debug/{konva → konva-master}/src/Group.ts +0 -0
- /package/debug/{konva → konva-master}/src/Layer.ts +0 -0
- /package/debug/{konva → konva-master}/src/Node.ts +0 -0
- /package/debug/{konva → konva-master}/src/PointerEvents.ts +0 -0
- /package/debug/{konva → konva-master}/src/Shape.ts +0 -0
- /package/debug/{konva → konva-master}/src/Stage.ts +0 -0
- /package/debug/{konva → konva-master}/src/Tween.ts +0 -0
- /package/debug/{konva → konva-master}/src/Util.ts +0 -0
- /package/debug/{konva → konva-master}/src/Validators.ts +0 -0
- /package/debug/{konva → konva-master}/src/_CoreInternals.ts +0 -0
- /package/debug/{konva → konva-master}/src/_FullInternals.ts +0 -0
- /package/debug/{konva → konva-master}/src/canvas-backend.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Blur.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Brighten.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Brightness.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Contrast.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Emboss.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Enhance.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Grayscale.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/HSL.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/HSV.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Invert.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Kaleidoscope.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Mask.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Noise.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Pixelate.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Posterize.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/RGB.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/RGBA.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Sepia.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Solarize.ts +0 -0
- /package/debug/{konva → konva-master}/src/filters/Threshold.ts +0 -0
- /package/debug/{konva → konva-master}/src/index.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Arc.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Arrow.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Circle.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Ellipse.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Image.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Label.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Line.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Path.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Rect.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/RegularPolygon.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Ring.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Sprite.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Star.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/TextPath.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Transformer.ts +0 -0
- /package/debug/{konva → konva-master}/src/shapes/Wedge.ts +0 -0
- /package/debug/{konva → konva-master}/src/skia-backend.ts +0 -0
- /package/debug/{konva → konva-master}/src/types.ts +0 -0
- /package/debug/{konva → konva-master}/tsconfig.json +0 -0
- /package/debug/{konva → konva-master}/tsconfig.test.json +0 -0
|
@@ -8,6 +8,7 @@ import { classRegistry } from '../../ClassRegistry.mjs';
|
|
|
8
8
|
import { graphemeSplit } from '../../util/lang_string.mjs';
|
|
9
9
|
import { createCanvasElementFor } from '../../util/misc/dom.mjs';
|
|
10
10
|
import { layoutText } from '../../text/layout.mjs';
|
|
11
|
+
import { segmentGraphemes } from '../../text/unicode.mjs';
|
|
11
12
|
import { hasStyleChanged, stylesToArray, stylesFromArray } from '../../util/misc/textStyles.mjs';
|
|
12
13
|
import { getPathSegmentsInfo, getPointOnPath } from '../../util/path/index.mjs';
|
|
13
14
|
import '../Object/FabricObject.mjs';
|
|
@@ -149,6 +150,15 @@ class FabricText extends StyledText {
|
|
|
149
150
|
* Does not return dimensions.
|
|
150
151
|
*/
|
|
151
152
|
initDimensions() {
|
|
153
|
+
// Check if font is ready for accurate measurements
|
|
154
|
+
// Only block initialization if it's a critical font loading situation
|
|
155
|
+
const fontReady = this._isFontReady();
|
|
156
|
+
if (!fontReady && !this.initialized) {
|
|
157
|
+
// Only schedule font loading on first initialization
|
|
158
|
+
this._scheduleInitAfterFontLoad();
|
|
159
|
+
// Continue with fallback measurements for now
|
|
160
|
+
}
|
|
161
|
+
|
|
152
162
|
// Use advanced layout if enabled
|
|
153
163
|
if (this.enableAdvancedLayout && !this.path) {
|
|
154
164
|
return this.initDimensionsAdvanced();
|
|
@@ -165,7 +175,21 @@ class FabricText extends StyledText {
|
|
|
165
175
|
}
|
|
166
176
|
if (this.textAlign.includes(JUSTIFY)) {
|
|
167
177
|
// once text is measured we need to make space fatter to make justified text.
|
|
168
|
-
|
|
178
|
+
// Ensure __charBounds exists before calling enlargeSpaces
|
|
179
|
+
if (this.__charBounds && this.__charBounds.length > 0) {
|
|
180
|
+
this.enlargeSpaces();
|
|
181
|
+
} else {
|
|
182
|
+
console.warn('⚠️ __charBounds not ready for justify alignment, deferring enlargeSpaces');
|
|
183
|
+
// Defer the justify calculation until the next frame
|
|
184
|
+
setTimeout(() => {
|
|
185
|
+
if (this.__charBounds && this.__charBounds.length > 0 && this.enlargeSpaces) {
|
|
186
|
+
var _this$canvas;
|
|
187
|
+
console.log('🔧 Applying deferred justify alignment');
|
|
188
|
+
this.enlargeSpaces();
|
|
189
|
+
(_this$canvas = this.canvas) === null || _this$canvas === void 0 || _this$canvas.requestRenderAll();
|
|
190
|
+
}
|
|
191
|
+
}, 0);
|
|
192
|
+
}
|
|
169
193
|
}
|
|
170
194
|
}
|
|
171
195
|
|
|
@@ -174,8 +198,9 @@ class FabricText extends StyledText {
|
|
|
174
198
|
*/
|
|
175
199
|
enlargeSpaces() {
|
|
176
200
|
let diffSpace, currentLineWidth, numberOfSpaces, accumulatedSpace, line, charBound, spaces;
|
|
201
|
+
const isRtl = this.direction === 'rtl';
|
|
177
202
|
for (let i = 0, len = this._textLines.length; i < len; i++) {
|
|
178
|
-
if (this.textAlign
|
|
203
|
+
if (!this.textAlign.includes('justify') && (i === len - 1 || this.isEndOfWrapping(i))) {
|
|
179
204
|
continue;
|
|
180
205
|
}
|
|
181
206
|
accumulatedSpace = 0;
|
|
@@ -184,15 +209,47 @@ class FabricText extends StyledText {
|
|
|
184
209
|
if (currentLineWidth < this.width && (spaces = this.textLines[i].match(this._reSpacesAndTabs))) {
|
|
185
210
|
numberOfSpaces = spaces.length;
|
|
186
211
|
diffSpace = (this.width - currentLineWidth) / numberOfSpaces;
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
212
|
+
console.log(`🔧 EnlargeSpaces Line ${i}:`);
|
|
213
|
+
console.log(` Current width: ${currentLineWidth}, Target: ${this.width}`);
|
|
214
|
+
console.log(` Spaces: ${numberOfSpaces}, diffSpace: ${diffSpace.toFixed(2)}`);
|
|
215
|
+
if (isRtl) {
|
|
216
|
+
for (let j = 0; j < line.length; j++) {
|
|
217
|
+
if (this._reSpaceAndTab.test(line[j])) ;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// For RTL, we need to work backwards through the visual positions
|
|
221
|
+
// but still update logical positions correctly
|
|
222
|
+
let spaceCount = 0;
|
|
223
|
+
for (let j = 0; j <= line.length; j++) {
|
|
224
|
+
charBound = this.__charBounds[i][j];
|
|
225
|
+
if (charBound) {
|
|
226
|
+
if (this._reSpaceAndTab.test(line[j])) {
|
|
227
|
+
charBound.width += diffSpace;
|
|
228
|
+
charBound.kernedWidth += diffSpace;
|
|
229
|
+
spaceCount++;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// For RTL, shift all characters to the right by the total expansion
|
|
233
|
+
// minus the expansion that comes after this character
|
|
234
|
+
const remainingSpaces = numberOfSpaces - spaceCount;
|
|
235
|
+
const shiftAmount = remainingSpaces * diffSpace;
|
|
236
|
+
charBound.left += shiftAmount;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
// LTR processing (original logic)
|
|
241
|
+
for (let j = 0; j <= line.length; j++) {
|
|
242
|
+
charBound = this.__charBounds[i][j];
|
|
243
|
+
if (charBound) {
|
|
244
|
+
if (this._reSpaceAndTab.test(line[j])) {
|
|
245
|
+
charBound.width += diffSpace;
|
|
246
|
+
charBound.kernedWidth += diffSpace;
|
|
247
|
+
charBound.left += accumulatedSpace;
|
|
248
|
+
accumulatedSpace += diffSpace;
|
|
249
|
+
} else {
|
|
250
|
+
charBound.left += accumulatedSpace;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
196
253
|
}
|
|
197
254
|
}
|
|
198
255
|
}
|
|
@@ -270,6 +327,18 @@ class FabricText extends StyledText {
|
|
|
270
327
|
|
|
271
328
|
// Convert layout to legacy format for compatibility
|
|
272
329
|
this._convertLayoutToLegacyFormat(layout);
|
|
330
|
+
|
|
331
|
+
// Ensure justify alignment is properly applied for compatibility with legacy rendering
|
|
332
|
+
if (this.textAlign.includes(JUSTIFY)) {
|
|
333
|
+
// Force enlarge spaces after advanced layout calculation
|
|
334
|
+
setTimeout(() => {
|
|
335
|
+
if (this.enlargeSpaces) {
|
|
336
|
+
var _this$canvas2;
|
|
337
|
+
this.enlargeSpaces();
|
|
338
|
+
(_this$canvas2 = this.canvas) === null || _this$canvas2 === void 0 || _this$canvas2.renderAll();
|
|
339
|
+
}
|
|
340
|
+
}, 0);
|
|
341
|
+
}
|
|
273
342
|
this.dirty = true;
|
|
274
343
|
}
|
|
275
344
|
|
|
@@ -850,7 +919,15 @@ class FabricText extends StyledText {
|
|
|
850
919
|
if (currentDirection !== this.direction) {
|
|
851
920
|
ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');
|
|
852
921
|
ctx.direction = isLtr ? 'ltr' : 'rtl';
|
|
853
|
-
|
|
922
|
+
|
|
923
|
+
// For justify alignments, we need to set the correct canvas text alignment
|
|
924
|
+
// This is crucial for RTL text to render in the correct order
|
|
925
|
+
if (isJustify) {
|
|
926
|
+
// Justify uses LEFT alignment as a base, letting the character positioning handle justification
|
|
927
|
+
ctx.textAlign = LEFT;
|
|
928
|
+
} else {
|
|
929
|
+
ctx.textAlign = isLtr ? LEFT : RIGHT;
|
|
930
|
+
}
|
|
854
931
|
}
|
|
855
932
|
top -= lineHeight * this._fontSizeFraction / this.lineHeight;
|
|
856
933
|
if (shortCut) {
|
|
@@ -1086,9 +1163,21 @@ class FabricText extends StyledText {
|
|
|
1086
1163
|
direction = this.direction,
|
|
1087
1164
|
isEndOfWrapping = this.isEndOfWrapping(lineIndex);
|
|
1088
1165
|
let leftOffset = 0;
|
|
1089
|
-
|
|
1090
|
-
|
|
1166
|
+
|
|
1167
|
+
// Handle justify alignments (excluding last lines and wrapped line ends)
|
|
1168
|
+
const isJustifyLine = textAlign === JUSTIFY || textAlign === JUSTIFY_CENTER && !isEndOfWrapping || textAlign === JUSTIFY_RIGHT && !isEndOfWrapping || textAlign === JUSTIFY_LEFT && !isEndOfWrapping;
|
|
1169
|
+
if (isJustifyLine) {
|
|
1170
|
+
// Justify lines should start at the left edge for LTR and right edge for RTL
|
|
1171
|
+
// The space distribution is handled by enlargeSpaces()
|
|
1172
|
+
if (direction === 'rtl') {
|
|
1173
|
+
// For RTL justify, we need to account for the line being right-aligned
|
|
1174
|
+
return 0;
|
|
1175
|
+
} else {
|
|
1176
|
+
return 0;
|
|
1177
|
+
}
|
|
1091
1178
|
}
|
|
1179
|
+
|
|
1180
|
+
// Handle non-justify alignments
|
|
1092
1181
|
if (textAlign === CENTER) {
|
|
1093
1182
|
leftOffset = lineDiff / 2;
|
|
1094
1183
|
}
|
|
@@ -1101,6 +1190,8 @@ class FabricText extends StyledText {
|
|
|
1101
1190
|
if (textAlign === JUSTIFY_RIGHT) {
|
|
1102
1191
|
leftOffset = lineDiff;
|
|
1103
1192
|
}
|
|
1193
|
+
|
|
1194
|
+
// Apply RTL adjustments for non-justify alignments
|
|
1104
1195
|
if (direction === 'rtl') {
|
|
1105
1196
|
if (textAlign === RIGHT || textAlign === JUSTIFY || textAlign === JUSTIFY_RIGHT) {
|
|
1106
1197
|
leftOffset = 0;
|
|
@@ -1259,7 +1350,19 @@ class FabricText extends StyledText {
|
|
|
1259
1350
|
fontSize = this.fontSize
|
|
1260
1351
|
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
1261
1352
|
let forMeasuring = arguments.length > 1 ? arguments[1] : undefined;
|
|
1262
|
-
|
|
1353
|
+
let parsedFontFamily = fontFamily.includes("'") || fontFamily.includes('"') || fontFamily.includes(',') || FabricText.genericFonts.includes(fontFamily.toLowerCase()) ? fontFamily : `"${fontFamily}"`;
|
|
1354
|
+
|
|
1355
|
+
// For fonts like STV that don't support English/Latin characters,
|
|
1356
|
+
// add fallback fonts for consistent rendering of unsupported characters
|
|
1357
|
+
// Only add fallbacks during actual rendering, not for measurements
|
|
1358
|
+
if (!forMeasuring &&
|
|
1359
|
+
// Only during rendering, not measuring
|
|
1360
|
+
!fontFamily.includes(',') && (
|
|
1361
|
+
// Don't add fallbacks if already has them
|
|
1362
|
+
fontFamily.toLowerCase().includes('stv') || fontFamily.toLowerCase().includes('arabic') || fontFamily.toLowerCase().includes('naskh') || fontFamily.toLowerCase().includes('kufi'))) {
|
|
1363
|
+
// Add fallback fonts for unsupported characters (spaces, punctuation, etc.)
|
|
1364
|
+
parsedFontFamily = `${parsedFontFamily}, "Arial Unicode MS", Arial, sans-serif`;
|
|
1365
|
+
}
|
|
1263
1366
|
return [fontStyle, fontWeight, `${forMeasuring ? this.CACHE_FONT_SIZE : fontSize}px`, parsedFontFamily].join(' ');
|
|
1264
1367
|
}
|
|
1265
1368
|
|
|
@@ -1303,7 +1406,13 @@ class FabricText extends StyledText {
|
|
|
1303
1406
|
newLine = ['\n'];
|
|
1304
1407
|
let newText = [];
|
|
1305
1408
|
for (let i = 0; i < lines.length; i++) {
|
|
1306
|
-
|
|
1409
|
+
// Use BiDi-aware grapheme splitting for RTL text
|
|
1410
|
+
if (this.direction === 'rtl' || this._containsArabicText(lines[i])) {
|
|
1411
|
+
newLines[i] = segmentGraphemes(lines[i]);
|
|
1412
|
+
console.log(`🔤 BiDi-aware split line ${i}: "${lines[i]}" -> [${newLines[i].join(', ')}]`);
|
|
1413
|
+
} else {
|
|
1414
|
+
newLines[i] = this.graphemeSplit(lines[i]);
|
|
1415
|
+
}
|
|
1307
1416
|
newText = newText.concat(newLines[i], newLine);
|
|
1308
1417
|
}
|
|
1309
1418
|
newText.pop();
|
|
@@ -1315,6 +1424,14 @@ class FabricText extends StyledText {
|
|
|
1315
1424
|
};
|
|
1316
1425
|
}
|
|
1317
1426
|
|
|
1427
|
+
/**
|
|
1428
|
+
* Check if text contains Arabic characters
|
|
1429
|
+
* @private
|
|
1430
|
+
*/
|
|
1431
|
+
_containsArabicText(text) {
|
|
1432
|
+
return /[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]/.test(text);
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1318
1435
|
/**
|
|
1319
1436
|
* Returns object representation of an instance
|
|
1320
1437
|
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
|
|
@@ -1437,6 +1554,88 @@ class FabricText extends StyledText {
|
|
|
1437
1554
|
|
|
1438
1555
|
/* _FROM_SVG_END_ */
|
|
1439
1556
|
|
|
1557
|
+
/**
|
|
1558
|
+
* Check if the font is ready for accurate measurements
|
|
1559
|
+
* @private
|
|
1560
|
+
*/
|
|
1561
|
+
_isFontReady() {
|
|
1562
|
+
if (typeof document === 'undefined' || !('fonts' in document)) {
|
|
1563
|
+
return true; // Assume ready in non-browser environments
|
|
1564
|
+
}
|
|
1565
|
+
try {
|
|
1566
|
+
return document.fonts.check(`${this.fontSize}px ${this.fontFamily}`);
|
|
1567
|
+
} catch (e) {
|
|
1568
|
+
return true; // Fallback to assuming ready if check fails
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
/**
|
|
1573
|
+
* Schedule re-initialization after font loads
|
|
1574
|
+
* @private
|
|
1575
|
+
*/
|
|
1576
|
+
_scheduleInitAfterFontLoad() {
|
|
1577
|
+
if (typeof document === 'undefined' || !('fonts' in document)) {
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
// Only schedule if not already waiting
|
|
1582
|
+
if (this._fontLoadScheduled) {
|
|
1583
|
+
return;
|
|
1584
|
+
}
|
|
1585
|
+
this._fontLoadScheduled = true;
|
|
1586
|
+
const fontSpec = `${this.fontSize}px ${this.fontFamily}`;
|
|
1587
|
+
document.fonts.load(fontSpec).then(() => {
|
|
1588
|
+
this._fontLoadScheduled = false;
|
|
1589
|
+
// Re-initialize dimensions with proper font metrics
|
|
1590
|
+
this.initDimensions();
|
|
1591
|
+
|
|
1592
|
+
// Extra step for justify alignment after font loading
|
|
1593
|
+
if (this.textAlign && this.textAlign.includes(JUSTIFY)) {
|
|
1594
|
+
setTimeout(() => {
|
|
1595
|
+
var _this$canvas3;
|
|
1596
|
+
if (this.enlargeSpaces) {
|
|
1597
|
+
this.enlargeSpaces();
|
|
1598
|
+
}
|
|
1599
|
+
(_this$canvas3 = this.canvas) === null || _this$canvas3 === void 0 || _this$canvas3.requestRenderAll();
|
|
1600
|
+
}, 10);
|
|
1601
|
+
} else {
|
|
1602
|
+
var _this$canvas4;
|
|
1603
|
+
(_this$canvas4 = this.canvas) === null || _this$canvas4 === void 0 || _this$canvas4.requestRenderAll();
|
|
1604
|
+
}
|
|
1605
|
+
}).catch(() => {
|
|
1606
|
+
this._fontLoadScheduled = false;
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
/**
|
|
1611
|
+
* Force complete text re-initialization (useful after JSON loading)
|
|
1612
|
+
*/
|
|
1613
|
+
forceTextReinitialization() {
|
|
1614
|
+
console.log('🔄 Force reinitializing text object');
|
|
1615
|
+
|
|
1616
|
+
// Clear all caches
|
|
1617
|
+
this._clearCache();
|
|
1618
|
+
this.dirty = true;
|
|
1619
|
+
|
|
1620
|
+
// Force text splitting to rebuild internal structures
|
|
1621
|
+
this._splitText();
|
|
1622
|
+
|
|
1623
|
+
// Re-initialize dimensions
|
|
1624
|
+
this.initDimensions();
|
|
1625
|
+
|
|
1626
|
+
// Special handling for justify alignment
|
|
1627
|
+
if (this.textAlign && this.textAlign.includes(JUSTIFY)) {
|
|
1628
|
+
// Ensure justify is applied after dimensions are set
|
|
1629
|
+
setTimeout(() => {
|
|
1630
|
+
if (this.__charBounds && this.__charBounds.length > 0 && this.enlargeSpaces) {
|
|
1631
|
+
var _this$canvas5;
|
|
1632
|
+
this.enlargeSpaces();
|
|
1633
|
+
(_this$canvas5 = this.canvas) === null || _this$canvas5 === void 0 || _this$canvas5.requestRenderAll();
|
|
1634
|
+
}
|
|
1635
|
+
}, 10);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1440
1639
|
/**
|
|
1441
1640
|
* Returns FabricText instance from an object representation
|
|
1442
1641
|
* @param {Object} object plain js Object to create an instance from
|
|
@@ -1448,6 +1647,93 @@ class FabricText extends StyledText {
|
|
|
1448
1647
|
styles: stylesFromArray(object.styles || {}, object.text)
|
|
1449
1648
|
}, {
|
|
1450
1649
|
extraParam: 'text'
|
|
1650
|
+
}).then(textObject => {
|
|
1651
|
+
// Ensure text object is properly initialized after JSON deserialization
|
|
1652
|
+
// This is critical for justify alignment and other text layout features
|
|
1653
|
+
textObject.initialized = true;
|
|
1654
|
+
|
|
1655
|
+
// Force reinitialization to ensure proper layout
|
|
1656
|
+
if (textObject._clearCache) {
|
|
1657
|
+
textObject._clearCache();
|
|
1658
|
+
}
|
|
1659
|
+
textObject.dirty = true;
|
|
1660
|
+
|
|
1661
|
+
// Check if we need to wait for font loading (especially for custom fonts like STV)
|
|
1662
|
+
const fontSpec = `${textObject.fontSize}px ${textObject.fontFamily}`;
|
|
1663
|
+
|
|
1664
|
+
// For custom fonts, ensure they're loaded before initializing dimensions
|
|
1665
|
+
if (typeof document !== 'undefined' && 'fonts' in document && textObject.fontFamily !== 'Arial' && textObject.fontFamily !== 'Times New Roman') {
|
|
1666
|
+
return document.fonts.load(fontSpec).then(() => {
|
|
1667
|
+
var _textObject$fontFamil;
|
|
1668
|
+
console.log(`🔤 Font loaded for JSON object: ${fontSpec}`);
|
|
1669
|
+
// Ensure initialized flag is set again (in case constructor reset it)
|
|
1670
|
+
textObject.initialized = true;
|
|
1671
|
+
|
|
1672
|
+
// Special handling for STV fonts which have measurement issues
|
|
1673
|
+
const isStvFont = (_textObject$fontFamil = textObject.fontFamily) === null || _textObject$fontFamil === void 0 ? void 0 : _textObject$fontFamil.toLowerCase().includes('stv');
|
|
1674
|
+
if (isStvFont) {
|
|
1675
|
+
console.log(`🔤 STV font detected, using enhanced reinitialization`);
|
|
1676
|
+
|
|
1677
|
+
// Clear all cached state that might interfere with browser wrapping
|
|
1678
|
+
textObject._browserWrapCache = null;
|
|
1679
|
+
textObject._lastDimensionState = null;
|
|
1680
|
+
textObject._browserWrapInitialized = false;
|
|
1681
|
+
console.log(`🔤 STV font: Cleared all cached states for fresh initialization`);
|
|
1682
|
+
|
|
1683
|
+
// Force browser wrapping flag for STV fonts
|
|
1684
|
+
textObject._usingBrowserWrapping = true;
|
|
1685
|
+
console.log(`🔤 STV font: Forcing browser wrapping flag during JSON load`);
|
|
1686
|
+
|
|
1687
|
+
// Multiple initialization attempts for STV fonts
|
|
1688
|
+
const reinitWithDelay = attempt => {
|
|
1689
|
+
if (textObject.forceTextReinitialization) {
|
|
1690
|
+
textObject.forceTextReinitialization();
|
|
1691
|
+
} else {
|
|
1692
|
+
textObject.initDimensions();
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
// Check if width is still problematic after initialization
|
|
1696
|
+
if (textObject.width < 50 && attempt < 3) {
|
|
1697
|
+
console.log(`🔤 STV font width still ${textObject.width}px, retrying in ${100 * attempt}ms (attempt ${attempt + 1}/3)`);
|
|
1698
|
+
setTimeout(() => reinitWithDelay(attempt + 1), 100 * attempt);
|
|
1699
|
+
}
|
|
1700
|
+
};
|
|
1701
|
+
reinitWithDelay(0);
|
|
1702
|
+
} else {
|
|
1703
|
+
// Use specialized reinitialization for Textbox objects
|
|
1704
|
+
if (textObject.forceTextReinitialization) {
|
|
1705
|
+
console.log(`🔤 Using Textbox specialized reinitialization`);
|
|
1706
|
+
textObject.forceTextReinitialization();
|
|
1707
|
+
} else {
|
|
1708
|
+
// Reinitialize dimensions with proper font metrics
|
|
1709
|
+
textObject.initDimensions();
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
return textObject;
|
|
1713
|
+
}).catch(() => {
|
|
1714
|
+
console.warn(`⚠️ Font loading failed for ${fontSpec}, proceeding with fallback`);
|
|
1715
|
+
// Ensure initialized flag is set again
|
|
1716
|
+
textObject.initialized = true;
|
|
1717
|
+
|
|
1718
|
+
// Still initialize dimensions even if font loading fails
|
|
1719
|
+
if (textObject.forceTextReinitialization) {
|
|
1720
|
+
textObject.forceTextReinitialization();
|
|
1721
|
+
} else {
|
|
1722
|
+
textObject.initDimensions();
|
|
1723
|
+
}
|
|
1724
|
+
return textObject;
|
|
1725
|
+
});
|
|
1726
|
+
} else {
|
|
1727
|
+
// Standard fonts - ensure initialized and use appropriate method
|
|
1728
|
+
textObject.initialized = true;
|
|
1729
|
+
if (textObject.forceTextReinitialization) {
|
|
1730
|
+
console.log(`🔤 Using Textbox specialized reinitialization for standard font`);
|
|
1731
|
+
textObject.forceTextReinitialization();
|
|
1732
|
+
} else {
|
|
1733
|
+
textObject.initDimensions();
|
|
1734
|
+
}
|
|
1735
|
+
return textObject;
|
|
1736
|
+
}
|
|
1451
1737
|
});
|
|
1452
1738
|
}
|
|
1453
1739
|
}
|