layout/xul/nsBox.cpp

branch
TOR_BUG_9701
changeset 10
ac0c01689b40
equal deleted inserted replaced
-1:000000000000 0:0c191c0e436d
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/. */
5
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>
24
25 using namespace mozilla;
26
27 #ifdef DEBUG_LAYOUT
28 int32_t gIndent = 0;
29 #endif
30
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
41
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 }
51
52 void
53 nsBox::ListBox(nsAutoString& aResult)
54 {
55 nsAutoString name;
56 GetBoxName(name);
57
58 char addr[100];
59 sprintf(addr, "[@%p] ", static_cast<void*>(this));
60
61 aResult.AppendASCII(addr);
62 aResult.Append(name);
63 aResult.AppendLiteral(" ");
64
65 nsIContent* content = GetContent();
66
67 // add on all the set attributes
68 if (content) {
69 nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content));
70 nsCOMPtr<nsIDOMMozNamedAttrMap> namedMap;
71
72 node->GetAttributes(getter_AddRefs(namedMap));
73 uint32_t length;
74 namedMap->GetLength(&length);
75
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 }
87
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 }
96
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
111
112 #ifdef DEBUG_LAYOUT
113 void
114 nsBox::GetBoxName(nsAutoString& aName)
115 {
116 aName.AssignLiteral("Box");
117 }
118 #endif
119
120 nsresult
121 nsBox::BeginLayout(nsBoxLayoutState& aState)
122 {
123 #ifdef DEBUG_LAYOUT
124
125 nsBoxAddIndents();
126 printf("Layout: ");
127 DumpBox(stdout);
128 printf("\n");
129 gIndent++;
130 #endif
131
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;
136
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 }
145
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());
152
153 #ifdef DEBUG_LAYOUT
154 PropagateDebug(aState);
155 #endif
156
157 return NS_OK;
158 }
159
160 NS_IMETHODIMP
161 nsBox::DoLayout(nsBoxLayoutState& aState)
162 {
163 return NS_OK;
164 }
165
166 nsresult
167 nsBox::EndLayout(nsBoxLayoutState& aState)
168 {
169
170 #ifdef DEBUG_LAYOUT
171 --gIndent;
172 #endif
173
174 return SyncLayout(aState);
175 }
176
177 bool nsBox::gGotTheme = false;
178 nsITheme* nsBox::gTheme = nullptr;
179
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 }
190
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 }
197
198 /* static */ void
199 nsBox::Shutdown()
200 {
201 gGotTheme = false;
202 NS_IF_RELEASE(gTheme);
203 }
204
205 nsresult
206 nsBox::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild)
207 {
208 return NS_OK;
209 }
210
211 nsresult
212 nsIFrame::GetClientRect(nsRect& aClientRect)
213 {
214 aClientRect = mRect;
215 aClientRect.MoveTo(0,0);
216
217 nsMargin borderPadding;
218 GetBorderAndPadding(borderPadding);
219
220 aClientRect.Deflate(borderPadding);
221
222 if (aClientRect.width < 0)
223 aClientRect.width = 0;
224
225 if (aClientRect.height < 0)
226 aClientRect.height = 0;
227
228 // NS_ASSERTION(aClientRect.width >=0 && aClientRect.height >= 0, "Content Size < 0");
229
230 return NS_OK;
231 }
232
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");
237
238 nsRect rect(mRect);
239
240 uint32_t flags = 0;
241 GetLayoutFlags(flags);
242
243 uint32_t stateFlags = aState.LayoutFlags();
244
245 flags |= stateFlags;
246
247 if ((flags & NS_FRAME_NO_MOVE_FRAME) == NS_FRAME_NO_MOVE_FRAME)
248 SetSize(aRect.Size());
249 else
250 SetRect(aRect);
251
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 }
258
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 }
265
266
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 }
279
280 void
281 nsBox::GetLayoutFlags(uint32_t& aFlags)
282 {
283 aFlags = 0;
284 }
285
286
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;
294
295 nsMargin padding;
296 rv = GetPadding(padding);
297 if (NS_FAILED(rv))
298 return rv;
299
300 aBorderAndPadding += padding;
301
302 return rv;
303 }
304
305 nsresult
306 nsBox::GetBorder(nsMargin& aMargin)
307 {
308 aMargin.SizeTo(0,0,0,0);
309
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 }
325
326 aMargin = StyleBorder()->GetComputedBorder();
327
328 return NS_OK;
329 }
330
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;
341
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 }
354
355 aMargin.SizeTo(0,0,0,0);
356 StylePadding()->GetPadding(aMargin);
357
358 return NS_OK;
359 }
360
361 nsresult
362 nsBox::GetMargin(nsMargin& aMargin)
363 {
364 aMargin.SizeTo(0,0,0,0);
365 StyleMargin()->GetMargin(aMargin);
366
367 return NS_OK;
368 }
369
370 void
371 nsBox::SizeNeedsRecalc(nsSize& aSize)
372 {
373 aSize.width = -1;
374 aSize.height = -1;
375 }
376
377 void
378 nsBox::CoordNeedsRecalc(nscoord& aFlex)
379 {
380 aFlex = -1;
381 }
382
383 bool
384 nsBox::DoesNeedRecalc(const nsSize& aSize)
385 {
386 return (aSize.width == -1 || aSize.height == -1);
387 }
388
389 bool
390 nsBox::DoesNeedRecalc(nscoord aCoord)
391 {
392 return (aCoord == -1);
393 }
394
395 nsSize
396 nsBox::GetPrefSize(nsBoxLayoutState& aState)
397 {
398 NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
399
400 nsSize pref(0,0);
401 DISPLAY_PREF_SIZE(this, pref);
402
403 if (IsCollapsed())
404 return pref;
405
406 AddBorderAndPadding(pref);
407 bool widthSet, heightSet;
408 nsIFrame::AddCSSPrefSize(this, pref, widthSet, heightSet);
409
410 nsSize minSize = GetMinSize(aState);
411 nsSize maxSize = GetMaxSize(aState);
412 return BoundsCheck(minSize, pref, maxSize);
413 }
414
415 nsSize
416 nsBox::GetMinSize(nsBoxLayoutState& aState)
417 {
418 NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
419
420 nsSize min(0,0);
421 DISPLAY_MIN_SIZE(this, min);
422
423 if (IsCollapsed())
424 return min;
425
426 AddBorderAndPadding(min);
427 bool widthSet, heightSet;
428 nsIFrame::AddCSSMinSize(aState, this, min, widthSet, heightSet);
429 return min;
430 }
431
432 nsSize
433 nsBox::GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState)
434 {
435 return nsSize(0, 0);
436 }
437
438 nsSize
439 nsBox::GetMaxSize(nsBoxLayoutState& aState)
440 {
441 NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
442
443 nsSize maxSize(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
444 DISPLAY_MAX_SIZE(this, maxSize);
445
446 if (IsCollapsed())
447 return maxSize;
448
449 AddBorderAndPadding(maxSize);
450 bool widthSet, heightSet;
451 nsIFrame::AddCSSMaxSize(this, maxSize, widthSet, heightSet);
452 return maxSize;
453 }
454
455 nscoord
456 nsBox::GetFlex(nsBoxLayoutState& aState)
457 {
458 nscoord flex = 0;
459
460 nsIFrame::AddCSSFlex(aState, this, flex);
461
462 return flex;
463 }
464
465 uint32_t
466 nsIFrame::GetOrdinal()
467 {
468 uint32_t ordinal = StyleXUL()->mBoxOrdinal;
469
470 // When present, attribute value overrides CSS.
471 nsIContent* content = GetContent();
472 if (content && content->IsXUL()) {
473 nsresult error;
474 nsAutoString value;
475
476 content->GetAttr(kNameSpaceID_None, nsGkAtoms::ordinal, value);
477 if (!value.IsEmpty()) {
478 ordinal = value.ToInteger(&error);
479 }
480 }
481
482 return ordinal;
483 }
484
485 nscoord
486 nsBox::GetBoxAscent(nsBoxLayoutState& aState)
487 {
488 if (IsCollapsed())
489 return 0;
490
491 return GetPrefSize(aState).height;
492 }
493
494 bool
495 nsBox::IsCollapsed()
496 {
497 return StyleVisibility()->mVisible == NS_STYLE_VISIBILITY_COLLAPSE;
498 }
499
500 nsresult
501 nsIFrame::Layout(nsBoxLayoutState& aState)
502 {
503 NS_ASSERTION(aState.GetRenderingContext(), "must have rendering context");
504
505 nsBox *box = static_cast<nsBox*>(this);
506 DISPLAY_LAYOUT(box);
507
508 box->BeginLayout(aState);
509
510 box->DoLayout(aState);
511
512 box->EndLayout(aState);
513
514 return NS_OK;
515 }
516
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 }
526
527 nsresult
528 nsBox::SyncLayout(nsBoxLayoutState& aState)
529 {
530 /*
531 if (IsCollapsed()) {
532 CollapseChild(aState, this, true);
533 return NS_OK;
534 }
535 */
536
537
538 if (GetStateBits() & NS_FRAME_IS_DIRTY)
539 Redraw(aState);
540
541 RemoveStateBits(NS_FRAME_HAS_DIRTY_CHILDREN | NS_FRAME_IS_DIRTY
542 | NS_FRAME_FIRST_REFLOW | NS_FRAME_IN_REFLOW);
543
544 nsPresContext* presContext = aState.PresContext();
545
546 uint32_t flags = 0;
547 GetLayoutFlags(flags);
548
549 uint32_t stateFlags = aState.LayoutFlags();
550
551 flags |= stateFlags;
552
553 nsRect visualOverflow;
554
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 }
569
570 FinishAndStoreOverflow(overflowAreas, GetSize());
571 visualOverflow = overflowAreas.VisualOverflow();
572 }
573
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 }
581
582 return NS_OK;
583 }
584
585 nsresult
586 nsIFrame::Redraw(nsBoxLayoutState& aState)
587 {
588 if (aState.PaintingDisabled())
589 return NS_OK;
590
591 // nsStackLayout, at least, expects us to repaint descendants even
592 // if a damage rect is provided
593 InvalidateFrameSubtree();
594
595 return NS_OK;
596 }
597
598 bool
599 nsIFrame::AddCSSPrefSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet)
600 {
601 aWidthSet = false;
602 aHeightSet = false;
603
604 // add in the css min, max, pref
605 const nsStylePosition* position = aBox->StylePosition();
606
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 }
625
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 }
639
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;
647
648 content->GetAttr(kNameSpaceID_None, nsGkAtoms::width, value);
649 if (!value.IsEmpty()) {
650 value.Trim("%");
651
652 aSize.width =
653 nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
654 aWidthSet = true;
655 }
656
657 content->GetAttr(kNameSpaceID_None, nsGkAtoms::height, value);
658 if (!value.IsEmpty()) {
659 value.Trim("%");
660
661 aSize.height =
662 nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
663 aHeightSet = true;
664 }
665 }
666
667 return (aWidthSet && aHeightSet);
668 }
669
670
671 bool
672 nsIFrame::AddCSSMinSize(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize& aSize,
673 bool &aWidthSet, bool &aHeightSet)
674 {
675 aWidthSet = false;
676 aHeightSet = false;
677
678 bool canOverride = true;
679
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 }
701
702 // add in the css min, max, pref
703 const nsStylePosition* position = aBox->StylePosition();
704
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)
728
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)
746
747 nsIContent* content = aBox->GetContent();
748 if (content && content->IsXUL()) {
749 nsAutoString value;
750 nsresult error;
751
752 content->GetAttr(kNameSpaceID_None, nsGkAtoms::minwidth, value);
753 if (!value.IsEmpty())
754 {
755 value.Trim("%");
756
757 nscoord val =
758 nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
759 if (val > aSize.width)
760 aSize.width = val;
761 aWidthSet = true;
762 }
763
764 content->GetAttr(kNameSpaceID_None, nsGkAtoms::minheight, value);
765 if (!value.IsEmpty())
766 {
767 value.Trim("%");
768
769 nscoord val =
770 nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
771 if (val > aSize.height)
772 aSize.height = val;
773
774 aHeightSet = true;
775 }
776 }
777
778 return (aWidthSet && aHeightSet);
779 }
780
781 bool
782 nsIFrame::AddCSSMaxSize(nsIFrame* aBox, nsSize& aSize, bool &aWidthSet, bool &aHeightSet)
783 {
784 aWidthSet = false;
785 aHeightSet = false;
786
787 // add in the css min, max, pref
788 const nsStylePosition* position = aBox->StylePosition();
789
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'
802
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'
809
810 nsIContent* content = aBox->GetContent();
811 if (content && content->IsXUL()) {
812 nsAutoString value;
813 nsresult error;
814
815 content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxwidth, value);
816 if (!value.IsEmpty()) {
817 value.Trim("%");
818
819 nscoord val =
820 nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
821 aSize.width = val;
822 aWidthSet = true;
823 }
824
825 content->GetAttr(kNameSpaceID_None, nsGkAtoms::maxheight, value);
826 if (!value.IsEmpty()) {
827 value.Trim("%");
828
829 nscoord val =
830 nsPresContext::CSSPixelsToAppUnits(value.ToInteger(&error));
831 aSize.height = val;
832
833 aHeightSet = true;
834 }
835 }
836
837 return (aWidthSet || aHeightSet);
838 }
839
840 bool
841 nsIFrame::AddCSSFlex(nsBoxLayoutState& aState, nsIFrame* aBox, nscoord& aFlex)
842 {
843 bool flexSet = false;
844
845 // get the flexibility
846 aFlex = aBox->StyleXUL()->mBoxFlex;
847
848 // attribute value overrides CSS
849 nsIContent* content = aBox->GetContent();
850 if (content && content->IsXUL()) {
851 nsresult error;
852 nsAutoString value;
853
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 }
861
862 if (aFlex < 0)
863 aFlex = 0;
864 if (aFlex >= nscoord_MAX)
865 aFlex = nscoord_MAX - 1;
866
867 return flexSet || aFlex > 0;
868 }
869
870 void
871 nsBox::AddBorderAndPadding(nsSize& aSize)
872 {
873 AddBorderAndPadding(this, aSize);
874 }
875
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 }
883
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 }
891
892 void
893 nsBox::AddMargin(nsSize& aSize, const nsMargin& aMargin)
894 {
895 if (aSize.width != NS_INTRINSICSIZE)
896 aSize.width += aMargin.left + aMargin.right;
897
898 if (aSize.height != NS_INTRINSICSIZE)
899 aSize.height += aMargin.top + aMargin.bottom;
900 }
901
902 nscoord
903 nsBox::BoundsCheck(nscoord aMin, nscoord aPref, nscoord aMax)
904 {
905 if (aPref > aMax)
906 aPref = aMax;
907
908 if (aPref < aMin)
909 aPref = aMin;
910
911 return aPref;
912 }
913
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 }
920
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 }
927
928 #ifdef DEBUG_LAYOUT
929 nsresult
930 nsBox::SetDebug(nsBoxLayoutState& aState, bool aDebug)
931 {
932 return NS_OK;
933 }
934
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;
942
943 nsIFrame* child = GetChildBox();
944 nsIFrame* hit = nullptr;
945
946 *aBox = nullptr;
947 while (nullptr != child) {
948 nsresult rv = child->GetDebugBoxAt(aPoint - child->GetOffsetTo(this), &hit);
949
950 if (NS_SUCCEEDED(rv) && hit) {
951 *aBox = hit;
952 }
953 child = child->GetNextBox();
954 }
955
956 // found a child
957 if (*aBox) {
958 return NS_OK;
959 }
960
961 return NS_ERROR_FAILURE;
962 }
963
964
965 nsresult
966 nsBox::GetDebug(bool& aDebug)
967 {
968 aDebug = false;
969 return NS_OK;
970 }
971
972 #endif

mercurial