tor-browser

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

SVGFEImageElement.cpp (15258B)


      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/SVGFEImageElement.h"
      8 
      9 #include "imgIContainer.h"
     10 #include "mozilla/RefPtr.h"
     11 #include "mozilla/SVGObserverUtils.h"
     12 #include "mozilla/dom/BindContext.h"
     13 #include "mozilla/dom/Document.h"
     14 #include "mozilla/dom/FetchPriority.h"
     15 #include "mozilla/dom/SVGFEImageElementBinding.h"
     16 #include "mozilla/dom/SVGFilterElement.h"
     17 #include "mozilla/dom/UserActivation.h"
     18 #include "mozilla/gfx/2D.h"
     19 #include "nsContentUtils.h"
     20 #include "nsLayoutUtils.h"
     21 #include "nsNetUtil.h"
     22 
     23 NS_IMPL_NS_NEW_SVG_ELEMENT(FEImage)
     24 
     25 using namespace mozilla::gfx;
     26 
     27 namespace mozilla::dom {
     28 
     29 JSObject* SVGFEImageElement::WrapNode(JSContext* aCx,
     30                                      JS::Handle<JSObject*> aGivenProto) {
     31  return SVGFEImageElement_Binding::Wrap(aCx, this, aGivenProto);
     32 }
     33 
     34 SVGElement::StringInfo SVGFEImageElement::sStringInfo[3] = {
     35    {nsGkAtoms::result, kNameSpaceID_None, true},
     36    {nsGkAtoms::href, kNameSpaceID_None, true},
     37    {nsGkAtoms::href, kNameSpaceID_XLink, true}};
     38 
     39 // Cycle collection magic -- based on SVGUseElement
     40 NS_IMPL_CYCLE_COLLECTION_CLASS(SVGFEImageElement)
     41 
     42 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(SVGFEImageElement,
     43                                                SVGFEImageElementBase)
     44  tmp->mImageContentObserver = nullptr;
     45 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     46 
     47 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(SVGFEImageElement,
     48                                                  SVGFEImageElementBase)
     49  SVGObserverUtils::TraverseFEImageObserver(tmp, &cb);
     50 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     51 
     52 //----------------------------------------------------------------------
     53 // nsISupports methods
     54 
     55 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED(SVGFEImageElement,
     56                                             SVGFEImageElementBase,
     57                                             imgINotificationObserver,
     58                                             nsIImageLoadingContent)
     59 
     60 //----------------------------------------------------------------------
     61 // Implementation
     62 
     63 SVGFEImageElement::SVGFEImageElement(
     64    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
     65    : SVGFEImageElementBase(std::move(aNodeInfo)) {
     66  // We start out broken
     67  AddStatesSilently(ElementState::BROKEN);
     68 }
     69 
     70 SVGFEImageElement::~SVGFEImageElement() { nsImageLoadingContent::Destroy(); }
     71 
     72 //----------------------------------------------------------------------
     73 
     74 void SVGFEImageElement::UpdateSrcURI() {
     75  nsAutoString href;
     76  HrefAsString(href);
     77 
     78  mImageContentObserver = nullptr;
     79  mSrcURI = nullptr;
     80  if (!href.IsEmpty()) {
     81    StringToURI(href, OwnerDoc(), getter_AddRefs(mSrcURI));
     82  }
     83 }
     84 
     85 void SVGFEImageElement::LoadSelectedImage(bool aAlwaysLoad,
     86                                          bool aStopLazyLoading) {
     87  // Make sure we don't get in a recursive death-spiral
     88  bool isEqual;
     89  if (mSrcURI && NS_SUCCEEDED(mSrcURI->Equals(GetBaseURI(), &isEqual)) &&
     90      isEqual) {
     91    // Image URI matches our URI exactly! Bail out.
     92    return;
     93  }
     94 
     95  const bool kNotify = true;
     96 
     97  if (SVGObserverUtils::GetAndObserveFEImageContent(this)) {
     98    // We have a local target, don't try to load an image.
     99    CancelImageRequests(kNotify);
    100    return;
    101  }
    102 
    103  nsresult rv = NS_ERROR_FAILURE;
    104  if (mSrcURI || (mStringAttributes[HREF].IsExplicitlySet() ||
    105                  mStringAttributes[XLINK_HREF].IsExplicitlySet())) {
    106    rv = LoadImage(mSrcURI, /* aForce = */ true, kNotify, eImageLoadType_Normal,
    107                   LoadFlags(), OwnerDoc());
    108  }
    109 
    110  if (NS_FAILED(rv)) {
    111    CancelImageRequests(kNotify);
    112  }
    113 }
    114 
    115 //----------------------------------------------------------------------
    116 // EventTarget methods:
    117 
    118 void SVGFEImageElement::AsyncEventRunning(AsyncEventDispatcher* aEvent) {
    119  nsImageLoadingContent::AsyncEventRunning(aEvent);
    120 }
    121 
    122 //----------------------------------------------------------------------
    123 // nsIContent methods:
    124 
    125 bool SVGFEImageElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
    126                                       const nsAString& aValue,
    127                                       nsIPrincipal* aMaybeScriptedPrincipal,
    128                                       nsAttrValue& aResult) {
    129  if (aNamespaceID == kNameSpaceID_None) {
    130    if (aAttribute == nsGkAtoms::crossorigin) {
    131      ParseCORSValue(aValue, aResult);
    132      return true;
    133    }
    134    if (aAttribute == nsGkAtoms::fetchpriority) {
    135      ParseFetchPriority(aValue, aResult);
    136      return true;
    137    }
    138  }
    139  return SVGFEImageElementBase::ParseAttribute(
    140      aNamespaceID, aAttribute, aValue, aMaybeScriptedPrincipal, aResult);
    141 }
    142 
    143 void SVGFEImageElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
    144                                     const nsAttrValue* aValue,
    145                                     const nsAttrValue* aOldValue,
    146                                     nsIPrincipal* aSubjectPrincipal,
    147                                     bool aNotify) {
    148  bool forceReload = false;
    149  if (aName == nsGkAtoms::href && (aNamespaceID == kNameSpaceID_XLink ||
    150                                   aNamespaceID == kNameSpaceID_None)) {
    151    if (aNamespaceID == kNameSpaceID_XLink &&
    152        mStringAttributes[HREF].IsExplicitlySet()) {
    153      // href overrides xlink:href
    154      return;
    155    }
    156    UpdateSrcURI();
    157    forceReload = true;
    158  } else if (aNamespaceID == kNameSpaceID_None &&
    159             aName == nsGkAtoms::crossorigin) {
    160    forceReload = GetCORSMode() != AttrValueToCORSMode(aOldValue);
    161  }
    162 
    163  if (forceReload) {
    164    QueueImageTask(mSrcURI, /* aAlwaysLoad = */ true, aNotify);
    165  }
    166 
    167  return SVGFEImageElementBase::AfterSetAttr(
    168      aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
    169 }
    170 
    171 nsresult SVGFEImageElement::BindToTree(BindContext& aContext,
    172                                       nsINode& aParent) {
    173  nsresult rv = SVGFEImageElementBase::BindToTree(aContext, aParent);
    174  NS_ENSURE_SUCCESS(rv, rv);
    175 
    176  nsImageLoadingContent::BindToTree(aContext, aParent);
    177 
    178  if (aContext.InComposedDoc()) {
    179    aContext.OwnerDoc().SetUseCounter(eUseCounter_custom_feImage);
    180  }
    181 
    182  return rv;
    183 }
    184 
    185 void SVGFEImageElement::UnbindFromTree(UnbindContext& aContext) {
    186  mImageContentObserver = nullptr;
    187  nsImageLoadingContent::UnbindFromTree();
    188  SVGFEImageElementBase::UnbindFromTree(aContext);
    189 }
    190 
    191 void SVGFEImageElement::DestroyContent() {
    192  ClearImageLoadTask();
    193 
    194  nsImageLoadingContent::Destroy();
    195  SVGFEImageElementBase::DestroyContent();
    196 }
    197 
    198 //----------------------------------------------------------------------
    199 // nsINode methods
    200 
    201 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGFEImageElement)
    202 
    203 void SVGFEImageElement::NodeInfoChanged(Document* aOldDoc) {
    204  SVGFEImageElementBase::NodeInfoChanged(aOldDoc);
    205 
    206  // Reparse the URI if needed. Note that we can't check whether we already have
    207  // a parsed URI, because it might be null even if we have a valid href
    208  // attribute, if we tried to parse with a different base.
    209  UpdateSrcURI();
    210 
    211  QueueImageTask(mSrcURI, /* aAlwaysLoad = */ true, /* aNotify = */ false);
    212 }
    213 
    214 //----------------------------------------------------------------------
    215 //  nsImageLoadingContent methods:
    216 
    217 CORSMode SVGFEImageElement::GetCORSMode() {
    218  return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
    219 }
    220 
    221 void SVGFEImageElement::GetFetchPriority(nsAString& aFetchPriority) const {
    222  GetEnumAttr(nsGkAtoms::fetchpriority, kFetchPriorityAttributeValueAuto,
    223              aFetchPriority);
    224 }
    225 
    226 //----------------------------------------------------------------------
    227 // nsIDOMSVGFEImageElement methods
    228 
    229 FilterPrimitiveDescription SVGFEImageElement::GetPrimitiveDescription(
    230    SVGFilterInstance* aInstance, const IntRect& aFilterSubregion,
    231    const nsTArray<bool>& aInputsAreTainted,
    232    nsTArray<RefPtr<SourceSurface>>& aInputImages) {
    233  nsIFrame* frame = GetPrimaryFrame();
    234  if (!frame) {
    235    return FilterPrimitiveDescription();
    236  }
    237 
    238  nsCOMPtr<imgIRequest> currentRequest;
    239  GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
    240             getter_AddRefs(currentRequest));
    241 
    242  nsCOMPtr<imgIContainer> imageContainer;
    243  if (currentRequest) {
    244    currentRequest->GetImage(getter_AddRefs(imageContainer));
    245  }
    246 
    247  RefPtr<SourceSurface> image;
    248  nsIntSize nativeSize;
    249  if (imageContainer) {
    250    if (NS_FAILED(imageContainer->GetWidth(&nativeSize.width))) {
    251      nativeSize.width = kFallbackIntrinsicWidthInPixels;
    252    }
    253    if (NS_FAILED(imageContainer->GetHeight(&nativeSize.height))) {
    254      nativeSize.height = kFallbackIntrinsicHeightInPixels;
    255    }
    256    uint32_t flags =
    257        imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
    258    image = imageContainer->GetFrameAtSize(nativeSize,
    259                                           imgIContainer::FRAME_CURRENT, flags);
    260  }
    261 
    262  if (!image) {
    263    return FilterPrimitiveDescription();
    264  }
    265 
    266  Matrix viewBoxTM = SVGContentUtils::GetViewBoxTransform(
    267      aFilterSubregion.width, aFilterSubregion.height, 0, 0, nativeSize.width,
    268      nativeSize.height, mPreserveAspectRatio);
    269  Matrix TM = viewBoxTM;
    270  TM.PostTranslate(aFilterSubregion.x, aFilterSubregion.y);
    271 
    272  SamplingFilter samplingFilter =
    273      nsLayoutUtils::GetSamplingFilterForFrame(frame);
    274 
    275  ImageAttributes atts;
    276  atts.mFilter = (uint32_t)samplingFilter;
    277  atts.mTransform = TM;
    278 
    279  // Append the image to aInputImages and store its index in the description.
    280  size_t imageIndex = aInputImages.Length();
    281  aInputImages.AppendElement(image);
    282  atts.mInputIndex = (uint32_t)imageIndex;
    283  return FilterPrimitiveDescription(AsVariant(std::move(atts)));
    284 }
    285 
    286 bool SVGFEImageElement::AttributeAffectsRendering(int32_t aNameSpaceID,
    287                                                  nsAtom* aAttribute) const {
    288  // nsGkAtoms::href is deliberately omitted as the frame has special
    289  // handling to load the image
    290  return SVGFEImageElementBase::AttributeAffectsRendering(aNameSpaceID,
    291                                                          aAttribute) ||
    292         (aNameSpaceID == kNameSpaceID_None &&
    293          aAttribute == nsGkAtoms::preserveAspectRatio);
    294 }
    295 
    296 bool SVGFEImageElement::OutputIsTainted(const nsTArray<bool>& aInputsAreTainted,
    297                                        nsIPrincipal* aReferencePrincipal) {
    298  nsresult rv;
    299  nsCOMPtr<imgIRequest> currentRequest;
    300  GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
    301             getter_AddRefs(currentRequest));
    302 
    303  if (!currentRequest) {
    304    return false;
    305  }
    306 
    307  nsCOMPtr<nsIPrincipal> principal;
    308  rv = currentRequest->GetImagePrincipal(getter_AddRefs(principal));
    309  if (NS_FAILED(rv) || !principal) {
    310    return true;
    311  }
    312 
    313  // If CORS was used to load the image, the page is allowed to read from it.
    314  if (nsLayoutUtils::ImageRequestUsesCORS(currentRequest)) {
    315    return false;
    316  }
    317 
    318  if (aReferencePrincipal->Subsumes(principal)) {
    319    // The page is allowed to read from the image.
    320    return false;
    321  }
    322 
    323  return true;
    324 }
    325 
    326 //----------------------------------------------------------------------
    327 // SVGElement methods
    328 
    329 already_AddRefed<DOMSVGAnimatedString> SVGFEImageElement::Href() {
    330  return mStringAttributes[HREF].IsExplicitlySet() ||
    331                 !mStringAttributes[XLINK_HREF].IsExplicitlySet()
    332             ? mStringAttributes[HREF].ToDOMAnimatedString(this)
    333             : mStringAttributes[XLINK_HREF].ToDOMAnimatedString(this);
    334 }
    335 
    336 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
    337 SVGFEImageElement::PreserveAspectRatio() {
    338  return mPreserveAspectRatio.ToDOMAnimatedPreserveAspectRatio(this);
    339 }
    340 
    341 SVGAnimatedPreserveAspectRatio*
    342 SVGFEImageElement::GetAnimatedPreserveAspectRatio() {
    343  return &mPreserveAspectRatio;
    344 }
    345 
    346 SVGElement::StringAttributesInfo SVGFEImageElement::GetStringInfo() {
    347  return StringAttributesInfo(mStringAttributes, sStringInfo,
    348                              std::size(sStringInfo));
    349 }
    350 
    351 //----------------------------------------------------------------------
    352 // nsIImageLoadingContent methods
    353 NS_IMETHODIMP_(void)
    354 SVGFEImageElement::FrameCreated(nsIFrame* aFrame) {
    355  nsImageLoadingContent::FrameCreated(aFrame);
    356 
    357  auto mode = aFrame->PresContext()->ImageAnimationMode();
    358  if (mode == mImageAnimationMode) {
    359    return;
    360  }
    361 
    362  mImageAnimationMode = mode;
    363 
    364  if (mPendingRequest) {
    365    nsCOMPtr<imgIContainer> container;
    366    mPendingRequest->GetImage(getter_AddRefs(container));
    367    if (container) {
    368      container->SetAnimationMode(mode);
    369    }
    370  }
    371 
    372  if (mCurrentRequest) {
    373    nsCOMPtr<imgIContainer> container;
    374    mCurrentRequest->GetImage(getter_AddRefs(container));
    375    if (container) {
    376      container->SetAnimationMode(mode);
    377    }
    378  }
    379 }
    380 
    381 //----------------------------------------------------------------------
    382 // imgINotificationObserver methods
    383 
    384 void SVGFEImageElement::Notify(imgIRequest* aRequest, int32_t aType,
    385                               const nsIntRect* aData) {
    386  nsImageLoadingContent::Notify(aRequest, aType, aData);
    387 
    388  if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
    389    // Request a decode
    390    nsCOMPtr<imgIContainer> container;
    391    aRequest->GetImage(getter_AddRefs(container));
    392    MOZ_ASSERT(container, "who sent the notification then?");
    393    container->StartDecoding(imgIContainer::FLAG_NONE);
    394    container->SetAnimationMode(mImageAnimationMode);
    395  }
    396 
    397  if (aType == imgINotificationObserver::LOAD_COMPLETE ||
    398      aType == imgINotificationObserver::FRAME_UPDATE ||
    399      aType == imgINotificationObserver::SIZE_AVAILABLE) {
    400    if (auto* filter = SVGFilterElement::FromNodeOrNull(GetParent())) {
    401      SVGObserverUtils::InvalidateDirectRenderingObservers(filter);
    402    }
    403  }
    404 }
    405 
    406 void SVGFEImageElement::DidAnimateAttribute(int32_t aNameSpaceID,
    407                                            nsAtom* aAttribute) {
    408  if ((aNameSpaceID == kNameSpaceID_None ||
    409       aNameSpaceID == kNameSpaceID_XLink) &&
    410      aAttribute == nsGkAtoms::href) {
    411    UpdateSrcURI();
    412    QueueImageTask(mSrcURI, /* aAlwaysLoad = */ true, /* aNotify */ true);
    413  }
    414  SVGFEImageElementBase::DidAnimateAttribute(aNameSpaceID, aAttribute);
    415 }
    416 
    417 //----------------------------------------------------------------------
    418 // Public helper methods
    419 
    420 void SVGFEImageElement::HrefAsString(nsAString& aHref) {
    421  if (mStringAttributes[HREF].IsExplicitlySet()) {
    422    mStringAttributes[HREF].GetBaseValue(aHref, this);
    423  } else {
    424    mStringAttributes[XLINK_HREF].GetBaseValue(aHref, this);
    425  }
    426 }
    427 
    428 void SVGFEImageElement::NotifyImageContentChanged() {
    429  // We don't support rendering fragments yet (bug 455986)
    430 }
    431 
    432 void SVGFEImageElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
    433                                               size_t* aNodeSize) const {
    434  SVGElement::AddSizeOfExcludingThis(aSizes, aNodeSize);
    435 
    436  // It is okay to include the size of mSrcURI here even though it might have
    437  // strong references from elsewhere because the URI was created for this
    438  // object, in nsImageLoadingContent::StringToURI(). Only objects that created
    439  // their own URI will call nsIURI::SizeOfIncludingThis().
    440  if (mSrcURI) {
    441    *aNodeSize += mSrcURI->SizeOfIncludingThis(aSizes.mState.mMallocSizeOf);
    442  }
    443 }
    444 
    445 }  // namespace mozilla::dom