Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 sw=2 et tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : //
8 : // Eric Vaughan
9 : // Netscape Communications
10 : //
11 : // See documentation in associated header file
12 : //
13 :
14 : // How boxes layout
15 : // ----------------
16 : // Boxes layout a bit differently than html. html does a bottom up layout. Where boxes do a top down.
17 : // 1) First thing a box does it goes out and askes each child for its min, max, and preferred sizes.
18 : // 2) It then adds them up to determine its size.
19 : // 3) If the box was asked to layout it self intrinically it will layout its children at their preferred size
20 : // otherwise it will layout the child at the size it was told to. It will squeeze or stretch its children if
21 : // Necessary.
22 : //
23 : // However there is a catch. Some html components like block frames can not determine their preferred size.
24 : // this is their size if they were laid out intrinsically. So the box will flow the child to determine this can
25 : // cache the value.
26 :
27 : // Boxes and Incremental Reflow
28 : // ----------------------------
29 : // Boxes layout out top down by adding up their children's min, max, and preferred sizes. Only problem is if a incremental
30 : // reflow occurs. The preferred size of a child deep in the hierarchy could change. And this could change
31 : // any number of syblings around the box. Basically any children in the reflow chain must have their caches cleared
32 : // so when asked for there current size they can relayout themselves.
33 :
34 : #include "nsBoxFrame.h"
35 :
36 : #include "gfxUtils.h"
37 : #include "mozilla/gfx/2D.h"
38 : #include "nsBoxLayoutState.h"
39 : #include "mozilla/dom/Touch.h"
40 : #include "mozilla/Move.h"
41 : #include "nsStyleContext.h"
42 : #include "nsPlaceholderFrame.h"
43 : #include "nsPresContext.h"
44 : #include "nsCOMPtr.h"
45 : #include "nsNameSpaceManager.h"
46 : #include "nsGkAtoms.h"
47 : #include "nsIContent.h"
48 : #include "nsHTMLParts.h"
49 : #include "nsViewManager.h"
50 : #include "nsView.h"
51 : #include "nsIPresShell.h"
52 : #include "nsCSSRendering.h"
53 : #include "nsIServiceManager.h"
54 : #include "nsBoxLayout.h"
55 : #include "nsSprocketLayout.h"
56 : #include "nsIScrollableFrame.h"
57 : #include "nsWidgetsCID.h"
58 : #include "nsCSSAnonBoxes.h"
59 : #include "nsContainerFrame.h"
60 : #include "nsIDOMElement.h"
61 : #include "nsITheme.h"
62 : #include "nsTransform2D.h"
63 : #include "mozilla/EventStateManager.h"
64 : #include "nsIDOMEvent.h"
65 : #include "nsDisplayList.h"
66 : #include "mozilla/Preferences.h"
67 : #include "nsThemeConstants.h"
68 : #include "nsLayoutUtils.h"
69 : #include "nsSliderFrame.h"
70 : #include <algorithm>
71 :
72 : // Needed for Print Preview
73 : #include "nsIURI.h"
74 :
75 : #include "mozilla/TouchEvents.h"
76 :
77 : using namespace mozilla;
78 : using namespace mozilla::dom;
79 : using namespace mozilla::gfx;
80 :
81 : //define DEBUG_REDRAW
82 :
83 : #define DEBUG_SPRING_SIZE 8
84 : #define DEBUG_BORDER_SIZE 2
85 : #define COIL_SIZE 8
86 :
87 : //#define TEST_SANITY
88 :
89 : #ifdef DEBUG_rods
90 : //#define DO_NOISY_REFLOW
91 : #endif
92 :
93 : #ifdef DEBUG_LAYOUT
94 : bool nsBoxFrame::gDebug = false;
95 : nsIFrame* nsBoxFrame::mDebugChild = nullptr;
96 : #endif
97 :
98 : nsIFrame*
99 0 : NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot, nsBoxLayout* aLayoutManager)
100 : {
101 : return new (aPresShell) nsBoxFrame(aContext, nsBoxFrame::kClassID,
102 0 : aIsRoot, aLayoutManager);
103 : }
104 :
105 : nsIFrame*
106 105 : NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
107 : {
108 105 : return new (aPresShell) nsBoxFrame(aContext);
109 : }
110 :
111 105 : NS_IMPL_FRAMEARENA_HELPERS(nsBoxFrame)
112 :
113 : #ifdef DEBUG
114 5714 : NS_QUERYFRAME_HEAD(nsBoxFrame)
115 0 : NS_QUERYFRAME_ENTRY(nsBoxFrame)
116 5714 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
117 : #endif
118 :
119 232 : nsBoxFrame::nsBoxFrame(nsStyleContext* aContext,
120 : ClassID aID,
121 : bool aIsRoot,
122 232 : nsBoxLayout* aLayoutManager)
123 : : nsContainerFrame(aContext, aID)
124 : , mFlex(0)
125 232 : , mAscent(0)
126 : {
127 232 : mState |= NS_STATE_IS_HORIZONTAL;
128 232 : mState |= NS_STATE_AUTO_STRETCH;
129 :
130 232 : if (aIsRoot)
131 2 : mState |= NS_STATE_IS_ROOT;
132 :
133 232 : mValign = vAlign_Top;
134 232 : mHalign = hAlign_Left;
135 :
136 : // if no layout manager specified us the static sprocket layout
137 464 : nsCOMPtr<nsBoxLayout> layout = aLayoutManager;
138 :
139 232 : if (layout == nullptr) {
140 232 : NS_NewSprocketLayout(layout);
141 : }
142 :
143 232 : SetXULLayoutManager(layout);
144 232 : }
145 :
146 56 : nsBoxFrame::~nsBoxFrame()
147 : {
148 56 : }
149 :
150 : void
151 232 : nsBoxFrame::SetInitialChildList(ChildListID aListID,
152 : nsFrameList& aChildList)
153 : {
154 232 : nsContainerFrame::SetInitialChildList(aListID, aChildList);
155 232 : if (aListID == kPrincipalList) {
156 : // initialize our list of infos.
157 464 : nsBoxLayoutState state(PresContext());
158 232 : CheckBoxOrder();
159 232 : if (mLayoutManager)
160 224 : mLayoutManager->ChildrenSet(this, state, mFrames.FirstChild());
161 : }
162 232 : }
163 :
164 : /* virtual */ void
165 623 : nsBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
166 : {
167 623 : nsContainerFrame::DidSetStyleContext(aOldStyleContext);
168 :
169 : // The values that CacheAttributes() computes depend on our style,
170 : // so we need to recompute them here...
171 623 : CacheAttributes();
172 623 : }
173 :
174 : /**
175 : * Initialize us. This is a good time to get the alignment of the box
176 : */
177 : void
178 232 : nsBoxFrame::Init(nsIContent* aContent,
179 : nsContainerFrame* aParent,
180 : nsIFrame* aPrevInFlow)
181 : {
182 232 : nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
183 :
184 232 : if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) {
185 226 : AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
186 : }
187 :
188 232 : MarkIntrinsicISizesDirty();
189 :
190 232 : CacheAttributes();
191 :
192 : #ifdef DEBUG_LAYOUT
193 : // if we are root and this
194 : if (mState & NS_STATE_IS_ROOT) {
195 : GetDebugPref();
196 : }
197 : #endif
198 :
199 232 : UpdateMouseThrough();
200 :
201 : // register access key
202 232 : RegUnregAccessKey(true);
203 232 : }
204 :
205 200 : void nsBoxFrame::UpdateMouseThrough()
206 : {
207 200 : if (mContent) {
208 : static nsIContent::AttrValuesArray strings[] =
209 : {&nsGkAtoms::never, &nsGkAtoms::always, nullptr};
210 400 : switch (mContent->FindAttrValueIn(kNameSpaceID_None,
211 200 : nsGkAtoms::mousethrough, strings, eCaseMatters)) {
212 1 : case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break;
213 3 : case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break;
214 : case 2: {
215 0 : RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS);
216 0 : RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER);
217 0 : break;
218 : }
219 : }
220 : }
221 200 : }
222 :
223 : void
224 855 : nsBoxFrame::CacheAttributes()
225 : {
226 : /*
227 : printf("Caching: ");
228 : XULDumpBox(stdout);
229 : printf("\n");
230 : */
231 :
232 855 : mValign = vAlign_Top;
233 855 : mHalign = hAlign_Left;
234 :
235 855 : bool orient = false;
236 855 : GetInitialOrientation(orient);
237 855 : if (orient)
238 572 : mState |= NS_STATE_IS_HORIZONTAL;
239 : else
240 283 : mState &= ~NS_STATE_IS_HORIZONTAL;
241 :
242 855 : bool normal = true;
243 855 : GetInitialDirection(normal);
244 855 : if (normal)
245 855 : mState |= NS_STATE_IS_DIRECTION_NORMAL;
246 : else
247 0 : mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
248 :
249 855 : GetInitialVAlignment(mValign);
250 855 : GetInitialHAlignment(mHalign);
251 :
252 855 : bool equalSize = false;
253 855 : GetInitialEqualSize(equalSize);
254 855 : if (equalSize)
255 0 : mState |= NS_STATE_EQUAL_SIZE;
256 : else
257 855 : mState &= ~NS_STATE_EQUAL_SIZE;
258 :
259 855 : bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
260 855 : GetInitialAutoStretch(autostretch);
261 855 : if (autostretch)
262 611 : mState |= NS_STATE_AUTO_STRETCH;
263 : else
264 244 : mState &= ~NS_STATE_AUTO_STRETCH;
265 :
266 :
267 : #ifdef DEBUG_LAYOUT
268 : bool debug = mState & NS_STATE_SET_TO_DEBUG;
269 : bool debugSet = GetInitialDebug(debug);
270 : if (debugSet) {
271 : mState |= NS_STATE_DEBUG_WAS_SET;
272 : if (debug)
273 : mState |= NS_STATE_SET_TO_DEBUG;
274 : else
275 : mState &= ~NS_STATE_SET_TO_DEBUG;
276 : } else {
277 : mState &= ~NS_STATE_DEBUG_WAS_SET;
278 : }
279 : #endif
280 855 : }
281 :
282 : #ifdef DEBUG_LAYOUT
283 : bool
284 : nsBoxFrame::GetInitialDebug(bool& aDebug)
285 : {
286 : if (!GetContent())
287 : return false;
288 :
289 : static nsIContent::AttrValuesArray strings[] =
290 : {&nsGkAtoms::_false, &nsGkAtoms::_true, nullptr};
291 : int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None,
292 : nsGkAtoms::debug, strings, eCaseMatters);
293 : if (index >= 0) {
294 : aDebug = index == 1;
295 : return true;
296 : }
297 :
298 : return false;
299 : }
300 : #endif
301 :
302 : bool
303 856 : nsBoxFrame::GetInitialHAlignment(nsBoxFrame::Halignment& aHalign)
304 : {
305 856 : if (!GetContent())
306 0 : return false;
307 :
308 : // XXXdwh Everything inside this if statement is deprecated code.
309 : static nsIContent::AttrValuesArray alignStrings[] =
310 : {&nsGkAtoms::left, &nsGkAtoms::right, nullptr};
311 : static const Halignment alignValues[] = {hAlign_Left, hAlign_Right};
312 1712 : int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
313 1712 : alignStrings, eCaseMatters);
314 856 : if (index >= 0) {
315 0 : aHalign = alignValues[index];
316 0 : return true;
317 : }
318 :
319 : // Now that the deprecated stuff is out of the way, we move on to check the appropriate
320 : // attribute. For horizontal boxes, we are checking the PACK attribute. For vertical boxes
321 : // we are checking the ALIGN attribute.
322 856 : nsIAtom* attrName = IsXULHorizontal() ? nsGkAtoms::pack : nsGkAtoms::align;
323 : static nsIContent::AttrValuesArray strings[] =
324 : {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center, &nsGkAtoms::end, nullptr};
325 : static const Halignment values[] =
326 : {hAlign_Left/*not used*/, hAlign_Left, hAlign_Center, hAlign_Right};
327 856 : index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName,
328 856 : strings, eCaseMatters);
329 :
330 856 : if (index == nsIContent::ATTR_VALUE_NO_MATCH) {
331 : // The attr was present but had a nonsensical value. Revert to the default.
332 0 : return false;
333 : }
334 856 : if (index > 0) {
335 19 : aHalign = values[index];
336 19 : return true;
337 : }
338 :
339 : // Now that we've checked for the attribute it's time to check CSS. For
340 : // horizontal boxes we're checking PACK. For vertical boxes we are checking
341 : // ALIGN.
342 837 : const nsStyleXUL* boxInfo = StyleXUL();
343 837 : if (IsXULHorizontal()) {
344 566 : switch (boxInfo->mBoxPack) {
345 : case StyleBoxPack::Start:
346 439 : aHalign = nsBoxFrame::hAlign_Left;
347 439 : return true;
348 : case StyleBoxPack::Center:
349 127 : aHalign = nsBoxFrame::hAlign_Center;
350 127 : return true;
351 : case StyleBoxPack::End:
352 0 : aHalign = nsBoxFrame::hAlign_Right;
353 0 : return true;
354 : default: // Nonsensical value. Just bail.
355 0 : return false;
356 : }
357 : }
358 : else {
359 271 : switch (boxInfo->mBoxAlign) {
360 : case StyleBoxAlign::Start:
361 0 : aHalign = nsBoxFrame::hAlign_Left;
362 0 : return true;
363 : case StyleBoxAlign::Center:
364 3 : aHalign = nsBoxFrame::hAlign_Center;
365 3 : return true;
366 : case StyleBoxAlign::End:
367 0 : aHalign = nsBoxFrame::hAlign_Right;
368 0 : return true;
369 : default: // Nonsensical value. Just bail.
370 268 : return false;
371 : }
372 : }
373 :
374 : return false;
375 : }
376 :
377 : bool
378 856 : nsBoxFrame::GetInitialVAlignment(nsBoxFrame::Valignment& aValign)
379 : {
380 856 : if (!GetContent())
381 0 : return false;
382 :
383 : static nsIContent::AttrValuesArray valignStrings[] =
384 : {&nsGkAtoms::top, &nsGkAtoms::baseline, &nsGkAtoms::middle, &nsGkAtoms::bottom, nullptr};
385 : static const Valignment valignValues[] =
386 : {vAlign_Top, vAlign_BaseLine, vAlign_Middle, vAlign_Bottom};
387 1712 : int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::valign,
388 1712 : valignStrings, eCaseMatters);
389 856 : if (index >= 0) {
390 0 : aValign = valignValues[index];
391 0 : return true;
392 : }
393 :
394 : // Now that the deprecated stuff is out of the way, we move on to check the appropriate
395 : // attribute. For horizontal boxes, we are checking the ALIGN attribute. For vertical boxes
396 : // we are checking the PACK attribute.
397 856 : nsIAtom* attrName = IsXULHorizontal() ? nsGkAtoms::align : nsGkAtoms::pack;
398 : static nsIContent::AttrValuesArray strings[] =
399 : {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center,
400 : &nsGkAtoms::baseline, &nsGkAtoms::end, nullptr};
401 : static const Valignment values[] =
402 : {vAlign_Top/*not used*/, vAlign_Top, vAlign_Middle, vAlign_BaseLine, vAlign_Bottom};
403 856 : index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName,
404 856 : strings, eCaseMatters);
405 856 : if (index == nsIContent::ATTR_VALUE_NO_MATCH) {
406 : // The attr was present but had a nonsensical value. Revert to the default.
407 0 : return false;
408 : }
409 856 : if (index > 0) {
410 54 : aValign = values[index];
411 54 : return true;
412 : }
413 :
414 : // Now that we've checked for the attribute it's time to check CSS. For
415 : // horizontal boxes we're checking ALIGN. For vertical boxes we are checking
416 : // PACK.
417 802 : const nsStyleXUL* boxInfo = StyleXUL();
418 802 : if (IsXULHorizontal()) {
419 526 : switch (boxInfo->mBoxAlign) {
420 : case StyleBoxAlign::Start:
421 0 : aValign = nsBoxFrame::vAlign_Top;
422 0 : return true;
423 : case StyleBoxAlign::Center:
424 180 : aValign = nsBoxFrame::vAlign_Middle;
425 180 : return true;
426 : case StyleBoxAlign::Baseline:
427 0 : aValign = nsBoxFrame::vAlign_BaseLine;
428 0 : return true;
429 : case StyleBoxAlign::End:
430 2 : aValign = nsBoxFrame::vAlign_Bottom;
431 2 : return true;
432 : default: // Nonsensical value. Just bail.
433 344 : return false;
434 : }
435 : }
436 : else {
437 276 : switch (boxInfo->mBoxPack) {
438 : case StyleBoxPack::Start:
439 273 : aValign = nsBoxFrame::vAlign_Top;
440 273 : return true;
441 : case StyleBoxPack::Center:
442 3 : aValign = nsBoxFrame::vAlign_Middle;
443 3 : return true;
444 : case StyleBoxPack::End:
445 0 : aValign = nsBoxFrame::vAlign_Bottom;
446 0 : return true;
447 : default: // Nonsensical value. Just bail.
448 0 : return false;
449 : }
450 : }
451 :
452 : return false;
453 : }
454 :
455 : void
456 853 : nsBoxFrame::GetInitialOrientation(bool& aIsHorizontal)
457 : {
458 : // see if we are a vertical or horizontal box.
459 853 : if (!GetContent())
460 0 : return;
461 :
462 : // Check the style system first.
463 853 : const nsStyleXUL* boxInfo = StyleXUL();
464 853 : if (boxInfo->mBoxOrient == StyleBoxOrient::Horizontal) {
465 590 : aIsHorizontal = true;
466 : } else {
467 263 : aIsHorizontal = false;
468 : }
469 :
470 : // Now see if we have an attribute. The attribute overrides
471 : // the style system value.
472 : static nsIContent::AttrValuesArray strings[] =
473 : {&nsGkAtoms::vertical, &nsGkAtoms::horizontal, nullptr};
474 1706 : int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::orient,
475 1706 : strings, eCaseMatters);
476 853 : if (index >= 0) {
477 86 : aIsHorizontal = index == 1;
478 : }
479 : }
480 :
481 : void
482 856 : nsBoxFrame::GetInitialDirection(bool& aIsNormal)
483 : {
484 856 : if (!GetContent())
485 0 : return;
486 :
487 856 : if (IsXULHorizontal()) {
488 : // For horizontal boxes only, we initialize our value based off the CSS 'direction' property.
489 : // This means that BiDI users will end up with horizontally inverted chrome.
490 573 : aIsNormal = (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR); // If text runs RTL then so do we.
491 : }
492 : else
493 283 : aIsNormal = true; // Assume a normal direction in the vertical case.
494 :
495 : // Now check the style system to see if we should invert aIsNormal.
496 856 : const nsStyleXUL* boxInfo = StyleXUL();
497 856 : if (boxInfo->mBoxDirection == StyleBoxDirection::Reverse) {
498 0 : aIsNormal = !aIsNormal; // Invert our direction.
499 : }
500 :
501 : // Now see if we have an attribute. The attribute overrides
502 : // the style system value.
503 856 : if (IsXULHorizontal()) {
504 : static nsIContent::AttrValuesArray strings[] =
505 : {&nsGkAtoms::reverse, &nsGkAtoms::ltr, &nsGkAtoms::rtl, nullptr};
506 1146 : int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::dir,
507 1146 : strings, eCaseMatters);
508 573 : if (index >= 0) {
509 0 : bool values[] = {!aIsNormal, true, false};
510 0 : aIsNormal = values[index];
511 : }
512 283 : } else if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir,
513 : nsGkAtoms::reverse, eCaseMatters)) {
514 0 : aIsNormal = !aIsNormal;
515 : }
516 : }
517 :
518 : /* Returns true if it was set.
519 : */
520 : bool
521 856 : nsBoxFrame::GetInitialEqualSize(bool& aEqualSize)
522 : {
523 : // see if we are a vertical or horizontal box.
524 856 : if (!GetContent())
525 0 : return false;
526 :
527 856 : if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::equalsize,
528 : nsGkAtoms::always, eCaseMatters)) {
529 0 : aEqualSize = true;
530 0 : return true;
531 : }
532 :
533 856 : return false;
534 : }
535 :
536 : /* Returns true if it was set.
537 : */
538 : bool
539 856 : nsBoxFrame::GetInitialAutoStretch(bool& aStretch)
540 : {
541 856 : if (!GetContent())
542 0 : return false;
543 :
544 : // Check the align attribute.
545 : static nsIContent::AttrValuesArray strings[] =
546 : {&nsGkAtoms::_empty, &nsGkAtoms::stretch, nullptr};
547 1712 : int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align,
548 1712 : strings, eCaseMatters);
549 856 : if (index != nsIContent::ATTR_MISSING && index != 0) {
550 59 : aStretch = index == 1;
551 59 : return true;
552 : }
553 :
554 : // Check the CSS box-align property.
555 797 : const nsStyleXUL* boxInfo = StyleXUL();
556 797 : aStretch = (boxInfo->mBoxAlign == StyleBoxAlign::Stretch);
557 :
558 797 : return true;
559 : }
560 :
561 : void
562 32 : nsBoxFrame::DidReflow(nsPresContext* aPresContext,
563 : const ReflowInput* aReflowInput,
564 : nsDidReflowStatus aStatus)
565 : {
566 : nsFrameState preserveBits =
567 32 : mState & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
568 32 : nsFrame::DidReflow(aPresContext, aReflowInput, aStatus);
569 32 : mState |= preserveBits;
570 32 : }
571 :
572 : bool
573 438 : nsBoxFrame::HonorPrintBackgroundSettings()
574 : {
575 756 : return (!mContent || !mContent->IsInNativeAnonymousSubtree()) &&
576 756 : nsContainerFrame::HonorPrintBackgroundSettings();
577 : }
578 :
579 : #ifdef DO_NOISY_REFLOW
580 : static int myCounter = 0;
581 : static void printSize(char * aDesc, nscoord aSize)
582 : {
583 : printf(" %s: ", aDesc);
584 : if (aSize == NS_UNCONSTRAINEDSIZE) {
585 : printf("UC");
586 : } else {
587 : printf("%d", aSize);
588 : }
589 : }
590 : #endif
591 :
592 : /* virtual */ nscoord
593 8 : nsBoxFrame::GetMinISize(gfxContext *aRenderingContext)
594 : {
595 : nscoord result;
596 16 : DISPLAY_MIN_WIDTH(this, result);
597 :
598 16 : nsBoxLayoutState state(PresContext(), aRenderingContext);
599 8 : nsSize minSize = GetXULMinSize(state);
600 :
601 : // GetXULMinSize returns border-box width, and we want to return content
602 : // width. Since Reflow uses the reflow state's border and padding, we
603 : // actually just want to subtract what GetXULMinSize added, which is the
604 : // result of GetXULBorderAndPadding.
605 8 : nsMargin bp;
606 8 : GetXULBorderAndPadding(bp);
607 :
608 8 : result = minSize.width - bp.LeftRight();
609 8 : result = std::max(result, 0);
610 :
611 16 : return result;
612 : }
613 :
614 : /* virtual */ nscoord
615 7 : nsBoxFrame::GetPrefISize(gfxContext *aRenderingContext)
616 : {
617 : nscoord result;
618 14 : DISPLAY_PREF_WIDTH(this, result);
619 :
620 14 : nsBoxLayoutState state(PresContext(), aRenderingContext);
621 7 : nsSize prefSize = GetXULPrefSize(state);
622 :
623 : // GetXULPrefSize returns border-box width, and we want to return content
624 : // width. Since Reflow uses the reflow state's border and padding, we
625 : // actually just want to subtract what GetXULPrefSize added, which is the
626 : // result of GetXULBorderAndPadding.
627 7 : nsMargin bp;
628 7 : GetXULBorderAndPadding(bp);
629 :
630 7 : result = prefSize.width - bp.LeftRight();
631 7 : result = std::max(result, 0);
632 :
633 14 : return result;
634 : }
635 :
636 : void
637 32 : nsBoxFrame::Reflow(nsPresContext* aPresContext,
638 : ReflowOutput& aDesiredSize,
639 : const ReflowInput& aReflowInput,
640 : nsReflowStatus& aStatus)
641 : {
642 32 : MarkInReflow();
643 : // If you make changes to this method, please keep nsLeafBoxFrame::Reflow
644 : // in sync, if the changes are applicable there.
645 :
646 32 : DO_GLOBAL_REFLOW_COUNT("nsBoxFrame");
647 64 : DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
648 :
649 32 : NS_ASSERTION(aReflowInput.ComputedWidth() >=0 &&
650 : aReflowInput.ComputedHeight() >= 0, "Computed Size < 0");
651 :
652 : #ifdef DO_NOISY_REFLOW
653 : printf("\n-------------Starting BoxFrame Reflow ----------------------------\n");
654 : printf("%p ** nsBF::Reflow %d ", this, myCounter++);
655 :
656 : printSize("AW", aReflowInput.AvailableWidth());
657 : printSize("AH", aReflowInput.AvailableHeight());
658 : printSize("CW", aReflowInput.ComputedWidth());
659 : printSize("CH", aReflowInput.ComputedHeight());
660 :
661 : printf(" *\n");
662 :
663 : #endif
664 :
665 32 : aStatus.Reset();
666 :
667 : // create the layout state
668 32 : nsBoxLayoutState state(aPresContext, aReflowInput.mRenderingContext,
669 96 : &aReflowInput, aReflowInput.mReflowDepth);
670 :
671 32 : WritingMode wm = aReflowInput.GetWritingMode();
672 : LogicalSize computedSize(wm, aReflowInput.ComputedISize(),
673 32 : aReflowInput.ComputedBSize());
674 :
675 32 : LogicalMargin m = aReflowInput.ComputedLogicalBorderPadding();
676 : // GetXULBorderAndPadding(m);
677 :
678 32 : LogicalSize prefSize(wm);
679 :
680 : // if we are told to layout intrinsic then get our preferred size.
681 32 : NS_ASSERTION(computedSize.ISize(wm) != NS_INTRINSICSIZE,
682 : "computed inline size should always be computed");
683 32 : if (computedSize.BSize(wm) == NS_INTRINSICSIZE) {
684 2 : nsSize physicalPrefSize = GetXULPrefSize(state);
685 2 : nsSize minSize = GetXULMinSize(state);
686 2 : nsSize maxSize = GetXULMaxSize(state);
687 : // XXXbz isn't GetXULPrefSize supposed to bounds-check for us?
688 2 : physicalPrefSize = BoundsCheck(minSize, physicalPrefSize, maxSize);
689 2 : prefSize = LogicalSize(wm, physicalPrefSize);
690 : }
691 :
692 : // get our desiredSize
693 32 : computedSize.ISize(wm) += m.IStart(wm) + m.IEnd(wm);
694 :
695 32 : if (aReflowInput.ComputedBSize() == NS_INTRINSICSIZE) {
696 2 : computedSize.BSize(wm) = prefSize.BSize(wm);
697 : // prefSize is border-box but min/max constraints are content-box.
698 : nscoord blockDirBorderPadding =
699 2 : aReflowInput.ComputedLogicalBorderPadding().BStartEnd(wm);
700 2 : nscoord contentBSize = computedSize.BSize(wm) - blockDirBorderPadding;
701 : // Note: contentHeight might be negative, but that's OK because min-height
702 : // is never negative.
703 2 : computedSize.BSize(wm) = aReflowInput.ApplyMinMaxHeight(contentBSize) +
704 : blockDirBorderPadding;
705 : } else {
706 30 : computedSize.BSize(wm) += m.BStart(wm) + m.BEnd(wm);
707 : }
708 :
709 32 : nsSize physicalSize = computedSize.GetPhysicalSize(wm);
710 64 : nsRect r(mRect.x, mRect.y, physicalSize.width, physicalSize.height);
711 :
712 32 : SetXULBounds(state, r);
713 :
714 : // layout our children
715 32 : XULLayout(state);
716 :
717 : // ok our child could have gotten bigger. So lets get its bounds
718 :
719 : // get the ascent
720 32 : LogicalSize boxSize = GetLogicalSize(wm);
721 32 : nscoord ascent = boxSize.BSize(wm);
722 :
723 : // getting the ascent could be a lot of work. Don't get it if
724 : // we are the root. The viewport doesn't care about it.
725 32 : if (!(mState & NS_STATE_IS_ROOT)) {
726 10 : ascent = GetXULBoxAscent(state);
727 : }
728 :
729 32 : aDesiredSize.SetSize(wm, boxSize);
730 32 : aDesiredSize.SetBlockStartAscent(ascent);
731 :
732 32 : aDesiredSize.mOverflowAreas = GetOverflowAreas();
733 :
734 : #ifdef DO_NOISY_REFLOW
735 : {
736 : printf("%p ** nsBF(done) W:%d H:%d ", this, aDesiredSize.Width(), aDesiredSize.Height());
737 :
738 : if (maxElementSize) {
739 : printf("MW:%d\n", *maxElementWidth);
740 : } else {
741 : printf("MW:?\n");
742 : }
743 :
744 : }
745 : #endif
746 :
747 32 : ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus);
748 :
749 32 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
750 32 : }
751 :
752 : nsSize
753 1801 : nsBoxFrame::GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState)
754 : {
755 1801 : NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
756 : "must have rendering context");
757 :
758 1801 : nsSize size(0,0);
759 3602 : DISPLAY_PREF_SIZE(this, size);
760 1801 : if (!DoesNeedRecalc(mPrefSize)) {
761 1414 : return mPrefSize;
762 : }
763 :
764 : #ifdef DEBUG_LAYOUT
765 : PropagateDebug(aBoxLayoutState);
766 : #endif
767 :
768 387 : if (IsXULCollapsed())
769 17 : return size;
770 :
771 : // if the size was not completely redefined in CSS then ask our children
772 : bool widthSet, heightSet;
773 370 : if (!nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet))
774 : {
775 367 : if (mLayoutManager) {
776 367 : nsSize layoutSize = mLayoutManager->GetXULPrefSize(this, aBoxLayoutState);
777 367 : if (!widthSet)
778 332 : size.width = layoutSize.width;
779 367 : if (!heightSet)
780 360 : size.height = layoutSize.height;
781 : }
782 : else {
783 0 : size = nsBox::GetXULPrefSize(aBoxLayoutState);
784 : }
785 : }
786 :
787 370 : nsSize minSize = GetXULMinSize(aBoxLayoutState);
788 370 : nsSize maxSize = GetXULMaxSize(aBoxLayoutState);
789 370 : mPrefSize = BoundsCheck(minSize, size, maxSize);
790 :
791 370 : return mPrefSize;
792 : }
793 :
794 : nscoord
795 1837 : nsBoxFrame::GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState)
796 : {
797 1837 : if (!DoesNeedRecalc(mAscent))
798 1040 : return mAscent;
799 :
800 : #ifdef DEBUG_LAYOUT
801 : PropagateDebug(aBoxLayoutState);
802 : #endif
803 :
804 797 : if (IsXULCollapsed())
805 125 : return 0;
806 :
807 672 : if (mLayoutManager)
808 672 : mAscent = mLayoutManager->GetAscent(this, aBoxLayoutState);
809 : else
810 0 : mAscent = nsBox::GetXULBoxAscent(aBoxLayoutState);
811 :
812 672 : return mAscent;
813 : }
814 :
815 : nsSize
816 2495 : nsBoxFrame::GetXULMinSize(nsBoxLayoutState& aBoxLayoutState)
817 : {
818 2495 : NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
819 : "must have rendering context");
820 :
821 2495 : nsSize size(0,0);
822 4990 : DISPLAY_MIN_SIZE(this, size);
823 2495 : if (!DoesNeedRecalc(mMinSize)) {
824 2079 : return mMinSize;
825 : }
826 :
827 : #ifdef DEBUG_LAYOUT
828 : PropagateDebug(aBoxLayoutState);
829 : #endif
830 :
831 416 : if (IsXULCollapsed())
832 33 : return size;
833 :
834 : // if the size was not completely redefined in CSS then ask our children
835 : bool widthSet, heightSet;
836 383 : if (!nsIFrame::AddXULMinSize(aBoxLayoutState, this, size, widthSet, heightSet))
837 : {
838 343 : if (mLayoutManager) {
839 343 : nsSize layoutSize = mLayoutManager->GetXULMinSize(this, aBoxLayoutState);
840 343 : if (!widthSet)
841 262 : size.width = layoutSize.width;
842 343 : if (!heightSet)
843 320 : size.height = layoutSize.height;
844 : }
845 : else {
846 0 : size = nsBox::GetXULMinSize(aBoxLayoutState);
847 : }
848 : }
849 :
850 383 : mMinSize = size;
851 :
852 383 : return size;
853 : }
854 :
855 : nsSize
856 1960 : nsBoxFrame::GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState)
857 : {
858 1960 : NS_ASSERTION(aBoxLayoutState.GetRenderingContext(),
859 : "must have rendering context");
860 :
861 1960 : nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
862 3920 : DISPLAY_MAX_SIZE(this, size);
863 1960 : if (!DoesNeedRecalc(mMaxSize)) {
864 1542 : return mMaxSize;
865 : }
866 :
867 : #ifdef DEBUG_LAYOUT
868 : PropagateDebug(aBoxLayoutState);
869 : #endif
870 :
871 418 : if (IsXULCollapsed())
872 29 : return size;
873 :
874 : // if the size was not completely redefined in CSS then ask our children
875 : bool widthSet, heightSet;
876 389 : if (!nsIFrame::AddXULMaxSize(this, size, widthSet, heightSet))
877 : {
878 363 : if (mLayoutManager) {
879 363 : nsSize layoutSize = mLayoutManager->GetXULMaxSize(this, aBoxLayoutState);
880 363 : if (!widthSet)
881 363 : size.width = layoutSize.width;
882 363 : if (!heightSet)
883 363 : size.height = layoutSize.height;
884 : }
885 : else {
886 0 : size = nsBox::GetXULMaxSize(aBoxLayoutState);
887 : }
888 : }
889 :
890 389 : mMaxSize = size;
891 :
892 389 : return size;
893 : }
894 :
895 : nscoord
896 1395 : nsBoxFrame::GetXULFlex()
897 : {
898 1395 : if (!DoesNeedRecalc(mFlex))
899 1031 : return mFlex;
900 :
901 364 : mFlex = nsBox::GetXULFlex();
902 :
903 364 : return mFlex;
904 : }
905 :
906 : /**
907 : * If subclassing please subclass this method not layout.
908 : * layout will call this method.
909 : */
910 : NS_IMETHODIMP
911 594 : nsBoxFrame::DoXULLayout(nsBoxLayoutState& aState)
912 : {
913 594 : uint32_t oldFlags = aState.LayoutFlags();
914 594 : aState.SetLayoutFlags(0);
915 :
916 594 : nsresult rv = NS_OK;
917 594 : if (mLayoutManager) {
918 594 : CoordNeedsRecalc(mAscent);
919 594 : rv = mLayoutManager->XULLayout(this, aState);
920 : }
921 :
922 594 : aState.SetLayoutFlags(oldFlags);
923 :
924 594 : if (HasAbsolutelyPositionedChildren()) {
925 : // Set up a |reflowInput| to pass into ReflowAbsoluteFrames
926 0 : WritingMode wm = GetWritingMode();
927 : ReflowInput reflowInput(aState.PresContext(), this,
928 : aState.GetRenderingContext(),
929 0 : LogicalSize(wm, GetLogicalSize().ISize(wm),
930 0 : NS_UNCONSTRAINEDSIZE));
931 :
932 : // Set up a |desiredSize| to pass into ReflowAbsoluteFrames
933 0 : ReflowOutput desiredSize(reflowInput);
934 0 : desiredSize.Width() = mRect.width;
935 0 : desiredSize.Height() = mRect.height;
936 :
937 : // get the ascent (cribbed from ::Reflow)
938 0 : nscoord ascent = mRect.height;
939 :
940 : // getting the ascent could be a lot of work. Don't get it if
941 : // we are the root. The viewport doesn't care about it.
942 0 : if (!(mState & NS_STATE_IS_ROOT)) {
943 0 : ascent = GetXULBoxAscent(aState);
944 : }
945 0 : desiredSize.SetBlockStartAscent(ascent);
946 0 : desiredSize.mOverflowAreas = GetOverflowAreas();
947 :
948 0 : AddStateBits(NS_FRAME_IN_REFLOW);
949 : // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
950 : // (just a dummy value; hopefully that's OK)
951 0 : nsReflowStatus reflowStatus;
952 0 : ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
953 0 : reflowInput, reflowStatus);
954 0 : RemoveStateBits(NS_FRAME_IN_REFLOW);
955 : }
956 :
957 594 : return rv;
958 : }
959 :
960 : void
961 56 : nsBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
962 : {
963 : // unregister access key
964 56 : RegUnregAccessKey(false);
965 :
966 : // clean up the container box's layout manager and child boxes
967 56 : SetXULLayoutManager(nullptr);
968 :
969 56 : nsContainerFrame::DestroyFrom(aDestructRoot);
970 56 : }
971 :
972 : #ifdef DEBUG_LAYOUT
973 : nsresult
974 : nsBoxFrame::SetXULDebug(nsBoxLayoutState& aState, bool aDebug)
975 : {
976 : // see if our state matches the given debug state
977 : bool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG;
978 : bool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet);
979 :
980 : // if it doesn't then tell each child below us the new debug state
981 : if (debugChanged)
982 : {
983 : if (aDebug) {
984 : mState |= NS_STATE_CURRENTLY_IN_DEBUG;
985 : } else {
986 : mState &= ~NS_STATE_CURRENTLY_IN_DEBUG;
987 : }
988 :
989 : SetDebugOnChildList(aState, mFirstChild, aDebug);
990 :
991 : MarkIntrinsicISizesDirty();
992 : }
993 :
994 : return NS_OK;
995 : }
996 : #endif
997 :
998 : /* virtual */ void
999 1285 : nsBoxFrame::MarkIntrinsicISizesDirty()
1000 : {
1001 1285 : SizeNeedsRecalc(mPrefSize);
1002 1285 : SizeNeedsRecalc(mMinSize);
1003 1285 : SizeNeedsRecalc(mMaxSize);
1004 1285 : CoordNeedsRecalc(mFlex);
1005 1285 : CoordNeedsRecalc(mAscent);
1006 :
1007 1285 : if (mLayoutManager) {
1008 2444 : nsBoxLayoutState state(PresContext());
1009 1222 : mLayoutManager->IntrinsicISizesDirty(this, state);
1010 : }
1011 :
1012 : // Don't call base class method, since everything it does is within an
1013 : // IsXULBoxWrapped check.
1014 1285 : }
1015 :
1016 : void
1017 13 : nsBoxFrame::RemoveFrame(ChildListID aListID,
1018 : nsIFrame* aOldFrame)
1019 : {
1020 13 : NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
1021 13 : nsPresContext* presContext = PresContext();
1022 26 : nsBoxLayoutState state(presContext);
1023 :
1024 : // remove the child frame
1025 13 : mFrames.RemoveFrame(aOldFrame);
1026 :
1027 : // notify the layout manager
1028 13 : if (mLayoutManager)
1029 13 : mLayoutManager->ChildrenRemoved(this, state, aOldFrame);
1030 :
1031 : // destroy the child frame
1032 13 : aOldFrame->Destroy();
1033 :
1034 : // mark us dirty and generate a reflow command
1035 13 : PresContext()->PresShell()->
1036 13 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
1037 26 : NS_FRAME_HAS_DIRTY_CHILDREN);
1038 13 : }
1039 :
1040 : void
1041 22 : nsBoxFrame::InsertFrames(ChildListID aListID,
1042 : nsIFrame* aPrevFrame,
1043 : nsFrameList& aFrameList)
1044 : {
1045 22 : NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
1046 : "inserting after sibling frame with different parent");
1047 22 : NS_ASSERTION(!aPrevFrame || mFrames.ContainsFrame(aPrevFrame),
1048 : "inserting after sibling frame not in our child list");
1049 22 : NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
1050 44 : nsBoxLayoutState state(PresContext());
1051 :
1052 : // insert the child frames
1053 : const nsFrameList::Slice& newFrames =
1054 22 : mFrames.InsertFrames(this, aPrevFrame, aFrameList);
1055 :
1056 : // notify the layout manager
1057 22 : if (mLayoutManager)
1058 22 : mLayoutManager->ChildrenInserted(this, state, aPrevFrame, newFrames);
1059 :
1060 : // Make sure to check box order _after_ notifying the layout
1061 : // manager; otherwise the slice we give the layout manager will
1062 : // just be bogus. If the layout manager cares about the order, we
1063 : // just lose.
1064 22 : CheckBoxOrder();
1065 :
1066 : #ifdef DEBUG_LAYOUT
1067 : // if we are in debug make sure our children are in debug as well.
1068 : if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
1069 : SetDebugOnChildList(state, mFrames.FirstChild(), true);
1070 : #endif
1071 :
1072 22 : PresContext()->PresShell()->
1073 22 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
1074 44 : NS_FRAME_HAS_DIRTY_CHILDREN);
1075 22 : }
1076 :
1077 :
1078 : void
1079 8 : nsBoxFrame::AppendFrames(ChildListID aListID,
1080 : nsFrameList& aFrameList)
1081 : {
1082 8 : NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids");
1083 16 : nsBoxLayoutState state(PresContext());
1084 :
1085 : // append the new frames
1086 8 : const nsFrameList::Slice& newFrames = mFrames.AppendFrames(this, aFrameList);
1087 :
1088 : // notify the layout manager
1089 8 : if (mLayoutManager)
1090 0 : mLayoutManager->ChildrenAppended(this, state, newFrames);
1091 :
1092 : // Make sure to check box order _after_ notifying the layout
1093 : // manager; otherwise the slice we give the layout manager will
1094 : // just be bogus. If the layout manager cares about the order, we
1095 : // just lose.
1096 8 : CheckBoxOrder();
1097 :
1098 : #ifdef DEBUG_LAYOUT
1099 : // if we are in debug make sure our children are in debug as well.
1100 : if (mState & NS_STATE_CURRENTLY_IN_DEBUG)
1101 : SetDebugOnChildList(state, mFrames.FirstChild(), true);
1102 : #endif
1103 :
1104 : // XXXbz why is this NS_FRAME_FIRST_REFLOW check here?
1105 8 : if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
1106 0 : PresContext()->PresShell()->
1107 0 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
1108 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
1109 : }
1110 8 : }
1111 :
1112 : /* virtual */ nsContainerFrame*
1113 688 : nsBoxFrame::GetContentInsertionFrame()
1114 : {
1115 688 : if (GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK)
1116 0 : return PrincipalChildList().FirstChild()->GetContentInsertionFrame();
1117 688 : return nsContainerFrame::GetContentInsertionFrame();
1118 : }
1119 :
1120 : nsresult
1121 114 : nsBoxFrame::AttributeChanged(int32_t aNameSpaceID,
1122 : nsIAtom* aAttribute,
1123 : int32_t aModType)
1124 : {
1125 114 : nsresult rv = nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
1126 114 : aModType);
1127 :
1128 : // Ignore 'width', 'height', 'screenX', 'screenY' and 'sizemode' on a
1129 : // <window>.
1130 228 : if (mContent->IsAnyOfXULElements(nsGkAtoms::window,
1131 : nsGkAtoms::page,
1132 : nsGkAtoms::dialog,
1133 119 : nsGkAtoms::wizard) &&
1134 5 : (nsGkAtoms::width == aAttribute ||
1135 3 : nsGkAtoms::height == aAttribute ||
1136 2 : nsGkAtoms::screenX == aAttribute ||
1137 2 : nsGkAtoms::screenY == aAttribute ||
1138 1 : nsGkAtoms::sizemode == aAttribute)) {
1139 2 : return rv;
1140 : }
1141 :
1142 224 : if (aAttribute == nsGkAtoms::width ||
1143 224 : aAttribute == nsGkAtoms::height ||
1144 224 : aAttribute == nsGkAtoms::align ||
1145 224 : aAttribute == nsGkAtoms::valign ||
1146 224 : aAttribute == nsGkAtoms::left ||
1147 224 : aAttribute == nsGkAtoms::top ||
1148 224 : aAttribute == nsGkAtoms::right ||
1149 224 : aAttribute == nsGkAtoms::bottom ||
1150 224 : aAttribute == nsGkAtoms::start ||
1151 224 : aAttribute == nsGkAtoms::end ||
1152 224 : aAttribute == nsGkAtoms::minwidth ||
1153 224 : aAttribute == nsGkAtoms::maxwidth ||
1154 224 : aAttribute == nsGkAtoms::minheight ||
1155 224 : aAttribute == nsGkAtoms::maxheight ||
1156 224 : aAttribute == nsGkAtoms::flex ||
1157 223 : aAttribute == nsGkAtoms::orient ||
1158 222 : aAttribute == nsGkAtoms::pack ||
1159 222 : aAttribute == nsGkAtoms::dir ||
1160 222 : aAttribute == nsGkAtoms::mousethrough ||
1161 111 : aAttribute == nsGkAtoms::equalsize) {
1162 :
1163 2 : if (aAttribute == nsGkAtoms::align ||
1164 2 : aAttribute == nsGkAtoms::valign ||
1165 1 : aAttribute == nsGkAtoms::orient ||
1166 0 : aAttribute == nsGkAtoms::pack ||
1167 : #ifdef DEBUG_LAYOUT
1168 : aAttribute == nsGkAtoms::debug ||
1169 : #endif
1170 0 : aAttribute == nsGkAtoms::dir) {
1171 :
1172 1 : mValign = nsBoxFrame::vAlign_Top;
1173 1 : mHalign = nsBoxFrame::hAlign_Left;
1174 :
1175 1 : bool orient = true;
1176 1 : GetInitialOrientation(orient);
1177 1 : if (orient)
1178 1 : mState |= NS_STATE_IS_HORIZONTAL;
1179 : else
1180 0 : mState &= ~NS_STATE_IS_HORIZONTAL;
1181 :
1182 1 : bool normal = true;
1183 1 : GetInitialDirection(normal);
1184 1 : if (normal)
1185 1 : mState |= NS_STATE_IS_DIRECTION_NORMAL;
1186 : else
1187 0 : mState &= ~NS_STATE_IS_DIRECTION_NORMAL;
1188 :
1189 1 : GetInitialVAlignment(mValign);
1190 1 : GetInitialHAlignment(mHalign);
1191 :
1192 1 : bool equalSize = false;
1193 1 : GetInitialEqualSize(equalSize);
1194 1 : if (equalSize)
1195 0 : mState |= NS_STATE_EQUAL_SIZE;
1196 : else
1197 1 : mState &= ~NS_STATE_EQUAL_SIZE;
1198 :
1199 : #ifdef DEBUG_LAYOUT
1200 : bool debug = mState & NS_STATE_SET_TO_DEBUG;
1201 : bool debugSet = GetInitialDebug(debug);
1202 : if (debugSet) {
1203 : mState |= NS_STATE_DEBUG_WAS_SET;
1204 :
1205 : if (debug)
1206 : mState |= NS_STATE_SET_TO_DEBUG;
1207 : else
1208 : mState &= ~NS_STATE_SET_TO_DEBUG;
1209 : } else {
1210 : mState &= ~NS_STATE_DEBUG_WAS_SET;
1211 : }
1212 : #endif
1213 :
1214 1 : bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH);
1215 1 : GetInitialAutoStretch(autostretch);
1216 1 : if (autostretch)
1217 1 : mState |= NS_STATE_AUTO_STRETCH;
1218 : else
1219 0 : mState &= ~NS_STATE_AUTO_STRETCH;
1220 : }
1221 0 : else if (aAttribute == nsGkAtoms::left ||
1222 0 : aAttribute == nsGkAtoms::top ||
1223 0 : aAttribute == nsGkAtoms::right ||
1224 0 : aAttribute == nsGkAtoms::bottom ||
1225 0 : aAttribute == nsGkAtoms::start ||
1226 0 : aAttribute == nsGkAtoms::end) {
1227 0 : mState &= ~NS_STATE_STACK_NOT_POSITIONED;
1228 : }
1229 0 : else if (aAttribute == nsGkAtoms::mousethrough) {
1230 0 : UpdateMouseThrough();
1231 : }
1232 :
1233 1 : PresContext()->PresShell()->
1234 1 : FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
1235 : }
1236 111 : else if (aAttribute == nsGkAtoms::ordinal) {
1237 0 : nsIFrame* parent = GetParentXULBox(this);
1238 : // If our parent is not a box, there's not much we can do... but in that
1239 : // case our ordinal doesn't matter anyway, so that's ok.
1240 : // Also don't bother with popup frames since they are kept on the
1241 : // kPopupList and XULRelayoutChildAtOrdinal() only handles
1242 : // principal children.
1243 0 : if (parent && !(GetStateBits() & NS_FRAME_OUT_OF_FLOW) &&
1244 0 : StyleDisplay()->mDisplay != mozilla::StyleDisplay::MozPopup) {
1245 0 : parent->XULRelayoutChildAtOrdinal(this);
1246 : // XXXldb Should this instead be a tree change on the child or parent?
1247 0 : PresContext()->PresShell()->
1248 : FrameNeedsReflow(parent, nsIPresShell::eStyleChange,
1249 0 : NS_FRAME_IS_DIRTY);
1250 : }
1251 : }
1252 : // If the accesskey changed, register for the new value
1253 : // The old value has been unregistered in nsXULElement::SetAttr
1254 111 : else if (aAttribute == nsGkAtoms::accesskey) {
1255 0 : RegUnregAccessKey(true);
1256 : }
1257 111 : else if (aAttribute == nsGkAtoms::rows &&
1258 0 : mContent->IsXULElement(nsGkAtoms::tree)) {
1259 : // Reflow ourselves and all our children if "rows" changes, since
1260 : // nsTreeBodyFrame's layout reads this from its parent (this frame).
1261 0 : PresContext()->PresShell()->
1262 0 : FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
1263 : }
1264 :
1265 112 : return rv;
1266 : }
1267 :
1268 : #ifdef DEBUG_LAYOUT
1269 : void
1270 : nsBoxFrame::GetDebugPref()
1271 : {
1272 : gDebug = Preferences::GetBool("xul.debug.box");
1273 : }
1274 :
1275 : class nsDisplayXULDebug : public nsDisplayItem {
1276 : public:
1277 : nsDisplayXULDebug(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) :
1278 : nsDisplayItem(aBuilder, aFrame) {
1279 : MOZ_COUNT_CTOR(nsDisplayXULDebug);
1280 : }
1281 : #ifdef NS_BUILD_REFCNT_LOGGING
1282 : virtual ~nsDisplayXULDebug() {
1283 : MOZ_COUNT_DTOR(nsDisplayXULDebug);
1284 : }
1285 : #endif
1286 :
1287 : virtual void HitTest(nsDisplayListBuilder* aBuilder, nsRect aRect,
1288 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
1289 : nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2);
1290 : static_cast<nsBoxFrame*>(mFrame)->
1291 : DisplayDebugInfoFor(this, rectCenter - ToReferenceFrame());
1292 : aOutFrames->AppendElement(this);
1293 : }
1294 : virtual void Paint(nsDisplayListBuilder* aBuilder
1295 : gfxContext* aCtx);
1296 : NS_DISPLAY_DECL_NAME("XULDebug", TYPE_XUL_DEBUG)
1297 : };
1298 :
1299 : void
1300 : nsDisplayXULDebug::Paint(nsDisplayListBuilder* aBuilder,
1301 : gfxContext* aCtx)
1302 : {
1303 : static_cast<nsBoxFrame*>(mFrame)->
1304 : PaintXULDebugOverlay(*aCtx->GetDrawTarget(), ToReferenceFrame());
1305 : }
1306 :
1307 : static void
1308 : PaintXULDebugBackground(nsIFrame* aFrame, DrawTarget* aDrawTarget,
1309 : const nsRect& aDirtyRect, nsPoint aPt)
1310 : {
1311 : static_cast<nsBoxFrame*>(aFrame)->PaintXULDebugBackground(aDrawTarget, aPt);
1312 : }
1313 : #endif
1314 :
1315 : void
1316 1916 : nsBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
1317 : const nsRect& aDirtyRect,
1318 : const nsDisplayListSet& aLists)
1319 : {
1320 1916 : bool forceLayer = false;
1321 :
1322 1916 : if (GetContent()->IsXULElement()) {
1323 : // forcelayer is only supported on XUL elements with box layout
1324 1796 : if (GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
1325 0 : forceLayer = true;
1326 : }
1327 : // Check for frames that are marked as a part of the region used
1328 : // in calculating glass margins on Windows.
1329 1796 : const nsStyleDisplay* styles = StyleDisplay();
1330 1796 : if (styles && styles->mAppearance == NS_THEME_WIN_EXCLUDE_GLASS) {
1331 0 : aBuilder->AddWindowExcludeGlassRegion(
1332 0 : nsRect(aBuilder->ToReferenceFrame(this), GetSize()));
1333 : }
1334 : }
1335 :
1336 3832 : nsDisplayListCollection tempLists;
1337 1916 : const nsDisplayListSet& destination = forceLayer ? tempLists : aLists;
1338 :
1339 1916 : DisplayBorderBackgroundOutline(aBuilder, destination);
1340 :
1341 : #ifdef DEBUG_LAYOUT
1342 : if (mState & NS_STATE_CURRENTLY_IN_DEBUG) {
1343 : destination.BorderBackground()->AppendNewToTop(new (aBuilder)
1344 : nsDisplayGeneric(aBuilder, this, PaintXULDebugBackground,
1345 : "XULDebugBackground"));
1346 : destination.Outlines()->AppendNewToTop(new (aBuilder)
1347 : nsDisplayXULDebug(aBuilder, this));
1348 : }
1349 : #endif
1350 :
1351 3832 : Maybe<nsDisplayListBuilder::AutoContainerASRTracker> contASRTracker;
1352 1916 : if (forceLayer) {
1353 0 : contASRTracker.emplace(aBuilder);
1354 : }
1355 :
1356 1916 : BuildDisplayListForChildren(aBuilder, aDirtyRect, destination);
1357 :
1358 : // see if we have to draw a selection frame around this container
1359 1916 : DisplaySelectionOverlay(aBuilder, destination.Content());
1360 :
1361 1916 : if (forceLayer) {
1362 : // This is a bit of a hack. Collect up all descendant display items
1363 : // and merge them into a single Content() list. This can cause us
1364 : // to violate CSS stacking order, but forceLayer is a magic
1365 : // XUL-only extension anyway.
1366 0 : nsDisplayList masterList;
1367 0 : masterList.AppendToTop(tempLists.BorderBackground());
1368 0 : masterList.AppendToTop(tempLists.BlockBorderBackgrounds());
1369 0 : masterList.AppendToTop(tempLists.Floats());
1370 0 : masterList.AppendToTop(tempLists.Content());
1371 0 : masterList.AppendToTop(tempLists.PositionedDescendants());
1372 0 : masterList.AppendToTop(tempLists.Outlines());
1373 :
1374 0 : const ActiveScrolledRoot* ownLayerASR = contASRTracker->GetContainerASR();
1375 :
1376 0 : DisplayListClipState::AutoSaveRestore ownLayerClipState(aBuilder);
1377 0 : ownLayerClipState.ClearUpToASR(ownLayerASR);
1378 :
1379 : // Wrap the list to make it its own layer
1380 0 : aLists.Content()->AppendNewToTop(new (aBuilder)
1381 0 : nsDisplayOwnLayer(aBuilder, this, &masterList, ownLayerASR));
1382 : }
1383 1916 : }
1384 :
1385 : void
1386 1745 : nsBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder,
1387 : const nsRect& aDirtyRect,
1388 : const nsDisplayListSet& aLists)
1389 : {
1390 1745 : nsIFrame* kid = mFrames.FirstChild();
1391 : // Put each child's background onto the BlockBorderBackgrounds list
1392 : // to emulate the existing two-layer XUL painting scheme.
1393 1745 : nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
1394 : // The children should be in the right order
1395 9479 : while (kid) {
1396 3867 : BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set);
1397 3867 : kid = kid->GetNextSibling();
1398 : }
1399 1745 : }
1400 :
1401 : // REVIEW: PaintChildren did a few things none of which are a big deal
1402 : // anymore:
1403 : // * Paint some debugging rects for this frame.
1404 : // This is done by nsDisplayXULDebugBackground, which goes in the
1405 : // BorderBackground() layer so it isn't clipped by OVERFLOW_CLIP.
1406 : // * Apply OVERFLOW_CLIP to the children.
1407 : // This is now in nsFrame::BuildDisplayListForStackingContext/Child.
1408 : // * Actually paint the children.
1409 : // Moved to BuildDisplayList.
1410 : // * Paint per-kid debug information.
1411 : // This is done by nsDisplayXULDebug, which is in the Outlines()
1412 : // layer so it goes on top. This means it is not clipped by OVERFLOW_CLIP,
1413 : // whereas it did used to respect OVERFLOW_CLIP, but too bad.
1414 : #ifdef DEBUG_LAYOUT
1415 : void
1416 : nsBoxFrame::PaintXULDebugBackground(DrawTarget* aDrawTarget, nsPoint aPt)
1417 : {
1418 : nsMargin border;
1419 : GetXULBorder(border);
1420 :
1421 : nsMargin debugBorder;
1422 : nsMargin debugMargin;
1423 : nsMargin debugPadding;
1424 :
1425 : bool isHorizontal = IsXULHorizontal();
1426 :
1427 : GetDebugBorder(debugBorder);
1428 : PixelMarginToTwips(debugBorder);
1429 :
1430 : GetDebugMargin(debugMargin);
1431 : PixelMarginToTwips(debugMargin);
1432 :
1433 : GetDebugPadding(debugPadding);
1434 : PixelMarginToTwips(debugPadding);
1435 :
1436 : nsRect inner(mRect);
1437 : inner.MoveTo(aPt);
1438 : inner.Deflate(debugMargin);
1439 : inner.Deflate(border);
1440 : //nsRect borderRect(inner);
1441 :
1442 : int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
1443 :
1444 : ColorPattern color(ToDeviceColor(isHorizontal ? Color(0.f, 0.f, 1.f, 1.f) :
1445 : Color(1.f, 0.f, 0.f, 1.f)));
1446 :
1447 : //left
1448 : nsRect r(inner);
1449 : r.width = debugBorder.left;
1450 : aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
1451 :
1452 : // top
1453 : r = inner;
1454 : r.height = debugBorder.top;
1455 : aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
1456 :
1457 : //right
1458 : r = inner;
1459 : r.x = r.x + r.width - debugBorder.right;
1460 : r.width = debugBorder.right;
1461 : aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
1462 :
1463 : //bottom
1464 : r = inner;
1465 : r.y = r.y + r.height - debugBorder.bottom;
1466 : r.height = debugBorder.bottom;
1467 : aDrawTarget->FillRect(NSRectToRect(r, appUnitsPerDevPixel), color);
1468 :
1469 : // If we have dirty children or we are dirty place a green border around us.
1470 : if (NS_SUBTREE_DIRTY(this)) {
1471 : nsRect dirty(inner);
1472 : ColorPattern green(ToDeviceColor(Color(0.f, 1.f, 0.f, 1.f)));
1473 : aDrawTarget->StrokeRect(NSRectToRect(dirty, appUnitsPerDevPixel), green);
1474 : }
1475 : }
1476 :
1477 : void
1478 : nsBoxFrame::PaintXULDebugOverlay(DrawTarget& aDrawTarget, nsPoint aPt)
1479 : {
1480 : nsMargin border;
1481 : GetXULBorder(border);
1482 :
1483 : nsMargin debugMargin;
1484 : GetDebugMargin(debugMargin);
1485 : PixelMarginToTwips(debugMargin);
1486 :
1487 : nsRect inner(mRect);
1488 : inner.MoveTo(aPt);
1489 : inner.Deflate(debugMargin);
1490 : inner.Deflate(border);
1491 :
1492 : nscoord onePixel = GetPresContext()->IntScaledPixelsToTwips(1);
1493 :
1494 : kid = nsBox::GetChildXULBox(this);
1495 : while (nullptr != kid) {
1496 : bool isHorizontal = IsXULHorizontal();
1497 :
1498 : nscoord x, y, borderSize, spacerSize;
1499 :
1500 : nsRect cr(kid->mRect);
1501 : nsMargin margin;
1502 : kid->GetXULMargin(margin);
1503 : cr.Inflate(margin);
1504 :
1505 : if (isHorizontal)
1506 : {
1507 : cr.y = inner.y;
1508 : x = cr.x;
1509 : y = cr.y + onePixel;
1510 : spacerSize = debugBorder.top - onePixel*4;
1511 : } else {
1512 : cr.x = inner.x;
1513 : x = cr.y;
1514 : y = cr.x + onePixel;
1515 : spacerSize = debugBorder.left - onePixel*4;
1516 : }
1517 :
1518 : nscoord flex = kid->GetXULFlex();
1519 :
1520 : if (!kid->IsXULCollapsed()) {
1521 : if (isHorizontal)
1522 : borderSize = cr.width;
1523 : else
1524 : borderSize = cr.height;
1525 :
1526 : DrawSpacer(GetPresContext(), aDrawTarget, isHorizontal, flex, x, y, borderSize, spacerSize);
1527 : }
1528 :
1529 : kid = GetNextXULBox(kid);
1530 : }
1531 : }
1532 : #endif
1533 :
1534 : #ifdef DEBUG_LAYOUT
1535 : void
1536 : nsBoxFrame::GetBoxName(nsAutoString& aName)
1537 : {
1538 : GetFrameName(aName);
1539 : }
1540 : #endif
1541 :
1542 : #ifdef DEBUG_FRAME_DUMP
1543 : nsresult
1544 0 : nsBoxFrame::GetFrameName(nsAString& aResult) const
1545 : {
1546 0 : return MakeFrameName(NS_LITERAL_STRING("Box"), aResult);
1547 : }
1548 : #endif
1549 :
1550 : #ifdef DEBUG_LAYOUT
1551 : nsresult
1552 : nsBoxFrame::GetXULDebug(bool& aDebug)
1553 : {
1554 : aDebug = (mState & NS_STATE_CURRENTLY_IN_DEBUG);
1555 : return NS_OK;
1556 : }
1557 : #endif
1558 :
1559 : // REVIEW: nsBoxFrame::GetFrameForPoint is a problem because of 'mousethrough'
1560 : // attribute support. Here's how it works:
1561 : // * For each child frame F, we determine the target frame T(F) by recursively
1562 : // invoking GetFrameForPoint on the child
1563 : // * Let F' be the last child frame such that T(F') doesn't have mousethrough.
1564 : // If F' exists, return T(F')
1565 : // * Otherwise let F'' be the first child frame such that T(F'') is non-null.
1566 : // If F'' exists, return T(F'')
1567 : // * Otherwise return this frame, if this frame contains the point
1568 : // * Otherwise return null
1569 : // It's not clear how this should work for more complex z-ordering situations.
1570 : // The basic principle seems to be that if a frame F has a descendant
1571 : // 'mousethrough' frame that includes the target position, then F
1572 : // will not receive events (unless it overrides GetFrameForPoint).
1573 : // A 'mousethrough' frame will only receive an event if, after applying that rule,
1574 : // all eligible frames are 'mousethrough'; the bottom-most inner-most 'mousethrough'
1575 : // frame is then chosen (the first eligible frame reached in a
1576 : // traversal of the frame tree --- pre/post is irrelevant since ancestors
1577 : // of the mousethrough frames can't be eligible).
1578 : // IMHO this is very bogus and adds a great deal of complexity for something
1579 : // that is very rarely used. So I'm redefining 'mousethrough' to the following:
1580 : // a frame with mousethrough is transparent to mouse events. This is compatible
1581 : // with the way 'mousethrough' is used in Seamonkey's navigator.xul and
1582 : // Firefox's browser.xul. The only other place it's used is in the 'expander'
1583 : // XBL binding, which in our tree is only used by Thunderbird SMIME Advanced
1584 : // Preferences, and I can't figure out what that does, so I'll have to test it.
1585 : // If it's broken I'll probably just change the binding to use it more sensibly.
1586 : // This new behaviour is implemented in nsDisplayList::HitTest.
1587 : // REVIEW: This debug-box stuff is annoying. I'm just going to put debug boxes
1588 : // in the outline layer and avoid GetDebugBoxAt.
1589 :
1590 : // REVIEW: GetCursor had debug-only event dumping code. I have replaced it
1591 : // with instrumentation in nsDisplayXULDebug.
1592 :
1593 : #ifdef DEBUG_LAYOUT
1594 : void
1595 : nsBoxFrame::DrawLine(DrawTarget& aDrawTarget, bool aHorizontal, nscoord x1, nscoord y1, nscoord x2, nscoord y2)
1596 : {
1597 : nsPoint p1(x1, y1);
1598 : nsPoint p2(x2, y2);
1599 : if (!aHorizontal) {
1600 : Swap(p1.x, p1.y);
1601 : Swap(p2.x, p2.y);
1602 : }
1603 : ColorPattern white(ToDeviceColor(Color(1.f, 1.f, 1.f, 1.f)));
1604 : StrokeLineWithSnapping(p1, p2, PresContext()->AppUnitsPerDevPixel(),
1605 : aDrawTarget, color);
1606 : }
1607 :
1608 : void
1609 : nsBoxFrame::FillRect(DrawTarget& aDrawTarget, bool aHorizontal, nscoord x, nscoord y, nscoord width, nscoord height)
1610 : {
1611 : Rect rect = NSRectToSnappedRect(aHorizontal ? nsRect(x, y, width, height) :
1612 : nsRect(y, x, height, width),
1613 : PresContext()->AppUnitsPerDevPixel(),
1614 : aDrawTarget);
1615 : ColorPattern white(ToDeviceColor(Color(1.f, 1.f, 1.f, 1.f)));
1616 : aDrawTarget.FillRect(rect, white);
1617 : }
1618 :
1619 : void
1620 : nsBoxFrame::DrawSpacer(nsPresContext* aPresContext, DrawTarget& aDrawTarget,
1621 : bool aHorizontal, int32_t flex, nscoord x, nscoord y,
1622 : nscoord size, nscoord spacerSize)
1623 : {
1624 : nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1);
1625 :
1626 : // if we do draw the coils
1627 : int distance = 0;
1628 : int center = 0;
1629 : int offset = 0;
1630 : int coilSize = COIL_SIZE*onePixel;
1631 : int halfSpacer = spacerSize/2;
1632 :
1633 : distance = size;
1634 : center = y + halfSpacer;
1635 : offset = x;
1636 :
1637 : int coils = distance/coilSize;
1638 :
1639 : int halfCoilSize = coilSize/2;
1640 :
1641 : if (flex == 0) {
1642 : DrawLine(aDrawTarget, aHorizontal, x,y + spacerSize/2, x + size, y + spacerSize/2);
1643 : } else {
1644 : for (int i=0; i < coils; i++)
1645 : {
1646 : DrawLine(aDrawTarget, aHorizontal, offset, center+halfSpacer, offset+halfCoilSize, center-halfSpacer);
1647 : DrawLine(aDrawTarget, aHorizontal, offset+halfCoilSize, center-halfSpacer, offset+coilSize, center+halfSpacer);
1648 :
1649 : offset += coilSize;
1650 : }
1651 : }
1652 :
1653 : FillRect(aDrawTarget, aHorizontal, x + size - spacerSize/2, y, spacerSize/2, spacerSize);
1654 : FillRect(aDrawTarget, aHorizontal, x, y, spacerSize/2, spacerSize);
1655 : }
1656 :
1657 : void
1658 : nsBoxFrame::GetDebugBorder(nsMargin& aInset)
1659 : {
1660 : aInset.SizeTo(2,2,2,2);
1661 :
1662 : if (IsXULHorizontal())
1663 : aInset.top = 10;
1664 : else
1665 : aInset.left = 10;
1666 : }
1667 :
1668 : void
1669 : nsBoxFrame::GetDebugMargin(nsMargin& aInset)
1670 : {
1671 : aInset.SizeTo(2,2,2,2);
1672 : }
1673 :
1674 : void
1675 : nsBoxFrame::GetDebugPadding(nsMargin& aPadding)
1676 : {
1677 : aPadding.SizeTo(2,2,2,2);
1678 : }
1679 :
1680 : void
1681 : nsBoxFrame::PixelMarginToTwips(nsMargin& aMarginPixels)
1682 : {
1683 : nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
1684 : aMarginPixels.left *= onePixel;
1685 : aMarginPixels.right *= onePixel;
1686 : aMarginPixels.top *= onePixel;
1687 : aMarginPixels.bottom *= onePixel;
1688 : }
1689 :
1690 : void
1691 : nsBoxFrame::GetValue(nsPresContext* aPresContext, const nsSize& a, const nsSize& b, char* ch)
1692 : {
1693 : float p2t = aPresContext->ScaledPixelsToTwips();
1694 :
1695 : char width[100];
1696 : char height[100];
1697 :
1698 : if (a.width == NS_INTRINSICSIZE)
1699 : sprintf(width,"%s","INF");
1700 : else
1701 : sprintf(width,"%d", nscoord(a.width/*/p2t*/));
1702 :
1703 : if (a.height == NS_INTRINSICSIZE)
1704 : sprintf(height,"%s","INF");
1705 : else
1706 : sprintf(height,"%d", nscoord(a.height/*/p2t*/));
1707 :
1708 :
1709 : sprintf(ch, "(%s%s, %s%s)", width, (b.width != NS_INTRINSICSIZE ? "[SET]" : ""),
1710 : height, (b.height != NS_INTRINSICSIZE ? "[SET]" : ""));
1711 :
1712 : }
1713 :
1714 : void
1715 : nsBoxFrame::GetValue(nsPresContext* aPresContext, int32_t a, int32_t b, char* ch)
1716 : {
1717 : if (a == NS_INTRINSICSIZE)
1718 : sprintf(ch, "%d[SET]", b);
1719 : else
1720 : sprintf(ch, "%d", a);
1721 : }
1722 :
1723 : nsresult
1724 : nsBoxFrame::DisplayDebugInfoFor(nsIFrame* aBox,
1725 : nsPoint& aPoint)
1726 : {
1727 : nsBoxLayoutState state(GetPresContext());
1728 :
1729 : nscoord x = aPoint.x;
1730 : nscoord y = aPoint.y;
1731 :
1732 : // get the area inside our border but not our debug margins.
1733 : nsRect insideBorder(aBox->mRect);
1734 : insideBorder.MoveTo(0,0):
1735 : nsMargin border(0,0,0,0);
1736 : aBox->GetXULBorderAndPadding(border);
1737 : insideBorder.Deflate(border);
1738 :
1739 : bool isHorizontal = IsXULHorizontal();
1740 :
1741 : if (!insideBorder.Contains(nsPoint(x,y)))
1742 : return NS_ERROR_FAILURE;
1743 :
1744 : //printf("%%%%%% inside box %%%%%%%\n");
1745 :
1746 : int count = 0;
1747 : nsIFrame* child = nsBox::GetChildXULBox(aBox);
1748 :
1749 : nsMargin m;
1750 : nsMargin m2;
1751 : GetDebugBorder(m);
1752 : PixelMarginToTwips(m);
1753 :
1754 : GetDebugMargin(m2);
1755 : PixelMarginToTwips(m2);
1756 :
1757 : m += m2;
1758 :
1759 : if ((isHorizontal && y < insideBorder.y + m.top) ||
1760 : (!isHorizontal && x < insideBorder.x + m.left)) {
1761 : //printf("**** inside debug border *******\n");
1762 : while (child)
1763 : {
1764 : const nsRect& r = child->mRect;
1765 :
1766 : // if we are not in the child. But in the spacer above the child.
1767 : if ((isHorizontal && x >= r.x && x < r.x + r.width) ||
1768 : (!isHorizontal && y >= r.y && y < r.y + r.height)) {
1769 : aCursor = NS_STYLE_CURSOR_POINTER;
1770 : // found it but we already showed it.
1771 : if (mDebugChild == child)
1772 : return NS_OK;
1773 :
1774 : if (aBox->GetContent()) {
1775 : printf("---------------\n");
1776 : XULDumpBox(stdout);
1777 : printf("\n");
1778 : }
1779 :
1780 : if (child->GetContent()) {
1781 : printf("child #%d: ", count);
1782 : child->XULDumpBox(stdout);
1783 : printf("\n");
1784 : }
1785 :
1786 : mDebugChild = child;
1787 :
1788 : nsSize prefSizeCSS(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
1789 : nsSize minSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
1790 : nsSize maxSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
1791 : nscoord flexCSS = NS_INTRINSICSIZE;
1792 :
1793 : bool widthSet, heightSet;
1794 : nsIFrame::AddXULPrefSize(child, prefSizeCSS, widthSet, heightSet);
1795 : nsIFrame::AddXULMinSize (state, child, minSizeCSS, widthSet, heightSet);
1796 : nsIFrame::AddXULMaxSize (child, maxSizeCSS, widthSet, heightSet);
1797 : nsIFrame::AddXULFlex (child, flexCSS);
1798 :
1799 : nsSize prefSize = child->GetXULPrefSize(state);
1800 : nsSize minSize = child->GetXULMinSize(state);
1801 : nsSize maxSize = child->GetXULMaxSize(state);
1802 : nscoord flexSize = child->GetXULFlex();
1803 : nscoord ascentSize = child->GetXULBoxAscent(state);
1804 :
1805 : char min[100];
1806 : char pref[100];
1807 : char max[100];
1808 : char calc[100];
1809 : char flex[100];
1810 : char ascent[100];
1811 :
1812 : nsSize actualSize;
1813 : GetFrameSizeWithMargin(child, actualSize);
1814 : nsSize actualSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE);
1815 :
1816 : GetValue(aPresContext, minSize, minSizeCSS, min);
1817 : GetValue(aPresContext, prefSize, prefSizeCSS, pref);
1818 : GetValue(aPresContext, maxSize, maxSizeCSS, max);
1819 : GetValue(aPresContext, actualSize, actualSizeCSS, calc);
1820 : GetValue(aPresContext, flexSize, flexCSS, flex);
1821 : GetValue(aPresContext, ascentSize, NS_INTRINSICSIZE, ascent);
1822 :
1823 :
1824 : printf("min%s, pref%s, max%s, actual%s, flex=%s, ascent=%s\n\n",
1825 : min,
1826 : pref,
1827 : max,
1828 : calc,
1829 : flex,
1830 : ascent
1831 : );
1832 :
1833 : return NS_OK;
1834 : }
1835 :
1836 : child = GetNextXULBox(child);
1837 : count++;
1838 : }
1839 : } else {
1840 : }
1841 :
1842 : mDebugChild = nullptr;
1843 :
1844 : return NS_OK;
1845 : }
1846 :
1847 : void
1848 : nsBoxFrame::SetDebugOnChildList(nsBoxLayoutState& aState, nsIFrame* aChild, bool aDebug)
1849 : {
1850 : nsIFrame* child = nsBox::GetChildXULBox(this);
1851 : while (child)
1852 : {
1853 : child->SetXULDebug(aState, aDebug);
1854 : child = GetNextXULBox(child);
1855 : }
1856 : }
1857 :
1858 : nsresult
1859 : nsBoxFrame::GetFrameSizeWithMargin(nsIFrame* aBox, nsSize& aSize)
1860 : {
1861 : nsRect rect(aBox->GetRect());
1862 : nsMargin margin(0,0,0,0);
1863 : aBox->GetXULMargin(margin);
1864 : rect.Inflate(margin);
1865 : aSize.width = rect.width;
1866 : aSize.height = rect.height;
1867 : return NS_OK;
1868 : }
1869 : #endif
1870 :
1871 : // If you make changes to this function, check its counterparts
1872 : // in nsTextBoxFrame and nsXULLabelFrame
1873 : void
1874 288 : nsBoxFrame::RegUnregAccessKey(bool aDoReg)
1875 : {
1876 288 : MOZ_ASSERT(mContent);
1877 :
1878 : // only support accesskeys for the following elements
1879 288 : if (!mContent->IsAnyOfXULElements(nsGkAtoms::button,
1880 : nsGkAtoms::toolbarbutton,
1881 : nsGkAtoms::checkbox,
1882 : nsGkAtoms::textbox,
1883 : nsGkAtoms::tab,
1884 : nsGkAtoms::radio)) {
1885 520 : return;
1886 : }
1887 :
1888 56 : nsAutoString accessKey;
1889 56 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
1890 :
1891 56 : if (accessKey.IsEmpty())
1892 56 : return;
1893 :
1894 : // With a valid PresContext we can get the ESM
1895 : // and register the access key
1896 0 : EventStateManager* esm = PresContext()->EventStateManager();
1897 :
1898 0 : uint32_t key = accessKey.First();
1899 0 : if (aDoReg)
1900 0 : esm->RegisterAccessKey(mContent, key);
1901 : else
1902 0 : esm->UnregisterAccessKey(mContent, key);
1903 : }
1904 :
1905 : bool
1906 262 : nsBoxFrame::SupportsOrdinalsInChildren()
1907 : {
1908 262 : return true;
1909 : }
1910 :
1911 : // Helper less-than-or-equal function, used in CheckBoxOrder() as a
1912 : // template-parameter for the sorting functions.
1913 : bool
1914 187 : IsBoxOrdinalLEQ(nsIFrame* aFrame1,
1915 : nsIFrame* aFrame2)
1916 : {
1917 : // If we've got a placeholder frame, use its out-of-flow frame's ordinal val.
1918 187 : nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1);
1919 187 : nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2);
1920 187 : return aRealFrame1->GetXULOrdinal() <= aRealFrame2->GetXULOrdinal();
1921 : }
1922 :
1923 : void
1924 262 : nsBoxFrame::CheckBoxOrder()
1925 : {
1926 524 : if (SupportsOrdinalsInChildren() &&
1927 262 : !nsIFrame::IsFrameListSorted<IsBoxOrdinalLEQ>(mFrames)) {
1928 0 : nsIFrame::SortFrameList<IsBoxOrdinalLEQ>(mFrames);
1929 : }
1930 262 : }
1931 :
1932 : nsresult
1933 141 : nsBoxFrame::LayoutChildAt(nsBoxLayoutState& aState, nsIFrame* aBox, const nsRect& aRect)
1934 : {
1935 : // get the current rect
1936 282 : nsRect oldRect(aBox->GetRect());
1937 141 : aBox->SetXULBounds(aState, aRect);
1938 :
1939 141 : bool layout = NS_SUBTREE_DIRTY(aBox);
1940 :
1941 141 : if (layout || (oldRect.width != aRect.width || oldRect.height != aRect.height)) {
1942 110 : return aBox->XULLayout(aState);
1943 : }
1944 :
1945 31 : return NS_OK;
1946 : }
1947 :
1948 : nsresult
1949 0 : nsBoxFrame::XULRelayoutChildAtOrdinal(nsIFrame* aChild)
1950 : {
1951 0 : if (!SupportsOrdinalsInChildren())
1952 0 : return NS_OK;
1953 :
1954 0 : uint32_t ord = aChild->GetXULOrdinal();
1955 :
1956 0 : nsIFrame* child = mFrames.FirstChild();
1957 0 : nsIFrame* newPrevSib = nullptr;
1958 :
1959 0 : while (child) {
1960 0 : if (ord < child->GetXULOrdinal()) {
1961 0 : break;
1962 : }
1963 :
1964 0 : if (child != aChild) {
1965 0 : newPrevSib = child;
1966 : }
1967 :
1968 0 : child = GetNextXULBox(child);
1969 : }
1970 :
1971 0 : if (aChild->GetPrevSibling() == newPrevSib) {
1972 : // This box is not moving.
1973 0 : return NS_OK;
1974 : }
1975 :
1976 : // Take |aChild| out of its old position in the child list.
1977 0 : mFrames.RemoveFrame(aChild);
1978 :
1979 : // Insert it after |newPrevSib| or at the start if it's null.
1980 0 : mFrames.InsertFrame(nullptr, newPrevSib, aChild);
1981 :
1982 0 : return NS_OK;
1983 : }
1984 :
1985 : /**
1986 : * This wrapper class lets us redirect mouse hits from descendant frames
1987 : * of a menu to the menu itself, if they didn't specify 'allowevents'.
1988 : *
1989 : * The wrapper simply turns a hit on a descendant element
1990 : * into a hit on the menu itself, unless there is an element between the target
1991 : * and the menu with the "allowevents" attribute.
1992 : *
1993 : * This is used by nsMenuFrame and nsTreeColFrame.
1994 : *
1995 : * Note that turning a hit on a descendant element into nullptr, so events
1996 : * could fall through to the menu background, might be an appealing simplification
1997 : * but it would mean slightly strange behaviour in some cases, because grabber
1998 : * wrappers can be created for many individual lists and items, so the exact
1999 : * fallthrough behaviour would be complex. E.g. an element with "allowevents"
2000 : * on top of the Content() list could receive the event even if it was covered
2001 : * by a PositionedDescenants() element without "allowevents". It is best to
2002 : * never convert a non-null hit into null.
2003 : */
2004 : // REVIEW: This is roughly of what nsMenuFrame::GetFrameForPoint used to do.
2005 : // I've made 'allowevents' affect child elements because that seems the only
2006 : // reasonable thing to do.
2007 0 : class nsDisplayXULEventRedirector final : public nsDisplayWrapList
2008 : {
2009 : public:
2010 0 : nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
2011 : nsIFrame* aFrame, nsDisplayItem* aItem,
2012 : nsIFrame* aTargetFrame)
2013 0 : : nsDisplayWrapList(aBuilder, aFrame, aItem), mTargetFrame(aTargetFrame) {}
2014 0 : nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder,
2015 : nsIFrame* aFrame, nsDisplayList* aList,
2016 : nsIFrame* aTargetFrame)
2017 0 : : nsDisplayWrapList(aBuilder, aFrame, aList), mTargetFrame(aTargetFrame) {}
2018 : virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
2019 : HitTestState* aState,
2020 : nsTArray<nsIFrame*> *aOutFrames) override;
2021 0 : virtual bool ShouldFlattenAway(nsDisplayListBuilder* aBuilder) override {
2022 0 : return false;
2023 : }
2024 0 : NS_DISPLAY_DECL_NAME("XULEventRedirector", TYPE_XUL_EVENT_REDIRECTOR)
2025 : private:
2026 : nsIFrame* mTargetFrame;
2027 : };
2028 :
2029 0 : void nsDisplayXULEventRedirector::HitTest(nsDisplayListBuilder* aBuilder,
2030 : const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames)
2031 : {
2032 0 : nsTArray<nsIFrame*> outFrames;
2033 0 : mList.HitTest(aBuilder, aRect, aState, &outFrames);
2034 :
2035 0 : bool topMostAdded = false;
2036 0 : uint32_t localLength = outFrames.Length();
2037 :
2038 0 : for (uint32_t i = 0; i < localLength; i++) {
2039 :
2040 0 : for (nsIContent* content = outFrames.ElementAt(i)->GetContent();
2041 0 : content && content != mTargetFrame->GetContent();
2042 0 : content = content->GetParent()) {
2043 0 : if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allowevents,
2044 : nsGkAtoms::_true, eCaseMatters)) {
2045 : // Events are allowed on 'frame', so let it go.
2046 0 : aOutFrames->AppendElement(outFrames.ElementAt(i));
2047 0 : topMostAdded = true;
2048 : }
2049 : }
2050 :
2051 : // If there was no hit on the topmost frame or its ancestors,
2052 : // add the target frame itself as the first candidate (see bug 562554).
2053 0 : if (!topMostAdded) {
2054 0 : topMostAdded = true;
2055 0 : aOutFrames->AppendElement(mTargetFrame);
2056 : }
2057 : }
2058 0 : }
2059 :
2060 : class nsXULEventRedirectorWrapper final : public nsDisplayWrapper
2061 : {
2062 : public:
2063 0 : explicit nsXULEventRedirectorWrapper(nsIFrame* aTargetFrame)
2064 0 : : mTargetFrame(aTargetFrame) {}
2065 0 : virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder,
2066 : nsIFrame* aFrame,
2067 : nsDisplayList* aList) override {
2068 : return new (aBuilder)
2069 0 : nsDisplayXULEventRedirector(aBuilder, aFrame, aList, mTargetFrame);
2070 : }
2071 0 : virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder,
2072 : nsDisplayItem* aItem) override {
2073 : return new (aBuilder)
2074 0 : nsDisplayXULEventRedirector(aBuilder, aItem->Frame(), aItem,
2075 0 : mTargetFrame);
2076 : }
2077 : private:
2078 : nsIFrame* mTargetFrame;
2079 : };
2080 :
2081 : void
2082 0 : nsBoxFrame::WrapListsInRedirector(nsDisplayListBuilder* aBuilder,
2083 : const nsDisplayListSet& aIn,
2084 : const nsDisplayListSet& aOut)
2085 : {
2086 0 : nsXULEventRedirectorWrapper wrapper(this);
2087 0 : wrapper.WrapLists(aBuilder, this, aIn, aOut);
2088 0 : }
2089 :
2090 : bool
2091 0 : nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsPoint &aPoint) {
2092 0 : LayoutDeviceIntPoint refPoint;
2093 0 : bool res = GetEventPoint(aEvent, refPoint);
2094 0 : aPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(
2095 : aEvent, refPoint, this);
2096 0 : return res;
2097 : }
2098 :
2099 : bool
2100 0 : nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, LayoutDeviceIntPoint& aPoint) {
2101 0 : NS_ENSURE_TRUE(aEvent, false);
2102 :
2103 0 : WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent();
2104 0 : if (touchEvent) {
2105 : // return false if there is more than one touch on the page, or if
2106 : // we can't find a touch point
2107 0 : if (touchEvent->mTouches.Length() != 1) {
2108 0 : return false;
2109 : }
2110 :
2111 0 : dom::Touch* touch = touchEvent->mTouches.SafeElementAt(0);
2112 0 : if (!touch) {
2113 0 : return false;
2114 : }
2115 0 : aPoint = touch->mRefPoint;
2116 : } else {
2117 0 : aPoint = aEvent->mRefPoint;
2118 : }
2119 0 : return true;
2120 : }
|