-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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(IText): **NO** clear context top during rendering #8560
Conversation
Build Stats
|
src/shapes/itext.class.ts
Outdated
@@ -273,7 +273,7 @@ export class IText extends ITextClickBehaviorMixin<ITextEvents> { | |||
* @param {CanvasRenderingContext2D} ctx Context to render on | |||
*/ | |||
render(ctx: CanvasRenderingContext2D) { | |||
this.clearContextTop(); | |||
// this.isEditing && this.clearContextTop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use blame and lets' see when it was introduced and in which context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linked to those 2 issues:
#3378
and
#3386
In the PR it was linked to this clearContextTop
https://github.com/fabricjs/fabric.js/pull/3388/files#diff-b8bf422caf940e8585d2c4dac83f8ef76ceb2a1c0ffbf986202492dad12a7cfaR335-R348
That was already safeguarded for isEditing and this.active ( that does not exist anymore )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in this PR here
https://github.com/fabricjs/fabric.js/pull/7802/files#diff-b8bf422caf940e8585d2c4dac83f8ef76ceb2a1c0ffbf986202492dad12a7cfaL281-L291
you removed clearContextTop from iText and you added it to generic object, but you lost the isEditing boolean.
So i would argue that the isEditing boolean should come back. no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am to blame indeed.
Why did I move it there in the first place? Does it make sense??
#3386 seems unrelated.
#3378 is, however the bug wasn't solved for all cases. I will add tests proving that.
I think I understand my confusion now.
https://github.com/fabricjs/fabric.js/blame/d6f9c8f98813717372c1510193edae123dbfba11/src/shapes/itext.class.js#L303-L320
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think it was moved to support dragging and in the process we did not notice the isEditing.
Is enough to add it back i suppose and add a test for isEditing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
next topic is clearContextTop
under initDimensions
I would argue this is not needed since canvas will have to render in order for visuals to update and now since contextTopDirty
is flagged this is taken care of.
Thoughts?
tests after this
src/shapes/textbox.class.ts
Outdated
this.clearContextTop(); | ||
if (this.isEditing) { | ||
this.initDelayedCursor(); | ||
this.clearContextTop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here
src/shapes/itext.class.ts
Outdated
this.clearContextTop(); | ||
if (this.isEditing) { | ||
this.initDelayedCursor(); | ||
this.clearContextTop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here
it become a large change to understand at a glance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explaining what is going on:
clearContextTop
suffers from a built in problem.
It clears the context with the known width/height values.
Efforts were made to overcome that (quite a lot it seems) and most of cases (distinct case no. 1, see below) were indeed fixed but not all (e.g. transforming). It did cause a need to track every case and clear the context before the change propagates to the instance, which is folly. More interaction, more cases, a mess.
The are 2 distinct cases in which we should consider how to act:
- changing selection only (which is not part of the rendering cycle due to perf, imperative in sight of context state)
- changing visuals (part of rendering, declarative in sight of context state)
Seems that efforts were focused on clearing context for the first case but the second case was neglected (rendering, transforming and many others). It can be understood since the first case was/is the main dev effort for making itext work. The second case is an integration thing, app level.
It is confusing. Some parts must be handled by the instance for perf reasons, same as brush.
But then we must have a mechanism that handles rendering.
Is that a good enough explanation?
The only immune way to cases is to mark the context as dirty and let the rendering cycle handle it. Same a brush does.
initDimensions
is a good example. The context was cleared before changes to size were committed to avoid leaving traces, but even though it is not 100% proof. Since canvas must be rendered in order for the new size to but visible we can safely hook to the rendering cycle.
Another thing that came to me is that
|
updated my explanation a bit |
src/mixins/itext_behavior.mixin.ts
Outdated
if (shouldClear) { | ||
this.clearContextTop(); | ||
} | ||
shouldClear && this.clearContextTop(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should investigate if the minifier does this for us and in case stop doing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in case it doesn't, u mean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how? everything is unreadable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think the minifier swap if (condition) { single line }
for condition && singleline
automatically
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not an issue of this pr but i don't think it make sense to be terse manualy now
@@ -306,19 +296,10 @@ export class IText extends ITextClickBehaviorMixin<ITextEvents> { | |||
} else { | |||
this.renderSelection(ctx, boundaries); | |||
} | |||
this.canvas!.contextTopDirty = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok the difference here is that swapping this with the one from our render function here https://github.com/fabricjs/fabric.js/pull/8560/files#diff-876b5f345ecc11628b120c60dfe0b3fde14630cc3940551bcb4ed23f41c580bcL275 we are swapping a partial contextTop clear with a full contextTop clear.
That is fine if it is needed and solves bugs.
Is that the case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indeed
re read my explanation. it is now clearer I hope. redone it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The render method calls renderCursorOrSelection
that runs only if in editing mode.
If the entire canvas is rendered it is 100% proof since the top context will be cleared by the canvas and then selection will be drawn by the instance that is being edited.
If we mess with the context outside w/o rendering canvas as we do with key/input events then we must clear context top as part of logic and we must take into account any changes to size of instance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add this to the decription
@asturur I have updated description and I am proud of it now. |
@asturur I am baffled I was thinking it is retina scaling, but I am not sure where the f*** it is |
So I am fed up with this shit and in reality I fixed it 🤬😡😖😱. |
Sorry i m a bit busy today but i m free tomorrow. |
Merged the retina fix. |
Merging now, great to have added tests. I had to revert the pure stylistic change i couldn't help myself. |
Motivation
There is an edge case where while using context top (free drawing) and a render occurs text instances render and clear their bbox from context top.
They shouldn't
Take a look at the video ending in a mouse up.
fabric.js.sandbox.-.Google.Chrome.2023-01-02.15-26-25_Trim.mp4
Description
clearContextTop
suffers from a built in problem.It clears the context with the known width/height values.
Efforts were made to overcome that (quite a lot it seems) and most of cases (distinct case no. 1, see below) were indeed fixed but not all (e.g. transforming). It did cause a need to track every case and clear the context before the change propagates to the instance, which is folly. More interaction, more cases, a mess.
There are 2 distinct cases in which we should consider how to act:
Seems that efforts were focused on clearing context for the first case but the second case was neglected (rendering, transforming and many others). It can be understood since the first case was/is the main dev effort for making itext work. The second case is an integration thing, app level.
Changes
removed clearing context top:
initDimensions
Gist
The render method calls
renderCursorOrSelection
that runs only if in editing mode.If executed it marks top context as dirty for the canvas rendering cycle.
Looking at what brush does and applying it to itext:
If the entire canvas is rendered it is 100% proof since the top context will be cleared by the canvas and then selection will be drawn by the instance that is being edited.
If we mess with the context w/o rendering canvas to handle selection as we do with key/input events then we must clear context top as part of logic and we must take into account any changes to size of instance and we should mark top context as dirty as well.
So the rule of thumb should be if we mess with selection alone then we call
clearContextTop
.initDimensions
is a good example for the confusion around this. The context was cleared before changes to size were committed to avoid leaving traces, but even though it was not 100% proof. Since canvas must be rendered in order for the new size to be visible it is a pure no. 2 distinct case so we can safely hook to the rendering cycle.In Action