Bug 234176 - Incorrect handling of NaN inside calc() for top-level calculation
Summary: Incorrect handling of NaN inside calc() for top-level calculation
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: CSS (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nikos Mouchtaris
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2021-12-10 14:42 PST by Mike Taylor
Modified: 2022-03-25 18:46 PDT (History)
13 users (show)

See Also:


Attachments
Patch (13.87 KB, patch)
2022-02-21 17:40 PST, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (12.98 KB, patch)
2022-02-21 23:05 PST, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (10.53 KB, patch)
2022-03-16 14:14 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (13.81 KB, patch)
2022-03-16 16:08 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (35.35 KB, patch)
2022-03-17 14:28 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (47.98 KB, patch)
2022-03-21 15:23 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (48.64 KB, patch)
2022-03-21 15:31 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (37.64 KB, patch)
2022-03-24 20:03 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (25.35 KB, patch)
2022-03-25 12:51 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (25.00 KB, patch)
2022-03-25 13:05 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff
Patch (16.22 KB, patch)
2022-03-25 15:28 PDT, Nikos Mouchtaris
simon.fraser: review+
Details | Formatted Diff | Diff
Patch (16.22 KB, patch)
2022-03-25 16:16 PDT, Nikos Mouchtaris
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mike Taylor 2021-12-10 14:42:00 PST
In https://drafts.csswg.org/css-values/#calc-type-checking, more specifically in https://drafts.csswg.org/css-values/#top-level-calculation, it states:

> If a top-level calculation (a math function not nested inside of another math function) would produce a value whose numeric part is NaN, it instead act as though the numeric part is +∞. 

Looking at https://wpt.fyi/results/css/css-values/calc-infinity-nan-computed.html?label=master&label=experimental&aligned&q=infinity-nan (source @ https://github.com/web-platform-tests/wpt/blob/master/css/css-values/calc-infinity-nan-computed.html#L19), Safari Tech Preview 136 is resolving "calc(NaN * 1px)" to "0", rather than ~Inifinity, like it does for "calc(infinity * 1px)".

Not sure if the spec was changed after the implementation in https://bugs.webkit.org/show_bug.cgi?id=231044, but it looks like a bug right now.

(there are other WPT failures, but I haven't looked closely at them)
Comment 1 Radar WebKit Bug Importer 2021-12-17 14:43:02 PST
<rdar://problem/86651372>
Comment 2 Nikos Mouchtaris 2022-02-21 17:40:27 PST
Created attachment 452804 [details]
Patch
Comment 3 EWS Watchlist 2022-02-21 17:42:06 PST
This patch modifies the imported WPT tests. Please ensure that any changes on the tests (not coming from a WPT import) are exported to WPT. Please see https://trac.webkit.org/wiki/WPTExportProcess
Comment 4 Jon Lee 2022-02-21 20:39:53 PST
Comment on attachment 452804 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=452804&action=review

> Source/WebCore/platform/animation/Animation.h:144
> +    void setDuration(double d) { m_duration = d; m_durationSet = true; }

Why remove the assert?
Comment 5 Nikos Mouchtaris 2022-02-21 23:05:36 PST
Created attachment 452831 [details]
Patch
Comment 6 Nikos Mouchtaris 2022-02-21 23:06:32 PST
(In reply to Jon Lee from comment #4)
> Comment on attachment 452804 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=452804&action=review
> 
> > Source/WebCore/platform/animation/Animation.h:144
> > +    void setDuration(double d) { m_duration = d; m_durationSet = true; }
> 
> Why remove the assert?

This was originally causing the test to crash but that is not the case now with the fix. Fixed.
Comment 7 Nikos Mouchtaris 2022-03-16 14:14:36 PDT
Created attachment 454892 [details]
Patch
Comment 8 Simon Fraser (smfr) 2022-03-16 16:02:36 PDT
Comment on attachment 454892 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=454892&action=review

> LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-infinity-nan-computed.html:48
> +// test_computed_value_greater_or_lower_than("width", "calc(NaN * 1px)", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1px)", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1cm)", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("width", "calc(NaN * 1rem)", APPROX_INFINITY);
> +
> +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1px - infinity * 1%)", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1px + infinity * 1%)", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("width", "calc(min(NaN * 1px, infinity * 1px) + max(infinity * 1px, -infinity * 1px))", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1px - max(infinity * 1%, 0%))", APPROX_INFINITY);
> +
> +// test_computed_value_greater_or_lower_than("width", "calc(max(infinity * 1px, 10px))", APPROX_INFINITY);
> +
> +// test_computed_value_greater_or_lower_than("margin-left", "calc(-infinity * 1px)", APPROX_NEGATIVE_INFINITY);
> +// test_computed_value_greater_or_lower_than("margin-left", "calc(min(1px, -infinity * 1%))", APPROX_NEGATIVE_INFINITY);
> +
> +// test_computed_value_greater_or_lower_than("margin-left", "calc(-infinity * 1%)", APPROX_NEGATIVE_INFINITY);
> +// test_computed_value_greater_or_lower_than("margin-left", "calc(max(10000px, 0px) + min(-infinity * 1px, infinity * 1px))", APPROX_NEGATIVE_INFINITY);
> +
> +// test_computed_value_greater_or_lower_than("margin-left", "calc(-infinity * 1px - infinity * 1px)", APPROX_NEGATIVE_INFINITY);
> +// test_computed_value_greater_or_lower_than("margin-left", "calc(min(-infinity * 1px, 10px))", APPROX_NEGATIVE_INFINITY);
> +
> +// // For <time>
> +// test_computed_value_greater_or_lower_than("animation-duration", "calc(NaN * 1s)", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("animation-duration", "calc(infinity * 1s)", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("animation-duration", "calc(1 / 0 * 1s)", APPROX_INFINITY);
> +// test_computed_value_greater_or_lower_than("animation-duration", "calc(max(infinity * 1s, 10s)", APPROX_INFINITY);
> +
> +// test_computed_value_greater_or_lower_than("transition-delay", "calc(-infinity* 1s)", APPROX_NEGATIVE_INFINITY);
> +// test_computed_value_greater_or_lower_than("transition-delay", "calc(max(10000s, 0s) + min(-infinity * 1s, infinity * 1s))", APPROX_NEGATIVE_INFINITY);
> +// test_computed_value_greater_or_lower_than("transition-delay", "calc(min(-infinity * 1s, 10s))", APPROX_NEGATIVE_INFINITY);

I don't think you meant to leave these all commented out.
Comment 9 Nikos Mouchtaris 2022-03-16 16:08:04 PDT
Created attachment 454906 [details]
Patch
Comment 10 Nikos Mouchtaris 2022-03-16 16:09:18 PDT
(In reply to Simon Fraser (smfr) from comment #8)
> Comment on attachment 454892 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=454892&action=review
> 
> > LayoutTests/imported/w3c/web-platform-tests/css/css-values/calc-infinity-nan-computed.html:48
> > +// test_computed_value_greater_or_lower_than("width", "calc(NaN * 1px)", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1px)", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1cm)", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("width", "calc(NaN * 1rem)", APPROX_INFINITY);
> > +
> > +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1px - infinity * 1%)", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1px + infinity * 1%)", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("width", "calc(min(NaN * 1px, infinity * 1px) + max(infinity * 1px, -infinity * 1px))", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("width", "calc(infinity * 1px - max(infinity * 1%, 0%))", APPROX_INFINITY);
> > +
> > +// test_computed_value_greater_or_lower_than("width", "calc(max(infinity * 1px, 10px))", APPROX_INFINITY);
> > +
> > +// test_computed_value_greater_or_lower_than("margin-left", "calc(-infinity * 1px)", APPROX_NEGATIVE_INFINITY);
> > +// test_computed_value_greater_or_lower_than("margin-left", "calc(min(1px, -infinity * 1%))", APPROX_NEGATIVE_INFINITY);
> > +
> > +// test_computed_value_greater_or_lower_than("margin-left", "calc(-infinity * 1%)", APPROX_NEGATIVE_INFINITY);
> > +// test_computed_value_greater_or_lower_than("margin-left", "calc(max(10000px, 0px) + min(-infinity * 1px, infinity * 1px))", APPROX_NEGATIVE_INFINITY);
> > +
> > +// test_computed_value_greater_or_lower_than("margin-left", "calc(-infinity * 1px - infinity * 1px)", APPROX_NEGATIVE_INFINITY);
> > +// test_computed_value_greater_or_lower_than("margin-left", "calc(min(-infinity * 1px, 10px))", APPROX_NEGATIVE_INFINITY);
> > +
> > +// // For <time>
> > +// test_computed_value_greater_or_lower_than("animation-duration", "calc(NaN * 1s)", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("animation-duration", "calc(infinity * 1s)", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("animation-duration", "calc(1 / 0 * 1s)", APPROX_INFINITY);
> > +// test_computed_value_greater_or_lower_than("animation-duration", "calc(max(infinity * 1s, 10s)", APPROX_INFINITY);
> > +
> > +// test_computed_value_greater_or_lower_than("transition-delay", "calc(-infinity* 1s)", APPROX_NEGATIVE_INFINITY);
> > +// test_computed_value_greater_or_lower_than("transition-delay", "calc(max(10000s, 0s) + min(-infinity * 1s, infinity * 1s))", APPROX_NEGATIVE_INFINITY);
> > +// test_computed_value_greater_or_lower_than("transition-delay", "calc(min(-infinity * 1s, 10s))", APPROX_NEGATIVE_INFINITY);
> 
> I don't think you meant to leave these all commented out.
Fixed.
Comment 11 Nikos Mouchtaris 2022-03-17 14:28:09 PDT
Created attachment 455028 [details]
Patch
Comment 12 Nikos Mouchtaris 2022-03-21 15:23:37 PDT
Created attachment 455281 [details]
Patch
Comment 13 Nikos Mouchtaris 2022-03-21 15:31:31 PDT
Created attachment 455286 [details]
Patch
Comment 14 Nikos Mouchtaris 2022-03-22 12:38:13 PDT
https://github.com/web-platform-tests/wpt/pull/33306
Comment 15 Nikos Mouchtaris 2022-03-24 20:03:10 PDT
Created attachment 455720 [details]
Patch
Comment 16 Nikos Mouchtaris 2022-03-25 12:51:14 PDT
Created attachment 455793 [details]
Patch
Comment 17 Nikos Mouchtaris 2022-03-25 13:05:51 PDT
Created attachment 455794 [details]
Patch
Comment 18 Simon Fraser (smfr) 2022-03-25 15:11:26 PDT
Comment on attachment 455794 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=455794&action=review

> Source/WebCore/css/calc/CSSCalcOperationNode.cpp:1524
> +    return depth ? result : convertToTopLevelValue(result);

Maybe it makes more sense for the caller to do this, rather than passing 'depth' into this function? There should be just one place we know we're at the root, I think?

> Source/WebCore/css/calc/CSSCalcOperationNode.h:134
> +    static double evaluateOperator(CalcOperator, const Vector<double>&, bool depth);

'depth' sounds integral, not boolean.

> Source/WebCore/css/calc/CSSCalcOperationNode.h:147
>      bool m_allowsNegativePercentageReference = false;
> +    bool m_depth = false;

= { false }

and depth should have a different name, or maybe be an enum class IsRoot : bool { No, Yes }
Comment 19 Nikos Mouchtaris 2022-03-25 15:28:02 PDT
Created attachment 455802 [details]
Patch
Comment 20 Nikos Mouchtaris 2022-03-25 15:28:32 PDT
(In reply to Simon Fraser (smfr) from comment #18)
> Comment on attachment 455794 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=455794&action=review
> 
> > Source/WebCore/css/calc/CSSCalcOperationNode.cpp:1524
> > +    return depth ? result : convertToTopLevelValue(result);
> 
> Maybe it makes more sense for the caller to do this, rather than passing
> 'depth' into this function? There should be just one place we know we're at
> the root, I think?
Fixed.
> 
> > Source/WebCore/css/calc/CSSCalcOperationNode.h:134
> > +    static double evaluateOperator(CalcOperator, const Vector<double>&, bool depth);
> 
> 'depth' sounds integral, not boolean.

Fixed.
> 
> > Source/WebCore/css/calc/CSSCalcOperationNode.h:147
> >      bool m_allowsNegativePercentageReference = false;
> > +    bool m_depth = false;
> 
> = { false }
> 
> and depth should have a different name, or maybe be an enum class IsRoot :
> bool { No, Yes }
Fixed.
Comment 21 Nikos Mouchtaris 2022-03-25 16:16:12 PDT
Created attachment 455808 [details]
Patch
Comment 22 EWS 2022-03-25 18:46:34 PDT
Committed r291911 (248899@main): <https://commits.webkit.org/248899@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 455808 [details].