Skip to content

Commit

Permalink
fix(IText): make clear contextTop always from the main render cycle (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ShaMan123 committed Mar 16, 2024
1 parent 34c34db commit d17af82
Show file tree
Hide file tree
Showing 14 changed files with 161 additions and 228 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
- feat(): DrawShape, DrawOval, DrawPoly [#8430](https://github.com/fabricjs/fabric.js/pull/8430)
- fix(): `_initRetinaScaling` initializaing the scaling regardless of settings in Canvas. [#8565](https://github.com/fabricjs/fabric.js/pull/8565)
- fix(): regression of canvas migration with pointer and sendPointToPlane [#8563](https://github.com/fabricjs/fabric.js/pull/8563)
- fix(IText): refactor clearing context top logic of itext to align with brush pattern, using the canvas rendering cycle in order to guard from edge cases #8560
- fix(Canvas): `_initRetinaScaling` initializaing the scaling regardless of settings in Canvas. [#8565](https://github.com/fabricjs/fabric.js/pull/8565)
- fix(Canvas): regression of canvas migration with pointer and sendPointToPlane [#8563](https://github.com/fabricjs/fabric.js/pull/8563)
- chore(TS): Use exports from files to build fabricJS, get rid of HEADER.js [#8549](https://github.com/fabricjs/fabric.js/pull/8549)
- chore(): rm `fabric.filterBackend` => `getFilterBackend` [#8487](https://github.com/fabricjs/fabric.js/pull/8487)
- chore(TS): migrate text SVG export mixin [#8486](https://github.com/fabricjs/fabric.js/pull/8486)
Expand Down
27 changes: 15 additions & 12 deletions src/canvas/canvas.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,21 @@ import {
TPointerEvent,
Transform,
} from '../EventTypeDefs';
import { Point } from '../point.class';
import {
addTransformToObject,
saveObjectTransform,
} from '../util/misc/objectTransforms';
import { StaticCanvas, TCanvasSizeOptions } from './static_canvas.class';
import {
isActiveSelection,
isCollection,
isFabricObjectCached,
} from '../util/types';
import { invertTransform, transformPoint } from '../util/misc/matrix';
import { isTransparent } from '../util/misc/isTransparent';
import { TOriginX, TOriginY, TSize } from '../typedefs';
import { degreesToRadians } from '../util/misc/radiansDegreesConversion';
import { getPointer, isTouchEvent } from '../util/dom_event';
import type { IText } from '../shapes/itext.class';
import { FabricObject } from '../shapes/Object/FabricObject';
import type { Textbox } from '../shapes/textbox.class';
Expand Down Expand Up @@ -1655,17 +1669,6 @@ export class SelectableCanvas<
super._setSVGObject(markup, instance, reviver);
instance.set(originalProperties);
}

setViewportTransform(vpt: TMat2D) {
if (
this.renderOnAddRemove &&
isInteractiveTextObject(this._activeObject) &&
this._activeObject.isEditing
) {
this._activeObject.clearContextTop();
}
super.setViewportTransform(vpt);
}
}

Object.assign(SelectableCanvas.prototype, {
Expand Down
4 changes: 4 additions & 0 deletions src/canvas/canvas_events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,12 @@ export class Canvas extends SelectableCanvas {
source?: FabricObject,
target?: FabricObject
) {
let dirty = false;
const ctx = this.contextTop;
if (source) {
source.clearContextTop(true);
source.renderDragSourceEffect(e);
dirty = true;
}
if (target) {
if (target !== source) {
Expand All @@ -354,8 +356,10 @@ export class Canvas extends SelectableCanvas {
target.clearContextTop(true);
}
target.renderDropTargetEffect(e);
dirty = true;
}
ctx.restore();
dirty && (this.contextTopDirty = true);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/shapes/Object/InteractiveObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ export class InteractiveFabricObject<
* Clears the canvas.contextTop in a specific area that corresponds to the object's bounding box
* that is in the canvas.contextContainer.
* This function is used to clear pieces of contextTop where we render ephemeral effects on top of the object.
* Example: blinking cursror text selection, drag effects.
* Example: blinking cursor text selection, drag effects.
* @todo discuss swapping restoreManually with a renderCallback, but think of async issues
* @param {Boolean} [restoreManually] When true won't restore the context after clear, in order to draw something else.
* @return {CanvasRenderingContext2D|undefined} canvas.contextTop that is either still transformed
Expand Down
37 changes: 12 additions & 25 deletions src/shapes/itext.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ export class IText extends ITextClickBehaviorMixin<ITextEvents> {
*/
initDimensions() {
this.isEditing && this.initDelayedCursor();
this.clearContextTop();
super.initDimensions();
}

Expand Down Expand Up @@ -272,22 +271,13 @@ export class IText extends ITextClickBehaviorMixin<ITextEvents> {
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
render(ctx: CanvasRenderingContext2D) {
this.clearContextTop();
super.render(ctx);
// clear the cursorOffsetCache, so we ensure to calculate once per renderCursor
// the correct position but not at every cursor animation.
this.cursorOffsetCache = {};
this.renderCursorOrSelection();
}

/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_render(ctx: CanvasRenderingContext2D) {
super._render(ctx);
}

/**
* Renders cursor or selection (depending on what exists)
* it does on the contextTop. If contextTop is not available, do nothing.
Expand All @@ -306,19 +296,10 @@ export class IText extends ITextClickBehaviorMixin<ITextEvents> {
} else {
this.renderSelection(ctx, boundaries);
}
this.canvas!.contextTopDirty = true;
ctx.restore();
}

/**
* Renders cursor on context Top, outside the animation cycle, on request
* Used for the drag/drop effect.
* If contextTop is not available, do nothing.
*/
renderCursorAt(selectionStart) {
const boundaries = this._getCursorBoundaries(selectionStart, true);
this._renderCursor(this.canvas.contextTop, boundaries, selectionStart);
}

/**
* Returns cursor boundaries (left, top, leftOffset, topOffset)
* left/top are left/top of entire text box
Expand Down Expand Up @@ -406,6 +387,16 @@ export class IText extends ITextClickBehaviorMixin<ITextEvents> {
return boundaries;
}

/**
* Renders cursor on context Top, outside the animation cycle, on request
* Used for the drag/drop effect.
* If contextTop is not available, do nothing.
*/
renderCursorAt(selectionStart: number) {
const boundaries = this._getCursorBoundaries(selectionStart, true);
this._renderCursor(this.canvas.contextTop, boundaries, selectionStart);
}

/**
* Renders cursor
* @param {Object} boundaries
Expand Down Expand Up @@ -468,11 +459,7 @@ export class IText extends ITextClickBehaviorMixin<ITextEvents> {
* Renders drag start text selection
*/
renderDragSourceEffect() {
if (
this.__isDragging &&
this.__dragStartSelection &&
this.__dragStartSelection
) {
if (this.__isDragging && this.__dragStartSelection) {
this._renderSelection(
this.canvas.contextTop,
this.__dragStartSelection,
Expand Down
1 change: 0 additions & 1 deletion src/shapes/textbox.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export class Textbox extends IText {
return;
}
this.isEditing && this.initDelayedCursor();
this.clearContextTop();
this._clearCache();
// clear dynamicMinWidth as it will be different after we re-wrap line
this.dynamicMinWidth = 0;
Expand Down
2 changes: 1 addition & 1 deletion test/lib/visualTestLoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@
}
await fabricCanvas.dispose();
done();
});
}, assert);
});
}
}
Expand Down
Loading

0 comments on commit d17af82

Please sign in to comment.