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