layout/generic/nsViewportFrame.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 * rendering object that is the root of the frame tree, which contains
michael@0 8 * the document's scrollbars and contains fixed-positioned elements
michael@0 9 */
michael@0 10
michael@0 11 #include "nsViewportFrame.h"
michael@0 12 #include "nsGkAtoms.h"
michael@0 13 #include "nsIScrollableFrame.h"
michael@0 14 #include "nsSubDocumentFrame.h"
michael@0 15 #include "nsAbsoluteContainingBlock.h"
michael@0 16 #include "GeckoProfiler.h"
michael@0 17
michael@0 18 using namespace mozilla;
michael@0 19
michael@0 20 nsIFrame*
michael@0 21 NS_NewViewportFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 22 {
michael@0 23 return new (aPresShell) ViewportFrame(aContext);
michael@0 24 }
michael@0 25
michael@0 26 NS_IMPL_FRAMEARENA_HELPERS(ViewportFrame)
michael@0 27 NS_QUERYFRAME_HEAD(ViewportFrame)
michael@0 28 NS_QUERYFRAME_ENTRY(ViewportFrame)
michael@0 29 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
michael@0 30
michael@0 31 void
michael@0 32 ViewportFrame::Init(nsIContent* aContent,
michael@0 33 nsIFrame* aParent,
michael@0 34 nsIFrame* aPrevInFlow)
michael@0 35 {
michael@0 36 Super::Init(aContent, aParent, aPrevInFlow);
michael@0 37
michael@0 38 nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this);
michael@0 39 if (parent) {
michael@0 40 nsFrameState state = parent->GetStateBits();
michael@0 41
michael@0 42 mState |= state & (NS_FRAME_IN_POPUP);
michael@0 43 }
michael@0 44 }
michael@0 45
michael@0 46 nsresult
michael@0 47 ViewportFrame::SetInitialChildList(ChildListID aListID,
michael@0 48 nsFrameList& aChildList)
michael@0 49 {
michael@0 50 // See which child list to add the frames to
michael@0 51 #ifdef DEBUG
michael@0 52 nsFrame::VerifyDirtyBitSet(aChildList);
michael@0 53 #endif
michael@0 54 return nsContainerFrame::SetInitialChildList(aListID, aChildList);
michael@0 55 }
michael@0 56
michael@0 57 void
michael@0 58 ViewportFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
michael@0 59 const nsRect& aDirtyRect,
michael@0 60 const nsDisplayListSet& aLists)
michael@0 61 {
michael@0 62 PROFILER_LABEL("ViewportFrame", "BuildDisplayList");
michael@0 63 nsIFrame* kid = mFrames.FirstChild();
michael@0 64 if (!kid)
michael@0 65 return;
michael@0 66
michael@0 67 // make the kid's BorderBackground our own. This ensures that the canvas
michael@0 68 // frame's background becomes our own background and therefore appears
michael@0 69 // below negative z-index elements.
michael@0 70 BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
michael@0 71 }
michael@0 72
michael@0 73 nsresult
michael@0 74 ViewportFrame::AppendFrames(ChildListID aListID,
michael@0 75 nsFrameList& aFrameList)
michael@0 76 {
michael@0 77 NS_ASSERTION(aListID == kPrincipalList ||
michael@0 78 aListID == GetAbsoluteListID(), "unexpected child list");
michael@0 79 NS_ASSERTION(aListID != GetAbsoluteListID() ||
michael@0 80 GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
michael@0 81 return nsContainerFrame::AppendFrames(aListID, aFrameList);
michael@0 82 }
michael@0 83
michael@0 84 nsresult
michael@0 85 ViewportFrame::InsertFrames(ChildListID aListID,
michael@0 86 nsIFrame* aPrevFrame,
michael@0 87 nsFrameList& aFrameList)
michael@0 88 {
michael@0 89 NS_ASSERTION(aListID == kPrincipalList ||
michael@0 90 aListID == GetAbsoluteListID(), "unexpected child list");
michael@0 91 NS_ASSERTION(aListID != GetAbsoluteListID() ||
michael@0 92 GetChildList(aListID).IsEmpty(), "Shouldn't have any kids!");
michael@0 93 return nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
michael@0 94 }
michael@0 95
michael@0 96 nsresult
michael@0 97 ViewportFrame::RemoveFrame(ChildListID aListID,
michael@0 98 nsIFrame* aOldFrame)
michael@0 99 {
michael@0 100 NS_ASSERTION(aListID == kPrincipalList ||
michael@0 101 aListID == GetAbsoluteListID(), "unexpected child list");
michael@0 102 return nsContainerFrame::RemoveFrame(aListID, aOldFrame);
michael@0 103 }
michael@0 104
michael@0 105 /* virtual */ nscoord
michael@0 106 ViewportFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
michael@0 107 {
michael@0 108 nscoord result;
michael@0 109 DISPLAY_MIN_WIDTH(this, result);
michael@0 110 if (mFrames.IsEmpty())
michael@0 111 result = 0;
michael@0 112 else
michael@0 113 result = mFrames.FirstChild()->GetMinWidth(aRenderingContext);
michael@0 114
michael@0 115 return result;
michael@0 116 }
michael@0 117
michael@0 118 /* virtual */ nscoord
michael@0 119 ViewportFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
michael@0 120 {
michael@0 121 nscoord result;
michael@0 122 DISPLAY_PREF_WIDTH(this, result);
michael@0 123 if (mFrames.IsEmpty())
michael@0 124 result = 0;
michael@0 125 else
michael@0 126 result = mFrames.FirstChild()->GetPrefWidth(aRenderingContext);
michael@0 127
michael@0 128 return result;
michael@0 129 }
michael@0 130
michael@0 131 nsPoint
michael@0 132 ViewportFrame::AdjustReflowStateForScrollbars(nsHTMLReflowState* aReflowState) const
michael@0 133 {
michael@0 134 // Get our prinicpal child frame and see if we're scrollable
michael@0 135 nsIFrame* kidFrame = mFrames.FirstChild();
michael@0 136 nsIScrollableFrame* scrollingFrame = do_QueryFrame(kidFrame);
michael@0 137
michael@0 138 if (scrollingFrame) {
michael@0 139 nsMargin scrollbars = scrollingFrame->GetActualScrollbarSizes();
michael@0 140 aReflowState->SetComputedWidth(aReflowState->ComputedWidth() -
michael@0 141 scrollbars.LeftRight());
michael@0 142 aReflowState->AvailableWidth() -= scrollbars.LeftRight();
michael@0 143 aReflowState->SetComputedHeightWithoutResettingResizeFlags(
michael@0 144 aReflowState->ComputedHeight() - scrollbars.TopBottom());
michael@0 145 return nsPoint(scrollbars.left, scrollbars.top);
michael@0 146 }
michael@0 147 return nsPoint(0, 0);
michael@0 148 }
michael@0 149
michael@0 150 nsRect
michael@0 151 ViewportFrame::AdjustReflowStateAsContainingBlock(nsHTMLReflowState* aReflowState) const
michael@0 152 {
michael@0 153 #ifdef DEBUG
michael@0 154 nsPoint offset =
michael@0 155 #endif
michael@0 156 AdjustReflowStateForScrollbars(aReflowState);
michael@0 157
michael@0 158 NS_ASSERTION(GetAbsoluteContainingBlock()->GetChildList().IsEmpty() ||
michael@0 159 (offset.x == 0 && offset.y == 0),
michael@0 160 "We don't handle correct positioning of fixed frames with "
michael@0 161 "scrollbars in odd positions");
michael@0 162
michael@0 163 // If a scroll position clamping scroll-port size has been set, layout
michael@0 164 // fixed position elements to this size instead of the computed size.
michael@0 165 nsRect rect(0, 0, aReflowState->ComputedWidth(), aReflowState->ComputedHeight());
michael@0 166 nsIPresShell* ps = PresContext()->PresShell();
michael@0 167 if (ps->IsScrollPositionClampingScrollPortSizeSet()) {
michael@0 168 rect.SizeTo(ps->GetScrollPositionClampingScrollPortSize());
michael@0 169 }
michael@0 170
michael@0 171 // Make sure content document fixed-position margins are respected.
michael@0 172 rect.Deflate(ps->GetContentDocumentFixedPositionMargins());
michael@0 173 return rect;
michael@0 174 }
michael@0 175
michael@0 176 nsresult
michael@0 177 ViewportFrame::Reflow(nsPresContext* aPresContext,
michael@0 178 nsHTMLReflowMetrics& aDesiredSize,
michael@0 179 const nsHTMLReflowState& aReflowState,
michael@0 180 nsReflowStatus& aStatus)
michael@0 181 {
michael@0 182 DO_GLOBAL_REFLOW_COUNT("ViewportFrame");
michael@0 183 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
michael@0 184 NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow");
michael@0 185
michael@0 186 // Initialize OUT parameters
michael@0 187 aStatus = NS_FRAME_COMPLETE;
michael@0 188
michael@0 189 // Because |Reflow| sets mComputedHeight on the child to
michael@0 190 // availableHeight.
michael@0 191 AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
michael@0 192
michael@0 193 // Set our size up front, since some parts of reflow depend on it
michael@0 194 // being already set. Note that the computed height may be
michael@0 195 // unconstrained; that's ok. Consumers should watch out for that.
michael@0 196 SetSize(nsSize(aReflowState.ComputedWidth(), aReflowState.ComputedHeight()));
michael@0 197
michael@0 198 // Reflow the main content first so that the placeholders of the
michael@0 199 // fixed-position frames will be in the right places on an initial
michael@0 200 // reflow.
michael@0 201 nscoord kidHeight = 0;
michael@0 202
michael@0 203 nsresult rv = NS_OK;
michael@0 204
michael@0 205 if (mFrames.NotEmpty()) {
michael@0 206 // Deal with a non-incremental reflow or an incremental reflow
michael@0 207 // targeted at our one-and-only principal child frame.
michael@0 208 if (aReflowState.ShouldReflowAllKids() ||
michael@0 209 aReflowState.mFlags.mVResize ||
michael@0 210 NS_SUBTREE_DIRTY(mFrames.FirstChild())) {
michael@0 211 // Reflow our one-and-only principal child frame
michael@0 212 nsIFrame* kidFrame = mFrames.FirstChild();
michael@0 213 nsHTMLReflowMetrics kidDesiredSize(aReflowState);
michael@0 214 nsSize availableSpace(aReflowState.AvailableWidth(),
michael@0 215 aReflowState.AvailableHeight());
michael@0 216 nsHTMLReflowState kidReflowState(aPresContext, aReflowState,
michael@0 217 kidFrame, availableSpace);
michael@0 218
michael@0 219 // Reflow the frame
michael@0 220 kidReflowState.SetComputedHeight(aReflowState.ComputedHeight());
michael@0 221 rv = ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
michael@0 222 0, 0, 0, aStatus);
michael@0 223 kidHeight = kidDesiredSize.Height();
michael@0 224
michael@0 225 FinishReflowChild(kidFrame, aPresContext, kidDesiredSize, nullptr, 0, 0, 0);
michael@0 226 } else {
michael@0 227 kidHeight = mFrames.FirstChild()->GetSize().height;
michael@0 228 }
michael@0 229 }
michael@0 230
michael@0 231 NS_ASSERTION(aReflowState.AvailableWidth() != NS_UNCONSTRAINEDSIZE,
michael@0 232 "shouldn't happen anymore");
michael@0 233
michael@0 234 // Return the max size as our desired size
michael@0 235 aDesiredSize.Width() = aReflowState.AvailableWidth();
michael@0 236 // Being flowed initially at an unconstrained height means we should
michael@0 237 // return our child's intrinsic size.
michael@0 238 aDesiredSize.Height() = aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE
michael@0 239 ? aReflowState.ComputedHeight()
michael@0 240 : kidHeight;
michael@0 241 aDesiredSize.SetOverflowAreasToDesiredBounds();
michael@0 242
michael@0 243 if (mFrames.NotEmpty()) {
michael@0 244 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mFrames.FirstChild());
michael@0 245 }
michael@0 246
michael@0 247 if (IsAbsoluteContainer()) {
michael@0 248 // Make a copy of the reflow state and change the computed width and height
michael@0 249 // to reflect the available space for the fixed items
michael@0 250 nsHTMLReflowState reflowState(aReflowState);
michael@0 251
michael@0 252 if (reflowState.AvailableHeight() == NS_UNCONSTRAINEDSIZE) {
michael@0 253 // We have an intrinsic-height document with abs-pos/fixed-pos children.
michael@0 254 // Set the available height and mComputedHeight to our chosen height.
michael@0 255 reflowState.AvailableHeight() = aDesiredSize.Height();
michael@0 256 // Not having border/padding simplifies things
michael@0 257 NS_ASSERTION(reflowState.ComputedPhysicalBorderPadding() == nsMargin(0,0,0,0),
michael@0 258 "Viewports can't have border/padding");
michael@0 259 reflowState.SetComputedHeight(aDesiredSize.Height());
michael@0 260 }
michael@0 261
michael@0 262 nsRect rect = AdjustReflowStateAsContainingBlock(&reflowState);
michael@0 263
michael@0 264 // Just reflow all the fixed-pos frames.
michael@0 265 rv = GetAbsoluteContainingBlock()->Reflow(this, aPresContext, reflowState, aStatus,
michael@0 266 rect,
michael@0 267 false, true, true, // XXX could be optimized
michael@0 268 &aDesiredSize.mOverflowAreas);
michael@0 269 }
michael@0 270
michael@0 271 // If we were dirty then do a repaint
michael@0 272 if (GetStateBits() & NS_FRAME_IS_DIRTY) {
michael@0 273 InvalidateFrame();
michael@0 274 }
michael@0 275
michael@0 276 // Clipping is handled by the document container (e.g., nsSubDocumentFrame),
michael@0 277 // so we don't need to change our overflow areas.
michael@0 278 bool overflowChanged = FinishAndStoreOverflow(&aDesiredSize);
michael@0 279 if (overflowChanged) {
michael@0 280 // We may need to alert our container to get it to pick up the
michael@0 281 // overflow change.
michael@0 282 nsSubDocumentFrame* container = static_cast<nsSubDocumentFrame*>
michael@0 283 (nsLayoutUtils::GetCrossDocParentFrame(this));
michael@0 284 if (container && !container->ShouldClipSubdocument()) {
michael@0 285 container->PresContext()->PresShell()->
michael@0 286 FrameNeedsReflow(container, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
michael@0 287 }
michael@0 288 }
michael@0 289
michael@0 290 NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus);
michael@0 291 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
michael@0 292 return rv;
michael@0 293 }
michael@0 294
michael@0 295 nsIAtom*
michael@0 296 ViewportFrame::GetType() const
michael@0 297 {
michael@0 298 return nsGkAtoms::viewportFrame;
michael@0 299 }
michael@0 300
michael@0 301 #ifdef DEBUG_FRAME_DUMP
michael@0 302 nsresult
michael@0 303 ViewportFrame::GetFrameName(nsAString& aResult) const
michael@0 304 {
michael@0 305 return MakeFrameName(NS_LITERAL_STRING("Viewport"), aResult);
michael@0 306 }
michael@0 307 #endif

mercurial