tor-browser

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

SVGImageElement.cpp (12304B)


      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/SVGImageElement.h"
      8 
      9 #include "SVGGeometryProperty.h"
     10 #include "imgINotificationObserver.h"
     11 #include "mozilla/dom/Document.h"
     12 #include "mozilla/dom/FetchPriority.h"
     13 #include "mozilla/dom/SVGImageElementBinding.h"
     14 #include "mozilla/dom/SVGLengthBinding.h"
     15 #include "mozilla/dom/UserActivation.h"
     16 #include "mozilla/gfx/2D.h"
     17 #include "nsCOMPtr.h"
     18 #include "nsContentUtils.h"
     19 #include "nsNetUtil.h"
     20 
     21 NS_IMPL_NS_NEW_SVG_ELEMENT(Image)
     22 
     23 using namespace mozilla::gfx;
     24 
     25 namespace mozilla::dom {
     26 
     27 JSObject* SVGImageElement::WrapNode(JSContext* aCx,
     28                                    JS::Handle<JSObject*> aGivenProto) {
     29  return SVGImageElement_Binding::Wrap(aCx, this, aGivenProto);
     30 }
     31 
     32 SVGElement::LengthInfo SVGImageElement::sLengthInfo[4] = {
     33    {nsGkAtoms::x, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
     34     SVGContentUtils::X},
     35    {nsGkAtoms::y, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
     36     SVGContentUtils::Y},
     37    {nsGkAtoms::width, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
     38     SVGContentUtils::X},
     39    {nsGkAtoms::height, 0, SVGLength_Binding::SVG_LENGTHTYPE_NUMBER,
     40     SVGContentUtils::Y},
     41 };
     42 
     43 SVGElement::StringInfo SVGImageElement::sStringInfo[2] = {
     44    {nsGkAtoms::href, kNameSpaceID_None, true},
     45    {nsGkAtoms::href, kNameSpaceID_XLink, true}};
     46 
     47 //----------------------------------------------------------------------
     48 // nsISupports methods
     49 
     50 NS_IMPL_ISUPPORTS_INHERITED(SVGImageElement, SVGImageElementBase,
     51                            imgINotificationObserver, nsIImageLoadingContent)
     52 
     53 //----------------------------------------------------------------------
     54 // Implementation
     55 
     56 namespace SVGT = SVGGeometryProperty::Tags;
     57 
     58 SVGImageElement::SVGImageElement(
     59    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
     60    : SVGImageElementBase(std::move(aNodeInfo)) {
     61  // We start out broken
     62  AddStatesSilently(ElementState::BROKEN);
     63 }
     64 
     65 SVGImageElement::~SVGImageElement() { nsImageLoadingContent::Destroy(); }
     66 
     67 NonCustomCSSPropertyId SVGImageElement::GetCSSPropertyIdForAttrEnum(
     68    uint8_t aAttrEnum) {
     69  switch (aAttrEnum) {
     70    case ATTR_X:
     71      return eCSSProperty_x;
     72    case ATTR_Y:
     73      return eCSSProperty_y;
     74    case ATTR_WIDTH:
     75      return eCSSProperty_width;
     76    case ATTR_HEIGHT:
     77      return eCSSProperty_height;
     78    default:
     79      MOZ_ASSERT_UNREACHABLE("Unknown attr enum");
     80      return eCSSProperty_UNKNOWN;
     81  }
     82 }
     83 //----------------------------------------------------------------------
     84 // nsINode methods
     85 
     86 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGImageElement)
     87 
     88 void SVGImageElement::NodeInfoChanged(Document* aOldDoc) {
     89  SVGImageElementBase::NodeInfoChanged(aOldDoc);
     90 
     91  // Reparse the URI if needed. Note that we can't check whether we already have
     92  // a parsed URI, because it might be null even if we have a valid href
     93  // attribute, if we tried to parse with a different base.
     94  UpdateSrcURI();
     95 
     96  QueueImageTask(mSrcURI, /* aAlwaysLoad = */ true, /* aNotify = */ false);
     97 }
     98 
     99 //----------------------------------------------------------------------
    100 
    101 already_AddRefed<DOMSVGAnimatedLength> SVGImageElement::X() {
    102  return mLengthAttributes[ATTR_X].ToDOMAnimatedLength(this);
    103 }
    104 
    105 already_AddRefed<DOMSVGAnimatedLength> SVGImageElement::Y() {
    106  return mLengthAttributes[ATTR_Y].ToDOMAnimatedLength(this);
    107 }
    108 
    109 already_AddRefed<DOMSVGAnimatedLength> SVGImageElement::Width() {
    110  return mLengthAttributes[ATTR_WIDTH].ToDOMAnimatedLength(this);
    111 }
    112 
    113 already_AddRefed<DOMSVGAnimatedLength> SVGImageElement::Height() {
    114  return mLengthAttributes[ATTR_HEIGHT].ToDOMAnimatedLength(this);
    115 }
    116 
    117 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
    118 SVGImageElement::PreserveAspectRatio() {
    119  return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
    120 }
    121 
    122 already_AddRefed<DOMSVGAnimatedString> SVGImageElement::Href() {
    123  return mStringAttributes[HREF].IsExplicitlySet() ||
    124                 !mStringAttributes[XLINK_HREF].IsExplicitlySet()
    125             ? mStringAttributes[HREF].ToDOMAnimatedString(this)
    126             : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
    127 }
    128 
    129 void SVGImageElement::GetDecoding(nsAString& aValue) {
    130  GetEnumAttr(nsGkAtoms::decoding, kDecodingTableDefault->tag, aValue);
    131 }
    132 
    133 already_AddRefed<Promise> SVGImageElement::Decode(ErrorResult& aRv) {
    134  return nsImageLoadingContent::QueueDecodeAsync(aRv);
    135 }
    136 
    137 //----------------------------------------------------------------------
    138 
    139 void SVGImageElement::UpdateSrcURI() {
    140  nsAutoString href;
    141  if (mStringAttributes[HREF].IsExplicitlySet()) {
    142    mStringAttributes[HREF].GetAnimValue(href, this);
    143  } else {
    144    mStringAttributes[XLINK_HREF].GetAnimValue(href, this);
    145  }
    146 
    147  mSrcURI = nullptr;
    148  if (!href.IsEmpty()) {
    149    StringToURI(href, OwnerDoc(), getter_AddRefs(mSrcURI));
    150  }
    151 }
    152 
    153 void SVGImageElement::LoadSelectedImage(bool aAlwaysLoad,
    154                                        bool aStopLazyLoading) {
    155  nsresult rv = NS_ERROR_FAILURE;
    156 
    157  const bool kNotify = true;
    158  if (mSrcURI || (mStringAttributes[HREF].IsExplicitlySet() ||
    159                  mStringAttributes[XLINK_HREF].IsExplicitlySet())) {
    160    rv = LoadImage(mSrcURI, /* aForce = */ true, kNotify, eImageLoadType_Normal,
    161                   LoadFlags(), OwnerDoc());
    162  }
    163 
    164  if (NS_FAILED(rv)) {
    165    CancelImageRequests(kNotify);
    166  }
    167 }
    168 
    169 Rect SVGImageElement::GeometryBounds(const Matrix& aToBoundsSpace) {
    170  Rect rect;
    171 
    172  DebugOnly<bool> ok =
    173      SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width,
    174                                      SVGT::Height>(this, &rect.x, &rect.y,
    175                                                    &rect.width, &rect.height);
    176  MOZ_ASSERT(ok, "SVGGeometryProperty::ResolveAll failed");
    177 
    178  if (rect.IsEmpty()) {
    179    // Rendering of the element disabled
    180    rect.SetEmpty();  // Make sure width/height are zero and not negative
    181  }
    182 
    183  return aToBoundsSpace.TransformBounds(rect);
    184 }
    185 
    186 //----------------------------------------------------------------------
    187 // EventTarget methods:
    188 
    189 void SVGImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
    190  nsImageLoadingContent::AsyncEventRunning(aEvent);
    191 }
    192 
    193 //----------------------------------------------------------------------
    194 //  nsImageLoadingContent methods:
    195 
    196 CORSMode SVGImageElement::GetCORSMode() {
    197  return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
    198 }
    199 
    200 void SVGImageElement::GetFetchPriority(nsAString& aFetchPriority) const {
    201  GetEnumAttr(nsGkAtoms::fetchpriority, kFetchPriorityAttributeValueAuto,
    202              aFetchPriority);
    203 }
    204 
    205 //----------------------------------------------------------------------
    206 // nsIContent methods:
    207 
    208 bool SVGImageElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
    209                                     const nsAString& aValue,
    210                                     nsIPrincipal* aMaybeScriptedPrincipal,
    211                                     nsAttrValue& aResult) {
    212  if (aNamespaceID == kNameSpaceID_None) {
    213    if (aAttribute == nsGkAtoms::crossorigin) {
    214      ParseCORSValue(aValue, aResult);
    215      return true;
    216    }
    217    if (aAttribute == nsGkAtoms::decoding) {
    218      return aResult.ParseEnumValue(aValue, kDecodingTable, false,
    219                                    kDecodingTableDefault);
    220    }
    221    if (aAttribute == nsGkAtoms::fetchpriority) {
    222      ParseFetchPriority(aValue, aResult);
    223      return true;
    224    }
    225  }
    226 
    227  return SVGImageElementBase::ParseAttribute(aNamespaceID, aAttribute, aValue,
    228                                             aMaybeScriptedPrincipal, aResult);
    229 }
    230 
    231 void SVGImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
    232                                   const nsAttrValue* aValue,
    233                                   const nsAttrValue* aOldValue,
    234                                   nsIPrincipal* aSubjectPrincipal,
    235                                   bool aNotify) {
    236  bool forceReload = false;
    237  if (aName == nsGkAtoms::href && (aNamespaceID == kNameSpaceID_None ||
    238                                   aNamespaceID == kNameSpaceID_XLink)) {
    239    if (aNamespaceID == kNameSpaceID_XLink &&
    240        mStringAttributes[HREF].IsExplicitlySet()) {
    241      // href overrides xlink:href
    242      return;
    243    }
    244    UpdateSrcURI();
    245    forceReload = true;
    246  } else if (aNamespaceID == kNameSpaceID_None) {
    247    if (aName == nsGkAtoms::decoding) {
    248      // Request sync or async image decoding.
    249      SetSyncDecodingHint(
    250          aValue && static_cast<ImageDecodingType>(aValue->GetEnumValue()) ==
    251                        ImageDecodingType::Sync);
    252    } else if (aName == nsGkAtoms::crossorigin) {
    253      forceReload = GetCORSMode() != AttrValueToCORSMode(aOldValue);
    254    }
    255  }
    256 
    257  if (forceReload) {
    258    mUseUrgentStartForChannel = UserActivation::IsHandlingUserInput();
    259    QueueImageTask(mSrcURI, /* aAlwaysLoad = */ true, aNotify);
    260  }
    261 
    262  return SVGImageElementBase::AfterSetAttr(
    263      aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
    264 }
    265 
    266 nsresult SVGImageElement::BindToTree(BindContext& aContext, nsINode& aParent) {
    267  nsresult rv = SVGImageElementBase::BindToTree(aContext, aParent);
    268  NS_ENSURE_SUCCESS(rv, rv);
    269 
    270  nsImageLoadingContent::BindToTree(aContext, aParent);
    271 
    272  return rv;
    273 }
    274 
    275 void SVGImageElement::UnbindFromTree(UnbindContext& aContext) {
    276  nsImageLoadingContent::UnbindFromTree();
    277  SVGImageElementBase::UnbindFromTree(aContext);
    278 }
    279 
    280 void SVGImageElement::DestroyContent() {
    281  ClearImageLoadTask();
    282 
    283  nsImageLoadingContent::Destroy();
    284  SVGImageElementBase::DestroyContent();
    285 }
    286 
    287 NS_IMETHODIMP_(bool)
    288 SVGImageElement::IsAttributeMapped(const nsAtom* name) const {
    289  return IsInLengthInfo(name, sLengthInfo) ||
    290         SVGImageElementBase::IsAttributeMapped(name);
    291 }
    292 
    293 //----------------------------------------------------------------------
    294 // SVGElement methods
    295 
    296 /* virtual */
    297 bool SVGImageElement::HasValidDimensions() const {
    298  float width, height;
    299 
    300  if (SVGGeometryProperty::ResolveAll<SVGT::Width, SVGT::Height>(this, &width,
    301                                                                 &height)) {
    302    return width > 0 && height > 0;
    303  }
    304  // This function might be called for an element in display:none subtree
    305  // (e.g. SMIL animateMotion), we fall back to use SVG attributes.
    306  return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() ||
    307          mLengthAttributes[ATTR_WIDTH].GetAnimValInSpecifiedUnits() > 0) &&
    308         (!mLengthAttributes[ATTR_HEIGHT].IsExplicitlySet() ||
    309          mLengthAttributes[ATTR_HEIGHT].GetAnimValInSpecifiedUnits() > 0);
    310 }
    311 
    312 SVGElement::LengthAttributesInfo SVGImageElement::GetLengthInfo() {
    313  return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
    314                              std::size(sLengthInfo));
    315 }
    316 
    317 SVGAnimatedPreserveAspectRatio*
    318 SVGImageElement::GetAnimatedPreserveAspectRatio() {
    319  return &mPreserveAspectRatio;
    320 }
    321 
    322 SVGElement::StringAttributesInfo SVGImageElement::GetStringInfo() {
    323  return StringAttributesInfo(mStringAttributes, sStringInfo,
    324                              std::size(sStringInfo));
    325 }
    326 
    327 void SVGImageElement::DidAnimateAttribute(int32_t aNameSpaceID,
    328                                          nsAtom* aAttribute) {
    329  if ((aNameSpaceID == kNameSpaceID_None ||
    330       aNameSpaceID == kNameSpaceID_XLink) &&
    331      aAttribute == nsGkAtoms::href) {
    332    UpdateSrcURI();
    333    mUseUrgentStartForChannel = false;
    334    QueueImageTask(mSrcURI, /* aAlwaysLoad = */ true, /* aNotify = */ true);
    335  }
    336  SVGImageElementBase::DidAnimateAttribute(aNameSpaceID, aAttribute);
    337 }
    338 
    339 void SVGImageElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
    340                                             size_t* aNodeSize) const {
    341  SVGElement::AddSizeOfExcludingThis(aSizes, aNodeSize);
    342 
    343  // It is okay to include the size of mSrcURI here even though it might have
    344  // strong references from elsewhere because the URI was created for this
    345  // object, in nsImageLoadingContent::StringToURI(). Only objects that created
    346  // their own URI will call nsIURI::SizeOfIncludingThis().
    347  if (mSrcURI) {
    348    *aNodeSize += mSrcURI->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
    349  }
    350 }
    351 
    352 }  // namespace mozilla::dom