WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
202815
[FTW] Correct radial gradient handling of various radius orderings
https://bugs.webkit.org/show_bug.cgi?id=202815
Summary
[FTW] Correct radial gradient handling of various radius orderings
Brent Fulgham
Reported
2019-10-10 11:21:08 PDT
The initial Direct2D Radial Gradient implementation did not properly handle cases where the order of the two radius arguments were not small-to-large. This led to incorrect drawing in some cases tested in the 'canvas/Philip' test set. This patch handles these cases.
Attachments
Patch
(4.35 KB, patch)
2019-10-10 11:27 PDT
,
Brent Fulgham
no flags
Details
Formatted Diff
Diff
Patch
(4.25 KB, patch)
2019-10-16 09:31 PDT
,
Brent Fulgham
no flags
Details
Formatted Diff
Diff
Patch
(5.12 KB, patch)
2019-10-16 17:32 PDT
,
Brent Fulgham
no flags
Details
Formatted Diff
Diff
Show Obsolete
(2)
View All
Add attachment
proposed patch, testcase, etc.
Brent Fulgham
Comment 1
2019-10-10 11:27:27 PDT
Created
attachment 380664
[details]
Patch
Brent Fulgham
Comment 2
2019-10-10 11:29:03 PDT
This corrects three radius gradient test cases.
Per Arne Vollan
Comment 3
2019-10-10 13:18:31 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:137 > - [&] (const RadialData& data) { > + [&] (RadialData& data) {
It does not seem like the data parameter is modified, can we keep the const modifier?
Brent Fulgham
Comment 4
2019-10-10 14:07:10 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:137 >> + [&] (RadialData& data) { > > It does not seem like the data parameter is modified, can we keep the const modifier?
Yes. I modified while experimenting with another change, and forgot to put this back. I'll fix it.
Per Arne Vollan
Comment 5
2019-10-10 17:57:36 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:99 > + std::stable_sort(gradientStops.begin(), gradientStops.end(), [](const D2D1_GRADIENT_STOP& a, const D2D1_GRADIENT_STOP& b) { > + return a.position < b.position; > + });
Is sorting needed here, or is it sufficient to reverse the list of gradient stops?
Fujii Hironori
Comment 6
2019-10-10 18:52:24 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:79 > if (data.startRadius && data.endRadius) {
Which test cases are using this code path? I can't find code setting startRadius and endRadius. Can they be negative values?
Fujii Hironori
Comment 7
2019-10-10 18:54:26 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
> Source/WebCore/PlatformFTW.cmake:3 > +else ()
Use NOT. And, indent the the inside. if (NOT APPLE) include(platform/ImageDecoders.cmake) endif ()
Fujii Hironori
Comment 8
2019-10-10 18:58:41 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:79 >> if (data.startRadius && data.endRadius) { > > Which test cases are using this code path? > I can't find code setting startRadius and endRadius. > Can they be negative values?
I found it. It is canvas.createRadialGradient.
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createRadialGradient
negative values are checked in CanvasRenderingContext2DBase::createRadialGradient.
Fujii Hironori
Comment 9
2019-10-10 19:16:43 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:83 > startPosition = 1.0 / startPosition;
Can startPosition be zero? Then, zero-devision can happen.
Fujii Hironori
Comment 10
2019-10-10 19:25:10 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:83 >> startPosition = 1.0 / startPosition; > > Can startPosition be zero? Then, zero-devision can happen.
Oops. Never mind. It is always >1.0.
Fujii Hironori
Comment 11
2019-10-10 19:41:45 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
>>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:79 >>> if (data.startRadius && data.endRadius) { >> >> Which test cases are using this code path? >> I can't find code setting startRadius and endRadius. >> Can they be negative values? > > I found it. It is canvas.createRadialGradient. >
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createRadialGradient
> > negative values are checked in CanvasRenderingContext2DBase::createRadialGradient.
I think this is not a right condition for restoring start position. It should be if (data.startRadius || data.endRadius) { I think swapping startRadius and endRadius should be done before. Then, this condition can be: if (data.startRadius) { I think this is the condition which is easy to understand when restoring start position is needed.
Fujii Hironori
Comment 12
2019-10-10 19:55:48 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
>>>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:79 >>>> if (data.startRadius && data.endRadius) { >>> >>> Which test cases are using this code path? >>> I can't find code setting startRadius and endRadius. >>> Can they be negative values? >> >> I found it. It is canvas.createRadialGradient. >>
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/createRadialGradient
>> >> negative values are checked in CanvasRenderingContext2DBase::createRadialGradient. > > I think this is not a right condition for restoring start position. It should be > > if (data.startRadius || data.endRadius) { > > I think swapping startRadius and endRadius should be done before. Then, this condition can be: > > if (data.startRadius) { > > I think this is the condition which is easy to understand when restoring start position is needed.
You should split reversing stops and restoring the first position if (data.startRadius > data.endRadius) { // Reverse stops... std::swap(data.startRadius, data.endRadius); } if (data.startRadius) { // Restore first position... }
Fujii Hironori
Comment 13
2019-10-10 21:20:01 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:143 > + offset.setHeight(offset.height() - radiusDiff);
In my understanding this is the real offset. Am I worng?
https://ibb.co/hFfD7D0
Brent Fulgham
Comment 14
2019-10-15 18:33:09 PDT
(In reply to Fujii Hironori from
comment #6
)
> Comment on
attachment 380664
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
> > > Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:79 > > if (data.startRadius && data.endRadius) { > > Which test cases are using this code path?
We hit this code path in the following cases: canvas/philip/tests/2d.gradient.radial.inside2.html canvas/philip/tests/2d.gradient.radial.inside3.html canvas/philip/tests/2d.gradient.radial.outside2.html canvas/philip/tests/2d.gradient.radial.outside3.html canvas/philip/tests/2d.gradient.radial.touch2.html
Brent Fulgham
Comment 15
2019-10-15 18:43:55 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
>> Source/WebCore/PlatformFTW.cmake:3 >> +else () > > Use NOT. And, indent the the inside. > > if (NOT APPLE) > include(platform/ImageDecoders.cmake) > endif ()
Okay
>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:143 >> + offset.setHeight(offset.height() - radiusDiff); > > In my understanding this is the real offset. Am I worng?
https://ibb.co/hFfD7D0
Yes -- I think that is correct.
Fujii Hironori
Comment 16
2019-10-16 01:07:18 PDT
Comment on
attachment 380664
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
>>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:143 >>> + offset.setHeight(offset.height() - radiusDiff); >> >> In my understanding this is the real offset. Am I worng?
https://ibb.co/hFfD7D0
> > Yes -- I think that is correct.
Then, offset should look like: offset = (point1 * startRadius - point0 * endRadius) / (startRadius - endRadius)
Brent Fulgham
Comment 17
2019-10-16 09:31:06 PDT
Created
attachment 381074
[details]
Patch
Brent Fulgham
Comment 18
2019-10-16 09:33:05 PDT
(In reply to Fujii Hironori from
comment #16
)
> Comment on
attachment 380664
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=380664&action=review
> > >>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:143 > >>> + offset.setHeight(offset.height() - radiusDiff); > >> > >> In my understanding this is the real offset. Am I worng?
https://ibb.co/hFfD7D0
> > > > Yes -- I think that is correct. > > Then, offset should look like: > > offset = (point1 * startRadius - point0 * endRadius) / (startRadius - > endRadius)
Thank you -- that actually corrected one additional test! :-)
Per Arne Vollan
Comment 19
2019-10-16 13:47:40 PDT
Comment on
attachment 381074
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=381074&action=review
> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:92 > + if (data.startRadius) { > float startPosition = std::abs(data.startRadius / data.endRadius);
Do we need to check that data.endRadius > 0 here, to avoid division by zero?
Brent Fulgham
Comment 20
2019-10-16 17:09:59 PDT
Comment on
attachment 381074
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=381074&action=review
>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:92 >> float startPosition = std::abs(data.startRadius / data.endRadius); > > Do we need to check that data.endRadius > 0 here, to avoid division by zero?
We require that data.startRadius and data.endRadius are > 0 on lines 79/80, so I don't think so?
Per Arne Vollan
Comment 21
2019-10-16 17:16:03 PDT
Comment on
attachment 381074
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=381074&action=review
>>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:92 >>> float startPosition = std::abs(data.startRadius / data.endRadius); >> >> Do we need to check that data.endRadius > 0 here, to avoid division by zero? > > We require that data.startRadius and data.endRadius are > 0 on lines 79/80, so I don't think so?
We seem to require that data.endRadius >= 0, perhaps the release assert should be changed?
Brent Fulgham
Comment 22
2019-10-16 17:23:42 PDT
Comment on
attachment 381074
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=381074&action=review
>>>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:92 >>>> float startPosition = std::abs(data.startRadius / data.endRadius); >>> >>> Do we need to check that data.endRadius > 0 here, to avoid division by zero? >> >> We require that data.startRadius and data.endRadius are > 0 on lines 79/80, so I don't think so? > > We seem to require that data.endRadius >= 0, perhaps the release assert should be changed?
Oh, I see. Good point. I'll change that. However, we require that data.startRadius <= data.endRadius, and then check that data.startRadius is non-zero, so I don't think it's possible to get here with a zero data.endRadius. But I'll add a RELEASE_ASSERT just to be sure.
Brent Fulgham
Comment 23
2019-10-16 17:32:32 PDT
Created
attachment 381138
[details]
Patch
Per Arne Vollan
Comment 24
2019-10-16 18:08:07 PDT
Comment on
attachment 381138
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=381138&action=review
R=me.
> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:147 > + if (!circleIsEntirelyContained(data.point0, data.startRadius, data.point1, data.endRadius)) > + offset = (data.point1.scaled(data.startRadius) - data.point0.scaled(data.endRadius)) / (data.endRadius - data.startRadius);
Why was this check needed? Did adding this check fix more tests?
WebKit Commit Bot
Comment 25
2019-10-16 18:53:24 PDT
Comment on
attachment 381138
[details]
Patch Clearing flags on attachment: 381138 Committed
r251221
: <
https://trac.webkit.org/changeset/251221
>
WebKit Commit Bot
Comment 26
2019-10-16 18:53:26 PDT
All reviewed patches have been landed. Closing bug.
Radar WebKit Bug Importer
Comment 27
2019-10-16 18:54:15 PDT
<
rdar://problem/56355288
>
Brent Fulgham
Comment 28
2019-10-16 19:13:09 PDT
Comment on
attachment 381138
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=381138&action=review
>> Source/WebCore/platform/graphics/win/GradientDirect2D.cpp:147 >> + offset = (data.point1.scaled(data.startRadius) - data.point0.scaled(data.endRadius)) / (data.endRadius - data.startRadius); > > Why was this check needed? Did adding this check fix more tests?
Yes. The behavior of the gradient is different if one circle is completely contained within the other. Then the focus calculation that Fujii proposed is not valid and produces incorrect rendering.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug