Bug 1700640 - Map width and height to aspect-ratio in <canvas>, <input type=image>, and <video>. r=boris

As per https://html.spec.whatwg.org/#attributes-for-embedded-content-and-images:

> The width and height attributes map to the aspect-ratio property on
> img, canvas, and video elements, and input elements with a type
> attribute in the Image Button state.

See https://github.com/whatwg/html/issues/6527 for the parsing issue
with canvas and zero. For now allow both behaviors in the tests.

We also remove the width-and-height-map-to-aspect-ratio pref, as it is
true everywhere and has been for a while.

Differential Revision: https://phabricator.services.mozilla.com/D109618
This commit is contained in:
Emilio Cobos Álvarez 2021-03-24 22:18:55 +00:00
parent c961ad004f
commit 7f5364389c
14 changed files with 136 additions and 108 deletions

View File

@ -597,6 +597,26 @@ nsChangeHint HTMLCanvasElement::GetAttributeChangeHint(const nsAtom* aAttribute,
return retval;
}
void HTMLCanvasElement::MapAttributesIntoRule(
const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
MapAspectRatioInto(aAttributes, aDecls);
MapCommonAttributesInto(aAttributes, aDecls);
}
nsMapRuleToAttributesFunc HTMLCanvasElement::GetAttributeMappingFunction()
const {
return &MapAttributesIntoRule;
}
NS_IMETHODIMP_(bool)
HTMLCanvasElement::IsAttributeMapped(const nsAtom* aAttribute) const {
static const MappedAttributeEntry attributes[] = {
{nsGkAtoms::width}, {nsGkAtoms::height}, {nullptr}};
static const MappedAttributeEntry* const map[] = {attributes,
sCommonAttributeMap};
return FindAttributeDependence(aAttribute, map);
}
bool HTMLCanvasElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,

View File

@ -281,14 +281,19 @@ class HTMLCanvasElement final : public nsGenericHTMLElement,
const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,
nsAttrValue& aResult) override;
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const override;
nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
int32_t aModType) const override;
nsMapRuleToAttributesFunc GetAttributeMappingFunction() const override;
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
nsresult CopyInnerTo(HTMLCanvasElement* aDest);
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
MappedDeclarations&);
/*
* Helpers called by various users of Canvas
*/

View File

@ -5133,8 +5133,8 @@ void HTMLInputElement::ImageInputMapAttributesIntoRule(
aDecls);
nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes,
aDecls);
nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes,
aDecls);
nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(
aAttributes, aDecls, MapAspectRatio::Yes);
// Images treat align as "float"
nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes,
aDecls);

View File

@ -163,7 +163,8 @@ bool HTMLVideoElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
void HTMLVideoElement::MapAttributesIntoRule(
const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls);
nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aDecls,
MapAspectRatio::Yes);
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aDecls);
}

View File

@ -1335,6 +1335,28 @@ void nsGenericHTMLElement::MapHeightAttributeInto(
}
}
static void DoMapAspectRatio(const nsAttrValue& aWidth,
const nsAttrValue& aHeight,
MappedDeclarations& aDecls) {
Maybe<double> w;
if (aWidth.Type() == nsAttrValue::eInteger) {
w.emplace(aWidth.GetIntegerValue());
} else if (aWidth.Type() == nsAttrValue::eDoubleValue) {
w.emplace(aWidth.GetDoubleValue());
}
Maybe<double> h;
if (aHeight.Type() == nsAttrValue::eInteger) {
h.emplace(aHeight.GetIntegerValue());
} else if (aHeight.Type() == nsAttrValue::eDoubleValue) {
h.emplace(aHeight.GetDoubleValue());
}
if (w && h) {
aDecls.SetAspectRatio(*w, *h);
}
}
void nsGenericHTMLElement::MapImageSizeAttributesInto(
const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls,
MapAspectRatio aMapAspectRatio) {
@ -1346,25 +1368,17 @@ void nsGenericHTMLElement::MapImageSizeAttributesInto(
if (height) {
MapDimensionAttributeInto(aDecls, eCSSProperty_height, *height);
}
if (StaticPrefs::layout_css_width_and_height_map_to_aspect_ratio_enabled() &&
aMapAspectRatio == MapAspectRatio::Yes && width && height) {
Maybe<double> w;
if (width->Type() == nsAttrValue::eInteger) {
w.emplace(width->GetIntegerValue());
} else if (width->Type() == nsAttrValue::eDoubleValue) {
w.emplace(width->GetDoubleValue());
}
if (aMapAspectRatio == MapAspectRatio::Yes && width && height) {
DoMapAspectRatio(*width, *height, aDecls);
}
}
Maybe<double> h;
if (height->Type() == nsAttrValue::eInteger) {
h.emplace(height->GetIntegerValue());
} else if (height->Type() == nsAttrValue::eDoubleValue) {
h.emplace(height->GetDoubleValue());
}
if (w && h && *w != 0 && *h != 0) {
aDecls.SetAspectRatio(*w, *h);
}
void nsGenericHTMLElement::MapAspectRatioInto(
const nsMappedAttributes* aAttributes, MappedDeclarations& aDecls) {
auto* width = aAttributes->GetAttr(nsGkAtoms::width);
auto* height = aAttributes->GetAttr(nsGkAtoms::height);
if (width && height) {
DoMapAspectRatio(*width, *height, aDecls);
}
}

View File

@ -519,6 +519,17 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase {
static void MapImageSizeAttributesInto(const nsMappedAttributes*,
mozilla::MappedDeclarations&,
MapAspectRatio = MapAspectRatio::No);
/**
* Helper to map the width and height attributes into the aspect-ratio
* property.
*
* If you also map the width/height attributes to width/height (as you should
* for any HTML element that isn't <canvas>) then you should use
* MapImageSizeAttributesInto instead, passing MapAspectRatio::Yes instead, as
* that'd be faster.
*/
static void MapAspectRatioInto(const nsMappedAttributes*,
mozilla::MappedDeclarations&);
/**
* Helper to map `width` attribute into a style struct.

View File

@ -6985,13 +6985,6 @@
value: true
mirror: always
# Are the width and height attributes on image-like elements mapped to the
# internal-for-now aspect-ratio property?
- name: layout.css.width-and-height-map-to-aspect-ratio.enabled
type: bool
value: true
mirror: always
# Whether :is() and :where() ignore errors inside their selector lists
# internally, rather than failing to parse altogether.
#

View File

@ -1,11 +1,2 @@
[canvas-aspect-ratio.html]
[Canvas width and height attributes are used as the surface size with contain:size]
expected: FAIL
[Computed style]
expected: FAIL
[Computed style for invalid ratios]
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1693029
expected:
if release_or_beta: FAIL
prefs: [layout.css.aspect-ratio.enabled:true]

View File

@ -1,9 +1,2 @@
[img-aspect-ratio.html]
prefs: [layout.css.width-and-height-map-to-aspect-ratio.enabled:true]
[Computed style]
expected: FAIL
[Computed style for invalid ratios]
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1693029
expected:
if release_or_beta: FAIL
prefs: [layout.css.aspect-ratio.enabled:true]

View File

@ -1,11 +1,2 @@
[video-aspect-ratio.html]
[Video width and height attributes are not used to infer aspect-ratio]
expected: FAIL
[Computed style]
expected: FAIL
[Computed style for invalid ratios]
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1693029
expected:
if release_or_beta: FAIL
prefs: [layout.css.aspect-ratio.enabled:true]

View File

@ -1,5 +1,5 @@
<!doctype html>
<title>Canvas width and height attributes are used as the surface size</title>
<title>Canvas width and height attributes are used as the surface size, and also to infer aspect ratio</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/aspect-ratio.js"></script>
@ -37,20 +37,22 @@ test(function() {
assert_ratio(canvas, 2.5);
}, "Canvas width and height attributes are used as the surface size");
test(function() {
test_computed_style("10", "20", "auto 10 / 20");
test_computed_style("0", "1", "auto 0 / 1");
test_computed_style("1", "0", "auto 1 / 0");
test_computed_style("0", "0", "auto 0 / 0");
test_computed_style("0.5", "1.5", "auto 0.5 / 1.5");
}, "Computed style");
test_computed_style("10", "20", "auto 10 / 20");
// These are invalid per spec, but see
// https://github.com/whatwg/html/issues/4961
test_computed_style("0", "1", ["auto", "auto 0 / 1"]);
test_computed_style("1", "0", ["auto", "auto 1 / 0"]);
test_computed_style("0", "0", ["auto", "auto 0 / 0"]);
test(function() {
test_computed_style(null, null, "auto");
test_computed_style("10", null, "auto");
test_computed_style(null, "20", "auto");
test_computed_style("xx", "20", "auto");
test_computed_style("10%", "20", "auto");
}, "Computed style for invalid ratios");
// See https://github.com/whatwg/html/issues/4961:
// https://html.spec.whatwg.org/#attr-canvas-width
// https://html.spec.whatwg.org/#rules-for-parsing-non-negative-integers
test_computed_style("0.5", "1.5", ["auto 0 / 1", "auto 0.5 / 1.5"]);
test_computed_style("10%", "20", ["auto", "auto 10 / 20"]);
test_computed_style(null, null, "auto");
test_computed_style("10", null, "auto");
test_computed_style(null, "20", "auto");
test_computed_style("xx", "20", "auto");
</script>

View File

@ -68,20 +68,20 @@ onload = t.step_func_done(function() {
assert_ratio(images[6], 133/106, "The original aspect ratio of blue.png");
});
test(function() {
test_computed_style("10", "20", "auto 10 / 20");
test_computed_style("0", "1", "auto 0 / 1");
test_computed_style("1", "0", "auto 1 / 0");
test_computed_style("0", "0", "auto 0 / 0");
test_computed_style("0.5", "1.5", "auto 0.5 / 1.5");
}, "Computed style");
test_computed_style("10", "20", "auto 10 / 20");
// These are invalid per spec, but see
// https://github.com/whatwg/html/issues/4961
test_computed_style("0", "1", "auto 0 / 1");
test_computed_style("1", "0", "auto 1 / 0");
test_computed_style("0", "0", "auto 0 / 0");
// https://html.spec.whatwg.org/#map-to-the-aspect-ratio-property
// https://html.spec.whatwg.org/#rules-for-parsing-non-zero-dimension-values
test_computed_style("0.5", "1.5", "auto 0.5 / 1.5");
test(function() {
test_computed_style(null, null, "auto");
test_computed_style("10", null, "auto");
test_computed_style(null, "20", "auto");
test_computed_style("xx", "20", "auto");
test_computed_style("10%", "20", "auto");
}, "Computed style for invalid ratios");
test_computed_style(null, null, "auto");
test_computed_style("10", null, "auto");
test_computed_style(null, "20", "auto");
test_computed_style("xx", "20", "auto");
test_computed_style("10%", "20", "auto");
</script>

View File

@ -1,10 +1,18 @@
function test_computed_style_aspect_ratio(tag, attributes, expected) {
var elem = document.createElement(tag);
for (name in attributes) {
let val = attributes[name];
if (val !== null)
elem.setAttribute(name, val);
}
document.body.appendChild(elem);
assert_equals(getComputedStyle(elem).aspectRatio, expected);
test(function() {
var elem = document.createElement(tag);
for (name in attributes) {
let val = attributes[name];
if (val !== null)
elem.setAttribute(name, val);
}
document.body.appendChild(elem);
let aspectRatio = getComputedStyle(elem).aspectRatio;
if (Array.isArray(expected)) {
assert_in_array(aspectRatio, expected);
} else {
assert_equals(aspectRatio, expected);
}
elem.remove();
}, `${tag} with ${JSON.stringify(attributes)}`);
}

View File

@ -1,5 +1,5 @@
<!doctype html>
<title>Video width and height attributes are not used to infer aspect-ratio</title>
<title>Video width and height attributes are used to infer aspect-ratio</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/media.js"></script>
@ -50,20 +50,19 @@ t.step(function() {
});
}, "aspect ratio for regular video");
test(function() {
test_computed_style("10", "20", "auto 10 / 20");
test_computed_style("0", "1", "auto 0 / 1");
test_computed_style("1", "0", "auto 1 / 0");
test_computed_style("0", "0", "auto 0 / 0");
test_computed_style("0.5", "1.5", "auto 0.5 / 1.5");
}, "Computed style");
test_computed_style("10", "20", "auto 10 / 20");
test_computed_style("0.5", "1.5", "auto 0.5 / 1.5");
test(function() {
test_computed_style(null, null, "auto");
test_computed_style("10", null, "auto");
test_computed_style(null, "20", "auto");
test_computed_style("xx", "20", "auto");
test_computed_style("10%", "20", "auto");
}, "Computed style for invalid ratios");
// These are invalid per spec, but see
// https://github.com/whatwg/html/issues/4961
test_computed_style("0", "1", ["auto", "auto 0 / 1"]);
test_computed_style("1", "0", ["auto", "auto 1 / 0"]);
test_computed_style("0", "0", ["auto", "auto 0 / 0"]);
test_computed_style(null, null, "auto");
test_computed_style("10", null, "auto");
test_computed_style(null, "20", "auto");
test_computed_style("xx", "20", "auto");
test_computed_style("10%", "20", "auto");
</script>