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