tor-browser

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

SVGFilterFrame.cpp (6382B)


      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 // Main header first:
      8 #include "SVGFilterFrame.h"
      9 
     10 // Keep others in (case-insensitive) order:
     11 #include "AutoReferenceChainGuard.h"
     12 #include "SVGElement.h"
     13 #include "SVGFilterInstance.h"
     14 #include "SVGObserverUtils.h"
     15 #include "gfxUtils.h"
     16 #include "mozilla/PresShell.h"
     17 #include "mozilla/dom/SVGFilterElement.h"
     18 #include "nsContentUtils.h"
     19 #include "nsGkAtoms.h"
     20 
     21 using namespace mozilla;
     22 using namespace mozilla::dom;
     23 
     24 nsIFrame* NS_NewSVGFilterFrame(mozilla::PresShell* aPresShell,
     25                               mozilla::ComputedStyle* aStyle) {
     26  return new (aPresShell)
     27      mozilla::SVGFilterFrame(aStyle, aPresShell->GetPresContext());
     28 }
     29 
     30 namespace mozilla {
     31 
     32 NS_IMPL_FRAMEARENA_HELPERS(SVGFilterFrame)
     33 
     34 uint16_t SVGFilterFrame::GetEnumValue(uint32_t aIndex, nsIContent* aDefault) {
     35  SVGAnimatedEnumeration& thisEnum =
     36      static_cast<SVGFilterElement*>(GetContent())->mEnumAttributes[aIndex];
     37 
     38  if (thisEnum.IsExplicitlySet()) {
     39    return thisEnum.GetAnimValue();
     40  }
     41 
     42  // Before we recurse, make sure we'll break reference loops and over long
     43  // reference chains:
     44  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     45  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     46                                        &sRefChainLengthCounter);
     47  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     48    // Break reference chain
     49    return static_cast<SVGFilterElement*>(aDefault)
     50        ->mEnumAttributes[aIndex]
     51        .GetAnimValue();
     52  }
     53 
     54  SVGFilterFrame* next = GetReferencedFilter();
     55 
     56  return next ? next->GetEnumValue(aIndex, aDefault)
     57              : static_cast<SVGFilterElement*>(aDefault)
     58                    ->mEnumAttributes[aIndex]
     59                    .GetAnimValue();
     60 }
     61 
     62 const SVGAnimatedLength* SVGFilterFrame::GetLengthValue(uint32_t aIndex,
     63                                                        nsIContent* aDefault) {
     64  const SVGAnimatedLength* thisLength =
     65      &static_cast<SVGFilterElement*>(GetContent())->mLengthAttributes[aIndex];
     66 
     67  if (thisLength->IsExplicitlySet()) {
     68    return thisLength;
     69  }
     70 
     71  // Before we recurse, make sure we'll break reference loops and over long
     72  // reference chains:
     73  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     74  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     75                                        &sRefChainLengthCounter);
     76  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     77    // Break reference chain
     78    return &static_cast<SVGFilterElement*>(aDefault)->mLengthAttributes[aIndex];
     79  }
     80 
     81  SVGFilterFrame* next = GetReferencedFilter();
     82 
     83  return next ? next->GetLengthValue(aIndex, aDefault)
     84              : &static_cast<SVGFilterElement*>(aDefault)
     85                     ->mLengthAttributes[aIndex];
     86 }
     87 
     88 const SVGFilterElement* SVGFilterFrame::GetFilterContent(nsIContent* aDefault) {
     89  for (nsIContent* child = mContent->GetFirstChild(); child;
     90       child = child->GetNextSibling()) {
     91    if (child->IsSVGFilterPrimitiveElement()) {
     92      return static_cast<SVGFilterElement*>(GetContent());
     93    }
     94  }
     95 
     96  // Before we recurse, make sure we'll break reference loops and over long
     97  // reference chains:
     98  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     99  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
    100                                        &sRefChainLengthCounter);
    101  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
    102    // Break reference chain
    103    return static_cast<SVGFilterElement*>(aDefault);
    104  }
    105 
    106  SVGFilterFrame* next = GetReferencedFilter();
    107 
    108  return next ? next->GetFilterContent(aDefault)
    109              : static_cast<SVGFilterElement*>(aDefault);
    110 }
    111 
    112 SVGFilterFrame* SVGFilterFrame::GetReferencedFilter() {
    113  if (mNoHRefURI) {
    114    return nullptr;
    115  }
    116 
    117  auto GetHref = [this](nsAString& aHref) {
    118    SVGFilterElement* filter = static_cast<SVGFilterElement*>(GetContent());
    119    if (filter->mStringAttributes[SVGFilterElement::HREF].IsExplicitlySet()) {
    120      filter->mStringAttributes[SVGFilterElement::HREF].GetAnimValue(aHref,
    121                                                                     filter);
    122    } else {
    123      filter->mStringAttributes[SVGFilterElement::XLINK_HREF].GetAnimValue(
    124          aHref, filter);
    125    }
    126    this->mNoHRefURI = aHref.IsEmpty();
    127  };
    128 
    129  nsIFrame* tframe = SVGObserverUtils::GetAndObserveTemplate(this, GetHref);
    130  if (tframe && tframe->IsSVGFilterFrame()) {
    131    return static_cast<SVGFilterFrame*>(tframe);
    132  }
    133  // We don't call SVGObserverUtils::RemoveTemplateObserver and set
    134  // `mNoHRefURI = false` here since we want to be invalidated if the ID
    135  // specified by our href starts resolving to a different/valid element.
    136 
    137  return nullptr;
    138 }
    139 
    140 nsresult SVGFilterFrame::AttributeChanged(int32_t aNameSpaceID,
    141                                          nsAtom* aAttribute,
    142                                          AttrModType aModType) {
    143  if (aNameSpaceID == kNameSpaceID_None &&
    144      (aAttribute == nsGkAtoms::x || aAttribute == nsGkAtoms::y ||
    145       aAttribute == nsGkAtoms::width || aAttribute == nsGkAtoms::height ||
    146       aAttribute == nsGkAtoms::filterUnits ||
    147       aAttribute == nsGkAtoms::primitiveUnits)) {
    148    SVGObserverUtils::InvalidateRenderingObservers(this);
    149  } else if ((aNameSpaceID == kNameSpaceID_XLink ||
    150              aNameSpaceID == kNameSpaceID_None) &&
    151             aAttribute == nsGkAtoms::href) {
    152    // Blow away our reference, if any
    153    SVGObserverUtils::RemoveTemplateObserver(this);
    154    mNoHRefURI = false;
    155    // And update whoever references us
    156    SVGObserverUtils::InvalidateRenderingObservers(this);
    157  }
    158  return SVGContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
    159                                             aModType);
    160 }
    161 
    162 #ifdef DEBUG
    163 void SVGFilterFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
    164                          nsIFrame* aPrevInFlow) {
    165  NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::filter),
    166               "Content is not an SVG filter");
    167 
    168  SVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
    169 }
    170 #endif /* DEBUG */
    171 
    172 }  // namespace mozilla