Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : // Main header first:
7 : #include "nsSVGFilterFrame.h"
8 :
9 : // Keep others in (case-insensitive) order:
10 : #include "AutoReferenceChainGuard.h"
11 : #include "gfxUtils.h"
12 : #include "nsGkAtoms.h"
13 : #include "nsSVGEffects.h"
14 : #include "nsSVGElement.h"
15 : #include "mozilla/dom/SVGFilterElement.h"
16 : #include "nsSVGFilterInstance.h"
17 : #include "nsSVGIntegrationUtils.h"
18 : #include "nsSVGUtils.h"
19 : #include "nsContentUtils.h"
20 :
21 : using namespace mozilla;
22 : using namespace mozilla::dom;
23 :
24 : nsIFrame*
25 0 : NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
26 : {
27 0 : return new (aPresShell) nsSVGFilterFrame(aContext);
28 : }
29 :
30 0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGFilterFrame)
31 :
32 : uint16_t
33 0 : nsSVGFilterFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
34 : {
35 : nsSVGEnum& thisEnum =
36 0 : static_cast<SVGFilterElement *>(mContent)->mEnumAttributes[aIndex];
37 :
38 0 : if (thisEnum.IsExplicitlySet())
39 0 : return thisEnum.GetAnimValue();
40 :
41 : // Before we recurse, make sure we'll break reference loops and over long
42 : // reference chains:
43 : static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
44 : AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
45 0 : &sRefChainLengthCounter);
46 0 : if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
47 : // Break reference chain
48 : return static_cast<SVGFilterElement *>(aDefault)->
49 0 : mEnumAttributes[aIndex].GetAnimValue();
50 : }
51 :
52 0 : nsSVGFilterFrame *next = GetReferencedFilter();
53 :
54 0 : return next ? next->GetEnumValue(aIndex, aDefault)
55 : : static_cast<SVGFilterElement *>(aDefault)->
56 0 : mEnumAttributes[aIndex].GetAnimValue();
57 : }
58 :
59 : const nsSVGLength2 *
60 0 : nsSVGFilterFrame::GetLengthValue(uint32_t aIndex, nsIContent *aDefault)
61 : {
62 : const nsSVGLength2 *thisLength =
63 0 : &static_cast<SVGFilterElement *>(mContent)->mLengthAttributes[aIndex];
64 :
65 0 : if (thisLength->IsExplicitlySet())
66 0 : return thisLength;
67 :
68 : // Before we recurse, make sure we'll break reference loops and over long
69 : // reference chains:
70 : static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
71 : AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
72 0 : &sRefChainLengthCounter);
73 0 : if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
74 : // Break reference chain
75 0 : return &static_cast<SVGFilterElement*>(aDefault)->mLengthAttributes[aIndex];
76 : }
77 :
78 0 : nsSVGFilterFrame *next = GetReferencedFilter();
79 :
80 0 : return next ? next->GetLengthValue(aIndex, aDefault)
81 0 : : &static_cast<SVGFilterElement *>(aDefault)->mLengthAttributes[aIndex];
82 : }
83 :
84 : const SVGFilterElement *
85 0 : nsSVGFilterFrame::GetFilterContent(nsIContent *aDefault)
86 : {
87 0 : for (nsIContent* child = mContent->GetFirstChild();
88 0 : child;
89 0 : child = child->GetNextSibling()) {
90 0 : RefPtr<nsSVGFE> primitive;
91 0 : CallQueryInterface(child, (nsSVGFE**)getter_AddRefs(primitive));
92 0 : if (primitive) {
93 0 : return static_cast<SVGFilterElement *>(mContent);
94 : }
95 : }
96 :
97 : // Before we recurse, make sure we'll break reference loops and over long
98 : // reference chains:
99 : static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
100 : AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
101 0 : &sRefChainLengthCounter);
102 0 : if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
103 : // Break reference chain
104 0 : return static_cast<SVGFilterElement*>(aDefault);
105 : }
106 :
107 0 : nsSVGFilterFrame *next = GetReferencedFilter();
108 :
109 0 : return next ? next->GetFilterContent(aDefault)
110 0 : : static_cast<SVGFilterElement*>(aDefault);
111 : }
112 :
113 : nsSVGFilterFrame *
114 0 : nsSVGFilterFrame::GetReferencedFilter()
115 : {
116 0 : if (mNoHRefURI)
117 0 : return nullptr;
118 :
119 : nsSVGPaintingProperty *property =
120 0 : GetProperty(nsSVGEffects::HrefAsPaintingProperty());
121 :
122 0 : if (!property) {
123 : // Fetch our Filter element's href or xlink:href attribute
124 0 : SVGFilterElement *filter = static_cast<SVGFilterElement *>(mContent);
125 0 : nsAutoString href;
126 0 : if (filter->mStringAttributes[SVGFilterElement::HREF].IsExplicitlySet()) {
127 : filter->mStringAttributes[SVGFilterElement::HREF]
128 0 : .GetAnimValue(href, filter);
129 : } else {
130 : filter->mStringAttributes[SVGFilterElement::XLINK_HREF]
131 0 : .GetAnimValue(href, filter);
132 : }
133 :
134 0 : if (href.IsEmpty()) {
135 0 : mNoHRefURI = true;
136 0 : return nullptr; // no URL
137 : }
138 :
139 : // Convert href to an nsIURI
140 0 : nsCOMPtr<nsIURI> targetURI;
141 0 : nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
142 0 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
143 0 : mContent->GetUncomposedDoc(), base);
144 :
145 : property =
146 0 : nsSVGEffects::GetPaintingProperty(targetURI, this,
147 0 : nsSVGEffects::HrefAsPaintingProperty());
148 0 : if (!property)
149 0 : return nullptr;
150 : }
151 :
152 0 : nsIFrame *result = property->GetReferencedFrame();
153 0 : if (!result)
154 0 : return nullptr;
155 :
156 0 : LayoutFrameType frameType = result->Type();
157 0 : if (frameType != LayoutFrameType::SVGFilter)
158 0 : return nullptr;
159 :
160 0 : return static_cast<nsSVGFilterFrame*>(result);
161 : }
162 :
163 : nsresult
164 0 : nsSVGFilterFrame::AttributeChanged(int32_t aNameSpaceID,
165 : nsIAtom* aAttribute,
166 : int32_t aModType)
167 : {
168 0 : if (aNameSpaceID == kNameSpaceID_None &&
169 0 : (aAttribute == nsGkAtoms::x ||
170 0 : aAttribute == nsGkAtoms::y ||
171 0 : aAttribute == nsGkAtoms::width ||
172 0 : aAttribute == nsGkAtoms::height ||
173 0 : aAttribute == nsGkAtoms::filterUnits ||
174 0 : aAttribute == nsGkAtoms::primitiveUnits)) {
175 0 : nsSVGEffects::InvalidateDirectRenderingObservers(this);
176 0 : } else if ((aNameSpaceID == kNameSpaceID_XLink ||
177 0 : aNameSpaceID == kNameSpaceID_None) &&
178 0 : aAttribute == nsGkAtoms::href) {
179 : // Blow away our reference, if any
180 0 : DeleteProperty(nsSVGEffects::HrefAsPaintingProperty());
181 0 : mNoHRefURI = false;
182 : // And update whoever references us
183 0 : nsSVGEffects::InvalidateDirectRenderingObservers(this);
184 : }
185 0 : return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
186 0 : aAttribute, aModType);
187 : }
188 :
189 : #ifdef DEBUG
190 : void
191 0 : nsSVGFilterFrame::Init(nsIContent* aContent,
192 : nsContainerFrame* aParent,
193 : nsIFrame* aPrevInFlow)
194 : {
195 0 : NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::filter),
196 : "Content is not an SVG filter");
197 :
198 0 : nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
199 0 : }
200 : #endif /* DEBUG */
|