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

BREAKING: refactor object rendering #8298

Closed
wants to merge 132 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
a486894
init
ShaMan123 Sep 16, 2022
744861c
refactor canvas caching
ShaMan123 Sep 16, 2022
e27507a
osOnscreen with group!
ShaMan123 Sep 16, 2022
9e7a83b
dump group caching!
ShaMan123 Sep 16, 2022
af0df92
cleanup image caching
ShaMan123 Sep 16, 2022
5b6570f
remove(): isOnACache
ShaMan123 Sep 16, 2022
2da07fa
Update object.class.ts
ShaMan123 Sep 16, 2022
1b23ebd
Update group.class.ts
ShaMan123 Sep 16, 2022
7686272
Update active_selection.class.ts
ShaMan123 Sep 16, 2022
b03f390
Update text.class.ts
ShaMan123 Sep 16, 2022
9fb5cf5
Update text.class.ts
ShaMan123 Sep 16, 2022
2ec8722
cleanup
ShaMan123 Sep 16, 2022
93dd7fe
Update static_canvas.class.ts
ShaMan123 Sep 17, 2022
ad99532
refactor drawCacheOnCanvas
ShaMan123 Sep 17, 2022
92faeed
m
ShaMan123 Sep 17, 2022
ec132eb
fix
ShaMan123 Sep 17, 2022
2805765
Update group.class.ts
ShaMan123 Sep 17, 2022
31e8d65
Update object.class.ts
ShaMan123 Sep 17, 2022
77b8668
f
ShaMan123 Sep 17, 2022
ad1437c
Update group.class.ts
ShaMan123 Sep 17, 2022
166bba3
fix
ShaMan123 Sep 17, 2022
c9d6eea
change signatrue+cleanup
ShaMan123 Sep 17, 2022
7f0794d
expose rendering context
ShaMan123 Sep 17, 2022
e2b7f97
add failing test
ShaMan123 Sep 17, 2022
8818ef7
correct golden
ShaMan123 Sep 17, 2022
93b7fc0
Update clippath.js
ShaMan123 Sep 17, 2022
0e38db4
current - error in golden
ShaMan123 Sep 17, 2022
99a323d
better test
ShaMan123 Sep 17, 2022
abb6601
failing test
ShaMan123 Sep 17, 2022
8e58dc3
Update object.class.ts
ShaMan123 Sep 17, 2022
aced76f
disable tests
ShaMan123 Sep 17, 2022
b26b71f
Update clippath.js
ShaMan123 Sep 17, 2022
92a2b58
Delete cachingGroupWithNestedShadow.png
ShaMan123 Sep 17, 2022
742c9b3
Update clippath.js
ShaMan123 Sep 17, 2022
d4268e7
goldens
ShaMan123 Sep 17, 2022
d4b3daf
revert(): move cavas cache back to Canvas
ShaMan123 Sep 18, 2022
85e5ab9
cleanup
ShaMan123 Sep 18, 2022
350bf64
Update canvas_events.mixin.ts
ShaMan123 Sep 18, 2022
9e44211
MAJOR
ShaMan123 Sep 18, 2022
f352991
Update canvas_dataurl_exporter.mixin.ts
ShaMan123 Sep 18, 2022
ec6dbd5
Update static_canvas.class.ts
ShaMan123 Sep 18, 2022
2b7d776
rename
ShaMan123 Sep 18, 2022
3c7c996
Update RenderingContext.ts
ShaMan123 Sep 18, 2022
5e62e56
shadow WIP
ShaMan123 Sep 18, 2022
54f12fe
rm
ShaMan123 Sep 18, 2022
2232db2
Update clippath.js
ShaMan123 Sep 18, 2022
4690d20
disable shadow change
ShaMan123 Sep 18, 2022
3ff9554
Update clippath.js
ShaMan123 Sep 18, 2022
c5694e3
Update object.class.ts
ShaMan123 Sep 18, 2022
b0315c3
Update clippath.js
ShaMan123 Sep 18, 2022
b07594b
fix
ShaMan123 Sep 18, 2022
412fcc3
Update RenderingContext.ts
ShaMan123 Sep 18, 2022
e5e56b9
cleanup TRenderingContext
ShaMan123 Sep 18, 2022
c33f877
Update RenderingContext.ts
ShaMan123 Sep 18, 2022
9cf1a13
Update canvas.class.ts
ShaMan123 Sep 18, 2022
6a06fdd
correct goldens
ShaMan123 Sep 18, 2022
8373bd0
fix tests
ShaMan123 Sep 18, 2022
e70c0da
refactor dirty logic
ShaMan123 Sep 18, 2022
d693045
Revert "correct goldens"
ShaMan123 Sep 18, 2022
dc4b686
Revert "Revert "correct goldens""
ShaMan123 Sep 18, 2022
4c3d948
Revert "Update canvas.class.ts"
ShaMan123 Sep 18, 2022
e658ad0
Update matrix.ts
ShaMan123 Sep 18, 2022
7af98ae
fix(): shadow projection
ShaMan123 Sep 18, 2022
b85939b
Update matrix.ts
ShaMan123 Sep 18, 2022
fadd6cb
goldens
ShaMan123 Sep 18, 2022
d1af3e2
Update clippath.js
ShaMan123 Sep 18, 2022
e363c70
Update object.js
ShaMan123 Sep 18, 2022
1cc173e
rename `needsItsOwnCache` => `shouldRenderInIsolation`
ShaMan123 Sep 18, 2022
6fe6172
rename: `_drawClipPath` => `drawClipPath`
ShaMan123 Sep 18, 2022
ed86260
cleanup
ShaMan123 Sep 18, 2022
10edb3a
canvas provider
ShaMan123 Sep 18, 2022
4554852
Update object.class.ts
ShaMan123 Sep 18, 2022
7c60cc9
fix shadow casting under cache
ShaMan123 Sep 19, 2022
7060c7a
cleanup
ShaMan123 Sep 19, 2022
2789c05
cleanup
ShaMan123 Sep 19, 2022
ff07bdf
extract
ShaMan123 Sep 19, 2022
914abeb
BREAKING: reference clipped object on `clipPath`
ShaMan123 Sep 19, 2022
a0850c5
typo
ShaMan123 Sep 19, 2022
63d6efd
docs: comment
ShaMan123 Sep 19, 2022
a3a72e4
fix(): scale before reotation to correct strokeWidth
ShaMan123 Sep 19, 2022
ab81bc0
Update shadow.js
ShaMan123 Sep 19, 2022
0efc315
goldens
ShaMan123 Sep 19, 2022
f012781
Revert "fix(): scale before reotation to correct strokeWidth"
ShaMan123 Sep 19, 2022
9c85717
no stroke
ShaMan123 Sep 19, 2022
0a463a1
fix(): `absolutePositioned` `calcTransformMatrix`
ShaMan123 Sep 20, 2022
687cc98
add stack trace
ShaMan123 Sep 20, 2022
4b0130b
Update object.svg_export.ts
ShaMan123 Sep 20, 2022
3001858
fix(): group svg export
ShaMan123 Sep 20, 2022
6e21b15
cleanup
ShaMan123 Sep 20, 2022
a4a9013
fix(): group svg export
ShaMan123 Sep 20, 2022
2c3ea4c
cleaner impl
ShaMan123 Sep 20, 2022
83d3755
imports
ShaMan123 Sep 20, 2022
6b2e167
Update object.svg_export.ts
ShaMan123 Sep 20, 2022
c716e64
ws
ShaMan123 Sep 20, 2022
2bb6551
Update object.svg_export.ts
ShaMan123 Sep 20, 2022
00468ca
Update group.js
ShaMan123 Sep 20, 2022
7987763
rename
ShaMan123 Sep 20, 2022
e18d5c6
rename + ws
ShaMan123 Sep 20, 2022
6a868f9
ws fix
ShaMan123 Sep 20, 2022
a5fb4b1
group svg export
ShaMan123 Sep 20, 2022
63adead
Revert "group svg export"
ShaMan123 Sep 20, 2022
343bf88
Squashed commit of the following:
ShaMan123 Sep 20, 2022
8b6975b
Revert "Squashed commit of the following:"
ShaMan123 Sep 20, 2022
efe6b5d
Merge branch 'master' into refactor-object-rendering
ShaMan123 Sep 20, 2022
edeec1d
Update CHANGELOG.md
ShaMan123 Sep 20, 2022
6df62e5
Merge branch 'master' into refactor-group-to-svg
ShaMan123 Sep 21, 2022
970e54c
rename for the last time
ShaMan123 Sep 21, 2022
75dd5a1
tidy
ShaMan123 Sep 22, 2022
be4e436
rename
ShaMan123 Sep 22, 2022
13f6c6b
goldens
ShaMan123 Sep 22, 2022
dca461a
todo/skip action option
ShaMan123 Sep 22, 2022
ac441f7
Update clippath.js
ShaMan123 Sep 22, 2022
b66a9eb
Update clippath.js
ShaMan123 Sep 22, 2022
e5174ad
rename clipping-9
ShaMan123 Sep 22, 2022
df52eda
Update z_svg_export.js
ShaMan123 Sep 22, 2022
ae7ccf4
move back for svg tests
ShaMan123 Sep 22, 2022
077e34a
fix after moving file
ShaMan123 Sep 22, 2022
d42f11b
ci(): do not generate golden from CI
ShaMan123 Sep 22, 2022
218da2a
Delete fabric.js.map
ShaMan123 Sep 22, 2022
8e44b1a
Update visualTestLoop.js
ShaMan123 Sep 22, 2022
230fa3b
Merge branch 'refactor-group-to-svg' of https://github.com/fabricjs/f…
ShaMan123 Sep 22, 2022
06e9b43
Update CHANGELOG.md
ShaMan123 Sep 22, 2022
7956e56
Update CHANGELOG.md
ShaMan123 Sep 22, 2022
dbc47f4
Merge branch 'master' into refactor-group-to-svg
ShaMan123 Sep 23, 2022
c69fd8c
revert(): visual test refactoring
ShaMan123 Sep 23, 2022
8c1f451
Update CHANGELOG.md
ShaMan123 Sep 23, 2022
186f4a6
revert to disabled
ShaMan123 Sep 23, 2022
876cd6b
Merge branch 'master' into refactor-object-rendering
ShaMan123 Oct 1, 2022
84b88aa
feat(): 2 step rendering
ShaMan123 Oct 1, 2022
593958c
Merge branch 'refactor-group-to-svg' into refactor-object-rendering
ShaMan123 Oct 1, 2022
f58206e
fix(): unit tests
ShaMan123 Oct 4, 2022
f161d65
fix error
ShaMan123 Feb 27, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [next]

- refactor(): svg export logic to use `calcOwnMatrix` as a prerequisite for a fix to `calcTransformMatrix` based on [#8298](https://github.com/fabricjs/fabric.js/pull/8298), [#8305](https://github.com/fabricjs/fabric.js/pull/8305)
- ci(build): safeguard concurrent unlocking [#8309](https://github.com/fabricjs/fabric.js/pull/8309)
- ci(): update stale bot [#8307](https://github.com/fabricjs/fabric.js/pull/8307)
- ci(test): await golden generation in visual tests [#8284](https://github.com/fabricjs/fabric.js/pull/8284)
Expand Down
168 changes: 168 additions & 0 deletions src/RenderingContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import { iMatrix } from './constants';
import { multiplyTransformMatrices } from './util/misc/matrix';
import { Canvas, TObject } from './__types__';

export type TRenderingListing = {
target: TObject;
/**
* object/canvas being clipped by the target
*/
clipping?: TObject | Canvas;
/**
* target is being cached
*/
caching?: boolean;
};

type TRenderingAction =
| 'requested'
| 'canvas-export'
| 'object-export'
| 'hit-test';

type TRenderingOptions = {
/**
* setting this flag to `false` disables offscreen validation, all objects will be rendered.
*/
offscreenValidation?: boolean;

action?: TRenderingAction;
};

export class RenderingContext implements TRenderingOptions {
offscreenValidation = true;
action?: TRenderingAction;

tree: TRenderingListing[] = [];

static init(listing?: TRenderingListing, options?: TRenderingOptions) {
const context = new RenderingContext(options);
listing && context.push(listing);
return context;
}

constructor({ action, offscreenValidation = true }: TRenderingOptions = {}) {
this.action = action;
this.offscreenValidation = offscreenValidation;
}

push(listing: TRenderingListing) {
this.tree.push(Object.freeze({ ...listing }));
}

update(target: TObject, listing: Omit<TRenderingListing, 'target'>) {
const index = this.findIndex(target);
index > -1 &&
this.tree.splice(
index,
1,
Object.freeze({
...this.tree[index],
...listing,
target,
})
);
}

validateAtBottomOfTree(target: TObject) {
const index = this.findIndex(target);
if (index === -1) {
this.push({ target });
} else if (index !== this.tree.length - 1) {
throw new Error('fabric: rendering tree has been violated');
}
return this.tree[this.tree.length - 1];
}

findIndex(target: TObject) {
for (let index = this.tree.length - 1; index >= 0; index--) {
if (this.tree[index].target === target) {
return index;
}
}
return -1;
}

find(target: TObject): TRenderingListing | undefined {
return this.tree[this.findIndex(target)];
}

private slice(from?: TObject, to?: TObject, inclusive = false) {
const start = from ? this.findIndex(from) : -1;
const end = to ? this.findIndex(to) : -1;
return this.tree
.slice(
start > -1 ? start : undefined,
end > -1 ? end + Number(inclusive) : undefined
)
.reverse();
}

private getTreeUpTo(target?: TObject) {
return this.slice(undefined, target, true);
}

private getAncestors(target?: TObject) {
return this.slice(undefined, target, false);
}

shouldPerformOffscreenValidation(target: TObject) {
return (
this.offscreenValidation &&
this.action !== 'hit-test' &&
this.action !== 'object-export' &&
!this.getTreeUpTo(target).some(
({ caching, clipping }) => !!caching || !!clipping
)
);
}

shouldFireRenderingEvent() {
return this.action === 'requested' || !this.action;
}

isNested(target: TObject) {
return !!target.group && this.findIndex(target) > 0;
}

isClipping(target: TObject) {
return !!this.find(target)?.clipping;
}

isOnClipPath(target: TObject) {
return this.getAncestors(target).some(({ clipping }) => clipping);
}

isCaching(target: TObject) {
return !!this.find(target)?.caching;
}

isOnCache(target: TObject) {
return this.getAncestors(target).some(({ caching }) => caching);
}

/**
*
* @param target
* @returns the transform from the viewer to `target`
*/
calcTransformMatrix(target: TObject) {
return this.getTreeUpTo(target)
.reverse()
.reduce(
(mat, { target }) =>
multiplyTransformMatrices(target.calcOwnMatrix(), mat),
iMatrix
);
}

fork(listing?: TRenderingListing) {
const context = new RenderingContext({
action: this.action,
offscreenValidation: this.offscreenValidation,
});
context.tree = [...this.tree];
listing && context.push(listing);
return context;
}
}
14 changes: 11 additions & 3 deletions src/canvas.class.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//@ts-nocheck
import { Point } from './point.class';
import { RenderingContext } from './RenderingContext';

(function (global) {
var fabric = global.fabric,
Expand Down Expand Up @@ -514,7 +515,7 @@ import { Point } from './point.class';
* @return {fabric.Canvas} instance
* @chainable
*/
renderAll: function () {
renderAll: function (isRequested = false) {
this.cancelRequestedRender();
if (this.destroyed) {
return;
Expand All @@ -533,7 +534,13 @@ import { Point } from './point.class';
}
!this._objectsToRender &&
(this._objectsToRender = this._chooseObjectsToRender());
this.renderCanvas(this.contextContainer, this._objectsToRender);
this.renderCanvas(
this.contextContainer,
this._objectsToRender,
new RenderingContext({
action: isRequested ? 'requested' : undefined,
})
);
return this;
},

Expand Down Expand Up @@ -587,6 +594,7 @@ import { Point } from './point.class';
// because we need to draw controls too.
if (
target.shouldCache() &&
!target.isNotVisible() &&
target._cacheCanvas &&
target !== this._activeObject
) {
Expand Down Expand Up @@ -623,7 +631,7 @@ import { Point } from './point.class';

ctx.save();
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
target.render(ctx);
target.render(ctx, new RenderingContext({ action: 'hit-test' }));
ctx.restore();

target.selectionBackgroundColor = originalColor;
Expand Down
21 changes: 17 additions & 4 deletions src/mixins/canvas_dataurl_exporter.mixin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
//@ts-nocheck

import { RenderingContext } from '../RenderingContext';

(function (global) {
var fabric = global.fabric;
fabric.util.object.extend(
Expand Down Expand Up @@ -66,7 +69,9 @@
* @param {Number} [options.top] Cropping top offset.
* @param {Number} [options.width] Cropping width.
* @param {Number} [options.height] Cropping height.
* @param {fabric.Object[]} [options.objects] Objects to render, overrides the `filter` option.
* @param {(object: fabric.Object) => boolean} [options.filter] Function to filter objects.
* @param {boolean} [options.objectExport] flag indicating exporting an object.
*/
toCanvasElement: function (multiplier, options) {
multiplier = multiplier || 1;
Expand All @@ -85,9 +90,11 @@
originalRetina = this.enableRetinaScaling,
canvasEl = fabric.util.createCanvasElement(),
originalContextTop = this.contextTop,
objectsToRender = options.filter
? this._objects.filter(options.filter)
: this._objects;
objectsToRender =
options.objects ||
(options.filter
? this._objects.filter(options.filter)
: this._objects);
canvasEl.width = scaledWidth;
canvasEl.height = scaledHeight;
this.contextTop = null;
Expand All @@ -97,7 +104,13 @@
this.width = scaledWidth;
this.height = scaledHeight;
this.calcViewportBoundaries();
this.renderCanvas(canvasEl.getContext('2d'), objectsToRender);
this.renderCanvas(
canvasEl.getContext('2d'),
objectsToRender,
new RenderingContext({
action: options.objectExport ? 'object-export' : 'canvas-export',
})
);
this.viewportTransform = vp;
this.width = originalWidth;
this.height = originalHeight;
Expand Down
3 changes: 2 additions & 1 deletion src/mixins/canvas_events.mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,8 @@ import { fireEvent } from '../util/fireEvent';
_onMouseDownInDrawingMode: function (e) {
this._isCurrentlyDrawing = true;
if (this.getActiveObject()) {
this.discardActiveObject(e).requestRenderAll();
this.discardActiveObject(e);
this.requestRenderAll();
}
var pointer = this.getPointer(e);
this.freeDrawingBrush.onMouseDown(pointer, { e: e, pointer: pointer });
Expand Down
Loading