no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / layout / svg / SVGFilterFrame.cpp
blob0b4544a36cc6b7dedd1769f55311bc5a19260d2a
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/. */
7 // Main header first:
8 #include "SVGFilterFrame.h"
10 // Keep others in (case-insensitive) order:
11 #include "AutoReferenceChainGuard.h"
12 #include "gfxUtils.h"
13 #include "mozilla/PresShell.h"
14 #include "mozilla/dom/SVGFilterElement.h"
15 #include "nsGkAtoms.h"
16 #include "SVGObserverUtils.h"
17 #include "SVGElement.h"
18 #include "SVGFilterInstance.h"
19 #include "nsContentUtils.h"
21 using namespace mozilla;
22 using namespace mozilla::dom;
24 nsIFrame* NS_NewSVGFilterFrame(mozilla::PresShell* aPresShell,
25 mozilla::ComputedStyle* aStyle) {
26 return new (aPresShell)
27 mozilla::SVGFilterFrame(aStyle, aPresShell->GetPresContext());
30 namespace mozilla {
32 NS_IMPL_FRAMEARENA_HELPERS(SVGFilterFrame)
34 uint16_t SVGFilterFrame::GetEnumValue(uint32_t aIndex, nsIContent* aDefault) {
35 SVGAnimatedEnumeration& thisEnum =
36 static_cast<SVGFilterElement*>(GetContent())->mEnumAttributes[aIndex];
38 if (thisEnum.IsExplicitlySet()) {
39 return thisEnum.GetAnimValue();
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();
54 SVGFilterFrame* next = GetReferencedFilter();
56 return next ? next->GetEnumValue(aIndex, aDefault)
57 : static_cast<SVGFilterElement*>(aDefault)
58 ->mEnumAttributes[aIndex]
59 .GetAnimValue();
62 const SVGAnimatedLength* SVGFilterFrame::GetLengthValue(uint32_t aIndex,
63 nsIContent* aDefault) {
64 const SVGAnimatedLength* thisLength =
65 &static_cast<SVGFilterElement*>(GetContent())->mLengthAttributes[aIndex];
67 if (thisLength->IsExplicitlySet()) {
68 return thisLength;
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];
81 SVGFilterFrame* next = GetReferencedFilter();
83 return next ? next->GetLengthValue(aIndex, aDefault)
84 : &static_cast<SVGFilterElement*>(aDefault)
85 ->mLengthAttributes[aIndex];
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());
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);
106 SVGFilterFrame* next = GetReferencedFilter();
108 return next ? next->GetFilterContent(aDefault)
109 : static_cast<SVGFilterElement*>(aDefault);
112 SVGFilterFrame* SVGFilterFrame::GetReferencedFilter() {
113 if (mNoHRefURI) {
114 return nullptr;
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);
126 this->mNoHRefURI = aHref.IsEmpty();
129 nsIFrame* tframe = SVGObserverUtils::GetAndObserveTemplate(this, GetHref);
130 if (tframe && tframe->IsSVGFilterFrame()) {
131 return static_cast<SVGFilterFrame*>(tframe);
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.
137 return nullptr;
140 nsresult SVGFilterFrame::AttributeChanged(int32_t aNameSpaceID,
141 nsAtom* aAttribute,
142 int32_t 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);
158 return SVGContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
159 aModType);
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");
168 SVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
170 #endif /* DEBUG */
172 } // namespace mozilla