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
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/
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
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * rendering object that is the root of the frame tree, which contains
40 * the document's scrollbars and contains fixed-positioned elements
44 #include "nsViewportFrame.h"
45 #include "nsHTMLParts.h"
46 #include "nsGkAtoms.h"
47 #include "nsIScrollableFrame.h"
48 #include "nsDisplayList.h"
51 NS_NewViewportFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
53 return new (aPresShell
) ViewportFrame(aContext
);
57 ViewportFrame::Init(nsIContent
* aContent
,
59 nsIFrame
* aPrevInFlow
)
61 return Super::Init(aContent
, aParent
, aPrevInFlow
);
65 ViewportFrame::Destroy()
67 mFixedContainer
.DestroyFrames(this);
68 nsContainerFrame::Destroy();
72 ViewportFrame::SetInitialChildList(nsIAtom
* aListName
,
77 // See which child list to add the frames to
79 nsFrame::VerifyDirtyBitSet(aChildList
);
81 if (nsGkAtoms::fixedList
== aListName
) {
82 rv
= mFixedContainer
.SetInitialChildList(this, aListName
, aChildList
);
85 rv
= nsContainerFrame::SetInitialChildList(aListName
, aChildList
);
92 ViewportFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
93 const nsRect
& aDirtyRect
,
94 const nsDisplayListSet
& aLists
)
96 // We don't need any special painting or event handling. We just need to
97 // mark our visible out-of-flow frames (i.e., the fixed position frames) so
98 // that display list construction is guaranteed to recurse into their
100 aBuilder
->MarkFramesForDisplayList(this, mFixedContainer
.GetFirstChild(), aDirtyRect
);
102 nsIFrame
* kid
= mFrames
.FirstChild();
106 // make the kid's BorderBackground our own. This ensures that the canvas
107 // frame's background becomes our own background and therefore appears
108 // below negative z-index elements.
109 return BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, aLists
);
113 ViewportFrame::AppendFrames(nsIAtom
* aListName
,
114 nsIFrame
* aFrameList
)
118 if (nsGkAtoms::fixedList
== aListName
) {
119 rv
= mFixedContainer
.AppendFrames(this, aListName
, aFrameList
);
122 // We only expect incremental changes for our fixed frames
123 NS_ERROR("unexpected child list");
124 rv
= NS_ERROR_INVALID_ARG
;
131 ViewportFrame::InsertFrames(nsIAtom
* aListName
,
132 nsIFrame
* aPrevFrame
,
133 nsIFrame
* aFrameList
)
137 if (nsGkAtoms::fixedList
== aListName
) {
138 rv
= mFixedContainer
.InsertFrames(this, aListName
, aPrevFrame
, aFrameList
);
141 // We only expect incremental changes for our fixed frames
142 NS_ERROR("unexpected child list");
143 rv
= NS_ERROR_INVALID_ARG
;
150 ViewportFrame::RemoveFrame(nsIAtom
* aListName
,
155 if (nsGkAtoms::fixedList
== aListName
) {
156 rv
= mFixedContainer
.RemoveFrame(this, aListName
, aOldFrame
);
159 // We only expect incremental changes for our fixed frames
160 NS_ERROR("unexpected child list");
161 rv
= NS_ERROR_INVALID_ARG
;
168 ViewportFrame::GetAdditionalChildListName(PRInt32 aIndex
) const
170 NS_PRECONDITION(aIndex
>= 0, "illegal index");
173 return nsGkAtoms::fixedList
;
180 ViewportFrame::GetFirstChild(nsIAtom
* aListName
) const
182 if (nsGkAtoms::fixedList
== aListName
) {
183 nsIFrame
* result
= nsnull
;
184 mFixedContainer
.FirstChild(this, aListName
, &result
);
188 return nsContainerFrame::GetFirstChild(aListName
);
191 /* virtual */ nscoord
192 ViewportFrame::GetMinWidth(nsIRenderingContext
*aRenderingContext
)
195 DISPLAY_MIN_WIDTH(this, result
);
196 if (mFrames
.IsEmpty())
199 result
= mFrames
.FirstChild()->GetMinWidth(aRenderingContext
);
201 // XXXldb Deal with mFixedContainer (matters for SizeToContent)!
206 /* virtual */ nscoord
207 ViewportFrame::GetPrefWidth(nsIRenderingContext
*aRenderingContext
)
210 DISPLAY_PREF_WIDTH(this, result
);
211 if (mFrames
.IsEmpty())
214 result
= mFrames
.FirstChild()->GetPrefWidth(aRenderingContext
);
216 // XXXldb Deal with mFixedContainer (matters for SizeToContent)!
222 ViewportFrame::AdjustReflowStateForScrollbars(nsHTMLReflowState
* aReflowState
) const
224 // Calculate how much room is available for fixed frames. That means
225 // determining if the viewport is scrollable and whether the vertical and/or
226 // horizontal scrollbars are visible
228 // Get our prinicpal child frame and see if we're scrollable
229 nsIFrame
* kidFrame
= mFrames
.FirstChild();
230 nsCOMPtr
<nsIScrollableFrame
> scrollingFrame(do_QueryInterface(kidFrame
));
232 if (scrollingFrame
) {
233 nsMargin scrollbars
= scrollingFrame
->GetActualScrollbarSizes();
234 aReflowState
->SetComputedWidth(aReflowState
->ComputedWidth() -
235 scrollbars
.LeftRight());
236 aReflowState
->availableWidth
-= scrollbars
.LeftRight();
237 aReflowState
->SetComputedHeight(aReflowState
->ComputedHeight() -
238 scrollbars
.TopBottom());
239 // XXX why don't we also adjust "aReflowState->availableHeight"?
240 return nsPoint(scrollbars
.left
, scrollbars
.top
);
242 return nsPoint(0, 0);
246 ViewportFrame::Reflow(nsPresContext
* aPresContext
,
247 nsHTMLReflowMetrics
& aDesiredSize
,
248 const nsHTMLReflowState
& aReflowState
,
249 nsReflowStatus
& aStatus
)
251 DO_GLOBAL_REFLOW_COUNT("ViewportFrame");
252 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
253 NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow");
255 // Initialize OUT parameters
256 aStatus
= NS_FRAME_COMPLETE
;
258 // Because |Reflow| sets mComputedHeight on the child to
260 AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT
);
262 // Reflow the main content first so that the placeholders of the
263 // fixed-position frames will be in the right places on an initial
265 nscoord kidHeight
= 0;
269 if (mFrames
.NotEmpty()) {
270 // Deal with a non-incremental reflow or an incremental reflow
271 // targeted at our one-and-only principal child frame.
272 if (aReflowState
.ShouldReflowAllKids() ||
273 aReflowState
.mFlags
.mVResize
||
274 NS_SUBTREE_DIRTY(mFrames
.FirstChild())) {
275 // Reflow our one-and-only principal child frame
276 nsIFrame
* kidFrame
= mFrames
.FirstChild();
277 nsHTMLReflowMetrics kidDesiredSize
;
278 nsSize
availableSpace(aReflowState
.availableWidth
,
279 aReflowState
.availableHeight
);
280 nsHTMLReflowState
kidReflowState(aPresContext
, aReflowState
,
281 kidFrame
, availableSpace
);
284 kidReflowState
.SetComputedHeight(aReflowState
.availableHeight
);
285 rv
= ReflowChild(kidFrame
, aPresContext
, kidDesiredSize
, kidReflowState
,
287 kidHeight
= kidDesiredSize
.height
;
289 FinishReflowChild(kidFrame
, aPresContext
, nsnull
, kidDesiredSize
, 0, 0, 0);
291 kidHeight
= mFrames
.FirstChild()->GetSize().height
;
295 NS_ASSERTION(aReflowState
.availableWidth
!= NS_UNCONSTRAINEDSIZE
,
296 "shouldn't happen anymore");
298 // Return the max size as our desired size
299 aDesiredSize
.width
= aReflowState
.availableWidth
;
300 // Being flowed initially at an unconstrained height means we should
301 // return our child's intrinsic size.
302 aDesiredSize
.height
= aReflowState
.availableHeight
!= NS_UNCONSTRAINEDSIZE
303 ? aReflowState
.availableHeight
306 // Make a copy of the reflow state and change the computed width and height
307 // to reflect the available space for the fixed items
308 nsHTMLReflowState
reflowState(aReflowState
);
309 nsPoint offset
= AdjustReflowStateForScrollbars(&reflowState
);
313 mFixedContainer
.FirstChild(this, nsGkAtoms::fixedList
, &f
);
314 NS_ASSERTION(!f
|| (offset
.x
== 0 && offset
.y
== 0),
315 "We don't handle correct positioning of fixed frames with "
316 "scrollbars in odd positions");
319 // Just reflow all the fixed-pos frames.
320 rv
= mFixedContainer
.Reflow(this, aPresContext
, reflowState
, aStatus
,
321 reflowState
.ComputedWidth(),
322 reflowState
.ComputedHeight(),
323 PR_FALSE
, PR_TRUE
, PR_TRUE
); // XXX could be optimized
325 // If we were dirty then do a repaint
326 if (GetStateBits() & NS_FRAME_IS_DIRTY
) {
327 nsRect
damageRect(0, 0, aDesiredSize
.width
, aDesiredSize
.height
);
328 Invalidate(damageRect
, PR_FALSE
);
331 // XXX Should we do something to clip our children to this?
332 aDesiredSize
.mOverflowArea
=
333 nsRect(nsPoint(0, 0), nsSize(aDesiredSize
.width
, aDesiredSize
.height
));
335 NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus
);
336 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
341 ViewportFrame::GetType() const
343 return nsGkAtoms::viewportFrame
;
347 ViewportFrame::IsContainingBlock() const
353 ViewportFrame::InvalidateInternal(const nsRect
& aDamageRect
,
354 nscoord aX
, nscoord aY
, nsIFrame
* aForChild
,
357 nsIFrame
* parent
= nsLayoutUtils::GetCrossDocParentFrame(this);
359 nsPoint pt
= GetOffsetTo(parent
);
360 parent
->InvalidateInternal(aDamageRect
, aX
+ pt
.x
, aY
+ pt
.y
, this, aImmediate
);
363 InvalidateRoot(aDamageRect
, aX
, aY
, aImmediate
);
368 ViewportFrame::GetFrameName(nsAString
& aResult
) const
370 return MakeFrameName(NS_LITERAL_STRING("Viewport"), aResult
);