1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla SVG project.
16 : *
17 : * The Initial Developer of the Original Code is IBM Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2006
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "nsSVGContainerFrame.h"
38 : #include "nsSVGUtils.h"
39 : #include "nsSVGOuterSVGFrame.h"
40 :
41 0 : NS_QUERYFRAME_HEAD(nsSVGContainerFrame)
42 0 : NS_QUERYFRAME_ENTRY(nsSVGContainerFrame)
43 0 : NS_QUERYFRAME_TAIL_INHERITING(nsSVGContainerFrameBase)
44 :
45 0 : NS_QUERYFRAME_HEAD(nsSVGDisplayContainerFrame)
46 0 : NS_QUERYFRAME_ENTRY(nsSVGDisplayContainerFrame)
47 0 : NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
48 0 : NS_QUERYFRAME_TAIL_INHERITING(nsSVGContainerFrame)
49 :
50 : nsIFrame*
51 0 : NS_NewSVGContainerFrame(nsIPresShell* aPresShell,
52 : nsStyleContext* aContext)
53 : {
54 0 : nsIFrame *frame = new (aPresShell) nsSVGContainerFrame(aContext);
55 : // If we were called directly, then the frame is for a <defs> or
56 : // an unknown element type. In both cases we prevent the content
57 : // from displaying directly.
58 0 : frame->AddStateBits(NS_STATE_SVG_NONDISPLAY_CHILD);
59 0 : return frame;
60 : }
61 :
62 0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGContainerFrame)
63 0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGDisplayContainerFrame)
64 :
65 : NS_IMETHODIMP
66 0 : nsSVGContainerFrame::AppendFrames(ChildListID aListID,
67 : nsFrameList& aFrameList)
68 : {
69 0 : return InsertFrames(aListID, mFrames.LastChild(), aFrameList);
70 : }
71 :
72 : NS_IMETHODIMP
73 0 : nsSVGContainerFrame::InsertFrames(ChildListID aListID,
74 : nsIFrame* aPrevFrame,
75 : nsFrameList& aFrameList)
76 : {
77 0 : NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
78 0 : NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
79 : "inserting after sibling frame with different parent");
80 :
81 0 : mFrames.InsertFrames(this, aPrevFrame, aFrameList);
82 :
83 0 : return NS_OK;
84 : }
85 :
86 : NS_IMETHODIMP
87 0 : nsSVGContainerFrame::RemoveFrame(ChildListID aListID,
88 : nsIFrame* aOldFrame)
89 : {
90 0 : NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
91 :
92 0 : mFrames.DestroyFrame(aOldFrame);
93 0 : return NS_OK;
94 : }
95 :
96 : NS_IMETHODIMP
97 0 : nsSVGDisplayContainerFrame::Init(nsIContent* aContent,
98 : nsIFrame* aParent,
99 : nsIFrame* aPrevInFlow)
100 : {
101 0 : if (!(GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
102 0 : AddStateBits(aParent->GetStateBits() &
103 : (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_SVG_CLIPPATH_CHILD |
104 0 : NS_STATE_SVG_REDRAW_SUSPENDED));
105 : }
106 0 : nsresult rv = nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
107 0 : return rv;
108 : }
109 :
110 : NS_IMETHODIMP
111 0 : nsSVGDisplayContainerFrame::InsertFrames(ChildListID aListID,
112 : nsIFrame* aPrevFrame,
113 : nsFrameList& aFrameList)
114 : {
115 : // memorize first old frame after insertion point
116 : // XXXbz once again, this would work a lot better if the nsIFrame
117 : // methods returned framelist iterators....
118 : nsIFrame* firstOldFrame = aPrevFrame ?
119 0 : aPrevFrame->GetNextSibling() : GetChildList(aListID).FirstChild();
120 0 : nsIFrame* firstNewFrame = aFrameList.FirstChild();
121 :
122 : // Insert the new frames
123 0 : nsSVGContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
124 :
125 : // Call InitialUpdate on the new frames ONLY if our nsSVGOuterSVGFrame has had
126 : // its initial reflow (our NS_FRAME_FIRST_REFLOW bit is clear) - bug 399863.
127 0 : if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
128 0 : for (nsIFrame* kid = firstNewFrame; kid != firstOldFrame;
129 : kid = kid->GetNextSibling()) {
130 0 : nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
131 0 : if (SVGFrame) {
132 0 : SVGFrame->InitialUpdate();
133 : }
134 : }
135 : }
136 :
137 0 : return NS_OK;
138 : }
139 :
140 : NS_IMETHODIMP
141 0 : nsSVGDisplayContainerFrame::RemoveFrame(ChildListID aListID,
142 : nsIFrame* aOldFrame)
143 : {
144 : // Force the invalidation before it's too late
145 0 : RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED);
146 :
147 0 : nsSVGUtils::InvalidateCoveredRegion(aOldFrame);
148 :
149 0 : nsresult rv = nsSVGContainerFrame::RemoveFrame(aListID, aOldFrame);
150 :
151 0 : if (!(GetStateBits() & (NS_STATE_SVG_NONDISPLAY_CHILD | NS_STATE_IS_OUTER_SVG))) {
152 0 : nsSVGUtils::NotifyAncestorsOfFilterRegionChange(this);
153 : }
154 :
155 0 : return rv;
156 : }
157 :
158 : //----------------------------------------------------------------------
159 : // nsISVGChildFrame methods
160 :
161 : NS_IMETHODIMP
162 0 : nsSVGDisplayContainerFrame::PaintSVG(nsRenderingContext* aContext,
163 : const nsIntRect *aDirtyRect)
164 : {
165 0 : const nsStyleDisplay *display = mStyleContext->GetStyleDisplay();
166 0 : if (display->mOpacity == 0.0)
167 0 : return NS_OK;
168 :
169 0 : for (nsIFrame* kid = mFrames.FirstChild(); kid;
170 : kid = kid->GetNextSibling()) {
171 0 : nsSVGUtils::PaintFrameWithEffects(aContext, aDirtyRect, kid);
172 : }
173 :
174 0 : return NS_OK;
175 : }
176 :
177 : NS_IMETHODIMP_(nsIFrame*)
178 0 : nsSVGDisplayContainerFrame::GetFrameForPoint(const nsPoint &aPoint)
179 : {
180 0 : return nsSVGUtils::HitTestChildren(this, aPoint);
181 : }
182 :
183 : NS_IMETHODIMP_(nsRect)
184 0 : nsSVGDisplayContainerFrame::GetCoveredRegion()
185 : {
186 0 : return nsSVGUtils::GetCoveredRegion(mFrames);
187 : }
188 :
189 : NS_IMETHODIMP
190 0 : nsSVGDisplayContainerFrame::UpdateCoveredRegion()
191 : {
192 0 : for (nsIFrame* kid = mFrames.FirstChild(); kid;
193 : kid = kid->GetNextSibling()) {
194 0 : nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
195 0 : if (SVGFrame) {
196 0 : SVGFrame->UpdateCoveredRegion();
197 : }
198 : }
199 0 : return NS_OK;
200 : }
201 :
202 : NS_IMETHODIMP
203 0 : nsSVGDisplayContainerFrame::InitialUpdate()
204 : {
205 0 : NS_ASSERTION(GetStateBits() & NS_FRAME_FIRST_REFLOW,
206 : "Yikes! We've been called already! Hopefully we weren't called "
207 : "before our nsSVGOuterSVGFrame's initial Reflow()!!!");
208 :
209 0 : for (nsIFrame* kid = mFrames.FirstChild(); kid;
210 : kid = kid->GetNextSibling()) {
211 0 : nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
212 0 : if (SVGFrame) {
213 0 : SVGFrame->InitialUpdate();
214 : }
215 : }
216 :
217 0 : NS_ASSERTION(!(mState & NS_FRAME_IN_REFLOW),
218 : "We don't actually participate in reflow");
219 :
220 : // Do unset the various reflow bits, though.
221 : mState &= ~(NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
222 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
223 :
224 0 : return NS_OK;
225 : }
226 :
227 : void
228 0 : nsSVGDisplayContainerFrame::NotifySVGChanged(PRUint32 aFlags)
229 : {
230 0 : NS_ABORT_IF_FALSE(!(aFlags & DO_NOT_NOTIFY_RENDERING_OBSERVERS) ||
231 : (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD),
232 : "Must be NS_STATE_SVG_NONDISPLAY_CHILD!");
233 :
234 0 : NS_ABORT_IF_FALSE(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
235 : "Invalidation logic may need adjusting");
236 :
237 0 : nsSVGUtils::NotifyChildrenOfSVGChange(this, aFlags);
238 0 : }
239 :
240 : void
241 0 : nsSVGDisplayContainerFrame::NotifyRedrawSuspended()
242 : {
243 0 : nsSVGUtils::NotifyRedrawSuspended(this);
244 0 : }
245 :
246 : void
247 0 : nsSVGDisplayContainerFrame::NotifyRedrawUnsuspended()
248 : {
249 0 : nsSVGUtils::NotifyRedrawUnsuspended(this);
250 0 : }
251 :
252 : gfxRect
253 0 : nsSVGDisplayContainerFrame::GetBBoxContribution(
254 : const gfxMatrix &aToBBoxUserspace,
255 : PRUint32 aFlags)
256 : {
257 0 : gfxRect bboxUnion(0.0, 0.0, 0.0, 0.0);
258 :
259 0 : nsIFrame* kid = mFrames.FirstChild();
260 0 : while (kid) {
261 0 : nsISVGChildFrame* svgKid = do_QueryFrame(kid);
262 0 : if (svgKid) {
263 0 : gfxMatrix transform = aToBBoxUserspace;
264 0 : nsIContent *content = kid->GetContent();
265 0 : if (content->IsSVG() && !content->IsNodeOfType(nsINode::eTEXT)) {
266 : transform = static_cast<nsSVGElement*>(content)->
267 0 : PrependLocalTransformsTo(aToBBoxUserspace);
268 : }
269 : bboxUnion =
270 0 : bboxUnion.Union(svgKid->GetBBoxContribution(transform, aFlags));
271 : }
272 0 : kid = kid->GetNextSibling();
273 : }
274 :
275 : return bboxUnion;
276 : }
|