1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsBox.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,972 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; 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 +#include "nsBoxLayoutState.h" 1.10 +#include "nsBox.h" 1.11 +#include "nsBoxFrame.h" 1.12 +#include "nsPresContext.h" 1.13 +#include "nsCOMPtr.h" 1.14 +#include "nsIContent.h" 1.15 +#include "nsContainerFrame.h" 1.16 +#include "nsNameSpaceManager.h" 1.17 +#include "nsGkAtoms.h" 1.18 +#include "nsFrameManager.h" 1.19 +#include "nsIDOMNode.h" 1.20 +#include "nsIDOMMozNamedAttrMap.h" 1.21 +#include "nsIDOMAttr.h" 1.22 +#include "nsITheme.h" 1.23 +#include "nsIServiceManager.h" 1.24 +#include "nsBoxLayout.h" 1.25 +#include "FrameLayerBuilder.h" 1.26 +#include <algorithm> 1.27 + 1.28 +using namespace mozilla; 1.29 + 1.30 +#ifdef DEBUG_LAYOUT 1.31 +int32_t gIndent = 0; 1.32 +#endif 1.33 + 1.34 +#ifdef DEBUG_LAYOUT 1.35 +void 1.36 +nsBoxAddIndents() 1.37 +{ 1.38 + for(int32_t i=0; i < gIndent; i++) 1.39 + { 1.40 + printf(" "); 1.41 + } 1.42 +} 1.43 +#endif 1.44 + 1.45 +#ifdef DEBUG_LAYOUT 1.46 +void 1.47 +nsBox::AppendAttribute(const nsAutoString& aAttribute, const nsAutoString& aValue, nsAutoString& aResult) 1.48 +{ 1.49 + aResult.Append(aAttribute); 1.50 + aResult.AppendLiteral("='"); 1.51 + aResult.Append(aValue); 1.52 + aResult.AppendLiteral("' "); 1.53 +} 1.54 + 1.55 +void 1.56 +nsBox::ListBox(nsAutoString& aResult) 1.57 +{ 1.58 + nsAutoString name; 1.59 + GetBoxName(name); 1.60 + 1.61 + char addr[100]; 1.62 + sprintf(addr, "[@%p] ", static_cast<void*>(this)); 1.63 + 1.64 + aResult.AppendASCII(addr); 1.65 + aResult.Append(name); 1.66 + aResult.AppendLiteral(" "); 1.67 + 1.68 + nsIContent* content = GetContent(); 1.69 + 1.70 + // add on all the set attributes 1.71 + if (content) { 1.72 + nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content)); 1.73 + nsCOMPtr<nsIDOMMozNamedAttrMap> namedMap; 1.74 + 1.75 + node->GetAttributes(getter_AddRefs(namedMap)); 1.76 + uint32_t length; 1.77 + namedMap->GetLength(&length); 1.78 + 1.79 + nsCOMPtr<nsIDOMAttr> attribute; 1.80 + for (uint32_t i = 0; i < length; ++i) 1.81 + { 1.82 + namedMap->Item(i, getter_AddRefs(attribute)); 1.83 + attribute->GetName(name); 1.84 + nsAutoString value; 1.85 + attribute->GetValue(value); 1.86 + AppendAttribute(name, value, aResult); 1.87 + } 1.88 + } 1.89 +} 1.90 + 1.91 +nsresult 1.92 +nsBox::DumpBox(FILE* aFile) 1.93 +{ 1.94 + nsAutoString s; 1.95 + ListBox(s); 1.96 + fprintf(aFile, "%s", NS_LossyConvertUTF16toASCII(s).get()); 1.97 + return NS_OK; 1.98 +} 1.99 + 1.100 +void 1.101 +nsBox::PropagateDebug(nsBoxLayoutState& aState) 1.102 +{ 1.103 + // propagate debug information 1.104 + if (mState & NS_STATE_DEBUG_WAS_SET) { 1.105 + if (mState & NS_STATE_SET_TO_DEBUG) 1.106 + SetDebug(aState, true); 1.107 + else 1.108 + SetDebug(aState, false); 1.109 + } else if (mState & NS_STATE_IS_ROOT) { 1.110 + SetDebug(aState, gDebug); 1.111 + } 1.112 +} 1.113 +#endif 1.114 + 1.115 +#ifdef DEBUG_LAYOUT 1.116 +void 1.117 +nsBox::GetBoxName(nsAutoString& aName) 1.118 +{ 1.119 + aName.AssignLiteral("Box"); 1.120 +} 1.121 +#endif 1.122 + 1.123 +nsresult 1.124 +nsBox::BeginLayout(nsBoxLayoutState& aState) 1.125 +{ 1.126 +#ifdef DEBUG_LAYOUT 1.127 + 1.128 + nsBoxAddIndents(); 1.129 + printf("Layout: "); 1.130 + DumpBox(stdout); 1.131 + printf("\n"); 1.132 + gIndent++; 1.133 +#endif 1.134 + 1.135 + // mark ourselves as dirty so no child under us 1.136 + // can post an incremental layout. 1.137 + // XXXldb Is this still needed? 1.138 + mState |= NS_FRAME_HAS_DIRTY_CHILDREN; 1.139 + 1.140 + if (GetStateBits() & NS_FRAME_IS_DIRTY) 1.141 + { 1.142 + // If the parent is dirty, all the children are dirty (nsHTMLReflowState 1.143 + // does this too). 1.144 + nsIFrame* box; 1.145 + for (box = GetChildBox(); box; box = box->GetNextBox()) 1.146 + box->AddStateBits(NS_FRAME_IS_DIRTY); 1.147 + } 1.148 + 1.149 + // Another copy-over from nsHTMLReflowState. 1.150 + // Since we are in reflow, we don't need to store these properties anymore. 1.151 + FrameProperties props = Properties(); 1.152 + props.Delete(UsedBorderProperty()); 1.153 + props.Delete(UsedPaddingProperty()); 1.154 + props.Delete(UsedMarginProperty()); 1.155 + 1.156 +#ifdef DEBUG_LAYOUT 1.157 + PropagateDebug(aState); 1.158 +#endif 1.159 + 1.160 + return NS_OK; 1.161 +} 1.162 + 1.163 +NS_IMETHODIMP 1.164 +nsBox::DoLayout(nsBoxLayoutState& aState) 1.165 +{ 1.166 + return NS_OK; 1.167 +} 1.168 + 1.169 +nsresult 1.170 +nsBox::EndLayout(nsBoxLayoutState& aState) 1.171 +{ 1.172 + 1.173 + #ifdef DEBUG_LAYOUT 1.174 + --gIndent; 1.175 + #endif 1.176 + 1.177 + return SyncLayout(aState); 1.178 +} 1.179 + 1.180 +bool nsBox::gGotTheme = false; 1.181 +nsITheme* nsBox::gTheme = nullptr; 1.182 + 1.183 +nsBox::nsBox() 1.184 +{ 1.185 + MOZ_COUNT_CTOR(nsBox); 1.186 + //mX = 0; 1.187 + //mY = 0; 1.188 + if (!gGotTheme) { 1.189 + gGotTheme = true; 1.190 + CallGetService("@mozilla.org/chrome/chrome-native-theme;1", &gTheme); 1.191 + } 1.192 +} 1.193 + 1.194 +nsBox::~nsBox() 1.195 +{ 1.196 + // NOTE: This currently doesn't get called for |nsBoxToBlockAdaptor| 1.197 + // objects, so don't rely on putting anything here. 1.198 + MOZ_COUNT_DTOR(nsBox); 1.199 +} 1.200 + 1.201 +/* static */ void 1.202 +nsBox::Shutdown() 1.203 +{ 1.204 + gGotTheme = false; 1.205 + NS_IF_RELEASE(gTheme); 1.206 +} 1.207 + 1.208 +nsresult 1.209 +nsBox::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild) 1.210 +{ 1.211 + return NS_OK; 1.212 +} 1.213 + 1.214 +nsresult 1.215 +nsIFrame::GetClientRect(nsRect& aClientRect) 1.216 +{ 1.217 + aClientRect = mRect; 1.218 + aClientRect.MoveTo(0,0); 1.219 + 1.220 + nsMargin borderPadding; 1.221 + GetBorderAndPadding(borderPadding); 1.222 + 1.223 + aClientRect.Deflate(borderPadding); 1.224 + 1.225 + if (aClientRect.width < 0) 1.226 + aClientRect.width = 0; 1.227 + 1.228 + if (aClientRect.height < 0) 1.229 + aClientRect.height = 0; 1.230 + 1.231 + // NS_ASSERTION(aClientRect.width >=0 && aClientRect.height >= 0, "Content Size < 0"); 1.232 + 1.233 + return NS_OK; 1.234 +} 1.235 + 1.236 +void 1.237 +nsBox::SetBounds(nsBoxLayoutState& aState, const nsRect& aRect, bool aRemoveOverflowAreas) 1.238 +{ 1.239 + NS_BOX_ASSERTION(this, aRect.width >=0 && aRect.height >= 0, "SetBounds Size < 0"); 1.240 + 1.241 + nsRect rect(mRect); 1.242 + 1.243 + uint32_t flags = 0; 1.244 + GetLayoutFlags(flags); 1.245 + 1.246 + uint32_t stateFlags = aState.LayoutFlags(); 1.247 + 1.248 + flags |= stateFlags; 1.249 + 1.250 + if ((flags & NS_FRAME_NO_MOVE_FRAME) == NS_FRAME_NO_MOVE_FRAME) 1.251 + SetSize(aRect.Size()); 1.252 + else 1.253 + SetRect(aRect); 1.254 + 1.255 + // Nuke the overflow area. The caller is responsible for restoring 1.256 + // it if necessary. 1.257 + if (aRemoveOverflowAreas) { 1.258 + // remove the previously stored overflow area 1.259 + ClearOverflowRects(); 1.260 + } 1.261 + 1.262 + if (!(flags & NS_FRAME_NO_MOVE_VIEW)) 1.263 + { 1.264 + nsContainerFrame::PositionFrameView(this); 1.265 + if ((rect.x != aRect.x) || (rect.y != aRect.y)) 1.266 + nsContainerFrame::PositionChildViews(this); 1.267 + } 1.268 + 1.269 + 1.270 + /* 1.271 + // only if the origin changed 1.272 + if ((rect.x != aRect.x) || (rect.y != aRect.y)) { 1.273 + if (frame->HasView()) { 1.274 + nsContainerFrame::PositionFrameView(presContext, frame, 1.275 + frame->GetView()); 1.276 + } else { 1.277 + nsContainerFrame::PositionChildViews(presContext, frame); 1.278 + } 1.279 + } 1.280 + */ 1.281 +} 1.282 + 1.283 +void 1.284 +nsBox::GetLayoutFlags(uint32_t& aFlags) 1.285 +{ 1.286 + aFlags = 0; 1.287 +} 1.288 + 1.289 + 1.290 +nsresult 1.291 +nsIFrame::GetBorderAndPadding(nsMargin& aBorderAndPadding) 1.292 +{ 1.293 + aBorderAndPadding.SizeTo(0, 0, 0, 0); 1.294 + nsresult rv = GetBorder(aBorderAndPadding); 1.295 + if (NS_FAILED(rv)) 1.296 + return rv; 1.297 + 1.298 + nsMargin padding; 1.299 + rv = GetPadding(padding); 1.300 + if (NS_FAILED(rv)) 1.301 + return rv; 1.302 + 1.303 + aBorderAndPadding += padding; 1.304 + 1.305 + return rv; 1.306 +} 1.307 + 1.308 +nsresult 1.309 +nsBox::GetBorder(nsMargin& aMargin) 1.310 +{ 1.311 + aMargin.SizeTo(0,0,0,0); 1.312 + 1.313 + const nsStyleDisplay* disp = StyleDisplay(); 1.314 + if (disp->mAppearance && gTheme) { 1.315 + // Go to the theme for the border. 1.316 + nsPresContext *context = PresContext(); 1.317 + if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) { 1.318 + nsIntMargin margin(0, 0, 0, 0); 1.319 + gTheme->GetWidgetBorder(context->DeviceContext(), this, 1.320 + disp->mAppearance, &margin); 1.321 + aMargin.top = context->DevPixelsToAppUnits(margin.top); 1.322 + aMargin.right = context->DevPixelsToAppUnits(margin.right); 1.323 + aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom); 1.324 + aMargin.left = context->DevPixelsToAppUnits(margin.left); 1.325 + return NS_OK; 1.326 + } 1.327 + } 1.328 + 1.329 + aMargin = StyleBorder()->GetComputedBorder(); 1.330 + 1.331 + return NS_OK; 1.332 +} 1.333 + 1.334 +nsresult 1.335 +nsBox::GetPadding(nsMargin& aMargin) 1.336 +{ 1.337 + const nsStyleDisplay *disp = StyleDisplay(); 1.338 + if (disp->mAppearance && gTheme) { 1.339 + // Go to the theme for the padding. 1.340 + nsPresContext *context = PresContext(); 1.341 + if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) { 1.342 + nsIntMargin margin(0, 0, 0, 0); 1.343 + bool useThemePadding; 1.344 + 1.345 + useThemePadding = gTheme->GetWidgetPadding(context->DeviceContext(), 1.346 + this, disp->mAppearance, 1.347 + &margin); 1.348 + if (useThemePadding) { 1.349 + aMargin.top = context->DevPixelsToAppUnits(margin.top); 1.350 + aMargin.right = context->DevPixelsToAppUnits(margin.right); 1.351 + aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom); 1.352 + aMargin.left = context->DevPixelsToAppUnits(margin.left); 1.353 + return NS_OK; 1.354 + } 1.355 + } 1.356 + } 1.357 + 1.358 + aMargin.SizeTo(0,0,0,0); 1.359 + StylePadding()->GetPadding(aMargin); 1.360 + 1.361 + return NS_OK; 1.362 +} 1.363 + 1.364 +nsresult 1.365 +nsBox::GetMargin(nsMargin& aMargin) 1.366 +{ 1.367 + aMargin.SizeTo(0,0,0,0); 1.368 + StyleMargin()->GetMargin(aMargin); 1.369 + 1.370 + return NS_OK; 1.371 +} 1.372 + 1.373 +void 1.374 +nsBox::SizeNeedsRecalc(nsSize& aSize) 1.375 +{ 1.376 + aSize.width = -1; 1.377 + aSize.height = -1; 1.378 +} 1.379 + 1.380 +void 1.381 +nsBox::CoordNeedsRecalc(nscoord& aFlex) 1.382 +{ 1.383 + aFlex = -1; 1.384 +} 1.385 + 1.386 +bool 1.387 +nsBox::DoesNeedRecalc(const nsSize& aSize) 1.388 +{ 1.389 + return (aSize.width == -1 || aSize.height == -1); 1.390 +} 1.391 + 1.392 +bool 1.393 +nsBox::DoesNeedRecalc(nscoord aCoord) 1.394 +{ 1.395 + return (aCoord == -1); 1.396 +} 1.397 + 1.398 +nsSize 1.399 +nsBox::GetPrefSize(nsBoxLayoutState& aState) 1.400 +{ 1.401 + NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); 1.402 + 1.403 + nsSize pref(0,0); 1.404 + DISPLAY_PREF_SIZE(this, pref); 1.405 + 1.406 + if (IsCollapsed()) 1.407 + return pref; 1.408 + 1.409 + AddBorderAndPadding(pref); 1.410 + bool widthSet, heightSet; 1.411 + nsIFrame::AddCSSPrefSize(this, pref, widthSet, heightSet); 1.412 + 1.413 + nsSize minSize = GetMinSize(aState); 1.414 + nsSize maxSize = GetMaxSize(aState); 1.415 + return BoundsCheck(minSize, pref, maxSize); 1.416 +} 1.417 + 1.418 +nsSize 1.419 +nsBox::GetMinSize(nsBoxLayoutState& aState) 1.420 +{ 1.421 + NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); 1.422 + 1.423 + nsSize min(0,0); 1.424 + DISPLAY_MIN_SIZE(this, min); 1.425 + 1.426 + if (IsCollapsed()) 1.427 + return min; 1.428 + 1.429 + AddBorderAndPadding(min); 1.430 + bool widthSet, heightSet; 1.431 + nsIFrame::AddCSSMinSize(aState, this, min, widthSet, heightSet); 1.432 + return min; 1.433 +} 1.434 + 1.435 +nsSize 1.436 +nsBox::GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState) 1.437 +{ 1.438 + return nsSize(0, 0); 1.439 +} 1.440 + 1.441 +nsSize 1.442 +nsBox::GetMaxSize(nsBoxLayoutState& aState) 1.443 +{ 1.444 + NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); 1.445 + 1.446 + nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE); 1.447 + DISPLAY_MAX_SIZE(this, maxSize); 1.448 + 1.449 + if (IsCollapsed()) 1.450 + return maxSize; 1.451 + 1.452 + AddBorderAndPadding(maxSize); 1.453 + bool widthSet, heightSet; 1.454 + nsIFrame::AddCSSMaxSize(this, maxSize, widthSet, heightSet); 1.455 + return maxSize; 1.456 +} 1.457 + 1.458 +nscoord 1.459 +nsBox::GetFlex(nsBoxLayoutState& aState) 1.460 +{ 1.461 + nscoord flex = 0; 1.462 + 1.463 + nsIFrame::AddCSSFlex(aState, this, flex); 1.464 + 1.465 + return flex; 1.466 +} 1.467 + 1.468 +uint32_t 1.469 +nsIFrame::GetOrdinal() 1.470 +{ 1.471 + uint32_t ordinal = StyleXUL()->mBoxOrdinal; 1.472 + 1.473 + // When present, attribute value overrides CSS. 1.474 + nsIContent* content = GetContent(); 1.475 + if (content && content->IsXUL()) { 1.476 + nsresult error; 1.477 + nsAutoString value; 1.478 + 1.479 + content->GetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, value); 1.480 + if (!value.IsEmpty()) { 1.481 + ordinal = value.ToInteger(&error); 1.482 + } 1.483 + } 1.484 + 1.485 + return ordinal; 1.486 +} 1.487 + 1.488 +nscoord 1.489 +nsBox::GetBoxAscent(nsBoxLayoutState& aState) 1.490 +{ 1.491 + if (IsCollapsed()) 1.492 + return 0; 1.493 + 1.494 + return GetPrefSize(aState).height; 1.495 +} 1.496 + 1.497 +bool 1.498 +nsBox::IsCollapsed() 1.499 +{ 1.500 + return StyleVisibility()->mVisible == NS_STYLE_VISIBILITY_COLLAPSE; 1.501 +} 1.502 + 1.503 +nsresult 1.504 +nsIFrame::Layout(nsBoxLayoutState& aState) 1.505 +{ 1.506 + NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); 1.507 + 1.508 + nsBox *box = static_cast<nsBox*>(this); 1.509 + DISPLAY_LAYOUT(box); 1.510 + 1.511 + box->BeginLayout(aState); 1.512 + 1.513 + box->DoLayout(aState); 1.514 + 1.515 + box->EndLayout(aState); 1.516 + 1.517 + return NS_OK; 1.518 +} 1.519 + 1.520 +bool 1.521 +nsBox::DoesClipChildren() 1.522 +{ 1.523 + const nsStyleDisplay* display = StyleDisplay(); 1.524 + NS_ASSERTION((display->mOverflowY == NS_STYLE_OVERFLOW_CLIP) == 1.525 + (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP), 1.526 + "If one overflow is clip, the other should be too"); 1.527 + return display->mOverflowX == NS_STYLE_OVERFLOW_CLIP; 1.528 +} 1.529 + 1.530 +nsresult 1.531 +nsBox::SyncLayout(nsBoxLayoutState& aState) 1.532 +{ 1.533 + /* 1.534 + if (IsCollapsed()) { 1.535 + CollapseChild(aState, this, true); 1.536 + return NS_OK; 1.537 + } 1.538 + */ 1.539 + 1.540 + 1.541 + if (GetStateBits() & NS_FRAME_IS_DIRTY) 1.542 + Redraw(aState); 1.543 + 1.544 + RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY 1.545 + | NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW); 1.546 + 1.547 + nsPresContext* presContext = aState.PresContext(); 1.548 + 1.549 + uint32_t flags = 0; 1.550 + GetLayoutFlags(flags); 1.551 + 1.552 + uint32_t stateFlags = aState.LayoutFlags(); 1.553 + 1.554 + flags |= stateFlags; 1.555 + 1.556 + nsRect visualOverflow; 1.557 + 1.558 + if (ComputesOwnOverflowArea()) { 1.559 + visualOverflow = GetVisualOverflowRect(); 1.560 + } 1.561 + else { 1.562 + nsRect rect(nsPoint(0, 0), GetSize()); 1.563 + nsOverflowAreas overflowAreas(rect, rect); 1.564 + if (!DoesClipChildren() && !IsCollapsed()) { 1.565 + // See if our child frames caused us to overflow after being laid 1.566 + // out. If so, store the overflow area. This normally can't happen 1.567 + // in XUL, but it can happen with the CSS 'outline' property and 1.568 + // possibly with other exotic stuff (e.g. relatively positioned 1.569 + // frames in HTML inside XUL). 1.570 + nsLayoutUtils::UnionChildOverflow(this, overflowAreas); 1.571 + } 1.572 + 1.573 + FinishAndStoreOverflow(overflowAreas, GetSize()); 1.574 + visualOverflow = overflowAreas.VisualOverflow(); 1.575 + } 1.576 + 1.577 + nsView* view = GetView(); 1.578 + if (view) { 1.579 + // Make sure the frame's view is properly sized and positioned and has 1.580 + // things like opacity correct 1.581 + nsContainerFrame::SyncFrameViewAfterReflow(presContext, this, view, 1.582 + visualOverflow, flags); 1.583 + } 1.584 + 1.585 + return NS_OK; 1.586 +} 1.587 + 1.588 +nsresult 1.589 +nsIFrame::Redraw(nsBoxLayoutState& aState) 1.590 +{ 1.591 + if (aState.PaintingDisabled()) 1.592 + return NS_OK; 1.593 + 1.594 + // nsStackLayout, at least, expects us to repaint descendants even 1.595 + // if a damage rect is provided 1.596 + InvalidateFrameSubtree(); 1.597 + 1.598 + return NS_OK; 1.599 +} 1.600 + 1.601 +bool 1.602 +nsIFrame::AddCSSPrefSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet) 1.603 +{ 1.604 + aWidthSet = false; 1.605 + aHeightSet = false; 1.606 + 1.607 + // add in the css min, max, pref 1.608 + const nsStylePosition* position = aBox->StylePosition(); 1.609 + 1.610 + // see if the width or height was specifically set 1.611 + // XXX Handle eStyleUnit_Enumerated? 1.612 + // (Handling the eStyleUnit_Enumerated types requires 1.613 + // GetPrefSize/GetMinSize methods that don't consider 1.614 + // (min-/max-/)(width/height) properties.) 1.615 + const nsStyleCoord &width = position->mWidth; 1.616 + if (width.GetUnit() == eStyleUnit_Coord) { 1.617 + aSize.width = width.GetCoordValue(); 1.618 + aWidthSet = true; 1.619 + } else if (width.IsCalcUnit()) { 1.620 + if (!width.CalcHasPercent()) { 1.621 + // pass 0 for percentage basis since we know there are no %s 1.622 + aSize.width = nsRuleNode::ComputeComputedCalc(width, 0); 1.623 + if (aSize.width < 0) 1.624 + aSize.width = 0; 1.625 + aWidthSet = true; 1.626 + } 1.627 + } 1.628 + 1.629 + const nsStyleCoord &height = position->mHeight; 1.630 + if (height.GetUnit() == eStyleUnit_Coord) { 1.631 + aSize.height = height.GetCoordValue(); 1.632 + aHeightSet = true; 1.633 + } else if (height.IsCalcUnit()) { 1.634 + if (!height.CalcHasPercent()) { 1.635 + // pass 0 for percentage basis since we know there are no %s 1.636 + aSize.height = nsRuleNode::ComputeComputedCalc(height, 0); 1.637 + if (aSize.height < 0) 1.638 + aSize.height = 0; 1.639 + aHeightSet = true; 1.640 + } 1.641 + } 1.642 + 1.643 + nsIContent* content = aBox->GetContent(); 1.644 + // ignore 'height' and 'width' attributes if the actual element is not XUL 1.645 + // For example, we might be magic XUL frames whose primary content is an HTML 1.646 + // <select> 1.647 + if (content && content->IsXUL()) { 1.648 + nsAutoString value; 1.649 + nsresult error; 1.650 + 1.651 + content->GetAttr(kNameSpaceID_None, nsGkAtoms::width, value); 1.652 + if (!value.IsEmpty()) { 1.653 + value.Trim("%"); 1.654 + 1.655 + aSize.width = 1.656 + nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); 1.657 + aWidthSet = true; 1.658 + } 1.659 + 1.660 + content->GetAttr(kNameSpaceID_None, nsGkAtoms::height, value); 1.661 + if (!value.IsEmpty()) { 1.662 + value.Trim("%"); 1.663 + 1.664 + aSize.height = 1.665 + nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); 1.666 + aHeightSet = true; 1.667 + } 1.668 + } 1.669 + 1.670 + return (aWidthSet && aHeightSet); 1.671 +} 1.672 + 1.673 + 1.674 +bool 1.675 +nsIFrame::AddCSSMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize, 1.676 + bool &aWidthSet, bool &aHeightSet) 1.677 +{ 1.678 + aWidthSet = false; 1.679 + aHeightSet = false; 1.680 + 1.681 + bool canOverride = true; 1.682 + 1.683 + // See if a native theme wants to supply a minimum size. 1.684 + const nsStyleDisplay* display = aBox->StyleDisplay(); 1.685 + if (display->mAppearance) { 1.686 + nsITheme *theme = aState.PresContext()->GetTheme(); 1.687 + if (theme && theme->ThemeSupportsWidget(aState.PresContext(), aBox, display->mAppearance)) { 1.688 + nsIntSize size; 1.689 + nsRenderingContext* rendContext = aState.GetRenderingContext(); 1.690 + if (rendContext) { 1.691 + theme->GetMinimumWidgetSize(rendContext, aBox, 1.692 + display->mAppearance, &size, &canOverride); 1.693 + if (size.width) { 1.694 + aSize.width = aState.PresContext()->DevPixelsToAppUnits(size.width); 1.695 + aWidthSet = true; 1.696 + } 1.697 + if (size.height) { 1.698 + aSize.height = aState.PresContext()->DevPixelsToAppUnits(size.height); 1.699 + aHeightSet = true; 1.700 + } 1.701 + } 1.702 + } 1.703 + } 1.704 + 1.705 + // add in the css min, max, pref 1.706 + const nsStylePosition* position = aBox->StylePosition(); 1.707 + 1.708 + // same for min size. Unfortunately min size is always set to 0. So for now 1.709 + // we will assume 0 (as a coord) means not set. 1.710 + const nsStyleCoord &minWidth = position->mMinWidth; 1.711 + if ((minWidth.GetUnit() == eStyleUnit_Coord && 1.712 + minWidth.GetCoordValue() != 0) || 1.713 + (minWidth.IsCalcUnit() && !minWidth.CalcHasPercent())) { 1.714 + nscoord min = nsRuleNode::ComputeCoordPercentCalc(minWidth, 0); 1.715 + if (!aWidthSet || (min > aSize.width && canOverride)) { 1.716 + aSize.width = min; 1.717 + aWidthSet = true; 1.718 + } 1.719 + } else if (minWidth.GetUnit() == eStyleUnit_Percent) { 1.720 + NS_ASSERTION(minWidth.GetPercentValue() == 0.0f, 1.721 + "Non-zero percentage values not currently supported"); 1.722 + aSize.width = 0; 1.723 + aWidthSet = true; // FIXME: should we really do this for 1.724 + // nonzero values? 1.725 + } 1.726 + // XXX Handle eStyleUnit_Enumerated? 1.727 + // (Handling the eStyleUnit_Enumerated types requires 1.728 + // GetPrefSize/GetMinSize methods that don't consider 1.729 + // (min-/max-/)(width/height) properties. 1.730 + // calc() with percentage is treated like '0' (unset) 1.731 + 1.732 + const nsStyleCoord &minHeight = position->mMinHeight; 1.733 + if ((minHeight.GetUnit() == eStyleUnit_Coord && 1.734 + minHeight.GetCoordValue() != 0) || 1.735 + (minHeight.IsCalcUnit() && !minHeight.CalcHasPercent())) { 1.736 + nscoord min = nsRuleNode::ComputeCoordPercentCalc(minHeight, 0); 1.737 + if (!aHeightSet || (min > aSize.height && canOverride)) { 1.738 + aSize.height = min; 1.739 + aHeightSet = true; 1.740 + } 1.741 + } else if (minHeight.GetUnit() == eStyleUnit_Percent) { 1.742 + NS_ASSERTION(position->mMinHeight.GetPercentValue() == 0.0f, 1.743 + "Non-zero percentage values not currently supported"); 1.744 + aSize.height = 0; 1.745 + aHeightSet = true; // FIXME: should we really do this for 1.746 + // nonzero values? 1.747 + } 1.748 + // calc() with percentage is treated like '0' (unset) 1.749 + 1.750 + nsIContent* content = aBox->GetContent(); 1.751 + if (content && content->IsXUL()) { 1.752 + nsAutoString value; 1.753 + nsresult error; 1.754 + 1.755 + content->GetAttr(kNameSpaceID_None, nsGkAtoms::minwidth, value); 1.756 + if (!value.IsEmpty()) 1.757 + { 1.758 + value.Trim("%"); 1.759 + 1.760 + nscoord val = 1.761 + nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); 1.762 + if (val > aSize.width) 1.763 + aSize.width = val; 1.764 + aWidthSet = true; 1.765 + } 1.766 + 1.767 + content->GetAttr(kNameSpaceID_None, nsGkAtoms::minheight, value); 1.768 + if (!value.IsEmpty()) 1.769 + { 1.770 + value.Trim("%"); 1.771 + 1.772 + nscoord val = 1.773 + nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); 1.774 + if (val > aSize.height) 1.775 + aSize.height = val; 1.776 + 1.777 + aHeightSet = true; 1.778 + } 1.779 + } 1.780 + 1.781 + return (aWidthSet && aHeightSet); 1.782 +} 1.783 + 1.784 +bool 1.785 +nsIFrame::AddCSSMaxSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet) 1.786 +{ 1.787 + aWidthSet = false; 1.788 + aHeightSet = false; 1.789 + 1.790 + // add in the css min, max, pref 1.791 + const nsStylePosition* position = aBox->StylePosition(); 1.792 + 1.793 + // and max 1.794 + // see if the width or height was specifically set 1.795 + // XXX Handle eStyleUnit_Enumerated? 1.796 + // (Handling the eStyleUnit_Enumerated types requires 1.797 + // GetPrefSize/GetMinSize methods that don't consider 1.798 + // (min-/max-/)(width/height) properties.) 1.799 + const nsStyleCoord maxWidth = position->mMaxWidth; 1.800 + if (maxWidth.ConvertsToLength()) { 1.801 + aSize.width = nsRuleNode::ComputeCoordPercentCalc(maxWidth, 0); 1.802 + aWidthSet = true; 1.803 + } 1.804 + // percentages and calc() with percentages are treated like 'none' 1.805 + 1.806 + const nsStyleCoord &maxHeight = position->mMaxHeight; 1.807 + if (maxHeight.ConvertsToLength()) { 1.808 + aSize.height = nsRuleNode::ComputeCoordPercentCalc(maxHeight, 0); 1.809 + aHeightSet = true; 1.810 + } 1.811 + // percentages and calc() with percentages are treated like 'none' 1.812 + 1.813 + nsIContent* content = aBox->GetContent(); 1.814 + if (content && content->IsXUL()) { 1.815 + nsAutoString value; 1.816 + nsresult error; 1.817 + 1.818 + content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxwidth, value); 1.819 + if (!value.IsEmpty()) { 1.820 + value.Trim("%"); 1.821 + 1.822 + nscoord val = 1.823 + nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); 1.824 + aSize.width = val; 1.825 + aWidthSet = true; 1.826 + } 1.827 + 1.828 + content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxheight, value); 1.829 + if (!value.IsEmpty()) { 1.830 + value.Trim("%"); 1.831 + 1.832 + nscoord val = 1.833 + nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); 1.834 + aSize.height = val; 1.835 + 1.836 + aHeightSet = true; 1.837 + } 1.838 + } 1.839 + 1.840 + return (aWidthSet || aHeightSet); 1.841 +} 1.842 + 1.843 +bool 1.844 +nsIFrame::AddCSSFlex(nsBoxLayoutState& aState, nsIFrame* aBox, nscoord& aFlex) 1.845 +{ 1.846 + bool flexSet = false; 1.847 + 1.848 + // get the flexibility 1.849 + aFlex = aBox->StyleXUL()->mBoxFlex; 1.850 + 1.851 + // attribute value overrides CSS 1.852 + nsIContent* content = aBox->GetContent(); 1.853 + if (content && content->IsXUL()) { 1.854 + nsresult error; 1.855 + nsAutoString value; 1.856 + 1.857 + content->GetAttr(kNameSpaceID_None, nsGkAtoms::flex, value); 1.858 + if (!value.IsEmpty()) { 1.859 + value.Trim("%"); 1.860 + aFlex = value.ToInteger(&error); 1.861 + flexSet = true; 1.862 + } 1.863 + } 1.864 + 1.865 + if (aFlex < 0) 1.866 + aFlex = 0; 1.867 + if (aFlex >= nscoord_MAX) 1.868 + aFlex = nscoord_MAX - 1; 1.869 + 1.870 + return flexSet || aFlex > 0; 1.871 +} 1.872 + 1.873 +void 1.874 +nsBox::AddBorderAndPadding(nsSize& aSize) 1.875 +{ 1.876 + AddBorderAndPadding(this, aSize); 1.877 +} 1.878 + 1.879 +void 1.880 +nsBox::AddBorderAndPadding(nsIFrame* aBox, nsSize& aSize) 1.881 +{ 1.882 + nsMargin borderPadding(0,0,0,0); 1.883 + aBox->GetBorderAndPadding(borderPadding); 1.884 + AddMargin(aSize, borderPadding); 1.885 +} 1.886 + 1.887 +void 1.888 +nsBox::AddMargin(nsIFrame* aChild, nsSize& aSize) 1.889 +{ 1.890 + nsMargin margin(0,0,0,0); 1.891 + aChild->GetMargin(margin); 1.892 + AddMargin(aSize, margin); 1.893 +} 1.894 + 1.895 +void 1.896 +nsBox::AddMargin(nsSize& aSize, const nsMargin& aMargin) 1.897 +{ 1.898 + if (aSize.width != NS_INTRINSICSIZE) 1.899 + aSize.width += aMargin.left + aMargin.right; 1.900 + 1.901 + if (aSize.height != NS_INTRINSICSIZE) 1.902 + aSize.height += aMargin.top + aMargin.bottom; 1.903 +} 1.904 + 1.905 +nscoord 1.906 +nsBox::BoundsCheck(nscoord aMin, nscoord aPref, nscoord aMax) 1.907 +{ 1.908 + if (aPref > aMax) 1.909 + aPref = aMax; 1.910 + 1.911 + if (aPref < aMin) 1.912 + aPref = aMin; 1.913 + 1.914 + return aPref; 1.915 +} 1.916 + 1.917 +nsSize 1.918 +nsBox::BoundsCheckMinMax(const nsSize& aMinSize, const nsSize& aMaxSize) 1.919 +{ 1.920 + return nsSize(std::max(aMaxSize.width, aMinSize.width), 1.921 + std::max(aMaxSize.height, aMinSize.height)); 1.922 +} 1.923 + 1.924 +nsSize 1.925 +nsBox::BoundsCheck(const nsSize& aMinSize, const nsSize& aPrefSize, const nsSize& aMaxSize) 1.926 +{ 1.927 + return nsSize(BoundsCheck(aMinSize.width, aPrefSize.width, aMaxSize.width), 1.928 + BoundsCheck(aMinSize.height, aPrefSize.height, aMaxSize.height)); 1.929 +} 1.930 + 1.931 +#ifdef DEBUG_LAYOUT 1.932 +nsresult 1.933 +nsBox::SetDebug(nsBoxLayoutState& aState, bool aDebug) 1.934 +{ 1.935 + return NS_OK; 1.936 +} 1.937 + 1.938 +NS_IMETHODIMP 1.939 +nsBox::GetDebugBoxAt( const nsPoint& aPoint, 1.940 + nsIFrame** aBox) 1.941 +{ 1.942 + nsRect thisRect(nsPoint(0,0), GetSize()); 1.943 + if (!thisRect.Contains(aPoint)) 1.944 + return NS_ERROR_FAILURE; 1.945 + 1.946 + nsIFrame* child = GetChildBox(); 1.947 + nsIFrame* hit = nullptr; 1.948 + 1.949 + *aBox = nullptr; 1.950 + while (nullptr != child) { 1.951 + nsresult rv = child->GetDebugBoxAt(aPoint - child->GetOffsetTo(this), &hit); 1.952 + 1.953 + if (NS_SUCCEEDED(rv) && hit) { 1.954 + *aBox = hit; 1.955 + } 1.956 + child = child->GetNextBox(); 1.957 + } 1.958 + 1.959 + // found a child 1.960 + if (*aBox) { 1.961 + return NS_OK; 1.962 + } 1.963 + 1.964 + return NS_ERROR_FAILURE; 1.965 +} 1.966 + 1.967 + 1.968 +nsresult 1.969 +nsBox::GetDebug(bool& aDebug) 1.970 +{ 1.971 + aDebug = false; 1.972 + return NS_OK; 1.973 +} 1.974 + 1.975 +#endif