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