layout/xul/nsBox.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial