1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsLeafBoxFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,381 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +// 1.10 +// Eric Vaughan 1.11 +// Netscape Communications 1.12 +// 1.13 +// See documentation in associated header file 1.14 +// 1.15 + 1.16 +#include "nsLeafBoxFrame.h" 1.17 +#include "nsBoxFrame.h" 1.18 +#include "nsCOMPtr.h" 1.19 +#include "nsGkAtoms.h" 1.20 +#include "nsPresContext.h" 1.21 +#include "nsStyleContext.h" 1.22 +#include "nsIContent.h" 1.23 +#include "nsNameSpaceManager.h" 1.24 +#include "nsBoxLayoutState.h" 1.25 +#include "nsWidgetsCID.h" 1.26 +#include "nsViewManager.h" 1.27 +#include "nsContainerFrame.h" 1.28 +#include "nsDisplayList.h" 1.29 +#include <algorithm> 1.30 + 1.31 +// 1.32 +// NS_NewLeafBoxFrame 1.33 +// 1.34 +// Creates a new Toolbar frame and returns it 1.35 +// 1.36 +nsIFrame* 1.37 +NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) 1.38 +{ 1.39 + return new (aPresShell) nsLeafBoxFrame(aPresShell, aContext); 1.40 +} 1.41 + 1.42 +NS_IMPL_FRAMEARENA_HELPERS(nsLeafBoxFrame) 1.43 + 1.44 +nsLeafBoxFrame::nsLeafBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext) 1.45 + : nsLeafFrame(aContext) 1.46 +{ 1.47 +} 1.48 + 1.49 +#ifdef DEBUG_LAYOUT 1.50 +void 1.51 +nsLeafBoxFrame::GetBoxName(nsAutoString& aName) 1.52 +{ 1.53 + GetFrameName(aName); 1.54 +} 1.55 +#endif 1.56 + 1.57 + 1.58 +/** 1.59 + * Initialize us. This is a good time to get the alignment of the box 1.60 + */ 1.61 +void 1.62 +nsLeafBoxFrame::Init( 1.63 + nsIContent* aContent, 1.64 + nsIFrame* aParent, 1.65 + nsIFrame* aPrevInFlow) 1.66 +{ 1.67 + nsLeafFrame::Init(aContent, aParent, aPrevInFlow); 1.68 + 1.69 + if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) { 1.70 + AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); 1.71 + } 1.72 + 1.73 + UpdateMouseThrough(); 1.74 +} 1.75 + 1.76 +nsresult 1.77 +nsLeafBoxFrame::AttributeChanged(int32_t aNameSpaceID, 1.78 + nsIAtom* aAttribute, 1.79 + int32_t aModType) 1.80 +{ 1.81 + nsresult rv = nsLeafFrame::AttributeChanged(aNameSpaceID, aAttribute, 1.82 + aModType); 1.83 + 1.84 + if (aAttribute == nsGkAtoms::mousethrough) 1.85 + UpdateMouseThrough(); 1.86 + 1.87 + return rv; 1.88 +} 1.89 + 1.90 +void nsLeafBoxFrame::UpdateMouseThrough() 1.91 +{ 1.92 + if (mContent) { 1.93 + static nsIContent::AttrValuesArray strings[] = 1.94 + {&nsGkAtoms::never, &nsGkAtoms::always, nullptr}; 1.95 + switch (mContent->FindAttrValueIn(kNameSpaceID_None, 1.96 + nsGkAtoms::mousethrough, 1.97 + strings, eCaseMatters)) { 1.98 + case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break; 1.99 + case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break; 1.100 + case 2: { 1.101 + RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); 1.102 + RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); 1.103 + break; 1.104 + } 1.105 + } 1.106 + } 1.107 +} 1.108 + 1.109 +void 1.110 +nsLeafBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.111 + const nsRect& aDirtyRect, 1.112 + const nsDisplayListSet& aLists) 1.113 +{ 1.114 + // REVIEW: GetFrameForPoint used to not report events for the background 1.115 + // layer, whereas this code will put an event receiver for this frame in the 1.116 + // BlockBorderBackground() list. But I don't see any need to preserve 1.117 + // that anomalous behaviour. The important thing I'm preserving is that 1.118 + // leaf boxes continue to receive events in the foreground layer. 1.119 + DisplayBorderBackgroundOutline(aBuilder, aLists); 1.120 + 1.121 + if (!aBuilder->IsForEventDelivery() || !IsVisibleForPainting(aBuilder)) 1.122 + return; 1.123 + 1.124 + aLists.Content()->AppendNewToTop(new (aBuilder) 1.125 + nsDisplayEventReceiver(aBuilder, this)); 1.126 +} 1.127 + 1.128 +/* virtual */ nscoord 1.129 +nsLeafBoxFrame::GetMinWidth(nsRenderingContext *aRenderingContext) 1.130 +{ 1.131 + nscoord result; 1.132 + DISPLAY_MIN_WIDTH(this, result); 1.133 + nsBoxLayoutState state(PresContext(), aRenderingContext); 1.134 + nsSize minSize = GetMinSize(state); 1.135 + 1.136 + // GetMinSize returns border-box width, and we want to return content 1.137 + // width. Since Reflow uses the reflow state's border and padding, we 1.138 + // actually just want to subtract what GetMinSize added, which is the 1.139 + // result of GetBorderAndPadding. 1.140 + nsMargin bp; 1.141 + GetBorderAndPadding(bp); 1.142 + 1.143 + result = minSize.width - bp.LeftRight(); 1.144 + 1.145 + return result; 1.146 +} 1.147 + 1.148 +/* virtual */ nscoord 1.149 +nsLeafBoxFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) 1.150 +{ 1.151 + nscoord result; 1.152 + DISPLAY_PREF_WIDTH(this, result); 1.153 + nsBoxLayoutState state(PresContext(), aRenderingContext); 1.154 + nsSize prefSize = GetPrefSize(state); 1.155 + 1.156 + // GetPrefSize returns border-box width, and we want to return content 1.157 + // width. Since Reflow uses the reflow state's border and padding, we 1.158 + // actually just want to subtract what GetPrefSize added, which is the 1.159 + // result of GetBorderAndPadding. 1.160 + nsMargin bp; 1.161 + GetBorderAndPadding(bp); 1.162 + 1.163 + result = prefSize.width - bp.LeftRight(); 1.164 + 1.165 + return result; 1.166 +} 1.167 + 1.168 +nscoord 1.169 +nsLeafBoxFrame::GetIntrinsicWidth() 1.170 +{ 1.171 + // No intrinsic width 1.172 + return 0; 1.173 +} 1.174 + 1.175 +nsSize 1.176 +nsLeafBoxFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext, 1.177 + nsSize aCBSize, nscoord aAvailableWidth, 1.178 + nsSize aMargin, nsSize aBorder, 1.179 + nsSize aPadding, bool aShrinkWrap) 1.180 +{ 1.181 + // Important: NOT calling our direct superclass here! 1.182 + return nsFrame::ComputeAutoSize(aRenderingContext, aCBSize, aAvailableWidth, 1.183 + aMargin, aBorder, aPadding, aShrinkWrap); 1.184 +} 1.185 + 1.186 +nsresult 1.187 +nsLeafBoxFrame::Reflow(nsPresContext* aPresContext, 1.188 + nsHTMLReflowMetrics& aDesiredSize, 1.189 + const nsHTMLReflowState& aReflowState, 1.190 + nsReflowStatus& aStatus) 1.191 +{ 1.192 + // This is mostly a copy of nsBoxFrame::Reflow(). 1.193 + // We aren't able to share an implementation because of the frame 1.194 + // class hierarchy. If you make changes here, please keep 1.195 + // nsBoxFrame::Reflow in sync. 1.196 + 1.197 + DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame"); 1.198 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.199 + 1.200 + NS_ASSERTION(aReflowState.ComputedWidth() >=0 && 1.201 + aReflowState.ComputedHeight() >= 0, "Computed Size < 0"); 1.202 + 1.203 +#ifdef DO_NOISY_REFLOW 1.204 + printf("\n-------------Starting LeafBoxFrame Reflow ----------------------------\n"); 1.205 + printf("%p ** nsLBF::Reflow %d R: ", this, myCounter++); 1.206 + switch (aReflowState.reason) { 1.207 + case eReflowReason_Initial: 1.208 + printf("Ini");break; 1.209 + case eReflowReason_Incremental: 1.210 + printf("Inc");break; 1.211 + case eReflowReason_Resize: 1.212 + printf("Rsz");break; 1.213 + case eReflowReason_StyleChange: 1.214 + printf("Sty");break; 1.215 + case eReflowReason_Dirty: 1.216 + printf("Drt "); 1.217 + break; 1.218 + default:printf("<unknown>%d", aReflowState.reason);break; 1.219 + } 1.220 + 1.221 + printSize("AW", aReflowState.AvailableWidth()); 1.222 + printSize("AH", aReflowState.AvailableHeight()); 1.223 + printSize("CW", aReflowState.ComputedWidth()); 1.224 + printSize("CH", aReflowState.ComputedHeight()); 1.225 + 1.226 + printf(" *\n"); 1.227 + 1.228 +#endif 1.229 + 1.230 + aStatus = NS_FRAME_COMPLETE; 1.231 + 1.232 + // create the layout state 1.233 + nsBoxLayoutState state(aPresContext, aReflowState.rendContext); 1.234 + 1.235 + nsSize computedSize(aReflowState.ComputedWidth(),aReflowState.ComputedHeight()); 1.236 + 1.237 + nsMargin m; 1.238 + m = aReflowState.ComputedPhysicalBorderPadding(); 1.239 + 1.240 + //GetBorderAndPadding(m); 1.241 + 1.242 + // this happens sometimes. So lets handle it gracefully. 1.243 + if (aReflowState.ComputedHeight() == 0) { 1.244 + nsSize minSize = GetMinSize(state); 1.245 + computedSize.height = minSize.height - m.top - m.bottom; 1.246 + } 1.247 + 1.248 + nsSize prefSize(0,0); 1.249 + 1.250 + // if we are told to layout intrinic then get our preferred size. 1.251 + if (computedSize.width == NS_INTRINSICSIZE || computedSize.height == NS_INTRINSICSIZE) { 1.252 + prefSize = GetPrefSize(state); 1.253 + nsSize minSize = GetMinSize(state); 1.254 + nsSize maxSize = GetMaxSize(state); 1.255 + prefSize = BoundsCheck(minSize, prefSize, maxSize); 1.256 + } 1.257 + 1.258 + // get our desiredSize 1.259 + if (aReflowState.ComputedWidth() == NS_INTRINSICSIZE) { 1.260 + computedSize.width = prefSize.width; 1.261 + } else { 1.262 + computedSize.width += m.left + m.right; 1.263 + } 1.264 + 1.265 + if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) { 1.266 + computedSize.height = prefSize.height; 1.267 + } else { 1.268 + computedSize.height += m.top + m.bottom; 1.269 + } 1.270 + 1.271 + // handle reflow state min and max sizes 1.272 + // XXXbz the width handling here seems to be wrong, since 1.273 + // mComputedMin/MaxWidth is a content-box size, whole 1.274 + // computedSize.width is a border-box size... 1.275 + if (computedSize.width > aReflowState.ComputedMaxWidth()) 1.276 + computedSize.width = aReflowState.ComputedMaxWidth(); 1.277 + 1.278 + if (computedSize.width < aReflowState.ComputedMinWidth()) 1.279 + computedSize.width = aReflowState.ComputedMinWidth(); 1.280 + 1.281 + // Now adjust computedSize.height for our min and max computed 1.282 + // height. The only problem is that those are content-box sizes, 1.283 + // while computedSize.height is a border-box size. So subtract off 1.284 + // m.TopBottom() before adjusting, then readd it. 1.285 + computedSize.height = std::max(0, computedSize.height - m.TopBottom()); 1.286 + computedSize.height = NS_CSS_MINMAX(computedSize.height, 1.287 + aReflowState.ComputedMinHeight(), 1.288 + aReflowState.ComputedMaxHeight()); 1.289 + computedSize.height += m.TopBottom(); 1.290 + 1.291 + nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height); 1.292 + 1.293 + SetBounds(state, r); 1.294 + 1.295 + // layout our children 1.296 + Layout(state); 1.297 + 1.298 + // ok our child could have gotten bigger. So lets get its bounds 1.299 + aDesiredSize.Width() = mRect.width; 1.300 + aDesiredSize.Height() = mRect.height; 1.301 + aDesiredSize.SetTopAscent(GetBoxAscent(state)); 1.302 + 1.303 + // the overflow rect is set in SetBounds() above 1.304 + aDesiredSize.mOverflowAreas = GetOverflowAreas(); 1.305 + 1.306 +#ifdef DO_NOISY_REFLOW 1.307 + { 1.308 + printf("%p ** nsLBF(done) W:%d H:%d ", this, aDesiredSize.Width(), aDesiredSize.Height()); 1.309 + 1.310 + if (maxElementWidth) { 1.311 + printf("MW:%d\n", *maxElementWidth); 1.312 + } else { 1.313 + printf("MW:?\n"); 1.314 + } 1.315 + 1.316 + } 1.317 +#endif 1.318 + 1.319 + return NS_OK; 1.320 +} 1.321 + 1.322 +#ifdef DEBUG_FRAME_DUMP 1.323 +nsresult 1.324 +nsLeafBoxFrame::GetFrameName(nsAString& aResult) const 1.325 +{ 1.326 + return MakeFrameName(NS_LITERAL_STRING("LeafBox"), aResult); 1.327 +} 1.328 +#endif 1.329 + 1.330 +nsIAtom* 1.331 +nsLeafBoxFrame::GetType() const 1.332 +{ 1.333 + return nsGkAtoms::leafBoxFrame; 1.334 +} 1.335 + 1.336 +nsresult 1.337 +nsLeafBoxFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo) 1.338 +{ 1.339 + MarkIntrinsicWidthsDirty(); 1.340 + return nsLeafFrame::CharacterDataChanged(aInfo); 1.341 +} 1.342 + 1.343 +/* virtual */ nsSize 1.344 +nsLeafBoxFrame::GetPrefSize(nsBoxLayoutState& aState) 1.345 +{ 1.346 + return nsBox::GetPrefSize(aState); 1.347 +} 1.348 + 1.349 +/* virtual */ nsSize 1.350 +nsLeafBoxFrame::GetMinSize(nsBoxLayoutState& aState) 1.351 +{ 1.352 + return nsBox::GetMinSize(aState); 1.353 +} 1.354 + 1.355 +/* virtual */ nsSize 1.356 +nsLeafBoxFrame::GetMaxSize(nsBoxLayoutState& aState) 1.357 +{ 1.358 + return nsBox::GetMaxSize(aState); 1.359 +} 1.360 + 1.361 +/* virtual */ nscoord 1.362 +nsLeafBoxFrame::GetFlex(nsBoxLayoutState& aState) 1.363 +{ 1.364 + return nsBox::GetFlex(aState); 1.365 +} 1.366 + 1.367 +/* virtual */ nscoord 1.368 +nsLeafBoxFrame::GetBoxAscent(nsBoxLayoutState& aState) 1.369 +{ 1.370 + return nsBox::GetBoxAscent(aState); 1.371 +} 1.372 + 1.373 +/* virtual */ void 1.374 +nsLeafBoxFrame::MarkIntrinsicWidthsDirty() 1.375 +{ 1.376 + // Don't call base class method, since everything it does is within an 1.377 + // IsBoxWrapped check. 1.378 +} 1.379 + 1.380 +NS_IMETHODIMP 1.381 +nsLeafBoxFrame::DoLayout(nsBoxLayoutState& aState) 1.382 +{ 1.383 + return nsBox::DoLayout(aState); 1.384 +}