tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HTMLSourceElement.cpp (8163B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/HTMLSourceElement.h"
      8 
      9 #include "mozilla/AttributeStyles.h"
     10 #include "mozilla/MappedDeclarationsBuilder.h"
     11 #include "mozilla/Preferences.h"
     12 #include "mozilla/dom/BlobURLProtocolHandler.h"
     13 #include "mozilla/dom/DocumentInlines.h"
     14 #include "mozilla/dom/HTMLImageElement.h"
     15 #include "mozilla/dom/HTMLMediaElement.h"
     16 #include "mozilla/dom/HTMLSourceElementBinding.h"
     17 #include "mozilla/dom/MediaList.h"
     18 #include "mozilla/dom/MediaSource.h"
     19 #include "mozilla/dom/ResponsiveImageSelector.h"
     20 #include "nsAttrValueOrString.h"
     21 #include "nsGkAtoms.h"
     22 
     23 NS_IMPL_NS_NEW_HTML_ELEMENT(Source)
     24 
     25 namespace mozilla::dom {
     26 
     27 HTMLSourceElement::HTMLSourceElement(
     28    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
     29    : nsGenericHTMLElement(std::move(aNodeInfo)) {}
     30 
     31 HTMLSourceElement::~HTMLSourceElement() = default;
     32 
     33 NS_IMPL_CYCLE_COLLECTION_INHERITED(HTMLSourceElement, nsGenericHTMLElement,
     34                                   mSrcMediaSource)
     35 
     36 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(HTMLSourceElement,
     37                                               nsGenericHTMLElement)
     38 
     39 NS_IMPL_ELEMENT_CLONE(HTMLSourceElement)
     40 
     41 bool HTMLSourceElement::MatchesCurrentMedia() {
     42  if (mMediaList) {
     43    return mMediaList->Matches(*OwnerDoc());
     44  }
     45 
     46  // No media specified
     47  return true;
     48 }
     49 
     50 /* static */
     51 bool HTMLSourceElement::WouldMatchMediaForDocument(const nsAString& aMedia,
     52                                                   const Document* aDocument) {
     53  if (aMedia.IsEmpty()) {
     54    return true;
     55  }
     56 
     57  RefPtr<MediaList> mediaList =
     58      MediaList::Create(NS_ConvertUTF16toUTF8(aMedia));
     59  return mediaList->Matches(*aDocument);
     60 }
     61 
     62 void HTMLSourceElement::UpdateMediaList(const nsAttrValue* aValue) {
     63  mMediaList = nullptr;
     64  if (!aValue) {
     65    return;
     66  }
     67 
     68  NS_ConvertUTF16toUTF8 mediaStr(nsAttrValueOrString(aValue).String());
     69  mMediaList = MediaList::Create(mediaStr);
     70 }
     71 
     72 bool HTMLSourceElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
     73                                       const nsAString& aValue,
     74                                       nsIPrincipal* aMaybeScriptedPrincipal,
     75                                       nsAttrValue& aResult) {
     76  if (aNamespaceID == kNameSpaceID_None &&
     77      (aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height)) {
     78    return aResult.ParseHTMLDimension(aValue);
     79  }
     80 
     81  return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
     82                                              aMaybeScriptedPrincipal, aResult);
     83 }
     84 
     85 void HTMLSourceElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
     86                                     const nsAttrValue* aValue,
     87                                     const nsAttrValue* aOldValue,
     88                                     nsIPrincipal* aMaybeScriptedPrincipal,
     89                                     bool aNotify) {
     90  if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::srcset) {
     91    mSrcsetTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
     92        this, nsAttrValueOrString(aValue).String(), aMaybeScriptedPrincipal);
     93  }
     94  // If we are associated with a <picture> with a valid <img>, notify it of
     95  // responsive parameter changes
     96  if (aNameSpaceID == kNameSpaceID_None &&
     97      (aName == nsGkAtoms::srcset || aName == nsGkAtoms::sizes ||
     98       aName == nsGkAtoms::media || aName == nsGkAtoms::type) &&
     99      IsInPicture()) {
    100    if (aName == nsGkAtoms::media) {
    101      UpdateMediaList(aValue);
    102    }
    103 
    104    nsAttrValueOrString value(aValue);
    105    // Find all img siblings after this <source> and notify them of the change
    106    nsCOMPtr<nsIContent> sibling = AsContent();
    107    while ((sibling = sibling->GetNextSibling())) {
    108      if (auto* img = HTMLImageElement::FromNode(sibling)) {
    109        if (aName == nsGkAtoms::srcset) {
    110          img->PictureSourceSrcsetChanged(this, value.String(), aNotify);
    111        } else if (aName == nsGkAtoms::sizes) {
    112          img->PictureSourceSizesChanged(this, value.String(), aNotify);
    113        } else if (aName == nsGkAtoms::media || aName == nsGkAtoms::type) {
    114          img->PictureSourceMediaOrTypeChanged(this, aNotify);
    115        }
    116      }
    117    }
    118  } else if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::media) {
    119    UpdateMediaList(aValue);
    120  } else if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::src) {
    121    nsAttrValueOrString srcValue(aValue);
    122    mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
    123        this, srcValue.String(), aMaybeScriptedPrincipal);
    124    mSrcMediaSource = nullptr;
    125    if (aValue) {
    126      nsCOMPtr<nsIURI> uri;
    127      NewURIFromString(srcValue.String(), getter_AddRefs(uri));
    128      if (uri && IsMediaSourceURI(uri)) {
    129        NS_GetSourceForMediaSourceURI(uri, getter_AddRefs(mSrcMediaSource));
    130      }
    131    }
    132  } else if (aNameSpaceID == kNameSpaceID_None &&
    133             IsAttributeMappedToImages(aName) && IsInPicture()) {
    134    BuildMappedAttributesForImage();
    135 
    136    nsCOMPtr<nsIContent> sibling = AsContent();
    137    while ((sibling = sibling->GetNextSibling())) {
    138      if (auto* img = HTMLImageElement::FromNode(sibling)) {
    139        img->PictureSourceDimensionChanged(this, aNotify);
    140      }
    141    }
    142  }
    143 
    144  return nsGenericHTMLElement::AfterSetAttr(
    145      aNameSpaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
    146 }
    147 
    148 nsresult HTMLSourceElement::BindToTree(BindContext& aContext,
    149                                       nsINode& aParent) {
    150  nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
    151  NS_ENSURE_SUCCESS(rv, rv);
    152 
    153  if (auto* media = HTMLMediaElement::FromNode(aParent)) {
    154    media->NotifyAddedSource();
    155  }
    156 
    157  if (aParent.IsHTMLElement(nsGkAtoms::picture)) {
    158    BuildMappedAttributesForImage();
    159  } else {
    160    mMappedAttributesForImage = nullptr;
    161  }
    162 
    163  return NS_OK;
    164 }
    165 
    166 void HTMLSourceElement::UnbindFromTree(UnbindContext& aContext) {
    167  mMappedAttributesForImage = nullptr;
    168  nsGenericHTMLElement::UnbindFromTree(aContext);
    169 }
    170 
    171 JSObject* HTMLSourceElement::WrapNode(JSContext* aCx,
    172                                      JS::Handle<JSObject*> aGivenProto) {
    173  return HTMLSourceElement_Binding::Wrap(aCx, this, aGivenProto);
    174 }
    175 
    176 /**
    177 * Helper to map the image source attributes.
    178 * Note: This will override the declaration created by the presentation
    179 * attributes of HTMLImageElement (i.e. mapped by MapImageSizeAttributeInto).
    180 * https://html.spec.whatwg.org/multipage/embedded-content.html#the-source-element
    181 */
    182 void HTMLSourceElement::BuildMappedAttributesForImage() {
    183  MOZ_ASSERT(NS_IsMainThread());
    184 
    185  mMappedAttributesForImage = nullptr;
    186 
    187  Document* document = GetComposedDoc();
    188  if (!document) {
    189    return;
    190  }
    191 
    192  const nsAttrValue* width = mAttrs.GetAttr(nsGkAtoms::width);
    193  const nsAttrValue* height = mAttrs.GetAttr(nsGkAtoms::height);
    194  if (!width && !height) {
    195    return;
    196  }
    197 
    198  MappedDeclarationsBuilder builder(*this, *document);
    199  // We should set the missing property values with auto value to make sure it
    200  // overrides the declaration created by the presentation attributes of
    201  // HTMLImageElement. This can make sure we compute the ratio-dependent axis
    202  // size properly by the natural aspect-ratio of the image.
    203  //
    204  // Note: The spec doesn't specify this, so we follow the implementation in
    205  // other browsers.
    206  // Spec issue: https://github.com/whatwg/html/issues/8178.
    207  if (width) {
    208    MapDimensionAttributeInto(builder, eCSSProperty_width, *width);
    209  } else {
    210    builder.SetAutoValue(eCSSProperty_width);
    211  }
    212 
    213  if (height) {
    214    MapDimensionAttributeInto(builder, eCSSProperty_height, *height);
    215  } else {
    216    builder.SetAutoValue(eCSSProperty_height);
    217  }
    218 
    219  if (width && height) {
    220    DoMapAspectRatio(*width, *height, builder);
    221  } else {
    222    builder.SetAutoValue(eCSSProperty_aspect_ratio);
    223  }
    224  mMappedAttributesForImage = builder.TakeDeclarationBlock();
    225 }
    226 
    227 }  // namespace mozilla::dom