Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(): Backports for broken features requests #9965

Merged
merged 13 commits into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
## [5.4.0]

- fix() fix an issue with offScreen detection and background/overlay Vpt setting [`#8896`](https://github.com/fabricjs/fabric.js/pull/8896)
- fix() removal of shadow for uncached text with decoration
- fix() active selection control drawing order
- fix() patterns for gradient sometimes hitting 0 size
- fix() Enliving of text on a path for classes different than plain Text
- fix() Some old style shifting bugs for text

## [5.2.1]

Expand Down
2 changes: 1 addition & 1 deletion HEADER.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */

var fabric = fabric || { version: '5.3.0' };
var fabric = fabric || { version: '5.4.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
Expand Down
80 changes: 59 additions & 21 deletions dist/fabric.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* build: `node build.js modules=ALL exclude=gestures,accessors,erasing requirejs minifier=uglifyjs` */
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */

var fabric = fabric || { version: '5.3.0' };
var fabric = fabric || { version: '5.4.0' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
Expand Down Expand Up @@ -9875,10 +9875,15 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
}
if (object) {
ctx.save();
var skipOffscreen = this.skipOffscreen;
// if the object doesn't move with the viewport,
// the offscreen concept does not apply;
this.skipOffscreen = needsVpt;
if (needsVpt) {
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
}
object.render(ctx);
this.skipOffscreen = skipOffscreen;
ctx.restore();
}
},
Expand Down Expand Up @@ -13105,8 +13110,8 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab

var _this = this;
this._hoveredTargets.forEach(function(_target){
_this.fire('mouse:out', { target: target, e: e });
_target && target.fire('mouseout', { e: e });
_this.fire('mouse:out', { target: _target, e: e });
_target && _target.fire('mouseout', { e: e });
});
this._hoveredTargets = [];
},
Expand Down Expand Up @@ -16018,8 +16023,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
var dims = this._limitCacheSize(this._getCacheCanvasDimensions()),
pCanvas = fabric.util.createCanvasElement(), pCtx, retinaScaling = this.canvas.getRetinaScaling(),
width = dims.x / this.scaleX / retinaScaling, height = dims.y / this.scaleY / retinaScaling;
pCanvas.width = width;
pCanvas.height = height;
pCanvas.width = Math.ceil(width);
pCanvas.height = Math.ceil(height);
pCtx = pCanvas.getContext('2d');
pCtx.beginPath(); pCtx.moveTo(0, 0); pCtx.lineTo(width, 0); pCtx.lineTo(width, height);
pCtx.lineTo(0, height); pCtx.closePath();
Expand Down Expand Up @@ -18055,7 +18060,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
drawControls: function(ctx, styleOverride) {
styleOverride = styleOverride || {};
ctx.save();
var retinaScaling = this.canvas.getRetinaScaling(), matrix, p;
var retinaScaling = 1, matrix, p;
if (this.canvas) {
retinaScaling = this.canvas.getRetinaScaling();
}
ctx.setTransform(retinaScaling, 0, 0, retinaScaling, 0, 0);
ctx.strokeStyle = ctx.fillStyle = styleOverride.cornerColor || this.cornerColor;
if (!this.transparentCorners) {
Expand Down Expand Up @@ -20857,7 +20865,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
_renderControls: function(ctx, styleOverride, childrenOverride) {
ctx.save();
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
this.callSuper('_renderControls', ctx, styleOverride);
childrenOverride = childrenOverride || { };
if (typeof childrenOverride.hasControls === 'undefined') {
childrenOverride.hasControls = false;
Expand All @@ -20866,6 +20873,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
for (var i = 0, len = this._objects.length; i < len; i++) {
this._objects[i]._renderControls(ctx, childrenOverride);
}
this.callSuper('_renderControls', ctx, styleOverride);
ctx.restore();
},
});
Expand Down Expand Up @@ -27249,6 +27257,11 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
if (!this[type] && !this.styleHas(type)) {
return;
}
ctx.save();
// if type is overline or linethrough we shouldn't cast shadow
if (type === 'overline' || type === 'linethrough') {
this._removeShadow(ctx);
}
var heightOfLine, size, _size,
lineLeftOffset, dy, _dy,
line, lastDecoration,
Expand Down Expand Up @@ -27335,9 +27348,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
);
topOffset += heightOfLine;
}
// if there is text background color no
// other shadows should be casted
this._removeShadow(ctx);
ctx.restore();
},

/**
Expand Down Expand Up @@ -27771,7 +27782,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
charIndex: selectionStart
};
}
selectionStart -= lines[i].length + this.missingNewlineOffset(i);
selectionStart -= lines[i].length + this.missingNewlineOffset(i, skipWrapping);
}
return {
lineIndex: i - 1,
Expand Down Expand Up @@ -28433,6 +28444,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
var styles = fabric.util.stylesFromArray(object.styles, object.text);
//copy object to prevent mutation
var objCopy = Object.assign({}, object, { styles: styles });
delete objCopy.path;
parseDecoration(objCopy);
if (objCopy.styles) {
for (var i in objCopy.styles) {
Expand All @@ -28441,7 +28453,17 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
}
}
}
fabric.Object._fromObject('IText', objCopy, callback, 'text');
fabric.Object._fromObject('IText', objCopy, function(textInstance) {
if (object.path) {
fabric.Object._fromObject('Path', object.path, function(pathInstance) {
textInstance.set('path', pathInstance);
callback(textInstance);
}, 'path');
}
else {
callback(textInstance);
}
}, 'text');
};
})();

Expand Down Expand Up @@ -29188,8 +29210,9 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
insertNewlineStyleObject: function(lineIndex, charIndex, qty, copiedStyle) {
var currentCharStyle,
newLineStyles = {},
somethingAdded = false,
isEndOfLine = this._unwrappedTextLines[lineIndex].length === charIndex;
someStyleIsCarryingOver = false,
originalLineLength = this._unwrappedTextLines[lineIndex].length,
isEndOfLine = originalLineLength === charIndex;

qty || (qty = 1);
this.shiftLineStyles(lineIndex, qty);
Expand All @@ -29201,7 +29224,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
for (var index in this.styles[lineIndex]) {
var numIndex = parseInt(index, 10);
if (numIndex >= charIndex) {
somethingAdded = true;
someStyleIsCarryingOver = true;
newLineStyles[numIndex - charIndex] = this.styles[lineIndex][index];
// remove lines from the previous line since they're on a new line now
if (!(isEndOfLine && charIndex === 0)) {
Expand All @@ -29210,14 +29233,16 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
}
}
var styleCarriedOver = false;
if (somethingAdded && !isEndOfLine) {
if (someStyleIsCarryingOver && !isEndOfLine) {
// if is end of line, the extra style we copied
// is probably not something we want
this.styles[lineIndex + qty] = newLineStyles;
styleCarriedOver = true;
}
if (styleCarriedOver) {
// skip the last line of since we already prepared it.
if (styleCarriedOver || originalLineLength > charIndex) {
// skip the last line of since we already prepared it
// or contains text without style that we don't want to style
// just because it changed lines
qty--;
}
// for the all the lines or all the other lines
Expand Down Expand Up @@ -30997,10 +31022,12 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
/**
* Detect if a line has a linebreak and so we need to account for it when moving
* and counting style.
* This is important only for splitByGrapheme at the end of wrapping.
* If we are not wrapping the offset is always 1
* @return Number
*/
missingNewlineOffset: function(lineIndex) {
if (this.splitByGrapheme) {
missingNewlineOffset: function(lineIndex, skipWrapping) {
if (this.splitByGrapheme && !skipWrapping) {
return this.isEndOfWrapping(lineIndex) ? 1 : 0;
}
return 1;
Expand Down Expand Up @@ -31065,7 +31092,18 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
var styles = fabric.util.stylesFromArray(object.styles, object.text);
//copy object to prevent mutation
var objCopy = Object.assign({}, object, { styles: styles });
return fabric.Object._fromObject('Textbox', objCopy, callback, 'text');
delete objCopy.path;
return fabric.Object._fromObject('Textbox', objCopy, function(textInstance) {
if (object.path) {
fabric.Object._fromObject('Path', object.path, function(pathInstance) {
textInstance.set('path', pathInstance);
callback(textInstance);
}, 'path');
}
else {
callback(textInstance);
}
}, 'text');
};
})(typeof exports !== 'undefined' ? exports : this);

Expand Down
2 changes: 1 addition & 1 deletion dist/fabric.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "fabric",
"description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
"homepage": "http://fabricjs.com/",
"version": "5.3.0",
"version": "5.4.0",
"author": "Juriy Zaytsev <kangax@gmail.com>",
"contributors": [
{
Expand Down
15 changes: 9 additions & 6 deletions src/mixins/itext_behavior.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -740,8 +740,9 @@
insertNewlineStyleObject: function(lineIndex, charIndex, qty, copiedStyle) {
var currentCharStyle,
newLineStyles = {},
somethingAdded = false,
isEndOfLine = this._unwrappedTextLines[lineIndex].length === charIndex;
someStyleIsCarryingOver = false,
originalLineLength = this._unwrappedTextLines[lineIndex].length,
isEndOfLine = originalLineLength === charIndex;

qty || (qty = 1);
this.shiftLineStyles(lineIndex, qty);
Expand All @@ -753,7 +754,7 @@
for (var index in this.styles[lineIndex]) {
var numIndex = parseInt(index, 10);
if (numIndex >= charIndex) {
somethingAdded = true;
someStyleIsCarryingOver = true;
newLineStyles[numIndex - charIndex] = this.styles[lineIndex][index];
// remove lines from the previous line since they're on a new line now
if (!(isEndOfLine && charIndex === 0)) {
Expand All @@ -762,14 +763,16 @@
}
}
var styleCarriedOver = false;
if (somethingAdded && !isEndOfLine) {
if (someStyleIsCarryingOver && !isEndOfLine) {
// if is end of line, the extra style we copied
// is probably not something we want
this.styles[lineIndex + qty] = newLineStyles;
styleCarriedOver = true;
}
if (styleCarriedOver) {
// skip the last line of since we already prepared it.
if (styleCarriedOver || originalLineLength > charIndex) {
// skip the last line of since we already prepared it
// or contains text without style that we don't want to style
// just because it changed lines
qty--;
}
// for the all the lines or all the other lines
Expand Down
2 changes: 1 addition & 1 deletion src/mixins/text_style.mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
charIndex: selectionStart
};
}
selectionStart -= lines[i].length + this.missingNewlineOffset(i);
selectionStart -= lines[i].length + this.missingNewlineOffset(i, skipWrapping);
}
return {
lineIndex: i - 1,
Expand Down
2 changes: 1 addition & 1 deletion src/shapes/active_selection.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@
_renderControls: function(ctx, styleOverride, childrenOverride) {
ctx.save();
ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
this.callSuper('_renderControls', ctx, styleOverride);
childrenOverride = childrenOverride || { };
if (typeof childrenOverride.hasControls === 'undefined') {
childrenOverride.hasControls = false;
Expand All @@ -134,6 +133,7 @@
for (var i = 0, len = this._objects.length; i < len; i++) {
this._objects[i]._renderControls(ctx, childrenOverride);
}
this.callSuper('_renderControls', ctx, styleOverride);
ctx.restore();
},
});
Expand Down
13 changes: 12 additions & 1 deletion src/shapes/itext.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@
var styles = fabric.util.stylesFromArray(object.styles, object.text);
//copy object to prevent mutation
var objCopy = Object.assign({}, object, { styles: styles });
delete objCopy.path;
parseDecoration(objCopy);
if (objCopy.styles) {
for (var i in objCopy.styles) {
Expand All @@ -521,6 +522,16 @@
}
}
}
fabric.Object._fromObject('IText', objCopy, callback, 'text');
fabric.Object._fromObject('IText', objCopy, function(textInstance) {
if (object.path) {
fabric.Object._fromObject('Path', object.path, function(pathInstance) {
textInstance.set('path', pathInstance);
callback(textInstance);
}, 'path');
}
else {
callback(textInstance);
}
}, 'text');
};
})();
4 changes: 2 additions & 2 deletions src/shapes/object.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -1577,8 +1577,8 @@
var dims = this._limitCacheSize(this._getCacheCanvasDimensions()),
pCanvas = fabric.util.createCanvasElement(), pCtx, retinaScaling = this.canvas.getRetinaScaling(),
width = dims.x / this.scaleX / retinaScaling, height = dims.y / this.scaleY / retinaScaling;
pCanvas.width = width;
pCanvas.height = height;
pCanvas.width = Math.ceil(width);
pCanvas.height = Math.ceil(height);
pCtx = pCanvas.getContext('2d');
pCtx.beginPath(); pCtx.moveTo(0, 0); pCtx.lineTo(width, 0); pCtx.lineTo(width, height);
pCtx.lineTo(0, height); pCtx.closePath();
Expand Down
9 changes: 6 additions & 3 deletions src/shapes/text.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -1353,6 +1353,11 @@
if (!this[type] && !this.styleHas(type)) {
return;
}
ctx.save();
// if type is overline or linethrough we shouldn't cast shadow
if (type === 'overline' || type === 'linethrough') {
this._removeShadow(ctx);
}
var heightOfLine, size, _size,
lineLeftOffset, dy, _dy,
line, lastDecoration,
Expand Down Expand Up @@ -1439,9 +1444,7 @@
);
topOffset += heightOfLine;
}
// if there is text background color no
// other shadows should be casted
this._removeShadow(ctx);
ctx.restore();
},

/**
Expand Down
19 changes: 16 additions & 3 deletions src/shapes/textbox.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,12 @@
/**
* Detect if a line has a linebreak and so we need to account for it when moving
* and counting style.
* This is important only for splitByGrapheme at the end of wrapping.
* If we are not wrapping the offset is always 1
* @return Number
*/
missingNewlineOffset: function(lineIndex) {
if (this.splitByGrapheme) {
missingNewlineOffset: function(lineIndex, skipWrapping) {
if (this.splitByGrapheme && !skipWrapping) {
return this.isEndOfWrapping(lineIndex) ? 1 : 0;
}
return 1;
Expand Down Expand Up @@ -456,6 +458,17 @@
var styles = fabric.util.stylesFromArray(object.styles, object.text);
//copy object to prevent mutation
var objCopy = Object.assign({}, object, { styles: styles });
return fabric.Object._fromObject('Textbox', objCopy, callback, 'text');
delete objCopy.path;
return fabric.Object._fromObject('Textbox', objCopy, function(textInstance) {
if (object.path) {
fabric.Object._fromObject('Path', object.path, function(pathInstance) {
textInstance.set('path', pathInstance);
callback(textInstance);
}, 'path');
}
else {
callback(textInstance);
}
}, 'text');
};
})(typeof exports !== 'undefined' ? exports : this);
Loading