Bug 1873802: Make nsRangeFrame place the thumb at the minimum position if it happens to get reflowed before its element is done being created. r=emilio

Some context:
- Our HTML parser treats element creation, attribute-parsing, and
  "DoneCreatingElement"-calls as being separate operations, and it can yield
  between them.
- HTMLInputElement doesn't sanitize its values until DoneCreatingElement has
  been called, presumably sanitization itself depends on values (e.g. min/max)
  that might not have been parsed yet.
- So if the HTML parser yields at just the right point (before
  DoneCreatingElement), then we might generate and reflow a nsRangeFrame whose
  underlying values (on the element) haven't yet been sanitized.

This patch handles this situation by exposing a getter to tell us whether
DoneCreatingElement has been called.  If that getter returns false, we assume
that value-sanitization hasn't happened, and we disregard the element's
(presumed-to-be-unsanitized) numeric values when determining the
range's thumb-position.

Differential Revision: https://phabricator.services.mozilla.com/D198331
This commit is contained in:
Daniel Holbert 2024-01-16 17:38:30 +00:00
parent 59d7d764bb
commit d6f406d8ba
4 changed files with 131 additions and 1 deletions

View File

@ -170,6 +170,10 @@ class HTMLInputElement final : public TextControlElement,
nsIPrincipal* aMaybeScriptedPrincipal,
nsAttrValue& aResult) override;
// Note: if this returns false, then attributes may not yet be sanitized
// (per SetValueInternal's dependence on mDoneCreating).
bool IsDoneCreating() const { return mDoneCreating; }
bool LastValueChangeWasInteractive() const {
return mLastValueChangeWasInteractive;
}

View File

@ -0,0 +1,114 @@
<html>
<head>
<script></script>
<script>
</script>
<!-- foo -->
<!-- foo -->
<button>jLNJegDr5m(\r74f??</button>
<details>
<summary>
<img></img>
</summary>
h45@|V+J)</details>
<p>
<title>N=y)sO6</title>
</p>
<iframe>B9xX</iframe>
<style>
</style>
<h2>
<form>
<object>
<param></param>
<param></param>
</object>
</form>
<q>
<ol>
<li></li>
</ol>
</q>
</h2>
<dir>#]76[#&lt;I%!&quot;Rrs.wL</dir>
<table>
<tbody>}}</tbody>
<video>
<track>rUe</track>
</video>
<caption>W9A1.&quot;\84gtu6%d</caption>
<colgroup>k9</colgroup>
<pre>6,$.MxUA&lt;F</pre>
<b>
<keygen>
</b>
</del>
<select>
<optgroup>
<option>Cm]</option>
<option>
<basefont></basefont>
<h3>
<data>
<canvas>
<svg>
<set />
<path>
<animateTransform />
</path>
<defs>
<feFuncA />
</defs>
<metadata>
<meshgradient>
<feMergeNode>
<feMergeNode>
<feFlood />
<altGlyphItem />
<clipPath />
<feDistantLight />
<solidcolor />
</feMergeNode>
<font />
<discard />
</feMergeNode>
<feDropShadow />
</meshgradient>
<feDiffuseLighting>
<fePointLight />
<fePointLight />
<feSpotLight />
</feDiffuseLighting>
</metadata>
<rect>
<discard />
<animateTransform />
</rect>
<text>
<set />
<tref>
<unknown>
<solidcolor>
<unknown />
<pattern>
<animateColor />
</pattern>
</solidcolor>
</unknown>
<text />
<meshrow />
</tref>
Text</text>
<mask />
<discard />
<feDistantLight />
<desc>0R</desc>
</svg>
<img></img>
</canvas>
</command>
<pre>
<video>
<track>
<input type="range">
<!-- foo -->

View File

@ -77,3 +77,4 @@ load 1617753.html
load 1679471.html
load 1690166-1.html
load 1690166-2.html
load 1873802-1.html

View File

@ -315,7 +315,18 @@ a11y::AccType nsRangeFrame::AccessibleType() { return a11y::eHTMLRangeType; }
#endif
double nsRangeFrame::GetValueAsFractionOfRange() {
return GetDoubleAsFractionOfRange(InputElement().GetValueAsDecimal());
const auto& input = InputElement();
if (MOZ_UNLIKELY(!input.IsDoneCreating())) {
// Our element isn't done being created, so its values haven't yet been
// sanitized! (It's rare that we'd be reflowed when our element is in this
// state, but it can happen if the parser decides to yield while processing
// its tasks to build the element.) We can't trust that any of our numeric
// values will make sense until they've been sanitized; so for now, just
// use 0.0 as a fallback fraction-of-range value here (i.e. behave as if
// we're at our minimum, which is how the spec handles some edge cases).
return 0.0;
}
return GetDoubleAsFractionOfRange(input.GetValueAsDecimal());
}
double nsRangeFrame::GetDoubleAsFractionOfRange(const Decimal& aValue) {