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 : // Keep in (case-insensitive) order:
7 : #include "nsContainerFrame.h"
8 : #include "nsContentUtils.h"
9 : #include "nsFrame.h"
10 : #include "nsGkAtoms.h"
11 : #include "nsIDOMMutationEvent.h"
12 : #include "nsLiteralString.h"
13 : #include "nsSVGEffects.h"
14 : #include "nsSVGFilters.h"
15 : #include "mozilla/dom/SVGFEImageElement.h"
16 :
17 : using namespace mozilla;
18 : using namespace mozilla::dom;
19 :
20 0 : class SVGFEImageFrame final : public nsFrame
21 : {
22 : friend nsIFrame*
23 : NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
24 : protected:
25 0 : explicit SVGFEImageFrame(nsStyleContext* aContext)
26 0 : : nsFrame(aContext, kClassID)
27 : {
28 0 : AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
29 :
30 : // This frame isn't actually displayed, but it contains an image and we want
31 : // to use the nsImageLoadingContent machinery for managing images, which
32 : // requires visibility tracking, so we enable visibility tracking and
33 : // forcibly mark it visible below.
34 0 : EnableVisibilityTracking();
35 0 : }
36 :
37 : public:
38 0 : NS_DECL_FRAMEARENA_HELPERS(SVGFEImageFrame)
39 :
40 : virtual void Init(nsIContent* aContent,
41 : nsContainerFrame* aParent,
42 : nsIFrame* aPrevInFlow) override;
43 : virtual void DestroyFrom(nsIFrame* aDestructRoot) override;
44 :
45 0 : virtual bool IsFrameOfType(uint32_t aFlags) const override
46 : {
47 0 : return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
48 : }
49 :
50 : #ifdef DEBUG_FRAME_DUMP
51 0 : virtual nsresult GetFrameName(nsAString& aResult) const override
52 : {
53 0 : return MakeFrameName(NS_LITERAL_STRING("SVGFEImage"), aResult);
54 : }
55 : #endif
56 :
57 : virtual nsresult AttributeChanged(int32_t aNameSpaceID,
58 : nsIAtom* aAttribute,
59 : int32_t aModType) override;
60 :
61 : void OnVisibilityChange(Visibility aNewVisibility,
62 : const Maybe<OnNonvisible>& aNonvisibleAction = Nothing()) override;
63 :
64 0 : virtual bool ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) override {
65 : // We don't maintain a visual overflow rect
66 0 : return false;
67 : }
68 : };
69 :
70 : nsIFrame*
71 0 : NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
72 : {
73 0 : return new (aPresShell) SVGFEImageFrame(aContext);
74 : }
75 :
76 0 : NS_IMPL_FRAMEARENA_HELPERS(SVGFEImageFrame)
77 :
78 : /* virtual */ void
79 0 : SVGFEImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
80 : {
81 0 : DecApproximateVisibleCount();
82 :
83 : nsCOMPtr<nsIImageLoadingContent> imageLoader =
84 0 : do_QueryInterface(nsFrame::mContent);
85 0 : if (imageLoader) {
86 0 : imageLoader->FrameDestroyed(this);
87 : }
88 :
89 0 : nsFrame::DestroyFrom(aDestructRoot);
90 0 : }
91 :
92 : void
93 0 : SVGFEImageFrame::Init(nsIContent* aContent,
94 : nsContainerFrame* aParent,
95 : nsIFrame* aPrevInFlow)
96 : {
97 0 : NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::feImage),
98 : "Trying to construct an SVGFEImageFrame for a "
99 : "content element that doesn't support the right interfaces");
100 :
101 0 : nsFrame::Init(aContent, aParent, aPrevInFlow);
102 :
103 : // We assume that feImage's are always visible.
104 : // This call must happen before the FrameCreated. This is because the
105 : // primary frame pointer on our content node isn't set until after this
106 : // function ends, so there is no way for the resulting OnVisibilityChange
107 : // notification to get a frame. FrameCreated has a workaround for this in
108 : // that it passes our frame around so it can be accessed. OnVisibilityChange
109 : // doesn't have that workaround.
110 0 : IncApproximateVisibleCount();
111 :
112 : nsCOMPtr<nsIImageLoadingContent> imageLoader =
113 0 : do_QueryInterface(nsFrame::mContent);
114 0 : if (imageLoader) {
115 0 : imageLoader->FrameCreated(this);
116 : }
117 0 : }
118 :
119 : nsresult
120 0 : SVGFEImageFrame::AttributeChanged(int32_t aNameSpaceID,
121 : nsIAtom* aAttribute,
122 : int32_t aModType)
123 : {
124 0 : SVGFEImageElement* element = static_cast<SVGFEImageElement*>(mContent);
125 0 : if (element->AttributeAffectsRendering(aNameSpaceID, aAttribute)) {
126 0 : MOZ_ASSERT(GetParent()->IsSVGFilterFrame(),
127 : "Observers observe the filter, so that's what we must invalidate");
128 0 : nsSVGEffects::InvalidateDirectRenderingObservers(GetParent());
129 : }
130 :
131 : // Currently our SMIL implementation does not modify the DOM attributes. Once
132 : // we implement the SVG 2 SMIL behaviour this can be removed
133 : // SVGFEImageElement::AfterSetAttr's implementation will be sufficient.
134 0 : if (aModType == nsIDOMMutationEvent::SMIL &&
135 0 : aAttribute == nsGkAtoms::href &&
136 0 : (aNameSpaceID == kNameSpaceID_XLink ||
137 : aNameSpaceID == kNameSpaceID_None)) {
138 : bool hrefIsSet =
139 0 : element->mStringAttributes[SVGFEImageElement::HREF].IsExplicitlySet() ||
140 : element->mStringAttributes[SVGFEImageElement::XLINK_HREF]
141 0 : .IsExplicitlySet();
142 0 : if (hrefIsSet) {
143 0 : element->LoadSVGImage(true, true);
144 : } else {
145 0 : element->CancelImageRequests(true);
146 : }
147 : }
148 :
149 0 : return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
150 : }
151 :
152 : void
153 0 : SVGFEImageFrame::OnVisibilityChange(Visibility aNewVisibility,
154 : const Maybe<OnNonvisible>& aNonvisibleAction)
155 : {
156 : nsCOMPtr<nsIImageLoadingContent> imageLoader =
157 0 : do_QueryInterface(nsFrame::mContent);
158 0 : if (!imageLoader) {
159 0 : MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
160 : nsFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
161 : return;
162 : }
163 :
164 0 : imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
165 :
166 0 : nsFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
167 : }
|