diff options
author | wolfbeast <mcwerewolf@gmail.com> | 2014-05-21 11:38:25 +0200 |
---|---|---|
committer | wolfbeast <mcwerewolf@gmail.com> | 2014-05-21 11:38:25 +0200 |
commit | d25ba7d760b017b038e5aa6c0a605b4a330eb68d (patch) | |
tree | 16ec27edc7d5f83986f16236d3a36a2682a0f37e /layout/generic/nsViewportFrame.cpp | |
parent | a942906574671868daf122284a9c4689e6924f74 (diff) | |
download | palemoon-gre-d25ba7d760b017b038e5aa6c0a605b4a330eb68d.tar.gz |
Recommit working copy to repo with proper line endings.
Diffstat (limited to 'layout/generic/nsViewportFrame.cpp')
-rw-r--r-- | layout/generic/nsViewportFrame.cpp | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/layout/generic/nsViewportFrame.cpp b/layout/generic/nsViewportFrame.cpp new file mode 100644 index 000000000..385809c12 --- /dev/null +++ b/layout/generic/nsViewportFrame.cpp @@ -0,0 +1,311 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +/* + * rendering object that is the root of the frame tree, which contains + * the document's scrollbars and contains fixed-positioned elements + */ + +#include "nsCOMPtr.h" +#include "nsViewportFrame.h" +#include "nsHTMLParts.h" +#include "nsGkAtoms.h" +#include "nsIScrollableFrame.h" +#include "nsDisplayList.h" +#include "FrameLayerBuilder.h" +#include "nsSubDocumentFrame.h" +#include "nsAbsoluteContainingBlock.h" +#include "GeckoProfiler.h" + +using namespace mozilla; + +nsIFrame* +NS_NewViewportFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) +{ + return new (aPresShell) ViewportFrame(aContext); +} + +NS_IMPL_FRAMEARENA_HELPERS(ViewportFrame) +NS_QUERYFRAME_HEAD(ViewportFrame) + NS_QUERYFRAME_ENTRY(ViewportFrame) +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) + +void +ViewportFrame::Init(nsIContent* aContent, + nsIFrame* aParent, + nsIFrame* aPrevInFlow) +{ + Super::Init(aContent, aParent, aPrevInFlow); + + nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this); + if (parent) { + nsFrameState state = parent->GetStateBits(); + + mState |= state & (NS_FRAME_IN_POPUP); + } +} + +NS_IMETHODIMP +ViewportFrame::SetInitialChildList(ChildListID aListID, + nsFrameList& aChildList) +{ + // See which child list to add the frames to +#ifdef DEBUG + nsFrame::VerifyDirtyBitSet(aChildList); +#endif + return nsContainerFrame::SetInitialChildList(aListID, aChildList); +} + +void +ViewportFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsRect& aDirtyRect, + const nsDisplayListSet& aLists) +{ + PROFILER_LABEL("ViewportFrame", "BuildDisplayList"); + nsIFrame* kid = mFrames.FirstChild(); + if (!kid) + return; + + // make the kid's BorderBackground our own. This ensures that the canvas + // frame's background becomes our own background and therefore appears + // below negative z-index elements. + BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); +} + +NS_IMETHODIMP +ViewportFrame::AppendFrames(ChildListID aListID, + nsFrameList& aFrameList) +{ + NS_ASSERTION(aListID == kPrincipalList || + aListID == GetAbsoluteListID(), "unexpected child list"); + NS_ASSERTION(aListID != GetAbsoluteListID() || + GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!"); + return nsContainerFrame::AppendFrames(aListID, aFrameList); +} + +NS_IMETHODIMP +ViewportFrame::InsertFrames(ChildListID aListID, + nsIFrame* aPrevFrame, + nsFrameList& aFrameList) +{ + NS_ASSERTION(aListID == kPrincipalList || + aListID == GetAbsoluteListID(), "unexpected child list"); + NS_ASSERTION(aListID != GetAbsoluteListID() || + GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!"); + return nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList); +} + +NS_IMETHODIMP +ViewportFrame::RemoveFrame(ChildListID aListID, + nsIFrame* aOldFrame) +{ + NS_ASSERTION(aListID == kPrincipalList || + aListID == GetAbsoluteListID(), "unexpected child list"); + return nsContainerFrame::RemoveFrame(aListID, aOldFrame); +} + +/* virtual */ nscoord +ViewportFrame::GetMinWidth(nsRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_MIN_WIDTH(this, result); + if (mFrames.IsEmpty()) + result = 0; + else + result = mFrames.FirstChild()->GetMinWidth(aRenderingContext); + + return result; +} + +/* virtual */ nscoord +ViewportFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) +{ + nscoord result; + DISPLAY_PREF_WIDTH(this, result); + if (mFrames.IsEmpty()) + result = 0; + else + result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext); + + return result; +} + +nsPoint +ViewportFrame::AdjustReflowStateForScrollbars(nsHTMLReflowState* aReflowState) const +{ + // Get our prinicpal child frame and see if we're scrollable + nsIFrame* kidFrame = mFrames.FirstChild(); + nsIScrollableFrame* scrollingFrame = do_QueryFrame(kidFrame); + + if (scrollingFrame) { + nsMargin scrollbars = scrollingFrame->GetActualScrollbarSizes(); + aReflowState->SetComputedWidth(aReflowState->ComputedWidth() - + scrollbars.LeftRight()); + aReflowState->availableWidth -= scrollbars.LeftRight(); + aReflowState->SetComputedHeightWithoutResettingResizeFlags( + aReflowState->ComputedHeight() - scrollbars.TopBottom()); + return nsPoint(scrollbars.left, scrollbars.top); + } + return nsPoint(0, 0); +} + +nsRect +ViewportFrame::AdjustReflowStateAsContainingBlock(nsHTMLReflowState* aReflowState) const +{ +#ifdef DEBUG + nsPoint offset = +#endif + AdjustReflowStateForScrollbars(aReflowState); + + NS_ASSERTION(GetAbsoluteContainingBlock()->GetChildList().IsEmpty() || + (offset.x == 0 && offset.y == 0), + "We don't handle correct positioning of fixed frames with " + "scrollbars in odd positions"); + + // If a scroll position clamping scroll-port size has been set, layout + // fixed position elements to this size instead of the computed size. + nsRect rect(0, 0, aReflowState->ComputedWidth(), aReflowState->ComputedHeight()); + nsIPresShell* ps = PresContext()->PresShell(); + if (ps->IsScrollPositionClampingScrollPortSizeSet()) { + rect.SizeTo(ps->GetScrollPositionClampingScrollPortSize()); + } + + // Make sure content document fixed-position margins are respected. + rect.Deflate(ps->GetContentDocumentFixedPositionMargins()); + return rect; +} + +NS_IMETHODIMP +ViewportFrame::Reflow(nsPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + DO_GLOBAL_REFLOW_COUNT("ViewportFrame"); + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); + NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow"); + + // Initialize OUT parameters + aStatus = NS_FRAME_COMPLETE; + + // Because |Reflow| sets mComputedHeight on the child to + // availableHeight. + AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); + + // Set our size up front, since some parts of reflow depend on it + // being already set. Note that the computed height may be + // unconstrained; that's ok. Consumers should watch out for that. + SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight())); + + // Reflow the main content first so that the placeholders of the + // fixed-position frames will be in the right places on an initial + // reflow. + nscoord kidHeight = 0; + + nsresult rv = NS_OK; + + if (mFrames.NotEmpty()) { + // Deal with a non-incremental reflow or an incremental reflow + // targeted at our one-and-only principal child frame. + if (aReflowState.ShouldReflowAllKids() || + aReflowState.mFlags.mVResize || + NS_SUBTREE_DIRTY(mFrames.FirstChild())) { + // Reflow our one-and-only principal child frame + nsIFrame* kidFrame = mFrames.FirstChild(); + nsHTMLReflowMetrics kidDesiredSize; + nsSize availableSpace(aReflowState.availableWidth, + aReflowState.availableHeight); + nsHTMLReflowState kidReflowState(aPresContext, aReflowState, + kidFrame, availableSpace); + + // Reflow the frame + kidReflowState.SetComputedHeight(aReflowState.ComputedHeight()); + rv = ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, + 0, 0, 0, aStatus); + kidHeight = kidDesiredSize.height; + + FinishReflowChild(kidFrame, aPresContext, nullptr, kidDesiredSize, 0, 0, 0); + } else { + kidHeight = mFrames.FirstChild()->GetSize().height; + } + } + + NS_ASSERTION(aReflowState.availableWidth != NS_UNCONSTRAINEDSIZE, + "shouldn't happen anymore"); + + // Return the max size as our desired size + aDesiredSize.width = aReflowState.availableWidth; + // Being flowed initially at an unconstrained height means we should + // return our child's intrinsic size. + aDesiredSize.height = aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE + ? aReflowState.ComputedHeight() + : kidHeight; + aDesiredSize.SetOverflowAreasToDesiredBounds(); + + if (mFrames.NotEmpty()) { + ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild()); + } + + if (IsAbsoluteContainer()) { + // Make a copy of the reflow state and change the computed width and height + // to reflect the available space for the fixed items + nsHTMLReflowState reflowState(aReflowState); + + if (reflowState.availableHeight == NS_UNCONSTRAINEDSIZE) { + // We have an intrinsic-height document with abs-pos/fixed-pos children. + // Set the available height and mComputedHeight to our chosen height. + reflowState.availableHeight = aDesiredSize.height; + // Not having border/padding simplifies things + NS_ASSERTION(reflowState.mComputedBorderPadding == nsMargin(0,0,0,0), + "Viewports can't have border/padding"); + reflowState.SetComputedHeight(aDesiredSize.height); + } + + nsRect rect = AdjustReflowStateAsContainingBlock(&reflowState); + + // Just reflow all the fixed-pos frames. + rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus, + rect, + false, true, true, // XXX could be optimized + &aDesiredSize.mOverflowAreas); + } + + // If we were dirty then do a repaint + if (GetStateBits() & NS_FRAME_IS_DIRTY) { + InvalidateFrame(); + } + + // Clipping is handled by the document container (e.g., nsSubDocumentFrame), + // so we don't need to change our overflow areas. + bool overflowChanged = FinishAndStoreOverflow(&aDesiredSize); + if (overflowChanged) { + // We may need to alert our container to get it to pick up the + // overflow change. + nsSubDocumentFrame* container = static_cast<nsSubDocumentFrame*> + (nsLayoutUtils::GetCrossDocParentFrame(this)); + if (container && !container->ShouldClipSubdocument()) { + container->PresContext()->PresShell()-> + FrameNeedsReflow(container, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); + } + } + + NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus); + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); + return rv; +} + +nsIAtom* +ViewportFrame::GetType() const +{ + return nsGkAtoms::viewportFrame; +} + +#ifdef DEBUG +NS_IMETHODIMP +ViewportFrame::GetFrameName(nsAString& aResult) const +{ + return MakeFrameName(NS_LITERAL_STRING("Viewport"), aResult); +} +#endif |