summaryrefslogtreecommitdiffstats
path: root/layout/svg/SVGFilterFrame.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /layout/svg/SVGFilterFrame.cpp
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'layout/svg/SVGFilterFrame.cpp')
-rw-r--r--layout/svg/SVGFilterFrame.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/layout/svg/SVGFilterFrame.cpp b/layout/svg/SVGFilterFrame.cpp
new file mode 100644
index 0000000000..0b4544a36c
--- /dev/null
+++ b/layout/svg/SVGFilterFrame.cpp
@@ -0,0 +1,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