Changeset 279108 in webkit


Ignore:
Timestamp:
Jun 22, 2021 1:06:05 AM (13 months ago)
Author:
cathiechen
Message:

Implement width and height attributes on source elements of <picture>
https://bugs.webkit.org/show_bug.cgi?id=222368

Reviewed by Darin Adler.

LayoutTests/imported/w3c:

  • web-platform-tests/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/picture-aspect-ratio-expected.txt:

Source/WebCore:

According to [1], the source element supports dimension attributes. The img element can use the width
and height attributes of the source element to determine its rendered dimensions and aspect-ratio.
In order to implement this, add m_sourceElement to HTMLImageElement to indicate the source element that
is selected. Also add invalidateAttributeMapping() to synchronize with the changes of source's attributes
to the img element. Then add collectExtraStyleForPresentationalHints() to collect style from source attributes.

[1] https://html.spec.whatwg.org/#the-source-element

  • dom/ElementData.h:
  • dom/StyledElement.cpp:

(WebCore::StyledElement::rebuildPresentationalHintStyle): collectExtraStyleForPresentationalHints() when rebuild.

  • dom/StyledElement.h:

(WebCore::StyledElement::collectExtraStyleForPresentationalHints): Add an interface to collect extra style from other elements.

  • html/HTMLElement.cpp:

(WebCore::HTMLElement::applyAspectRatioFromWidthAndHeightAttributesToStyle): Add width and height attributes as input variables.

  • html/HTMLElement.h:
  • html/HTMLImageElement.cpp:

(WebCore::HTMLImageElement::collectPresentationalHintsForAttribute):
(WebCore::HTMLImageElement::collectExtraStyleForPresentationalHints): If source element has width or height attributes, apply them
to width, height and aspect-ratio of the style.
(WebCore::HTMLImageElement::bestFitSourceFromPictureElement): Keep the source element.
(WebCore::HTMLImageElement::selectImageSource): Reset the source element to null if no candidate is found.
(WebCore::HTMLImageElement::sourceElement const):
(WebCore::HTMLImageElement::setSourceElement):
(WebCore::HTMLImageElement::invalidateAttributeMapping): Invalidate the presentationalHintStyle.

  • html/HTMLImageElement.h:
  • html/HTMLInputElement.cpp:

(WebCore::HTMLInputElement::collectPresentationalHintsForAttribute):

  • html/HTMLPictureElement.cpp:

(WebCore::HTMLPictureElement::sourceDimensionAttributesChanged): Call invalidateAttributeMapping if source element's attributes are changed.

  • html/HTMLPictureElement.h:
  • html/HTMLSourceElement.cpp:

(WebCore::HTMLSourceElement::attributeChanged): Call sourceDimensionAttributesChanged if width or height attributes are changed.

  • html/HTMLSourceElement.h:
  • html/HTMLSourceElement.idl:
  • html/HTMLVideoElement.cpp:

(WebCore::HTMLVideoElement::collectPresentationalHintsForAttribute):

LayoutTests:

Location:
trunk
Files:
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r279100 r279108  
     12021-06-22  Cathie Chen  <cathiechen@igalia.com>
     2
     3        Implement width and height attributes on source elements of <picture>
     4        https://bugs.webkit.org/show_bug.cgi?id=222368
     5
     6        Reviewed by Darin Adler.
     7
     8        * TestExpectations:
     9
    1102021-06-21  Carlos Alberto Lopez Perez  <clopez@igalia.com>
    211
  • trunk/LayoutTests/TestExpectations

    r279055 r279108  
    14341434imported/w3c/web-platform-tests/html/semantics/embedded-content/the-img-element/sizes/parse-a-sizes-attribute-standards-mode.html [ Failure Pass ]
    14351435imported/w3c/web-platform-tests/html/semantics/embedded-content/the-object-element/object-fallback-failed-cross-origin-navigation.sub.html [ Failure Pass ]
    1436 
    1437 # Newly importing aspect ratio test is flaky.
    1438 imported/w3c/web-platform-tests/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/picture-aspect-ratio.html [ Failure Pass ]
    14391436
    14401437# Newly importing W3C tests needed support for reftest-wait.
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r279099 r279108  
     12021-06-22  Cathie Chen  <cathiechen@igalia.com>
     2
     3        Implement width and height attributes on source elements of <picture>
     4        https://bugs.webkit.org/show_bug.cgi?id=222368
     5
     6        Reviewed by Darin Adler.
     7
     8        * web-platform-tests/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/picture-aspect-ratio-expected.txt:
     9
    1102021-06-21  Chris Dumez  <cdumez@apple.com>
    211
  • trunk/LayoutTests/imported/w3c/web-platform-tests/html/rendering/replaced-elements/attributes-for-embedded-content-and-images/picture-aspect-ratio-expected.txt

    r276498 r279108  
    1 
    2 
    31
    42
    53PASS source width and height attributes are used to infer aspect-ratio in <picture>
    6 FAIL Computed style for width/height/aspect-ratio assert_approx_equals: expected 1 +/- 0.001 but got Infinity
    7 FAIL Source width/height should take precedence over img attributes. assert_approx_equals: expected 2 +/- 0.001 but got 5
    8 FAIL Make sure style gets invalidated correctly when the source gets removed. assert_equals: expected "auto 250 / 50" but got "auto"
    9 FAIL If the <source> has only one of width/height, we don't get an aspect ratio, even if the <img> has both. assert_equals: expected "100px" but got "200px"
    10 FAIL If we don't have width/height on the source, we fall back to width/height on the <img>. assert_equals: expected "auto 200 / 100" but got "auto"
    11 FAIL If we only have one width attribute, we should get width mapped but no aspect ratio, even if <img> has attributes. assert_equals: expected "100px" but got "200px"
    12 FAIL If we only have height attribute, we should get height mapped but no aspect ratio, even if <img> has attributes. assert_equals: expected "auto" but got "200px"
    13 FAIL Dynamically changing width/height should change computed style assert_equals: expected "auto 100 / 100" but got "auto"
    14 FAIL Changing which <source> matches should change computed style assert_equals: expected "auto 100 / 100" but got "auto"
    15 FAIL Percentages on source should be ignored for aspect-ratio but used for width/height. assert_equals: expected 100 but got 0
    16 FAIL Trailing garbage should be ignored but not make the attribute invalid assert_equals: expected 100 but got 0
     4PASS Computed style for width/height/aspect-ratio
     5PASS Source width/height should take precedence over img attributes.
     6PASS Make sure style gets invalidated correctly when the source gets removed.
     7PASS If the <source> has only one of width/height, we don't get an aspect ratio, even if the <img> has both.
     8PASS If we don't have width/height on the source, we fall back to width/height on the <img>.
     9PASS If we only have one width attribute, we should get width mapped but no aspect ratio, even if <img> has attributes.
     10PASS If we only have height attribute, we should get height mapped but no aspect ratio, even if <img> has attributes.
     11PASS Dynamically changing width/height should change computed style
     12PASS Changing which <source> matches should change computed style
     13PASS Percentages on source should be ignored for aspect-ratio but used for width/height.
     14PASS Trailing garbage should be ignored but not make the attribute invalid
    1715PASS Loaded picture test: Both <source> and <img> are without width and height attributes
    18 FAIL Loaded picture test: <source> with width and height attributes, <img> without width and height attributes assert_equals: expected "auto 100 / 100" but got "auto"
    19 FAIL Loaded picture test: Both <source> and <img> are with width and height attributes assert_equals: expected "auto 100 / 100" but got "auto"
     16PASS Loaded picture test: <source> with width and height attributes, <img> without width and height attributes
     17PASS Loaded picture test: Both <source> and <img> are with width and height attributes
    2018
  • trunk/Source/WebCore/ChangeLog

    r279103 r279108  
     12021-06-22  Cathie Chen  <cathiechen@igalia.com>
     2
     3        Implement width and height attributes on source elements of <picture>
     4        https://bugs.webkit.org/show_bug.cgi?id=222368
     5
     6        Reviewed by Darin Adler.
     7
     8        According to [1], the source element supports dimension attributes. The img element can use the width
     9        and height attributes of the source element to determine its rendered dimensions and aspect-ratio.
     10        In order to implement this, add m_sourceElement to HTMLImageElement to indicate the source element that
     11        is selected. Also add invalidateAttributeMapping() to synchronize with the changes of source's attributes
     12        to the img element. Then add collectExtraStyleForPresentationalHints() to collect style from source attributes.
     13
     14        [1] https://html.spec.whatwg.org/#the-source-element
     15
     16        * dom/ElementData.h:
     17        * dom/StyledElement.cpp:
     18        (WebCore::StyledElement::rebuildPresentationalHintStyle): collectExtraStyleForPresentationalHints() when rebuild.
     19        * dom/StyledElement.h:
     20        (WebCore::StyledElement::collectExtraStyleForPresentationalHints): Add an interface to collect extra style from other elements.
     21        * html/HTMLElement.cpp:
     22        (WebCore::HTMLElement::applyAspectRatioFromWidthAndHeightAttributesToStyle): Add width and height attributes as input variables.
     23        * html/HTMLElement.h:
     24        * html/HTMLImageElement.cpp:
     25        (WebCore::HTMLImageElement::collectPresentationalHintsForAttribute):
     26        (WebCore::HTMLImageElement::collectExtraStyleForPresentationalHints): If source element has width or height attributes, apply them
     27        to width, height and aspect-ratio of the style.
     28        (WebCore::HTMLImageElement::bestFitSourceFromPictureElement): Keep the source element.
     29        (WebCore::HTMLImageElement::selectImageSource): Reset the source element to null if no candidate is found.
     30        (WebCore::HTMLImageElement::sourceElement const):
     31        (WebCore::HTMLImageElement::setSourceElement):
     32        (WebCore::HTMLImageElement::invalidateAttributeMapping): Invalidate the presentationalHintStyle.
     33        * html/HTMLImageElement.h:
     34        * html/HTMLInputElement.cpp:
     35        (WebCore::HTMLInputElement::collectPresentationalHintsForAttribute):
     36        * html/HTMLPictureElement.cpp:
     37        (WebCore::HTMLPictureElement::sourceDimensionAttributesChanged): Call invalidateAttributeMapping if source element's attributes are changed.
     38        * html/HTMLPictureElement.h:
     39        * html/HTMLSourceElement.cpp:
     40        (WebCore::HTMLSourceElement::attributeChanged): Call sourceDimensionAttributesChanged if width or height attributes are changed.
     41        * html/HTMLSourceElement.h:
     42        * html/HTMLSourceElement.idl:
     43        * html/HTMLVideoElement.cpp:
     44        (WebCore::HTMLVideoElement::collectPresentationalHintsForAttribute):
     45
    1462021-06-21  Jean-Yves Avenard  <jya@apple.com>
    247
  • trunk/Source/WebCore/dom/ElementData.h

    r278277 r279108  
    171171    friend class UniqueElementData;
    172172    friend class SVGElement;
     173    friend class HTMLImageElement;
    173174
    174175    void destroy();
  • trunk/Source/WebCore/dom/StyledElement.cpp

    r278669 r279108  
    3838#include "ElementRareData.h"
    3939#include "HTMLElement.h"
     40#include "HTMLImageElement.h"
    4041#include "HTMLParserIdioms.h"
    4142#include "InspectorInstrumentation.h"
     
    293294void StyledElement::rebuildPresentationalHintStyle()
    294295{
    295     RefPtr<StyleProperties> style = MutableStyleProperties::create(isSVGElement() ? SVGAttributeMode : HTMLQuirksMode);
     296    auto style = MutableStyleProperties::create(isSVGElement() ? SVGAttributeMode : HTMLQuirksMode);
    296297    for (const Attribute& attribute : attributesIterator())
    297         collectPresentationalHintsForAttribute(attribute.name(), attribute.value(), static_cast<MutableStyleProperties&>(*style));
     298        collectPresentationalHintsForAttribute(attribute.name(), attribute.value(), style);
     299
     300    if (is<HTMLImageElement>(*this))
     301        collectExtraStyleForPresentationalHints(style);
    298302
    299303    // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
     
    301305
    302306    elementData.setPresentationalHintStyleIsDirty(false);
    303     elementData.m_presentationalHintStyle = style->isEmpty() ? nullptr : WTFMove(style);
     307    if (style->isEmpty())
     308        elementData.m_presentationalHintStyle = nullptr;
     309    else
     310        elementData.m_presentationalHintStyle = WTFMove(style);
    304311}
    305312
  • trunk/Source/WebCore/dom/StyledElement.h

    r278277 r279108  
    6565    virtual void collectPresentationalHintsForAttribute(const QualifiedName&, const AtomString&, MutableStyleProperties&) { }
    6666    virtual const StyleProperties* additionalPresentationalHintStyle() const { return nullptr; }
     67    virtual void collectExtraStyleForPresentationalHints(MutableStyleProperties&) { }
    6768
    6869protected:
  • trunk/Source/WebCore/html/HTMLElement.cpp

    r278834 r279108  
    626626}
    627627
    628 void HTMLElement::applyAspectRatioFromWidthAndHeightAttributesToStyle(MutableStyleProperties& style)
     628void HTMLElement::applyAspectRatioFromWidthAndHeightAttributesToStyle(StringView widthAttribute, StringView heightAttribute, MutableStyleProperties& style)
    629629{
    630630    if (!document().settings().aspectRatioOfImgFromWidthAndHeightEnabled())
    631631        return;
    632632
    633     auto dimensionWidth = parseHTMLDimension(attributeWithoutSynchronization(widthAttr));
     633    auto dimensionWidth = parseHTMLDimension(widthAttribute);
    634634    if (!dimensionWidth || dimensionWidth->type != HTMLDimension::Type::Pixel)
    635635        return;
    636     auto dimensionHeight = parseHTMLDimension(attributeWithoutSynchronization(heightAttr));
     636    auto dimensionHeight = parseHTMLDimension(heightAttribute);
    637637    if (!dimensionHeight || dimensionHeight->type != HTMLDimension::Type::Pixel)
    638638        return;
  • trunk/Source/WebCore/html/HTMLElement.h

    r278765 r279108  
    158158    void addHTMLColorToStyle(MutableStyleProperties&, CSSPropertyID, const String& color);
    159159
    160     void applyAspectRatioFromWidthAndHeightAttributesToStyle(MutableStyleProperties&);
     160    void applyAspectRatioFromWidthAndHeightAttributesToStyle(StringView widthAttribute, StringView heightAttribute, MutableStyleProperties&);
    161161    void applyAlignmentAttributeToStyle(const AtomString&, MutableStyleProperties&);
    162162    void applyBorderAttributeToStyle(const AtomString&, MutableStyleProperties&);
  • trunk/Source/WebCore/html/HTMLImageElement.cpp

    r278765 r279108  
    3838#include "HTMLFormElement.h"
    3939#include "HTMLImageLoader.h"
     40#include "HTMLMapElement.h"
    4041#include "HTMLParserIdioms.h"
    4142#include "HTMLPictureElement.h"
    42 #include "HTMLMapElement.h"
    4343#include "HTMLSourceElement.h"
    4444#include "HTMLSrcsetParser.h"
     
    118118    if (name == widthAttr) {
    119119        addHTMLMultiLengthToStyle(style, CSSPropertyWidth, value);
    120         applyAspectRatioFromWidthAndHeightAttributesToStyle(style);
     120        applyAspectRatioFromWidthAndHeightAttributesToStyle(value, attributeWithoutSynchronization(heightAttr), style);
    121121    } else if (name == heightAttr) {
    122122        addHTMLMultiLengthToStyle(style, CSSPropertyHeight, value);
    123         applyAspectRatioFromWidthAndHeightAttributesToStyle(style);
     123        applyAspectRatioFromWidthAndHeightAttributesToStyle(attributeWithoutSynchronization(widthAttr), value, style);
    124124    } else if (name == borderAttr)
    125125        applyBorderAttributeToStyle(value, style);
     
    138138}
    139139
     140void HTMLImageElement::collectExtraStyleForPresentationalHints(MutableStyleProperties& style)
     141{
     142    if (!sourceElement())
     143        return;
     144    auto& widthAttrFromSource = sourceElement()->attributeWithoutSynchronization(widthAttr);
     145    auto& heightAttrFromSource = sourceElement()->attributeWithoutSynchronization(heightAttr);
     146    // If both width and height attributes of <source> is undefined, the style's value should not
     147    // be overwritten. Otherwise, <souce> will overwrite it. I.e., if <source> only has one attribute
     148    // defined, the other one and aspect-ratio shouldn't be set to auto.
     149    if (widthAttrFromSource.isNull() && heightAttrFromSource.isNull())
     150        return;
     151
     152    if (!widthAttrFromSource.isNull())
     153        addHTMLLengthToStyle(style, CSSPropertyWidth, widthAttrFromSource);
     154    else
     155        addPropertyToPresentationalHintStyle(style, CSSPropertyWidth, CSSValueAuto);
     156
     157    if (!heightAttrFromSource.isNull())
     158        addHTMLLengthToStyle(style, CSSPropertyHeight, heightAttrFromSource);
     159    else
     160        addPropertyToPresentationalHintStyle(style, CSSPropertyHeight, CSSValueAuto);
     161
     162    if (!widthAttrFromSource.isNull() && !heightAttrFromSource.isNull())
     163        applyAspectRatioFromWidthAndHeightAttributesToStyle(widthAttrFromSource, heightAttrFromSource, style);
     164    else
     165        addPropertyToPresentationalHintStyle(style, CSSPropertyAspectRatio, CSSValueAuto);
     166}
     167
    140168const AtomString& HTMLImageElement::imageSourceURL() const
    141169{
     
    192220
    193221        candidate = bestFitSourceForImageAttributes(document().deviceScaleFactor(), nullAtom(), srcset, sourceSize);
    194         if (!candidate.isEmpty())
     222        if (!candidate.isEmpty()) {
     223            setSourceElement(&source);
    195224            break;
     225        }
    196226    }
    197227
     
    218248    ImageCandidate candidate = bestFitSourceFromPictureElement();
    219249    if (candidate.isEmpty()) {
     250        setSourceElement(nullptr);
    220251        // If we don't have a <picture> or didn't find a source, then we use our own attributes.
    221252        SizesAttributeParser sizesParser(attributeWithoutSynchronization(sizesAttr).string(), document(), &m_mediaQueryDynamicResults);
     
    800831}
    801832
    802 }
     833HTMLSourceElement* HTMLImageElement::sourceElement() const
     834{
     835    return m_sourceElement.get();
     836}
     837
     838void HTMLImageElement::setSourceElement(HTMLSourceElement* sourceElement)
     839{
     840    if (m_sourceElement == sourceElement)
     841        return;
     842    m_sourceElement = makeWeakPtr(sourceElement);
     843    invalidateAttributeMapping();
     844}
     845
     846void HTMLImageElement::invalidateAttributeMapping()
     847{
     848    ensureUniqueElementData().setPresentationalHintStyleIsDirty(true);
     849    invalidateStyle();
     850}
     851
     852}
  • trunk/Source/WebCore/html/HTMLImageElement.h

    r278277 r279108  
    151151    bool hasPresentationalHintsForAttribute(const QualifiedName&) const override;
    152152    void collectPresentationalHintsForAttribute(const QualifiedName&, const AtomString&, MutableStyleProperties&) override;
     153    void collectExtraStyleForPresentationalHints(MutableStyleProperties&) override;
     154    void invalidateAttributeMapping();
    153155
    154156    void didAttachRenderers() override;
     
    183185
    184186    float effectiveImageDevicePixelRatio() const;
     187
     188    HTMLSourceElement* sourceElement() const;
     189    void setSourceElement(HTMLSourceElement*);
    185190
    186191    std::unique_ptr<HTMLImageLoader> m_imageLoader;
     
    197202
    198203    WeakPtr<HTMLPictureElement> m_pictureElement;
     204    // The source element that was selected to provide the source URL.
     205    WeakPtr<HTMLSourceElement> m_sourceElement;
    199206    MediaQueryDynamicResults m_mediaQueryDynamicResults;
    200207
  • trunk/Source/WebCore/html/HTMLInputElement.cpp

    r279054 r279108  
    715715            addHTMLLengthToStyle(style, CSSPropertyWidth, value);
    716716        if (isImageButton())
    717             applyAspectRatioFromWidthAndHeightAttributesToStyle(style);
     717            applyAspectRatioFromWidthAndHeightAttributesToStyle(value, attributeWithoutSynchronization(heightAttr), style);
    718718    } else if (name == heightAttr) {
    719719        if (m_inputType->shouldRespectHeightAndWidthAttributes())
    720720            addHTMLLengthToStyle(style, CSSPropertyHeight, value);
    721721        if (isImageButton())
    722             applyAspectRatioFromWidthAndHeightAttributesToStyle(style);
     722            applyAspectRatioFromWidthAndHeightAttributesToStyle(attributeWithoutSynchronization(widthAttr), value, style);
    723723    } else if (name == borderAttr && isImageButton())
    724724        applyBorderAttributeToStyle(value, style);
  • trunk/Source/WebCore/html/HTMLPictureElement.cpp

    r266360 r279108  
    6565}
    6666
     67void HTMLPictureElement::sourceDimensionAttributesChanged(const HTMLSourceElement& sourceElement)
     68{
     69    for (auto& element : childrenOfType<HTMLImageElement>(*this)) {
     70        if (&sourceElement == element.sourceElement())
     71            element.invalidateAttributeMapping();
     72    }
     73}
     74
    6775#if USE(SYSTEM_PREVIEW)
    6876bool HTMLPictureElement::isSystemPreviewImage()
  • trunk/Source/WebCore/html/HTMLPictureElement.h

    r264789 r279108  
    3737
    3838    void sourcesChanged();
     39    void sourceDimensionAttributesChanged(const HTMLSourceElement&);
    3940
    4041#if USE(SYSTEM_PREVIEW)
  • trunk/Source/WebCore/html/HTMLSourceElement.cpp

    r278185 r279108  
    206206}
    207207
    208 }
     208void HTMLSourceElement::attributeChanged(const QualifiedName& name, const AtomString& oldValue, const AtomString& newValue, AttributeModificationReason reason)
     209{
     210    if (name == widthAttr || name == heightAttr) {
     211        if (RefPtr parent = parentNode(); is<HTMLPictureElement>(parent))
     212            downcast<HTMLPictureElement>(*parent).sourceDimensionAttributesChanged(*this);
     213    }
     214    HTMLElement::attributeChanged(name, oldValue, newValue, reason);
     215}
     216
     217}
  • trunk/Source/WebCore/html/HTMLSourceElement.h

    r278253 r279108  
    5959    void parseAttribute(const QualifiedName&, const AtomString&) final;
    6060
     61    void attributeChanged(const QualifiedName&, const AtomString& oldValue, const AtomString& newValue, AttributeModificationReason) final;
     62
    6163    void errorEventTimerFired();
    6264
  • trunk/Source/WebCore/html/HTMLSourceElement.idl

    r267813 r279108  
    3333    [CEReactions=NotNeeded, Reflect] attribute DOMString sizes;
    3434    [CEReactions=NotNeeded, Reflect] attribute DOMString media;
     35    [CEReactions=NotNeeded, Reflect] attribute unsigned long width;
     36    [CEReactions=NotNeeded, Reflect] attribute unsigned long height;
    3537};
  • trunk/Source/WebCore/html/HTMLVideoElement.cpp

    r278277 r279108  
    116116    if (name == widthAttr) {
    117117        addHTMLLengthToStyle(style, CSSPropertyWidth, value);
    118         applyAspectRatioFromWidthAndHeightAttributesToStyle(style);
     118        applyAspectRatioFromWidthAndHeightAttributesToStyle(value, attributeWithoutSynchronization(heightAttr), style);
    119119    } else if (name == heightAttr) {
    120120        addHTMLLengthToStyle(style, CSSPropertyHeight, value);
    121         applyAspectRatioFromWidthAndHeightAttributesToStyle(style);
     121        applyAspectRatioFromWidthAndHeightAttributesToStyle(attributeWithoutSynchronization(widthAttr), value, style);
    122122    } else
    123123        HTMLMediaElement::collectPresentationalHintsForAttribute(name, value, style);
Note: See TracChangeset for help on using the changeset viewer.