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