Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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 | #include "nsBoxLayoutState.h" |
michael@0 | 7 | #include "nsBox.h" |
michael@0 | 8 | #include "nsBoxFrame.h" |
michael@0 | 9 | #include "nsPresContext.h" |
michael@0 | 10 | #include "nsCOMPtr.h" |
michael@0 | 11 | #include "nsIContent.h" |
michael@0 | 12 | #include "nsContainerFrame.h" |
michael@0 | 13 | #include "nsNameSpaceManager.h" |
michael@0 | 14 | #include "nsGkAtoms.h" |
michael@0 | 15 | #include "nsFrameManager.h" |
michael@0 | 16 | #include "nsIDOMNode.h" |
michael@0 | 17 | #include "nsIDOMMozNamedAttrMap.h" |
michael@0 | 18 | #include "nsIDOMAttr.h" |
michael@0 | 19 | #include "nsITheme.h" |
michael@0 | 20 | #include "nsIServiceManager.h" |
michael@0 | 21 | #include "nsBoxLayout.h" |
michael@0 | 22 | #include "FrameLayerBuilder.h" |
michael@0 | 23 | #include <algorithm> |
michael@0 | 24 | |
michael@0 | 25 | using namespace mozilla; |
michael@0 | 26 | |
michael@0 | 27 | #ifdef DEBUG_LAYOUT |
michael@0 | 28 | int32_t gIndent = 0; |
michael@0 | 29 | #endif |
michael@0 | 30 | |
michael@0 | 31 | #ifdef DEBUG_LAYOUT |
michael@0 | 32 | void |
michael@0 | 33 | nsBoxAddIndents() |
michael@0 | 34 | { |
michael@0 | 35 | for(int32_t i=0; i < gIndent; i++) |
michael@0 | 36 | { |
michael@0 | 37 | printf(" "); |
michael@0 | 38 | } |
michael@0 | 39 | } |
michael@0 | 40 | #endif |
michael@0 | 41 | |
michael@0 | 42 | #ifdef DEBUG_LAYOUT |
michael@0 | 43 | void |
michael@0 | 44 | nsBox::AppendAttribute(const nsAutoString& aAttribute, const nsAutoString& aValue, nsAutoString& aResult) |
michael@0 | 45 | { |
michael@0 | 46 | aResult.Append(aAttribute); |
michael@0 | 47 | aResult.AppendLiteral("='"); |
michael@0 | 48 | aResult.Append(aValue); |
michael@0 | 49 | aResult.AppendLiteral("' "); |
michael@0 | 50 | } |
michael@0 | 51 | |
michael@0 | 52 | void |
michael@0 | 53 | nsBox::ListBox(nsAutoString& aResult) |
michael@0 | 54 | { |
michael@0 | 55 | nsAutoString name; |
michael@0 | 56 | GetBoxName(name); |
michael@0 | 57 | |
michael@0 | 58 | char addr[100]; |
michael@0 | 59 | sprintf(addr, "[@%p] ", static_cast<void*>(this)); |
michael@0 | 60 | |
michael@0 | 61 | aResult.AppendASCII(addr); |
michael@0 | 62 | aResult.Append(name); |
michael@0 | 63 | aResult.AppendLiteral(" "); |
michael@0 | 64 | |
michael@0 | 65 | nsIContent* content = GetContent(); |
michael@0 | 66 | |
michael@0 | 67 | // add on all the set attributes |
michael@0 | 68 | if (content) { |
michael@0 | 69 | nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content)); |
michael@0 | 70 | nsCOMPtr<nsIDOMMozNamedAttrMap> namedMap; |
michael@0 | 71 | |
michael@0 | 72 | node->GetAttributes(getter_AddRefs(namedMap)); |
michael@0 | 73 | uint32_t length; |
michael@0 | 74 | namedMap->GetLength(&length); |
michael@0 | 75 | |
michael@0 | 76 | nsCOMPtr<nsIDOMAttr> attribute; |
michael@0 | 77 | for (uint32_t i = 0; i < length; ++i) |
michael@0 | 78 | { |
michael@0 | 79 | namedMap->Item(i, getter_AddRefs(attribute)); |
michael@0 | 80 | attribute->GetName(name); |
michael@0 | 81 | nsAutoString value; |
michael@0 | 82 | attribute->GetValue(value); |
michael@0 | 83 | AppendAttribute(name, value, aResult); |
michael@0 | 84 | } |
michael@0 | 85 | } |
michael@0 | 86 | } |
michael@0 | 87 | |
michael@0 | 88 | nsresult |
michael@0 | 89 | nsBox::DumpBox(FILE* aFile) |
michael@0 | 90 | { |
michael@0 | 91 | nsAutoString s; |
michael@0 | 92 | ListBox(s); |
michael@0 | 93 | fprintf(aFile, "%s", NS_LossyConvertUTF16toASCII(s).get()); |
michael@0 | 94 | return NS_OK; |
michael@0 | 95 | } |
michael@0 | 96 | |
michael@0 | 97 | void |
michael@0 | 98 | nsBox::PropagateDebug(nsBoxLayoutState& aState) |
michael@0 | 99 | { |
michael@0 | 100 | // propagate debug information |
michael@0 | 101 | if (mState & NS_STATE_DEBUG_WAS_SET) { |
michael@0 | 102 | if (mState & NS_STATE_SET_TO_DEBUG) |
michael@0 | 103 | SetDebug(aState, true); |
michael@0 | 104 | else |
michael@0 | 105 | SetDebug(aState, false); |
michael@0 | 106 | } else if (mState & NS_STATE_IS_ROOT) { |
michael@0 | 107 | SetDebug(aState, gDebug); |
michael@0 | 108 | } |
michael@0 | 109 | } |
michael@0 | 110 | #endif |
michael@0 | 111 | |
michael@0 | 112 | #ifdef DEBUG_LAYOUT |
michael@0 | 113 | void |
michael@0 | 114 | nsBox::GetBoxName(nsAutoString& aName) |
michael@0 | 115 | { |
michael@0 | 116 | aName.AssignLiteral("Box"); |
michael@0 | 117 | } |
michael@0 | 118 | #endif |
michael@0 | 119 | |
michael@0 | 120 | nsresult |
michael@0 | 121 | nsBox::BeginLayout(nsBoxLayoutState& aState) |
michael@0 | 122 | { |
michael@0 | 123 | #ifdef DEBUG_LAYOUT |
michael@0 | 124 | |
michael@0 | 125 | nsBoxAddIndents(); |
michael@0 | 126 | printf("Layout: "); |
michael@0 | 127 | DumpBox(stdout); |
michael@0 | 128 | printf("\n"); |
michael@0 | 129 | gIndent++; |
michael@0 | 130 | #endif |
michael@0 | 131 | |
michael@0 | 132 | // mark ourselves as dirty so no child under us |
michael@0 | 133 | // can post an incremental layout. |
michael@0 | 134 | // XXXldb Is this still needed? |
michael@0 | 135 | mState |= NS_FRAME_HAS_DIRTY_CHILDREN; |
michael@0 | 136 | |
michael@0 | 137 | if (GetStateBits() & NS_FRAME_IS_DIRTY) |
michael@0 | 138 | { |
michael@0 | 139 | // If the parent is dirty, all the children are dirty (nsHTMLReflowState |
michael@0 | 140 | // does this too). |
michael@0 | 141 | nsIFrame* box; |
michael@0 | 142 | for (box = GetChildBox(); box; box = box->GetNextBox()) |
michael@0 | 143 | box->AddStateBits(NS_FRAME_IS_DIRTY); |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | // Another copy-over from nsHTMLReflowState. |
michael@0 | 147 | // Since we are in reflow, we don't need to store these properties anymore. |
michael@0 | 148 | FrameProperties props = Properties(); |
michael@0 | 149 | props.Delete(UsedBorderProperty()); |
michael@0 | 150 | props.Delete(UsedPaddingProperty()); |
michael@0 | 151 | props.Delete(UsedMarginProperty()); |
michael@0 | 152 | |
michael@0 | 153 | #ifdef DEBUG_LAYOUT |
michael@0 | 154 | PropagateDebug(aState); |
michael@0 | 155 | #endif |
michael@0 | 156 | |
michael@0 | 157 | return NS_OK; |
michael@0 | 158 | } |
michael@0 | 159 | |
michael@0 | 160 | NS_IMETHODIMP |
michael@0 | 161 | nsBox::DoLayout(nsBoxLayoutState& aState) |
michael@0 | 162 | { |
michael@0 | 163 | return NS_OK; |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | nsresult |
michael@0 | 167 | nsBox::EndLayout(nsBoxLayoutState& aState) |
michael@0 | 168 | { |
michael@0 | 169 | |
michael@0 | 170 | #ifdef DEBUG_LAYOUT |
michael@0 | 171 | --gIndent; |
michael@0 | 172 | #endif |
michael@0 | 173 | |
michael@0 | 174 | return SyncLayout(aState); |
michael@0 | 175 | } |
michael@0 | 176 | |
michael@0 | 177 | bool nsBox::gGotTheme = false; |
michael@0 | 178 | nsITheme* nsBox::gTheme = nullptr; |
michael@0 | 179 | |
michael@0 | 180 | nsBox::nsBox() |
michael@0 | 181 | { |
michael@0 | 182 | MOZ_COUNT_CTOR(nsBox); |
michael@0 | 183 | //mX = 0; |
michael@0 | 184 | //mY = 0; |
michael@0 | 185 | if (!gGotTheme) { |
michael@0 | 186 | gGotTheme = true; |
michael@0 | 187 | CallGetService("@mozilla.org/chrome/chrome-native-theme;1", &gTheme); |
michael@0 | 188 | } |
michael@0 | 189 | } |
michael@0 | 190 | |
michael@0 | 191 | nsBox::~nsBox() |
michael@0 | 192 | { |
michael@0 | 193 | // NOTE: This currently doesn't get called for |nsBoxToBlockAdaptor| |
michael@0 | 194 | // objects, so don't rely on putting anything here. |
michael@0 | 195 | MOZ_COUNT_DTOR(nsBox); |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | /* static */ void |
michael@0 | 199 | nsBox::Shutdown() |
michael@0 | 200 | { |
michael@0 | 201 | gGotTheme = false; |
michael@0 | 202 | NS_IF_RELEASE(gTheme); |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | nsresult |
michael@0 | 206 | nsBox::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild) |
michael@0 | 207 | { |
michael@0 | 208 | return NS_OK; |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | nsresult |
michael@0 | 212 | nsIFrame::GetClientRect(nsRect& aClientRect) |
michael@0 | 213 | { |
michael@0 | 214 | aClientRect = mRect; |
michael@0 | 215 | aClientRect.MoveTo(0,0); |
michael@0 | 216 | |
michael@0 | 217 | nsMargin borderPadding; |
michael@0 | 218 | GetBorderAndPadding(borderPadding); |
michael@0 | 219 | |
michael@0 | 220 | aClientRect.Deflate(borderPadding); |
michael@0 | 221 | |
michael@0 | 222 | if (aClientRect.width < 0) |
michael@0 | 223 | aClientRect.width = 0; |
michael@0 | 224 | |
michael@0 | 225 | if (aClientRect.height < 0) |
michael@0 | 226 | aClientRect.height = 0; |
michael@0 | 227 | |
michael@0 | 228 | // NS_ASSERTION(aClientRect.width >=0 && aClientRect.height >= 0, "Content Size < 0"); |
michael@0 | 229 | |
michael@0 | 230 | return NS_OK; |
michael@0 | 231 | } |
michael@0 | 232 | |
michael@0 | 233 | void |
michael@0 | 234 | nsBox::SetBounds(nsBoxLayoutState& aState, const nsRect& aRect, bool aRemoveOverflowAreas) |
michael@0 | 235 | { |
michael@0 | 236 | NS_BOX_ASSERTION(this, aRect.width >=0 && aRect.height >= 0, "SetBounds Size < 0"); |
michael@0 | 237 | |
michael@0 | 238 | nsRect rect(mRect); |
michael@0 | 239 | |
michael@0 | 240 | uint32_t flags = 0; |
michael@0 | 241 | GetLayoutFlags(flags); |
michael@0 | 242 | |
michael@0 | 243 | uint32_t stateFlags = aState.LayoutFlags(); |
michael@0 | 244 | |
michael@0 | 245 | flags |= stateFlags; |
michael@0 | 246 | |
michael@0 | 247 | if ((flags & NS_FRAME_NO_MOVE_FRAME) == NS_FRAME_NO_MOVE_FRAME) |
michael@0 | 248 | SetSize(aRect.Size()); |
michael@0 | 249 | else |
michael@0 | 250 | SetRect(aRect); |
michael@0 | 251 | |
michael@0 | 252 | // Nuke the overflow area. The caller is responsible for restoring |
michael@0 | 253 | // it if necessary. |
michael@0 | 254 | if (aRemoveOverflowAreas) { |
michael@0 | 255 | // remove the previously stored overflow area |
michael@0 | 256 | ClearOverflowRects(); |
michael@0 | 257 | } |
michael@0 | 258 | |
michael@0 | 259 | if (!(flags & NS_FRAME_NO_MOVE_VIEW)) |
michael@0 | 260 | { |
michael@0 | 261 | nsContainerFrame::PositionFrameView(this); |
michael@0 | 262 | if ((rect.x != aRect.x) || (rect.y != aRect.y)) |
michael@0 | 263 | nsContainerFrame::PositionChildViews(this); |
michael@0 | 264 | } |
michael@0 | 265 | |
michael@0 | 266 | |
michael@0 | 267 | /* |
michael@0 | 268 | // only if the origin changed |
michael@0 | 269 | if ((rect.x != aRect.x) || (rect.y != aRect.y)) { |
michael@0 | 270 | if (frame->HasView()) { |
michael@0 | 271 | nsContainerFrame::PositionFrameView(presContext, frame, |
michael@0 | 272 | frame->GetView()); |
michael@0 | 273 | } else { |
michael@0 | 274 | nsContainerFrame::PositionChildViews(presContext, frame); |
michael@0 | 275 | } |
michael@0 | 276 | } |
michael@0 | 277 | */ |
michael@0 | 278 | } |
michael@0 | 279 | |
michael@0 | 280 | void |
michael@0 | 281 | nsBox::GetLayoutFlags(uint32_t& aFlags) |
michael@0 | 282 | { |
michael@0 | 283 | aFlags = 0; |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | |
michael@0 | 287 | nsresult |
michael@0 | 288 | nsIFrame::GetBorderAndPadding(nsMargin& aBorderAndPadding) |
michael@0 | 289 | { |
michael@0 | 290 | aBorderAndPadding.SizeTo(0, 0, 0, 0); |
michael@0 | 291 | nsresult rv = GetBorder(aBorderAndPadding); |
michael@0 | 292 | if (NS_FAILED(rv)) |
michael@0 | 293 | return rv; |
michael@0 | 294 | |
michael@0 | 295 | nsMargin padding; |
michael@0 | 296 | rv = GetPadding(padding); |
michael@0 | 297 | if (NS_FAILED(rv)) |
michael@0 | 298 | return rv; |
michael@0 | 299 | |
michael@0 | 300 | aBorderAndPadding += padding; |
michael@0 | 301 | |
michael@0 | 302 | return rv; |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | nsresult |
michael@0 | 306 | nsBox::GetBorder(nsMargin& aMargin) |
michael@0 | 307 | { |
michael@0 | 308 | aMargin.SizeTo(0,0,0,0); |
michael@0 | 309 | |
michael@0 | 310 | const nsStyleDisplay* disp = StyleDisplay(); |
michael@0 | 311 | if (disp->mAppearance && gTheme) { |
michael@0 | 312 | // Go to the theme for the border. |
michael@0 | 313 | nsPresContext *context = PresContext(); |
michael@0 | 314 | if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) { |
michael@0 | 315 | nsIntMargin margin(0, 0, 0, 0); |
michael@0 | 316 | gTheme->GetWidgetBorder(context->DeviceContext(), this, |
michael@0 | 317 | disp->mAppearance, &margin); |
michael@0 | 318 | aMargin.top = context->DevPixelsToAppUnits(margin.top); |
michael@0 | 319 | aMargin.right = context->DevPixelsToAppUnits(margin.right); |
michael@0 | 320 | aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom); |
michael@0 | 321 | aMargin.left = context->DevPixelsToAppUnits(margin.left); |
michael@0 | 322 | return NS_OK; |
michael@0 | 323 | } |
michael@0 | 324 | } |
michael@0 | 325 | |
michael@0 | 326 | aMargin = StyleBorder()->GetComputedBorder(); |
michael@0 | 327 | |
michael@0 | 328 | return NS_OK; |
michael@0 | 329 | } |
michael@0 | 330 | |
michael@0 | 331 | nsresult |
michael@0 | 332 | nsBox::GetPadding(nsMargin& aMargin) |
michael@0 | 333 | { |
michael@0 | 334 | const nsStyleDisplay *disp = StyleDisplay(); |
michael@0 | 335 | if (disp->mAppearance && gTheme) { |
michael@0 | 336 | // Go to the theme for the padding. |
michael@0 | 337 | nsPresContext *context = PresContext(); |
michael@0 | 338 | if (gTheme->ThemeSupportsWidget(context, this, disp->mAppearance)) { |
michael@0 | 339 | nsIntMargin margin(0, 0, 0, 0); |
michael@0 | 340 | bool useThemePadding; |
michael@0 | 341 | |
michael@0 | 342 | useThemePadding = gTheme->GetWidgetPadding(context->DeviceContext(), |
michael@0 | 343 | this, disp->mAppearance, |
michael@0 | 344 | &margin); |
michael@0 | 345 | if (useThemePadding) { |
michael@0 | 346 | aMargin.top = context->DevPixelsToAppUnits(margin.top); |
michael@0 | 347 | aMargin.right = context->DevPixelsToAppUnits(margin.right); |
michael@0 | 348 | aMargin.bottom = context->DevPixelsToAppUnits(margin.bottom); |
michael@0 | 349 | aMargin.left = context->DevPixelsToAppUnits(margin.left); |
michael@0 | 350 | return NS_OK; |
michael@0 | 351 | } |
michael@0 | 352 | } |
michael@0 | 353 | } |
michael@0 | 354 | |
michael@0 | 355 | aMargin.SizeTo(0,0,0,0); |
michael@0 | 356 | StylePadding()->GetPadding(aMargin); |
michael@0 | 357 | |
michael@0 | 358 | return NS_OK; |
michael@0 | 359 | } |
michael@0 | 360 | |
michael@0 | 361 | nsresult |
michael@0 | 362 | nsBox::GetMargin(nsMargin& aMargin) |
michael@0 | 363 | { |
michael@0 | 364 | aMargin.SizeTo(0,0,0,0); |
michael@0 | 365 | StyleMargin()->GetMargin(aMargin); |
michael@0 | 366 | |
michael@0 | 367 | return NS_OK; |
michael@0 | 368 | } |
michael@0 | 369 | |
michael@0 | 370 | void |
michael@0 | 371 | nsBox::SizeNeedsRecalc(nsSize& aSize) |
michael@0 | 372 | { |
michael@0 | 373 | aSize.width = -1; |
michael@0 | 374 | aSize.height = -1; |
michael@0 | 375 | } |
michael@0 | 376 | |
michael@0 | 377 | void |
michael@0 | 378 | nsBox::CoordNeedsRecalc(nscoord& aFlex) |
michael@0 | 379 | { |
michael@0 | 380 | aFlex = -1; |
michael@0 | 381 | } |
michael@0 | 382 | |
michael@0 | 383 | bool |
michael@0 | 384 | nsBox::DoesNeedRecalc(const nsSize& aSize) |
michael@0 | 385 | { |
michael@0 | 386 | return (aSize.width == -1 || aSize.height == -1); |
michael@0 | 387 | } |
michael@0 | 388 | |
michael@0 | 389 | bool |
michael@0 | 390 | nsBox::DoesNeedRecalc(nscoord aCoord) |
michael@0 | 391 | { |
michael@0 | 392 | return (aCoord == -1); |
michael@0 | 393 | } |
michael@0 | 394 | |
michael@0 | 395 | nsSize |
michael@0 | 396 | nsBox::GetPrefSize(nsBoxLayoutState& aState) |
michael@0 | 397 | { |
michael@0 | 398 | NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); |
michael@0 | 399 | |
michael@0 | 400 | nsSize pref(0,0); |
michael@0 | 401 | DISPLAY_PREF_SIZE(this, pref); |
michael@0 | 402 | |
michael@0 | 403 | if (IsCollapsed()) |
michael@0 | 404 | return pref; |
michael@0 | 405 | |
michael@0 | 406 | AddBorderAndPadding(pref); |
michael@0 | 407 | bool widthSet, heightSet; |
michael@0 | 408 | nsIFrame::AddCSSPrefSize(this, pref, widthSet, heightSet); |
michael@0 | 409 | |
michael@0 | 410 | nsSize minSize = GetMinSize(aState); |
michael@0 | 411 | nsSize maxSize = GetMaxSize(aState); |
michael@0 | 412 | return BoundsCheck(minSize, pref, maxSize); |
michael@0 | 413 | } |
michael@0 | 414 | |
michael@0 | 415 | nsSize |
michael@0 | 416 | nsBox::GetMinSize(nsBoxLayoutState& aState) |
michael@0 | 417 | { |
michael@0 | 418 | NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); |
michael@0 | 419 | |
michael@0 | 420 | nsSize min(0,0); |
michael@0 | 421 | DISPLAY_MIN_SIZE(this, min); |
michael@0 | 422 | |
michael@0 | 423 | if (IsCollapsed()) |
michael@0 | 424 | return min; |
michael@0 | 425 | |
michael@0 | 426 | AddBorderAndPadding(min); |
michael@0 | 427 | bool widthSet, heightSet; |
michael@0 | 428 | nsIFrame::AddCSSMinSize(aState, this, min, widthSet, heightSet); |
michael@0 | 429 | return min; |
michael@0 | 430 | } |
michael@0 | 431 | |
michael@0 | 432 | nsSize |
michael@0 | 433 | nsBox::GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState) |
michael@0 | 434 | { |
michael@0 | 435 | return nsSize(0, 0); |
michael@0 | 436 | } |
michael@0 | 437 | |
michael@0 | 438 | nsSize |
michael@0 | 439 | nsBox::GetMaxSize(nsBoxLayoutState& aState) |
michael@0 | 440 | { |
michael@0 | 441 | NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); |
michael@0 | 442 | |
michael@0 | 443 | nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE); |
michael@0 | 444 | DISPLAY_MAX_SIZE(this, maxSize); |
michael@0 | 445 | |
michael@0 | 446 | if (IsCollapsed()) |
michael@0 | 447 | return maxSize; |
michael@0 | 448 | |
michael@0 | 449 | AddBorderAndPadding(maxSize); |
michael@0 | 450 | bool widthSet, heightSet; |
michael@0 | 451 | nsIFrame::AddCSSMaxSize(this, maxSize, widthSet, heightSet); |
michael@0 | 452 | return maxSize; |
michael@0 | 453 | } |
michael@0 | 454 | |
michael@0 | 455 | nscoord |
michael@0 | 456 | nsBox::GetFlex(nsBoxLayoutState& aState) |
michael@0 | 457 | { |
michael@0 | 458 | nscoord flex = 0; |
michael@0 | 459 | |
michael@0 | 460 | nsIFrame::AddCSSFlex(aState, this, flex); |
michael@0 | 461 | |
michael@0 | 462 | return flex; |
michael@0 | 463 | } |
michael@0 | 464 | |
michael@0 | 465 | uint32_t |
michael@0 | 466 | nsIFrame::GetOrdinal() |
michael@0 | 467 | { |
michael@0 | 468 | uint32_t ordinal = StyleXUL()->mBoxOrdinal; |
michael@0 | 469 | |
michael@0 | 470 | // When present, attribute value overrides CSS. |
michael@0 | 471 | nsIContent* content = GetContent(); |
michael@0 | 472 | if (content && content->IsXUL()) { |
michael@0 | 473 | nsresult error; |
michael@0 | 474 | nsAutoString value; |
michael@0 | 475 | |
michael@0 | 476 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, value); |
michael@0 | 477 | if (!value.IsEmpty()) { |
michael@0 | 478 | ordinal = value.ToInteger(&error); |
michael@0 | 479 | } |
michael@0 | 480 | } |
michael@0 | 481 | |
michael@0 | 482 | return ordinal; |
michael@0 | 483 | } |
michael@0 | 484 | |
michael@0 | 485 | nscoord |
michael@0 | 486 | nsBox::GetBoxAscent(nsBoxLayoutState& aState) |
michael@0 | 487 | { |
michael@0 | 488 | if (IsCollapsed()) |
michael@0 | 489 | return 0; |
michael@0 | 490 | |
michael@0 | 491 | return GetPrefSize(aState).height; |
michael@0 | 492 | } |
michael@0 | 493 | |
michael@0 | 494 | bool |
michael@0 | 495 | nsBox::IsCollapsed() |
michael@0 | 496 | { |
michael@0 | 497 | return StyleVisibility()->mVisible == NS_STYLE_VISIBILITY_COLLAPSE; |
michael@0 | 498 | } |
michael@0 | 499 | |
michael@0 | 500 | nsresult |
michael@0 | 501 | nsIFrame::Layout(nsBoxLayoutState& aState) |
michael@0 | 502 | { |
michael@0 | 503 | NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context"); |
michael@0 | 504 | |
michael@0 | 505 | nsBox *box = static_cast<nsBox*>(this); |
michael@0 | 506 | DISPLAY_LAYOUT(box); |
michael@0 | 507 | |
michael@0 | 508 | box->BeginLayout(aState); |
michael@0 | 509 | |
michael@0 | 510 | box->DoLayout(aState); |
michael@0 | 511 | |
michael@0 | 512 | box->EndLayout(aState); |
michael@0 | 513 | |
michael@0 | 514 | return NS_OK; |
michael@0 | 515 | } |
michael@0 | 516 | |
michael@0 | 517 | bool |
michael@0 | 518 | nsBox::DoesClipChildren() |
michael@0 | 519 | { |
michael@0 | 520 | const nsStyleDisplay* display = StyleDisplay(); |
michael@0 | 521 | NS_ASSERTION((display->mOverflowY == NS_STYLE_OVERFLOW_CLIP) == |
michael@0 | 522 | (display->mOverflowX == NS_STYLE_OVERFLOW_CLIP), |
michael@0 | 523 | "If one overflow is clip, the other should be too"); |
michael@0 | 524 | return display->mOverflowX == NS_STYLE_OVERFLOW_CLIP; |
michael@0 | 525 | } |
michael@0 | 526 | |
michael@0 | 527 | nsresult |
michael@0 | 528 | nsBox::SyncLayout(nsBoxLayoutState& aState) |
michael@0 | 529 | { |
michael@0 | 530 | /* |
michael@0 | 531 | if (IsCollapsed()) { |
michael@0 | 532 | CollapseChild(aState, this, true); |
michael@0 | 533 | return NS_OK; |
michael@0 | 534 | } |
michael@0 | 535 | */ |
michael@0 | 536 | |
michael@0 | 537 | |
michael@0 | 538 | if (GetStateBits() & NS_FRAME_IS_DIRTY) |
michael@0 | 539 | Redraw(aState); |
michael@0 | 540 | |
michael@0 | 541 | RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY |
michael@0 | 542 | | NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW); |
michael@0 | 543 | |
michael@0 | 544 | nsPresContext* presContext = aState.PresContext(); |
michael@0 | 545 | |
michael@0 | 546 | uint32_t flags = 0; |
michael@0 | 547 | GetLayoutFlags(flags); |
michael@0 | 548 | |
michael@0 | 549 | uint32_t stateFlags = aState.LayoutFlags(); |
michael@0 | 550 | |
michael@0 | 551 | flags |= stateFlags; |
michael@0 | 552 | |
michael@0 | 553 | nsRect visualOverflow; |
michael@0 | 554 | |
michael@0 | 555 | if (ComputesOwnOverflowArea()) { |
michael@0 | 556 | visualOverflow = GetVisualOverflowRect(); |
michael@0 | 557 | } |
michael@0 | 558 | else { |
michael@0 | 559 | nsRect rect(nsPoint(0, 0), GetSize()); |
michael@0 | 560 | nsOverflowAreas overflowAreas(rect, rect); |
michael@0 | 561 | if (!DoesClipChildren() && !IsCollapsed()) { |
michael@0 | 562 | // See if our child frames caused us to overflow after being laid |
michael@0 | 563 | // out. If so, store the overflow area. This normally can't happen |
michael@0 | 564 | // in XUL, but it can happen with the CSS 'outline' property and |
michael@0 | 565 | // possibly with other exotic stuff (e.g. relatively positioned |
michael@0 | 566 | // frames in HTML inside XUL). |
michael@0 | 567 | nsLayoutUtils::UnionChildOverflow(this, overflowAreas); |
michael@0 | 568 | } |
michael@0 | 569 | |
michael@0 | 570 | FinishAndStoreOverflow(overflowAreas, GetSize()); |
michael@0 | 571 | visualOverflow = overflowAreas.VisualOverflow(); |
michael@0 | 572 | } |
michael@0 | 573 | |
michael@0 | 574 | nsView* view = GetView(); |
michael@0 | 575 | if (view) { |
michael@0 | 576 | // Make sure the frame's view is properly sized and positioned and has |
michael@0 | 577 | // things like opacity correct |
michael@0 | 578 | nsContainerFrame::SyncFrameViewAfterReflow(presContext, this, view, |
michael@0 | 579 | visualOverflow, flags); |
michael@0 | 580 | } |
michael@0 | 581 | |
michael@0 | 582 | return NS_OK; |
michael@0 | 583 | } |
michael@0 | 584 | |
michael@0 | 585 | nsresult |
michael@0 | 586 | nsIFrame::Redraw(nsBoxLayoutState& aState) |
michael@0 | 587 | { |
michael@0 | 588 | if (aState.PaintingDisabled()) |
michael@0 | 589 | return NS_OK; |
michael@0 | 590 | |
michael@0 | 591 | // nsStackLayout, at least, expects us to repaint descendants even |
michael@0 | 592 | // if a damage rect is provided |
michael@0 | 593 | InvalidateFrameSubtree(); |
michael@0 | 594 | |
michael@0 | 595 | return NS_OK; |
michael@0 | 596 | } |
michael@0 | 597 | |
michael@0 | 598 | bool |
michael@0 | 599 | nsIFrame::AddCSSPrefSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet) |
michael@0 | 600 | { |
michael@0 | 601 | aWidthSet = false; |
michael@0 | 602 | aHeightSet = false; |
michael@0 | 603 | |
michael@0 | 604 | // add in the css min, max, pref |
michael@0 | 605 | const nsStylePosition* position = aBox->StylePosition(); |
michael@0 | 606 | |
michael@0 | 607 | // see if the width or height was specifically set |
michael@0 | 608 | // XXX Handle eStyleUnit_Enumerated? |
michael@0 | 609 | // (Handling the eStyleUnit_Enumerated types requires |
michael@0 | 610 | // GetPrefSize/GetMinSize methods that don't consider |
michael@0 | 611 | // (min-/max-/)(width/height) properties.) |
michael@0 | 612 | const nsStyleCoord &width = position->mWidth; |
michael@0 | 613 | if (width.GetUnit() == eStyleUnit_Coord) { |
michael@0 | 614 | aSize.width = width.GetCoordValue(); |
michael@0 | 615 | aWidthSet = true; |
michael@0 | 616 | } else if (width.IsCalcUnit()) { |
michael@0 | 617 | if (!width.CalcHasPercent()) { |
michael@0 | 618 | // pass 0 for percentage basis since we know there are no %s |
michael@0 | 619 | aSize.width = nsRuleNode::ComputeComputedCalc(width, 0); |
michael@0 | 620 | if (aSize.width < 0) |
michael@0 | 621 | aSize.width = 0; |
michael@0 | 622 | aWidthSet = true; |
michael@0 | 623 | } |
michael@0 | 624 | } |
michael@0 | 625 | |
michael@0 | 626 | const nsStyleCoord &height = position->mHeight; |
michael@0 | 627 | if (height.GetUnit() == eStyleUnit_Coord) { |
michael@0 | 628 | aSize.height = height.GetCoordValue(); |
michael@0 | 629 | aHeightSet = true; |
michael@0 | 630 | } else if (height.IsCalcUnit()) { |
michael@0 | 631 | if (!height.CalcHasPercent()) { |
michael@0 | 632 | // pass 0 for percentage basis since we know there are no %s |
michael@0 | 633 | aSize.height = nsRuleNode::ComputeComputedCalc(height, 0); |
michael@0 | 634 | if (aSize.height < 0) |
michael@0 | 635 | aSize.height = 0; |
michael@0 | 636 | aHeightSet = true; |
michael@0 | 637 | } |
michael@0 | 638 | } |
michael@0 | 639 | |
michael@0 | 640 | nsIContent* content = aBox->GetContent(); |
michael@0 | 641 | // ignore 'height' and 'width' attributes if the actual element is not XUL |
michael@0 | 642 | // For example, we might be magic XUL frames whose primary content is an HTML |
michael@0 | 643 | // <select> |
michael@0 | 644 | if (content && content->IsXUL()) { |
michael@0 | 645 | nsAutoString value; |
michael@0 | 646 | nsresult error; |
michael@0 | 647 | |
michael@0 | 648 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::width, value); |
michael@0 | 649 | if (!value.IsEmpty()) { |
michael@0 | 650 | value.Trim("%"); |
michael@0 | 651 | |
michael@0 | 652 | aSize.width = |
michael@0 | 653 | nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); |
michael@0 | 654 | aWidthSet = true; |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::height, value); |
michael@0 | 658 | if (!value.IsEmpty()) { |
michael@0 | 659 | value.Trim("%"); |
michael@0 | 660 | |
michael@0 | 661 | aSize.height = |
michael@0 | 662 | nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); |
michael@0 | 663 | aHeightSet = true; |
michael@0 | 664 | } |
michael@0 | 665 | } |
michael@0 | 666 | |
michael@0 | 667 | return (aWidthSet && aHeightSet); |
michael@0 | 668 | } |
michael@0 | 669 | |
michael@0 | 670 | |
michael@0 | 671 | bool |
michael@0 | 672 | nsIFrame::AddCSSMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize, |
michael@0 | 673 | bool &aWidthSet, bool &aHeightSet) |
michael@0 | 674 | { |
michael@0 | 675 | aWidthSet = false; |
michael@0 | 676 | aHeightSet = false; |
michael@0 | 677 | |
michael@0 | 678 | bool canOverride = true; |
michael@0 | 679 | |
michael@0 | 680 | // See if a native theme wants to supply a minimum size. |
michael@0 | 681 | const nsStyleDisplay* display = aBox->StyleDisplay(); |
michael@0 | 682 | if (display->mAppearance) { |
michael@0 | 683 | nsITheme *theme = aState.PresContext()->GetTheme(); |
michael@0 | 684 | if (theme && theme->ThemeSupportsWidget(aState.PresContext(), aBox, display->mAppearance)) { |
michael@0 | 685 | nsIntSize size; |
michael@0 | 686 | nsRenderingContext* rendContext = aState.GetRenderingContext(); |
michael@0 | 687 | if (rendContext) { |
michael@0 | 688 | theme->GetMinimumWidgetSize(rendContext, aBox, |
michael@0 | 689 | display->mAppearance, &size, &canOverride); |
michael@0 | 690 | if (size.width) { |
michael@0 | 691 | aSize.width = aState.PresContext()->DevPixelsToAppUnits(size.width); |
michael@0 | 692 | aWidthSet = true; |
michael@0 | 693 | } |
michael@0 | 694 | if (size.height) { |
michael@0 | 695 | aSize.height = aState.PresContext()->DevPixelsToAppUnits(size.height); |
michael@0 | 696 | aHeightSet = true; |
michael@0 | 697 | } |
michael@0 | 698 | } |
michael@0 | 699 | } |
michael@0 | 700 | } |
michael@0 | 701 | |
michael@0 | 702 | // add in the css min, max, pref |
michael@0 | 703 | const nsStylePosition* position = aBox->StylePosition(); |
michael@0 | 704 | |
michael@0 | 705 | // same for min size. Unfortunately min size is always set to 0. So for now |
michael@0 | 706 | // we will assume 0 (as a coord) means not set. |
michael@0 | 707 | const nsStyleCoord &minWidth = position->mMinWidth; |
michael@0 | 708 | if ((minWidth.GetUnit() == eStyleUnit_Coord && |
michael@0 | 709 | minWidth.GetCoordValue() != 0) || |
michael@0 | 710 | (minWidth.IsCalcUnit() && !minWidth.CalcHasPercent())) { |
michael@0 | 711 | nscoord min = nsRuleNode::ComputeCoordPercentCalc(minWidth, 0); |
michael@0 | 712 | if (!aWidthSet || (min > aSize.width && canOverride)) { |
michael@0 | 713 | aSize.width = min; |
michael@0 | 714 | aWidthSet = true; |
michael@0 | 715 | } |
michael@0 | 716 | } else if (minWidth.GetUnit() == eStyleUnit_Percent) { |
michael@0 | 717 | NS_ASSERTION(minWidth.GetPercentValue() == 0.0f, |
michael@0 | 718 | "Non-zero percentage values not currently supported"); |
michael@0 | 719 | aSize.width = 0; |
michael@0 | 720 | aWidthSet = true; // FIXME: should we really do this for |
michael@0 | 721 | // nonzero values? |
michael@0 | 722 | } |
michael@0 | 723 | // XXX Handle eStyleUnit_Enumerated? |
michael@0 | 724 | // (Handling the eStyleUnit_Enumerated types requires |
michael@0 | 725 | // GetPrefSize/GetMinSize methods that don't consider |
michael@0 | 726 | // (min-/max-/)(width/height) properties. |
michael@0 | 727 | // calc() with percentage is treated like '0' (unset) |
michael@0 | 728 | |
michael@0 | 729 | const nsStyleCoord &minHeight = position->mMinHeight; |
michael@0 | 730 | if ((minHeight.GetUnit() == eStyleUnit_Coord && |
michael@0 | 731 | minHeight.GetCoordValue() != 0) || |
michael@0 | 732 | (minHeight.IsCalcUnit() && !minHeight.CalcHasPercent())) { |
michael@0 | 733 | nscoord min = nsRuleNode::ComputeCoordPercentCalc(minHeight, 0); |
michael@0 | 734 | if (!aHeightSet || (min > aSize.height && canOverride)) { |
michael@0 | 735 | aSize.height = min; |
michael@0 | 736 | aHeightSet = true; |
michael@0 | 737 | } |
michael@0 | 738 | } else if (minHeight.GetUnit() == eStyleUnit_Percent) { |
michael@0 | 739 | NS_ASSERTION(position->mMinHeight.GetPercentValue() == 0.0f, |
michael@0 | 740 | "Non-zero percentage values not currently supported"); |
michael@0 | 741 | aSize.height = 0; |
michael@0 | 742 | aHeightSet = true; // FIXME: should we really do this for |
michael@0 | 743 | // nonzero values? |
michael@0 | 744 | } |
michael@0 | 745 | // calc() with percentage is treated like '0' (unset) |
michael@0 | 746 | |
michael@0 | 747 | nsIContent* content = aBox->GetContent(); |
michael@0 | 748 | if (content && content->IsXUL()) { |
michael@0 | 749 | nsAutoString value; |
michael@0 | 750 | nsresult error; |
michael@0 | 751 | |
michael@0 | 752 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::minwidth, value); |
michael@0 | 753 | if (!value.IsEmpty()) |
michael@0 | 754 | { |
michael@0 | 755 | value.Trim("%"); |
michael@0 | 756 | |
michael@0 | 757 | nscoord val = |
michael@0 | 758 | nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); |
michael@0 | 759 | if (val > aSize.width) |
michael@0 | 760 | aSize.width = val; |
michael@0 | 761 | aWidthSet = true; |
michael@0 | 762 | } |
michael@0 | 763 | |
michael@0 | 764 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::minheight, value); |
michael@0 | 765 | if (!value.IsEmpty()) |
michael@0 | 766 | { |
michael@0 | 767 | value.Trim("%"); |
michael@0 | 768 | |
michael@0 | 769 | nscoord val = |
michael@0 | 770 | nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); |
michael@0 | 771 | if (val > aSize.height) |
michael@0 | 772 | aSize.height = val; |
michael@0 | 773 | |
michael@0 | 774 | aHeightSet = true; |
michael@0 | 775 | } |
michael@0 | 776 | } |
michael@0 | 777 | |
michael@0 | 778 | return (aWidthSet && aHeightSet); |
michael@0 | 779 | } |
michael@0 | 780 | |
michael@0 | 781 | bool |
michael@0 | 782 | nsIFrame::AddCSSMaxSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet) |
michael@0 | 783 | { |
michael@0 | 784 | aWidthSet = false; |
michael@0 | 785 | aHeightSet = false; |
michael@0 | 786 | |
michael@0 | 787 | // add in the css min, max, pref |
michael@0 | 788 | const nsStylePosition* position = aBox->StylePosition(); |
michael@0 | 789 | |
michael@0 | 790 | // and max |
michael@0 | 791 | // see if the width or height was specifically set |
michael@0 | 792 | // XXX Handle eStyleUnit_Enumerated? |
michael@0 | 793 | // (Handling the eStyleUnit_Enumerated types requires |
michael@0 | 794 | // GetPrefSize/GetMinSize methods that don't consider |
michael@0 | 795 | // (min-/max-/)(width/height) properties.) |
michael@0 | 796 | const nsStyleCoord maxWidth = position->mMaxWidth; |
michael@0 | 797 | if (maxWidth.ConvertsToLength()) { |
michael@0 | 798 | aSize.width = nsRuleNode::ComputeCoordPercentCalc(maxWidth, 0); |
michael@0 | 799 | aWidthSet = true; |
michael@0 | 800 | } |
michael@0 | 801 | // percentages and calc() with percentages are treated like 'none' |
michael@0 | 802 | |
michael@0 | 803 | const nsStyleCoord &maxHeight = position->mMaxHeight; |
michael@0 | 804 | if (maxHeight.ConvertsToLength()) { |
michael@0 | 805 | aSize.height = nsRuleNode::ComputeCoordPercentCalc(maxHeight, 0); |
michael@0 | 806 | aHeightSet = true; |
michael@0 | 807 | } |
michael@0 | 808 | // percentages and calc() with percentages are treated like 'none' |
michael@0 | 809 | |
michael@0 | 810 | nsIContent* content = aBox->GetContent(); |
michael@0 | 811 | if (content && content->IsXUL()) { |
michael@0 | 812 | nsAutoString value; |
michael@0 | 813 | nsresult error; |
michael@0 | 814 | |
michael@0 | 815 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxwidth, value); |
michael@0 | 816 | if (!value.IsEmpty()) { |
michael@0 | 817 | value.Trim("%"); |
michael@0 | 818 | |
michael@0 | 819 | nscoord val = |
michael@0 | 820 | nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); |
michael@0 | 821 | aSize.width = val; |
michael@0 | 822 | aWidthSet = true; |
michael@0 | 823 | } |
michael@0 | 824 | |
michael@0 | 825 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxheight, value); |
michael@0 | 826 | if (!value.IsEmpty()) { |
michael@0 | 827 | value.Trim("%"); |
michael@0 | 828 | |
michael@0 | 829 | nscoord val = |
michael@0 | 830 | nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error)); |
michael@0 | 831 | aSize.height = val; |
michael@0 | 832 | |
michael@0 | 833 | aHeightSet = true; |
michael@0 | 834 | } |
michael@0 | 835 | } |
michael@0 | 836 | |
michael@0 | 837 | return (aWidthSet || aHeightSet); |
michael@0 | 838 | } |
michael@0 | 839 | |
michael@0 | 840 | bool |
michael@0 | 841 | nsIFrame::AddCSSFlex(nsBoxLayoutState& aState, nsIFrame* aBox, nscoord& aFlex) |
michael@0 | 842 | { |
michael@0 | 843 | bool flexSet = false; |
michael@0 | 844 | |
michael@0 | 845 | // get the flexibility |
michael@0 | 846 | aFlex = aBox->StyleXUL()->mBoxFlex; |
michael@0 | 847 | |
michael@0 | 848 | // attribute value overrides CSS |
michael@0 | 849 | nsIContent* content = aBox->GetContent(); |
michael@0 | 850 | if (content && content->IsXUL()) { |
michael@0 | 851 | nsresult error; |
michael@0 | 852 | nsAutoString value; |
michael@0 | 853 | |
michael@0 | 854 | content->GetAttr(kNameSpaceID_None, nsGkAtoms::flex, value); |
michael@0 | 855 | if (!value.IsEmpty()) { |
michael@0 | 856 | value.Trim("%"); |
michael@0 | 857 | aFlex = value.ToInteger(&error); |
michael@0 | 858 | flexSet = true; |
michael@0 | 859 | } |
michael@0 | 860 | } |
michael@0 | 861 | |
michael@0 | 862 | if (aFlex < 0) |
michael@0 | 863 | aFlex = 0; |
michael@0 | 864 | if (aFlex >= nscoord_MAX) |
michael@0 | 865 | aFlex = nscoord_MAX - 1; |
michael@0 | 866 | |
michael@0 | 867 | return flexSet || aFlex > 0; |
michael@0 | 868 | } |
michael@0 | 869 | |
michael@0 | 870 | void |
michael@0 | 871 | nsBox::AddBorderAndPadding(nsSize& aSize) |
michael@0 | 872 | { |
michael@0 | 873 | AddBorderAndPadding(this, aSize); |
michael@0 | 874 | } |
michael@0 | 875 | |
michael@0 | 876 | void |
michael@0 | 877 | nsBox::AddBorderAndPadding(nsIFrame* aBox, nsSize& aSize) |
michael@0 | 878 | { |
michael@0 | 879 | nsMargin borderPadding(0,0,0,0); |
michael@0 | 880 | aBox->GetBorderAndPadding(borderPadding); |
michael@0 | 881 | AddMargin(aSize, borderPadding); |
michael@0 | 882 | } |
michael@0 | 883 | |
michael@0 | 884 | void |
michael@0 | 885 | nsBox::AddMargin(nsIFrame* aChild, nsSize& aSize) |
michael@0 | 886 | { |
michael@0 | 887 | nsMargin margin(0,0,0,0); |
michael@0 | 888 | aChild->GetMargin(margin); |
michael@0 | 889 | AddMargin(aSize, margin); |
michael@0 | 890 | } |
michael@0 | 891 | |
michael@0 | 892 | void |
michael@0 | 893 | nsBox::AddMargin(nsSize& aSize, const nsMargin& aMargin) |
michael@0 | 894 | { |
michael@0 | 895 | if (aSize.width != NS_INTRINSICSIZE) |
michael@0 | 896 | aSize.width += aMargin.left + aMargin.right; |
michael@0 | 897 | |
michael@0 | 898 | if (aSize.height != NS_INTRINSICSIZE) |
michael@0 | 899 | aSize.height += aMargin.top + aMargin.bottom; |
michael@0 | 900 | } |
michael@0 | 901 | |
michael@0 | 902 | nscoord |
michael@0 | 903 | nsBox::BoundsCheck(nscoord aMin, nscoord aPref, nscoord aMax) |
michael@0 | 904 | { |
michael@0 | 905 | if (aPref > aMax) |
michael@0 | 906 | aPref = aMax; |
michael@0 | 907 | |
michael@0 | 908 | if (aPref < aMin) |
michael@0 | 909 | aPref = aMin; |
michael@0 | 910 | |
michael@0 | 911 | return aPref; |
michael@0 | 912 | } |
michael@0 | 913 | |
michael@0 | 914 | nsSize |
michael@0 | 915 | nsBox::BoundsCheckMinMax(const nsSize& aMinSize, const nsSize& aMaxSize) |
michael@0 | 916 | { |
michael@0 | 917 | return nsSize(std::max(aMaxSize.width, aMinSize.width), |
michael@0 | 918 | std::max(aMaxSize.height, aMinSize.height)); |
michael@0 | 919 | } |
michael@0 | 920 | |
michael@0 | 921 | nsSize |
michael@0 | 922 | nsBox::BoundsCheck(const nsSize& aMinSize, const nsSize& aPrefSize, const nsSize& aMaxSize) |
michael@0 | 923 | { |
michael@0 | 924 | return nsSize(BoundsCheck(aMinSize.width, aPrefSize.width, aMaxSize.width), |
michael@0 | 925 | BoundsCheck(aMinSize.height, aPrefSize.height, aMaxSize.height)); |
michael@0 | 926 | } |
michael@0 | 927 | |
michael@0 | 928 | #ifdef DEBUG_LAYOUT |
michael@0 | 929 | nsresult |
michael@0 | 930 | nsBox::SetDebug(nsBoxLayoutState& aState, bool aDebug) |
michael@0 | 931 | { |
michael@0 | 932 | return NS_OK; |
michael@0 | 933 | } |
michael@0 | 934 | |
michael@0 | 935 | NS_IMETHODIMP |
michael@0 | 936 | nsBox::GetDebugBoxAt( const nsPoint& aPoint, |
michael@0 | 937 | nsIFrame** aBox) |
michael@0 | 938 | { |
michael@0 | 939 | nsRect thisRect(nsPoint(0,0), GetSize()); |
michael@0 | 940 | if (!thisRect.Contains(aPoint)) |
michael@0 | 941 | return NS_ERROR_FAILURE; |
michael@0 | 942 | |
michael@0 | 943 | nsIFrame* child = GetChildBox(); |
michael@0 | 944 | nsIFrame* hit = nullptr; |
michael@0 | 945 | |
michael@0 | 946 | *aBox = nullptr; |
michael@0 | 947 | while (nullptr != child) { |
michael@0 | 948 | nsresult rv = child->GetDebugBoxAt(aPoint - child->GetOffsetTo(this), &hit); |
michael@0 | 949 | |
michael@0 | 950 | if (NS_SUCCEEDED(rv) && hit) { |
michael@0 | 951 | *aBox = hit; |
michael@0 | 952 | } |
michael@0 | 953 | child = child->GetNextBox(); |
michael@0 | 954 | } |
michael@0 | 955 | |
michael@0 | 956 | // found a child |
michael@0 | 957 | if (*aBox) { |
michael@0 | 958 | return NS_OK; |
michael@0 | 959 | } |
michael@0 | 960 | |
michael@0 | 961 | return NS_ERROR_FAILURE; |
michael@0 | 962 | } |
michael@0 | 963 | |
michael@0 | 964 | |
michael@0 | 965 | nsresult |
michael@0 | 966 | nsBox::GetDebug(bool& aDebug) |
michael@0 | 967 | { |
michael@0 | 968 | aDebug = false; |
michael@0 | 969 | return NS_OK; |
michael@0 | 970 | } |
michael@0 | 971 | |
michael@0 | 972 | #endif |