1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsBoxFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2109 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 sw=2 et tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +// 1.11 +// Eric Vaughan 1.12 +// Netscape Communications 1.13 +// 1.14 +// See documentation in associated header file 1.15 +// 1.16 + 1.17 +// How boxes layout 1.18 +// ---------------- 1.19 +// Boxes layout a bit differently than html. html does a bottom up layout. Where boxes do a top down. 1.20 +// 1) First thing a box does it goes out and askes each child for its min, max, and preferred sizes. 1.21 +// 2) It then adds them up to determine its size. 1.22 +// 3) If the box was asked to layout it self intrinically it will layout its children at their preferred size 1.23 +// otherwise it will layout the child at the size it was told to. It will squeeze or stretch its children if 1.24 +// Necessary. 1.25 +// 1.26 +// However there is a catch. Some html components like block frames can not determine their preferred size. 1.27 +// this is their size if they were laid out intrinsically. So the box will flow the child to determine this can 1.28 +// cache the value. 1.29 + 1.30 +// Boxes and Incremental Reflow 1.31 +// ---------------------------- 1.32 +// Boxes layout out top down by adding up their children's min, max, and preferred sizes. Only problem is if a incremental 1.33 +// reflow occurs. The preferred size of a child deep in the hierarchy could change. And this could change 1.34 +// any number of syblings around the box. Basically any children in the reflow chain must have their caches cleared 1.35 +// so when asked for there current size they can relayout themselves. 1.36 + 1.37 +#include "nsBoxLayoutState.h" 1.38 +#include "nsBoxFrame.h" 1.39 +#include "mozilla/dom/Touch.h" 1.40 +#include "nsStyleContext.h" 1.41 +#include "nsPlaceholderFrame.h" 1.42 +#include "nsPresContext.h" 1.43 +#include "nsCOMPtr.h" 1.44 +#include "nsNameSpaceManager.h" 1.45 +#include "nsGkAtoms.h" 1.46 +#include "nsIContent.h" 1.47 +#include "nsHTMLParts.h" 1.48 +#include "nsViewManager.h" 1.49 +#include "nsView.h" 1.50 +#include "nsIPresShell.h" 1.51 +#include "nsCSSRendering.h" 1.52 +#include "nsIServiceManager.h" 1.53 +#include "nsBoxLayout.h" 1.54 +#include "nsSprocketLayout.h" 1.55 +#include "nsIScrollableFrame.h" 1.56 +#include "nsWidgetsCID.h" 1.57 +#include "nsCSSAnonBoxes.h" 1.58 +#include "nsContainerFrame.h" 1.59 +#include "nsIDOMElement.h" 1.60 +#include "nsITheme.h" 1.61 +#include "nsTransform2D.h" 1.62 +#include "mozilla/EventStateManager.h" 1.63 +#include "nsIDOMEvent.h" 1.64 +#include "nsDisplayList.h" 1.65 +#include "mozilla/Preferences.h" 1.66 +#include "nsThemeConstants.h" 1.67 +#include "nsLayoutUtils.h" 1.68 +#include <algorithm> 1.69 + 1.70 +// Needed for Print Preview 1.71 +#include "nsIURI.h" 1.72 + 1.73 +#include "mozilla/TouchEvents.h" 1.74 + 1.75 +using namespace mozilla; 1.76 +using namespace mozilla::dom; 1.77 + 1.78 +//define DEBUG_REDRAW 1.79 + 1.80 +#define DEBUG_SPRING_SIZE 8 1.81 +#define DEBUG_BORDER_SIZE 2 1.82 +#define COIL_SIZE 8 1.83 + 1.84 +//#define TEST_SANITY 1.85 + 1.86 +#ifdef DEBUG_rods 1.87 +//#define DO_NOISY_REFLOW 1.88 +#endif 1.89 + 1.90 +#ifdef DEBUG_LAYOUT 1.91 +bool nsBoxFrame::gDebug = false; 1.92 +nsIFrame* nsBoxFrame::mDebugChild = nullptr; 1.93 +#endif 1.94 + 1.95 +nsIFrame* 1.96 +NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot, nsBoxLayout* aLayoutManager) 1.97 +{ 1.98 + return new (aPresShell) nsBoxFrame(aPresShell, aContext, aIsRoot, aLayoutManager); 1.99 +} 1.100 + 1.101 +nsIFrame* 1.102 +NS_NewBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.103 +{ 1.104 + return new (aPresShell) nsBoxFrame(aPresShell, aContext); 1.105 +} 1.106 + 1.107 +NS_IMPL_FRAMEARENA_HELPERS(nsBoxFrame) 1.108 + 1.109 +#ifdef DEBUG 1.110 +NS_QUERYFRAME_HEAD(nsBoxFrame) 1.111 + NS_QUERYFRAME_ENTRY(nsBoxFrame) 1.112 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) 1.113 +#endif 1.114 + 1.115 +nsBoxFrame::nsBoxFrame(nsIPresShell* aPresShell, 1.116 + nsStyleContext* aContext, 1.117 + bool aIsRoot, 1.118 + nsBoxLayout* aLayoutManager) : 1.119 + nsContainerFrame(aContext) 1.120 +{ 1.121 + mState |= NS_STATE_IS_HORIZONTAL; 1.122 + mState |= NS_STATE_AUTO_STRETCH; 1.123 + 1.124 + if (aIsRoot) 1.125 + mState |= NS_STATE_IS_ROOT; 1.126 + 1.127 + mValign = vAlign_Top; 1.128 + mHalign = hAlign_Left; 1.129 + 1.130 + // if no layout manager specified us the static sprocket layout 1.131 + nsCOMPtr<nsBoxLayout> layout = aLayoutManager; 1.132 + 1.133 + if (layout == nullptr) { 1.134 + NS_NewSprocketLayout(aPresShell, layout); 1.135 + } 1.136 + 1.137 + SetLayoutManager(layout); 1.138 +} 1.139 + 1.140 +nsBoxFrame::~nsBoxFrame() 1.141 +{ 1.142 +} 1.143 + 1.144 +nsresult 1.145 +nsBoxFrame::SetInitialChildList(ChildListID aListID, 1.146 + nsFrameList& aChildList) 1.147 +{ 1.148 + nsresult r = nsContainerFrame::SetInitialChildList(aListID, aChildList); 1.149 + if (r == NS_OK) { 1.150 + // initialize our list of infos. 1.151 + nsBoxLayoutState state(PresContext()); 1.152 + CheckBoxOrder(); 1.153 + if (mLayoutManager) 1.154 + mLayoutManager->ChildrenSet(this, state, mFrames.FirstChild()); 1.155 + } else { 1.156 + NS_WARNING("Warning add child failed!!\n"); 1.157 + } 1.158 + 1.159 + return r; 1.160 +} 1.161 + 1.162 +/* virtual */ void 1.163 +nsBoxFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) 1.164 +{ 1.165 + nsContainerFrame::DidSetStyleContext(aOldStyleContext); 1.166 + 1.167 + // The values that CacheAttributes() computes depend on our style, 1.168 + // so we need to recompute them here... 1.169 + CacheAttributes(); 1.170 +} 1.171 + 1.172 +/** 1.173 + * Initialize us. This is a good time to get the alignment of the box 1.174 + */ 1.175 +void 1.176 +nsBoxFrame::Init(nsIContent* aContent, 1.177 + nsIFrame* aParent, 1.178 + nsIFrame* aPrevInFlow) 1.179 +{ 1.180 + nsContainerFrame::Init(aContent, aParent, aPrevInFlow); 1.181 + 1.182 + if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) { 1.183 + AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); 1.184 + } 1.185 + 1.186 + MarkIntrinsicWidthsDirty(); 1.187 + 1.188 + CacheAttributes(); 1.189 + 1.190 +#ifdef DEBUG_LAYOUT 1.191 + // if we are root and this 1.192 + if (mState & NS_STATE_IS_ROOT) 1.193 + GetDebugPref(GetPresContext()); 1.194 +#endif 1.195 + 1.196 + UpdateMouseThrough(); 1.197 + 1.198 + // register access key 1.199 + RegUnregAccessKey(true); 1.200 +} 1.201 + 1.202 +void nsBoxFrame::UpdateMouseThrough() 1.203 +{ 1.204 + if (mContent) { 1.205 + static nsIContent::AttrValuesArray strings[] = 1.206 + {&nsGkAtoms::never, &nsGkAtoms::always, nullptr}; 1.207 + switch (mContent->FindAttrValueIn(kNameSpaceID_None, 1.208 + nsGkAtoms::mousethrough, strings, eCaseMatters)) { 1.209 + case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break; 1.210 + case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break; 1.211 + case 2: { 1.212 + RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); 1.213 + RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); 1.214 + break; 1.215 + } 1.216 + } 1.217 + } 1.218 +} 1.219 + 1.220 +void 1.221 +nsBoxFrame::CacheAttributes() 1.222 +{ 1.223 + /* 1.224 + printf("Caching: "); 1.225 + DumpBox(stdout); 1.226 + printf("\n"); 1.227 + */ 1.228 + 1.229 + mValign = vAlign_Top; 1.230 + mHalign = hAlign_Left; 1.231 + 1.232 + bool orient = false; 1.233 + GetInitialOrientation(orient); 1.234 + if (orient) 1.235 + mState |= NS_STATE_IS_HORIZONTAL; 1.236 + else 1.237 + mState &= ~NS_STATE_IS_HORIZONTAL; 1.238 + 1.239 + bool normal = true; 1.240 + GetInitialDirection(normal); 1.241 + if (normal) 1.242 + mState |= NS_STATE_IS_DIRECTION_NORMAL; 1.243 + else 1.244 + mState &= ~NS_STATE_IS_DIRECTION_NORMAL; 1.245 + 1.246 + GetInitialVAlignment(mValign); 1.247 + GetInitialHAlignment(mHalign); 1.248 + 1.249 + bool equalSize = false; 1.250 + GetInitialEqualSize(equalSize); 1.251 + if (equalSize) 1.252 + mState |= NS_STATE_EQUAL_SIZE; 1.253 + else 1.254 + mState &= ~NS_STATE_EQUAL_SIZE; 1.255 + 1.256 + bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH); 1.257 + GetInitialAutoStretch(autostretch); 1.258 + if (autostretch) 1.259 + mState |= NS_STATE_AUTO_STRETCH; 1.260 + else 1.261 + mState &= ~NS_STATE_AUTO_STRETCH; 1.262 + 1.263 + 1.264 +#ifdef DEBUG_LAYOUT 1.265 + bool debug = mState & NS_STATE_SET_TO_DEBUG; 1.266 + bool debugSet = GetInitialDebug(debug); 1.267 + if (debugSet) { 1.268 + mState |= NS_STATE_DEBUG_WAS_SET; 1.269 + if (debug) 1.270 + mState |= NS_STATE_SET_TO_DEBUG; 1.271 + else 1.272 + mState &= ~NS_STATE_SET_TO_DEBUG; 1.273 + } else { 1.274 + mState &= ~NS_STATE_DEBUG_WAS_SET; 1.275 + } 1.276 +#endif 1.277 +} 1.278 + 1.279 +#ifdef DEBUG_LAYOUT 1.280 +bool 1.281 +nsBoxFrame::GetInitialDebug(bool& aDebug) 1.282 +{ 1.283 + if (!GetContent()) 1.284 + return false; 1.285 + 1.286 + static nsIContent::AttrValuesArray strings[] = 1.287 + {&nsGkAtoms::_false, &nsGkAtoms::_true, nullptr}; 1.288 + int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, 1.289 + nsGkAtoms::debug, strings, eCaseMatters); 1.290 + if (index >= 0) { 1.291 + aDebug = index == 1; 1.292 + return true; 1.293 + } 1.294 + 1.295 + return false; 1.296 +} 1.297 +#endif 1.298 + 1.299 +bool 1.300 +nsBoxFrame::GetInitialHAlignment(nsBoxFrame::Halignment& aHalign) 1.301 +{ 1.302 + if (!GetContent()) 1.303 + return false; 1.304 + 1.305 + // XXXdwh Everything inside this if statement is deprecated code. 1.306 + static nsIContent::AttrValuesArray alignStrings[] = 1.307 + {&nsGkAtoms::left, &nsGkAtoms::right, nullptr}; 1.308 + static const Halignment alignValues[] = {hAlign_Left, hAlign_Right}; 1.309 + int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align, 1.310 + alignStrings, eCaseMatters); 1.311 + if (index >= 0) { 1.312 + aHalign = alignValues[index]; 1.313 + return true; 1.314 + } 1.315 + 1.316 + // Now that the deprecated stuff is out of the way, we move on to check the appropriate 1.317 + // attribute. For horizontal boxes, we are checking the PACK attribute. For vertical boxes 1.318 + // we are checking the ALIGN attribute. 1.319 + nsIAtom* attrName = IsHorizontal() ? nsGkAtoms::pack : nsGkAtoms::align; 1.320 + static nsIContent::AttrValuesArray strings[] = 1.321 + {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center, &nsGkAtoms::end, nullptr}; 1.322 + static const Halignment values[] = 1.323 + {hAlign_Left/*not used*/, hAlign_Left, hAlign_Center, hAlign_Right}; 1.324 + index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName, 1.325 + strings, eCaseMatters); 1.326 + 1.327 + if (index == nsIContent::ATTR_VALUE_NO_MATCH) { 1.328 + // The attr was present but had a nonsensical value. Revert to the default. 1.329 + return false; 1.330 + } 1.331 + if (index > 0) { 1.332 + aHalign = values[index]; 1.333 + return true; 1.334 + } 1.335 + 1.336 + // Now that we've checked for the attribute it's time to check CSS. For 1.337 + // horizontal boxes we're checking PACK. For vertical boxes we are checking 1.338 + // ALIGN. 1.339 + const nsStyleXUL* boxInfo = StyleXUL(); 1.340 + if (IsHorizontal()) { 1.341 + switch (boxInfo->mBoxPack) { 1.342 + case NS_STYLE_BOX_PACK_START: 1.343 + aHalign = nsBoxFrame::hAlign_Left; 1.344 + return true; 1.345 + case NS_STYLE_BOX_PACK_CENTER: 1.346 + aHalign = nsBoxFrame::hAlign_Center; 1.347 + return true; 1.348 + case NS_STYLE_BOX_PACK_END: 1.349 + aHalign = nsBoxFrame::hAlign_Right; 1.350 + return true; 1.351 + default: // Nonsensical value. Just bail. 1.352 + return false; 1.353 + } 1.354 + } 1.355 + else { 1.356 + switch (boxInfo->mBoxAlign) { 1.357 + case NS_STYLE_BOX_ALIGN_START: 1.358 + aHalign = nsBoxFrame::hAlign_Left; 1.359 + return true; 1.360 + case NS_STYLE_BOX_ALIGN_CENTER: 1.361 + aHalign = nsBoxFrame::hAlign_Center; 1.362 + return true; 1.363 + case NS_STYLE_BOX_ALIGN_END: 1.364 + aHalign = nsBoxFrame::hAlign_Right; 1.365 + return true; 1.366 + default: // Nonsensical value. Just bail. 1.367 + return false; 1.368 + } 1.369 + } 1.370 + 1.371 + return false; 1.372 +} 1.373 + 1.374 +bool 1.375 +nsBoxFrame::GetInitialVAlignment(nsBoxFrame::Valignment& aValign) 1.376 +{ 1.377 + if (!GetContent()) 1.378 + return false; 1.379 + 1.380 + static nsIContent::AttrValuesArray valignStrings[] = 1.381 + {&nsGkAtoms::top, &nsGkAtoms::baseline, &nsGkAtoms::middle, &nsGkAtoms::bottom, nullptr}; 1.382 + static const Valignment valignValues[] = 1.383 + {vAlign_Top, vAlign_BaseLine, vAlign_Middle, vAlign_Bottom}; 1.384 + int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::valign, 1.385 + valignStrings, eCaseMatters); 1.386 + if (index >= 0) { 1.387 + aValign = valignValues[index]; 1.388 + return true; 1.389 + } 1.390 + 1.391 + // Now that the deprecated stuff is out of the way, we move on to check the appropriate 1.392 + // attribute. For horizontal boxes, we are checking the ALIGN attribute. For vertical boxes 1.393 + // we are checking the PACK attribute. 1.394 + nsIAtom* attrName = IsHorizontal() ? nsGkAtoms::align : nsGkAtoms::pack; 1.395 + static nsIContent::AttrValuesArray strings[] = 1.396 + {&nsGkAtoms::_empty, &nsGkAtoms::start, &nsGkAtoms::center, 1.397 + &nsGkAtoms::baseline, &nsGkAtoms::end, nullptr}; 1.398 + static const Valignment values[] = 1.399 + {vAlign_Top/*not used*/, vAlign_Top, vAlign_Middle, vAlign_BaseLine, vAlign_Bottom}; 1.400 + index = GetContent()->FindAttrValueIn(kNameSpaceID_None, attrName, 1.401 + strings, eCaseMatters); 1.402 + if (index == nsIContent::ATTR_VALUE_NO_MATCH) { 1.403 + // The attr was present but had a nonsensical value. Revert to the default. 1.404 + return false; 1.405 + } 1.406 + if (index > 0) { 1.407 + aValign = values[index]; 1.408 + return true; 1.409 + } 1.410 + 1.411 + // Now that we've checked for the attribute it's time to check CSS. For 1.412 + // horizontal boxes we're checking ALIGN. For vertical boxes we are checking 1.413 + // PACK. 1.414 + const nsStyleXUL* boxInfo = StyleXUL(); 1.415 + if (IsHorizontal()) { 1.416 + switch (boxInfo->mBoxAlign) { 1.417 + case NS_STYLE_BOX_ALIGN_START: 1.418 + aValign = nsBoxFrame::vAlign_Top; 1.419 + return true; 1.420 + case NS_STYLE_BOX_ALIGN_CENTER: 1.421 + aValign = nsBoxFrame::vAlign_Middle; 1.422 + return true; 1.423 + case NS_STYLE_BOX_ALIGN_BASELINE: 1.424 + aValign = nsBoxFrame::vAlign_BaseLine; 1.425 + return true; 1.426 + case NS_STYLE_BOX_ALIGN_END: 1.427 + aValign = nsBoxFrame::vAlign_Bottom; 1.428 + return true; 1.429 + default: // Nonsensical value. Just bail. 1.430 + return false; 1.431 + } 1.432 + } 1.433 + else { 1.434 + switch (boxInfo->mBoxPack) { 1.435 + case NS_STYLE_BOX_PACK_START: 1.436 + aValign = nsBoxFrame::vAlign_Top; 1.437 + return true; 1.438 + case NS_STYLE_BOX_PACK_CENTER: 1.439 + aValign = nsBoxFrame::vAlign_Middle; 1.440 + return true; 1.441 + case NS_STYLE_BOX_PACK_END: 1.442 + aValign = nsBoxFrame::vAlign_Bottom; 1.443 + return true; 1.444 + default: // Nonsensical value. Just bail. 1.445 + return false; 1.446 + } 1.447 + } 1.448 + 1.449 + return false; 1.450 +} 1.451 + 1.452 +void 1.453 +nsBoxFrame::GetInitialOrientation(bool& aIsHorizontal) 1.454 +{ 1.455 + // see if we are a vertical or horizontal box. 1.456 + if (!GetContent()) 1.457 + return; 1.458 + 1.459 + // Check the style system first. 1.460 + const nsStyleXUL* boxInfo = StyleXUL(); 1.461 + if (boxInfo->mBoxOrient == NS_STYLE_BOX_ORIENT_HORIZONTAL) 1.462 + aIsHorizontal = true; 1.463 + else 1.464 + aIsHorizontal = false; 1.465 + 1.466 + // Now see if we have an attribute. The attribute overrides 1.467 + // the style system value. 1.468 + static nsIContent::AttrValuesArray strings[] = 1.469 + {&nsGkAtoms::vertical, &nsGkAtoms::horizontal, nullptr}; 1.470 + int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::orient, 1.471 + strings, eCaseMatters); 1.472 + if (index >= 0) { 1.473 + aIsHorizontal = index == 1; 1.474 + } 1.475 +} 1.476 + 1.477 +void 1.478 +nsBoxFrame::GetInitialDirection(bool& aIsNormal) 1.479 +{ 1.480 + if (!GetContent()) 1.481 + return; 1.482 + 1.483 + if (IsHorizontal()) { 1.484 + // For horizontal boxes only, we initialize our value based off the CSS 'direction' property. 1.485 + // This means that BiDI users will end up with horizontally inverted chrome. 1.486 + aIsNormal = (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR); // If text runs RTL then so do we. 1.487 + } 1.488 + else 1.489 + aIsNormal = true; // Assume a normal direction in the vertical case. 1.490 + 1.491 + // Now check the style system to see if we should invert aIsNormal. 1.492 + const nsStyleXUL* boxInfo = StyleXUL(); 1.493 + if (boxInfo->mBoxDirection == NS_STYLE_BOX_DIRECTION_REVERSE) 1.494 + aIsNormal = !aIsNormal; // Invert our direction. 1.495 + 1.496 + // Now see if we have an attribute. The attribute overrides 1.497 + // the style system value. 1.498 + if (IsHorizontal()) { 1.499 + static nsIContent::AttrValuesArray strings[] = 1.500 + {&nsGkAtoms::reverse, &nsGkAtoms::ltr, &nsGkAtoms::rtl, nullptr}; 1.501 + int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::dir, 1.502 + strings, eCaseMatters); 1.503 + if (index >= 0) { 1.504 + bool values[] = {!aIsNormal, true, false}; 1.505 + aIsNormal = values[index]; 1.506 + } 1.507 + } else if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::dir, 1.508 + nsGkAtoms::reverse, eCaseMatters)) { 1.509 + aIsNormal = !aIsNormal; 1.510 + } 1.511 +} 1.512 + 1.513 +/* Returns true if it was set. 1.514 + */ 1.515 +bool 1.516 +nsBoxFrame::GetInitialEqualSize(bool& aEqualSize) 1.517 +{ 1.518 + // see if we are a vertical or horizontal box. 1.519 + if (!GetContent()) 1.520 + return false; 1.521 + 1.522 + if (GetContent()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::equalsize, 1.523 + nsGkAtoms::always, eCaseMatters)) { 1.524 + aEqualSize = true; 1.525 + return true; 1.526 + } 1.527 + 1.528 + return false; 1.529 +} 1.530 + 1.531 +/* Returns true if it was set. 1.532 + */ 1.533 +bool 1.534 +nsBoxFrame::GetInitialAutoStretch(bool& aStretch) 1.535 +{ 1.536 + if (!GetContent()) 1.537 + return false; 1.538 + 1.539 + // Check the align attribute. 1.540 + static nsIContent::AttrValuesArray strings[] = 1.541 + {&nsGkAtoms::_empty, &nsGkAtoms::stretch, nullptr}; 1.542 + int32_t index = GetContent()->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::align, 1.543 + strings, eCaseMatters); 1.544 + if (index != nsIContent::ATTR_MISSING && index != 0) { 1.545 + aStretch = index == 1; 1.546 + return true; 1.547 + } 1.548 + 1.549 + // Check the CSS box-align property. 1.550 + const nsStyleXUL* boxInfo = StyleXUL(); 1.551 + aStretch = (boxInfo->mBoxAlign == NS_STYLE_BOX_ALIGN_STRETCH); 1.552 + 1.553 + return true; 1.554 +} 1.555 + 1.556 +nsresult 1.557 +nsBoxFrame::DidReflow(nsPresContext* aPresContext, 1.558 + const nsHTMLReflowState* aReflowState, 1.559 + nsDidReflowStatus aStatus) 1.560 +{ 1.561 + nsFrameState preserveBits = 1.562 + mState & (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); 1.563 + nsresult rv = nsFrame::DidReflow(aPresContext, aReflowState, aStatus); 1.564 + mState |= preserveBits; 1.565 + return rv; 1.566 +} 1.567 + 1.568 +bool 1.569 +nsBoxFrame::HonorPrintBackgroundSettings() 1.570 +{ 1.571 + return (!mContent || !mContent->IsInNativeAnonymousSubtree()) && 1.572 + nsContainerFrame::HonorPrintBackgroundSettings(); 1.573 +} 1.574 + 1.575 +#ifdef DO_NOISY_REFLOW 1.576 +static int myCounter = 0; 1.577 +static void printSize(char * aDesc, nscoord aSize) 1.578 +{ 1.579 + printf(" %s: ", aDesc); 1.580 + if (aSize == NS_UNCONSTRAINEDSIZE) { 1.581 + printf("UC"); 1.582 + } else { 1.583 + printf("%d", aSize); 1.584 + } 1.585 +} 1.586 +#endif 1.587 + 1.588 +/* virtual */ nscoord 1.589 +nsBoxFrame::GetMinWidth(nsRenderingContext *aRenderingContext) 1.590 +{ 1.591 + nscoord result; 1.592 + DISPLAY_MIN_WIDTH(this, result); 1.593 + 1.594 + nsBoxLayoutState state(PresContext(), aRenderingContext); 1.595 + nsSize minSize = GetMinSize(state); 1.596 + 1.597 + // GetMinSize returns border-box width, and we want to return content 1.598 + // width. Since Reflow uses the reflow state's border and padding, we 1.599 + // actually just want to subtract what GetMinSize added, which is the 1.600 + // result of GetBorderAndPadding. 1.601 + nsMargin bp; 1.602 + GetBorderAndPadding(bp); 1.603 + 1.604 + result = minSize.width - bp.LeftRight(); 1.605 + result = std::max(result, 0); 1.606 + 1.607 + return result; 1.608 +} 1.609 + 1.610 +/* virtual */ nscoord 1.611 +nsBoxFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) 1.612 +{ 1.613 + nscoord result; 1.614 + DISPLAY_PREF_WIDTH(this, result); 1.615 + 1.616 + nsBoxLayoutState state(PresContext(), aRenderingContext); 1.617 + nsSize prefSize = GetPrefSize(state); 1.618 + 1.619 + // GetPrefSize returns border-box width, and we want to return content 1.620 + // width. Since Reflow uses the reflow state's border and padding, we 1.621 + // actually just want to subtract what GetPrefSize added, which is the 1.622 + // result of GetBorderAndPadding. 1.623 + nsMargin bp; 1.624 + GetBorderAndPadding(bp); 1.625 + 1.626 + result = prefSize.width - bp.LeftRight(); 1.627 + result = std::max(result, 0); 1.628 + 1.629 + return result; 1.630 +} 1.631 + 1.632 +nsresult 1.633 +nsBoxFrame::Reflow(nsPresContext* aPresContext, 1.634 + nsHTMLReflowMetrics& aDesiredSize, 1.635 + const nsHTMLReflowState& aReflowState, 1.636 + nsReflowStatus& aStatus) 1.637 +{ 1.638 + // If you make changes to this method, please keep nsLeafBoxFrame::Reflow 1.639 + // in sync, if the changes are applicable there. 1.640 + 1.641 + DO_GLOBAL_REFLOW_COUNT("nsBoxFrame"); 1.642 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.643 + 1.644 + NS_ASSERTION(aReflowState.ComputedWidth() >=0 && 1.645 + aReflowState.ComputedHeight() >= 0, "Computed Size < 0"); 1.646 + 1.647 +#ifdef DO_NOISY_REFLOW 1.648 + printf("\n-------------Starting BoxFrame Reflow ----------------------------\n"); 1.649 + printf("%p ** nsBF::Reflow %d ", this, myCounter++); 1.650 + 1.651 + printSize("AW", aReflowState.AvailableWidth()); 1.652 + printSize("AH", aReflowState.AvailableHeight()); 1.653 + printSize("CW", aReflowState.ComputedWidth()); 1.654 + printSize("CH", aReflowState.ComputedHeight()); 1.655 + 1.656 + printf(" *\n"); 1.657 + 1.658 +#endif 1.659 + 1.660 + aStatus = NS_FRAME_COMPLETE; 1.661 + 1.662 + // create the layout state 1.663 + nsBoxLayoutState state(aPresContext, aReflowState.rendContext, 1.664 + &aReflowState, aReflowState.mReflowDepth); 1.665 + 1.666 + nsSize computedSize(aReflowState.ComputedWidth(),aReflowState.ComputedHeight()); 1.667 + 1.668 + nsMargin m; 1.669 + m = aReflowState.ComputedPhysicalBorderPadding(); 1.670 + // GetBorderAndPadding(m); 1.671 + 1.672 + nsSize prefSize(0,0); 1.673 + 1.674 + // if we are told to layout intrinsic then get our preferred size. 1.675 + NS_ASSERTION(computedSize.width != NS_INTRINSICSIZE, 1.676 + "computed width should always be computed"); 1.677 + if (computedSize.height == NS_INTRINSICSIZE) { 1.678 + prefSize = GetPrefSize(state); 1.679 + nsSize minSize = GetMinSize(state); 1.680 + nsSize maxSize = GetMaxSize(state); 1.681 + // XXXbz isn't GetPrefSize supposed to bounds-check for us? 1.682 + prefSize = BoundsCheck(minSize, prefSize, maxSize); 1.683 + } 1.684 + 1.685 + // get our desiredSize 1.686 + computedSize.width += m.left + m.right; 1.687 + 1.688 + if (aReflowState.ComputedHeight() == NS_INTRINSICSIZE) { 1.689 + computedSize.height = prefSize.height; 1.690 + // prefSize is border-box but min/max constraints are content-box. 1.691 + nscoord verticalBorderPadding = 1.692 + aReflowState.ComputedPhysicalBorderPadding().TopBottom(); 1.693 + nscoord contentHeight = computedSize.height - verticalBorderPadding; 1.694 + // Note: contentHeight might be negative, but that's OK because min-height 1.695 + // is never negative. 1.696 + computedSize.height = aReflowState.ApplyMinMaxHeight(contentHeight) + 1.697 + verticalBorderPadding; 1.698 + } else { 1.699 + computedSize.height += m.top + m.bottom; 1.700 + } 1.701 + 1.702 + nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height); 1.703 + 1.704 + SetBounds(state, r); 1.705 + 1.706 + // layout our children 1.707 + Layout(state); 1.708 + 1.709 + // ok our child could have gotten bigger. So lets get its bounds 1.710 + 1.711 + // get the ascent 1.712 + nscoord ascent = mRect.height; 1.713 + 1.714 + // getting the ascent could be a lot of work. Don't get it if 1.715 + // we are the root. The viewport doesn't care about it. 1.716 + if (!(mState & NS_STATE_IS_ROOT)) { 1.717 + ascent = GetBoxAscent(state); 1.718 + } 1.719 + 1.720 + aDesiredSize.Width() = mRect.width; 1.721 + aDesiredSize.Height() = mRect.height; 1.722 + aDesiredSize.SetTopAscent(ascent); 1.723 + 1.724 + aDesiredSize.mOverflowAreas = GetOverflowAreas(); 1.725 + 1.726 +#ifdef DO_NOISY_REFLOW 1.727 + { 1.728 + printf("%p ** nsBF(done) W:%d H:%d ", this, aDesiredSize.Width(), aDesiredSize.Height()); 1.729 + 1.730 + if (maxElementSize) { 1.731 + printf("MW:%d\n", *maxElementWidth); 1.732 + } else { 1.733 + printf("MW:?\n"); 1.734 + } 1.735 + 1.736 + } 1.737 +#endif 1.738 + 1.739 + ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); 1.740 + 1.741 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.742 + return NS_OK; 1.743 +} 1.744 + 1.745 +nsSize 1.746 +nsBoxFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState) 1.747 +{ 1.748 + NS_ASSERTION(aBoxLayoutState.GetRenderingContext(), 1.749 + "must have rendering context"); 1.750 + 1.751 + nsSize size(0,0); 1.752 + DISPLAY_PREF_SIZE(this, size); 1.753 + if (!DoesNeedRecalc(mPrefSize)) { 1.754 + return mPrefSize; 1.755 + } 1.756 + 1.757 +#ifdef DEBUG_LAYOUT 1.758 + PropagateDebug(aBoxLayoutState); 1.759 +#endif 1.760 + 1.761 + if (IsCollapsed()) 1.762 + return size; 1.763 + 1.764 + // if the size was not completely redefined in CSS then ask our children 1.765 + bool widthSet, heightSet; 1.766 + if (!nsIFrame::AddCSSPrefSize(this, size, widthSet, heightSet)) 1.767 + { 1.768 + if (mLayoutManager) { 1.769 + nsSize layoutSize = mLayoutManager->GetPrefSize(this, aBoxLayoutState); 1.770 + if (!widthSet) 1.771 + size.width = layoutSize.width; 1.772 + if (!heightSet) 1.773 + size.height = layoutSize.height; 1.774 + } 1.775 + else { 1.776 + size = nsBox::GetPrefSize(aBoxLayoutState); 1.777 + } 1.778 + } 1.779 + 1.780 + nsSize minSize = GetMinSize(aBoxLayoutState); 1.781 + nsSize maxSize = GetMaxSize(aBoxLayoutState); 1.782 + mPrefSize = BoundsCheck(minSize, size, maxSize); 1.783 + 1.784 + return mPrefSize; 1.785 +} 1.786 + 1.787 +nscoord 1.788 +nsBoxFrame::GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) 1.789 +{ 1.790 + if (!DoesNeedRecalc(mAscent)) 1.791 + return mAscent; 1.792 + 1.793 +#ifdef DEBUG_LAYOUT 1.794 + PropagateDebug(aBoxLayoutState); 1.795 +#endif 1.796 + 1.797 + if (IsCollapsed()) 1.798 + return 0; 1.799 + 1.800 + if (mLayoutManager) 1.801 + mAscent = mLayoutManager->GetAscent(this, aBoxLayoutState); 1.802 + else 1.803 + mAscent = nsBox::GetBoxAscent(aBoxLayoutState); 1.804 + 1.805 + return mAscent; 1.806 +} 1.807 + 1.808 +nsSize 1.809 +nsBoxFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState) 1.810 +{ 1.811 + NS_ASSERTION(aBoxLayoutState.GetRenderingContext(), 1.812 + "must have rendering context"); 1.813 + 1.814 + nsSize size(0,0); 1.815 + DISPLAY_MIN_SIZE(this, size); 1.816 + if (!DoesNeedRecalc(mMinSize)) { 1.817 + return mMinSize; 1.818 + } 1.819 + 1.820 +#ifdef DEBUG_LAYOUT 1.821 + PropagateDebug(aBoxLayoutState); 1.822 +#endif 1.823 + 1.824 + if (IsCollapsed()) 1.825 + return size; 1.826 + 1.827 + // if the size was not completely redefined in CSS then ask our children 1.828 + bool widthSet, heightSet; 1.829 + if (!nsIFrame::AddCSSMinSize(aBoxLayoutState, this, size, widthSet, heightSet)) 1.830 + { 1.831 + if (mLayoutManager) { 1.832 + nsSize layoutSize = mLayoutManager->GetMinSize(this, aBoxLayoutState); 1.833 + if (!widthSet) 1.834 + size.width = layoutSize.width; 1.835 + if (!heightSet) 1.836 + size.height = layoutSize.height; 1.837 + } 1.838 + else { 1.839 + size = nsBox::GetMinSize(aBoxLayoutState); 1.840 + } 1.841 + } 1.842 + 1.843 + mMinSize = size; 1.844 + 1.845 + return size; 1.846 +} 1.847 + 1.848 +nsSize 1.849 +nsBoxFrame::GetMaxSize(nsBoxLayoutState& aBoxLayoutState) 1.850 +{ 1.851 + NS_ASSERTION(aBoxLayoutState.GetRenderingContext(), 1.852 + "must have rendering context"); 1.853 + 1.854 + nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE); 1.855 + DISPLAY_MAX_SIZE(this, size); 1.856 + if (!DoesNeedRecalc(mMaxSize)) { 1.857 + return mMaxSize; 1.858 + } 1.859 + 1.860 +#ifdef DEBUG_LAYOUT 1.861 + PropagateDebug(aBoxLayoutState); 1.862 +#endif 1.863 + 1.864 + if (IsCollapsed()) 1.865 + return size; 1.866 + 1.867 + // if the size was not completely redefined in CSS then ask our children 1.868 + bool widthSet, heightSet; 1.869 + if (!nsIFrame::AddCSSMaxSize(this, size, widthSet, heightSet)) 1.870 + { 1.871 + if (mLayoutManager) { 1.872 + nsSize layoutSize = mLayoutManager->GetMaxSize(this, aBoxLayoutState); 1.873 + if (!widthSet) 1.874 + size.width = layoutSize.width; 1.875 + if (!heightSet) 1.876 + size.height = layoutSize.height; 1.877 + } 1.878 + else { 1.879 + size = nsBox::GetMaxSize(aBoxLayoutState); 1.880 + } 1.881 + } 1.882 + 1.883 + mMaxSize = size; 1.884 + 1.885 + return size; 1.886 +} 1.887 + 1.888 +nscoord 1.889 +nsBoxFrame::GetFlex(nsBoxLayoutState& aBoxLayoutState) 1.890 +{ 1.891 + if (!DoesNeedRecalc(mFlex)) 1.892 + return mFlex; 1.893 + 1.894 + mFlex = nsBox::GetFlex(aBoxLayoutState); 1.895 + 1.896 + return mFlex; 1.897 +} 1.898 + 1.899 +/** 1.900 + * If subclassing please subclass this method not layout. 1.901 + * layout will call this method. 1.902 + */ 1.903 +NS_IMETHODIMP 1.904 +nsBoxFrame::DoLayout(nsBoxLayoutState& aState) 1.905 +{ 1.906 + uint32_t oldFlags = aState.LayoutFlags(); 1.907 + aState.SetLayoutFlags(0); 1.908 + 1.909 + nsresult rv = NS_OK; 1.910 + if (mLayoutManager) { 1.911 + CoordNeedsRecalc(mAscent); 1.912 + rv = mLayoutManager->Layout(this, aState); 1.913 + } 1.914 + 1.915 + aState.SetLayoutFlags(oldFlags); 1.916 + 1.917 + if (HasAbsolutelyPositionedChildren()) { 1.918 + // Set up a |reflowState| to pass into ReflowAbsoluteFrames 1.919 + nsHTMLReflowState reflowState(aState.PresContext(), this, 1.920 + aState.GetRenderingContext(), 1.921 + nsSize(mRect.width, NS_UNCONSTRAINEDSIZE)); 1.922 + 1.923 + // Set up a |desiredSize| to pass into ReflowAbsoluteFrames 1.924 + nsHTMLReflowMetrics desiredSize(reflowState); 1.925 + desiredSize.Width() = mRect.width; 1.926 + desiredSize.Height() = mRect.height; 1.927 + 1.928 + // get the ascent (cribbed from ::Reflow) 1.929 + nscoord ascent = mRect.height; 1.930 + 1.931 + // getting the ascent could be a lot of work. Don't get it if 1.932 + // we are the root. The viewport doesn't care about it. 1.933 + if (!(mState & NS_STATE_IS_ROOT)) { 1.934 + ascent = GetBoxAscent(aState); 1.935 + } 1.936 + desiredSize.SetTopAscent(ascent); 1.937 + desiredSize.mOverflowAreas = GetOverflowAreas(); 1.938 + 1.939 + AddStateBits(NS_FRAME_IN_REFLOW); 1.940 + // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames 1.941 + // (just a dummy value; hopefully that's OK) 1.942 + nsReflowStatus reflowStatus = NS_FRAME_COMPLETE; 1.943 + ReflowAbsoluteFrames(aState.PresContext(), desiredSize, 1.944 + reflowState, reflowStatus); 1.945 + RemoveStateBits(NS_FRAME_IN_REFLOW); 1.946 + } 1.947 + 1.948 + return rv; 1.949 +} 1.950 + 1.951 +void 1.952 +nsBoxFrame::DestroyFrom(nsIFrame* aDestructRoot) 1.953 +{ 1.954 + // unregister access key 1.955 + RegUnregAccessKey(false); 1.956 + 1.957 + // clean up the container box's layout manager and child boxes 1.958 + SetLayoutManager(nullptr); 1.959 + 1.960 + nsContainerFrame::DestroyFrom(aDestructRoot); 1.961 +} 1.962 + 1.963 +#ifdef DEBUG_LAYOUT 1.964 +nsresult 1.965 +nsBoxFrame::SetDebug(nsBoxLayoutState& aState, bool aDebug) 1.966 +{ 1.967 + // see if our state matches the given debug state 1.968 + bool debugSet = mState & NS_STATE_CURRENTLY_IN_DEBUG; 1.969 + bool debugChanged = (!aDebug && debugSet) || (aDebug && !debugSet); 1.970 + 1.971 + // if it doesn't then tell each child below us the new debug state 1.972 + if (debugChanged) 1.973 + { 1.974 + if (aDebug) { 1.975 + mState |= NS_STATE_CURRENTLY_IN_DEBUG; 1.976 + } else { 1.977 + mState &= ~NS_STATE_CURRENTLY_IN_DEBUG; 1.978 + } 1.979 + 1.980 + SetDebugOnChildList(aState, mFirstChild, aDebug); 1.981 + 1.982 + MarkIntrinsicWidthsDirty(); 1.983 + } 1.984 + 1.985 + return NS_OK; 1.986 +} 1.987 +#endif 1.988 + 1.989 +/* virtual */ void 1.990 +nsBoxFrame::MarkIntrinsicWidthsDirty() 1.991 +{ 1.992 + SizeNeedsRecalc(mPrefSize); 1.993 + SizeNeedsRecalc(mMinSize); 1.994 + SizeNeedsRecalc(mMaxSize); 1.995 + CoordNeedsRecalc(mFlex); 1.996 + CoordNeedsRecalc(mAscent); 1.997 + 1.998 + if (mLayoutManager) { 1.999 + nsBoxLayoutState state(PresContext()); 1.1000 + mLayoutManager->IntrinsicWidthsDirty(this, state); 1.1001 + } 1.1002 + 1.1003 + // Don't call base class method, since everything it does is within an 1.1004 + // IsBoxWrapped check. 1.1005 +} 1.1006 + 1.1007 +nsresult 1.1008 +nsBoxFrame::RemoveFrame(ChildListID aListID, 1.1009 + nsIFrame* aOldFrame) 1.1010 +{ 1.1011 + NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids"); 1.1012 + nsPresContext* presContext = PresContext(); 1.1013 + nsBoxLayoutState state(presContext); 1.1014 + 1.1015 + // remove the child frame 1.1016 + mFrames.RemoveFrame(aOldFrame); 1.1017 + 1.1018 + // notify the layout manager 1.1019 + if (mLayoutManager) 1.1020 + mLayoutManager->ChildrenRemoved(this, state, aOldFrame); 1.1021 + 1.1022 + // destroy the child frame 1.1023 + aOldFrame->Destroy(); 1.1024 + 1.1025 + // mark us dirty and generate a reflow command 1.1026 + PresContext()->PresShell()-> 1.1027 + FrameNeedsReflow(this, nsIPresShell::eTreeChange, 1.1028 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.1029 + return NS_OK; 1.1030 +} 1.1031 + 1.1032 +nsresult 1.1033 +nsBoxFrame::InsertFrames(ChildListID aListID, 1.1034 + nsIFrame* aPrevFrame, 1.1035 + nsFrameList& aFrameList) 1.1036 +{ 1.1037 + NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this, 1.1038 + "inserting after sibling frame with different parent"); 1.1039 + NS_ASSERTION(!aPrevFrame || mFrames.ContainsFrame(aPrevFrame), 1.1040 + "inserting after sibling frame not in our child list"); 1.1041 + NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids"); 1.1042 + nsBoxLayoutState state(PresContext()); 1.1043 + 1.1044 + // insert the child frames 1.1045 + const nsFrameList::Slice& newFrames = 1.1046 + mFrames.InsertFrames(this, aPrevFrame, aFrameList); 1.1047 + 1.1048 + // notify the layout manager 1.1049 + if (mLayoutManager) 1.1050 + mLayoutManager->ChildrenInserted(this, state, aPrevFrame, newFrames); 1.1051 + 1.1052 + // Make sure to check box order _after_ notifying the layout 1.1053 + // manager; otherwise the slice we give the layout manager will 1.1054 + // just be bogus. If the layout manager cares about the order, we 1.1055 + // just lose. 1.1056 + CheckBoxOrder(); 1.1057 + 1.1058 +#ifdef DEBUG_LAYOUT 1.1059 + // if we are in debug make sure our children are in debug as well. 1.1060 + if (mState & NS_STATE_CURRENTLY_IN_DEBUG) 1.1061 + SetDebugOnChildList(state, mFrames.FirstChild(), true); 1.1062 +#endif 1.1063 + 1.1064 + PresContext()->PresShell()-> 1.1065 + FrameNeedsReflow(this, nsIPresShell::eTreeChange, 1.1066 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.1067 + return NS_OK; 1.1068 +} 1.1069 + 1.1070 + 1.1071 +nsresult 1.1072 +nsBoxFrame::AppendFrames(ChildListID aListID, 1.1073 + nsFrameList& aFrameList) 1.1074 +{ 1.1075 + NS_PRECONDITION(aListID == kPrincipalList, "We don't support out-of-flow kids"); 1.1076 + nsBoxLayoutState state(PresContext()); 1.1077 + 1.1078 + // append the new frames 1.1079 + const nsFrameList::Slice& newFrames = mFrames.AppendFrames(this, aFrameList); 1.1080 + 1.1081 + // notify the layout manager 1.1082 + if (mLayoutManager) 1.1083 + mLayoutManager->ChildrenAppended(this, state, newFrames); 1.1084 + 1.1085 + // Make sure to check box order _after_ notifying the layout 1.1086 + // manager; otherwise the slice we give the layout manager will 1.1087 + // just be bogus. If the layout manager cares about the order, we 1.1088 + // just lose. 1.1089 + CheckBoxOrder(); 1.1090 + 1.1091 +#ifdef DEBUG_LAYOUT 1.1092 + // if we are in debug make sure our children are in debug as well. 1.1093 + if (mState & NS_STATE_CURRENTLY_IN_DEBUG) 1.1094 + SetDebugOnChildList(state, mFrames.FirstChild(), true); 1.1095 +#endif 1.1096 + 1.1097 + // XXXbz why is this NS_FRAME_FIRST_REFLOW check here? 1.1098 + if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) { 1.1099 + PresContext()->PresShell()-> 1.1100 + FrameNeedsReflow(this, nsIPresShell::eTreeChange, 1.1101 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.1102 + } 1.1103 + return NS_OK; 1.1104 +} 1.1105 + 1.1106 +/* virtual */ nsIFrame* 1.1107 +nsBoxFrame::GetContentInsertionFrame() 1.1108 +{ 1.1109 + if (GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) 1.1110 + return GetFirstPrincipalChild()->GetContentInsertionFrame(); 1.1111 + return nsContainerFrame::GetContentInsertionFrame(); 1.1112 +} 1.1113 + 1.1114 +nsresult 1.1115 +nsBoxFrame::AttributeChanged(int32_t aNameSpaceID, 1.1116 + nsIAtom* aAttribute, 1.1117 + int32_t aModType) 1.1118 +{ 1.1119 + nsresult rv = nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, 1.1120 + aModType); 1.1121 + 1.1122 + // Ignore 'width', 'height', 'screenX', 'screenY' and 'sizemode' on a 1.1123 + // <window>. 1.1124 + nsIAtom *tag = mContent->Tag(); 1.1125 + if ((tag == nsGkAtoms::window || 1.1126 + tag == nsGkAtoms::page || 1.1127 + tag == nsGkAtoms::dialog || 1.1128 + tag == nsGkAtoms::wizard) && 1.1129 + (nsGkAtoms::width == aAttribute || 1.1130 + nsGkAtoms::height == aAttribute || 1.1131 + nsGkAtoms::screenX == aAttribute || 1.1132 + nsGkAtoms::screenY == aAttribute || 1.1133 + nsGkAtoms::sizemode == aAttribute)) { 1.1134 + return rv; 1.1135 + } 1.1136 + 1.1137 + if (aAttribute == nsGkAtoms::width || 1.1138 + aAttribute == nsGkAtoms::height || 1.1139 + aAttribute == nsGkAtoms::align || 1.1140 + aAttribute == nsGkAtoms::valign || 1.1141 + aAttribute == nsGkAtoms::left || 1.1142 + aAttribute == nsGkAtoms::top || 1.1143 + aAttribute == nsGkAtoms::right || 1.1144 + aAttribute == nsGkAtoms::bottom || 1.1145 + aAttribute == nsGkAtoms::start || 1.1146 + aAttribute == nsGkAtoms::end || 1.1147 + aAttribute == nsGkAtoms::minwidth || 1.1148 + aAttribute == nsGkAtoms::maxwidth || 1.1149 + aAttribute == nsGkAtoms::minheight || 1.1150 + aAttribute == nsGkAtoms::maxheight || 1.1151 + aAttribute == nsGkAtoms::flex || 1.1152 + aAttribute == nsGkAtoms::orient || 1.1153 + aAttribute == nsGkAtoms::pack || 1.1154 + aAttribute == nsGkAtoms::dir || 1.1155 + aAttribute == nsGkAtoms::mousethrough || 1.1156 + aAttribute == nsGkAtoms::equalsize) { 1.1157 + 1.1158 + if (aAttribute == nsGkAtoms::align || 1.1159 + aAttribute == nsGkAtoms::valign || 1.1160 + aAttribute == nsGkAtoms::orient || 1.1161 + aAttribute == nsGkAtoms::pack || 1.1162 +#ifdef DEBUG_LAYOUT 1.1163 + aAttribute == nsGkAtoms::debug || 1.1164 +#endif 1.1165 + aAttribute == nsGkAtoms::dir) { 1.1166 + 1.1167 + mValign = nsBoxFrame::vAlign_Top; 1.1168 + mHalign = nsBoxFrame::hAlign_Left; 1.1169 + 1.1170 + bool orient = true; 1.1171 + GetInitialOrientation(orient); 1.1172 + if (orient) 1.1173 + mState |= NS_STATE_IS_HORIZONTAL; 1.1174 + else 1.1175 + mState &= ~NS_STATE_IS_HORIZONTAL; 1.1176 + 1.1177 + bool normal = true; 1.1178 + GetInitialDirection(normal); 1.1179 + if (normal) 1.1180 + mState |= NS_STATE_IS_DIRECTION_NORMAL; 1.1181 + else 1.1182 + mState &= ~NS_STATE_IS_DIRECTION_NORMAL; 1.1183 + 1.1184 + GetInitialVAlignment(mValign); 1.1185 + GetInitialHAlignment(mHalign); 1.1186 + 1.1187 + bool equalSize = false; 1.1188 + GetInitialEqualSize(equalSize); 1.1189 + if (equalSize) 1.1190 + mState |= NS_STATE_EQUAL_SIZE; 1.1191 + else 1.1192 + mState &= ~NS_STATE_EQUAL_SIZE; 1.1193 + 1.1194 +#ifdef DEBUG_LAYOUT 1.1195 + bool debug = mState & NS_STATE_SET_TO_DEBUG; 1.1196 + bool debugSet = GetInitialDebug(debug); 1.1197 + if (debugSet) { 1.1198 + mState |= NS_STATE_DEBUG_WAS_SET; 1.1199 + 1.1200 + if (debug) 1.1201 + mState |= NS_STATE_SET_TO_DEBUG; 1.1202 + else 1.1203 + mState &= ~NS_STATE_SET_TO_DEBUG; 1.1204 + } else { 1.1205 + mState &= ~NS_STATE_DEBUG_WAS_SET; 1.1206 + } 1.1207 +#endif 1.1208 + 1.1209 + bool autostretch = !!(mState & NS_STATE_AUTO_STRETCH); 1.1210 + GetInitialAutoStretch(autostretch); 1.1211 + if (autostretch) 1.1212 + mState |= NS_STATE_AUTO_STRETCH; 1.1213 + else 1.1214 + mState &= ~NS_STATE_AUTO_STRETCH; 1.1215 + } 1.1216 + else if (aAttribute == nsGkAtoms::left || 1.1217 + aAttribute == nsGkAtoms::top || 1.1218 + aAttribute == nsGkAtoms::right || 1.1219 + aAttribute == nsGkAtoms::bottom || 1.1220 + aAttribute == nsGkAtoms::start || 1.1221 + aAttribute == nsGkAtoms::end) { 1.1222 + mState &= ~NS_STATE_STACK_NOT_POSITIONED; 1.1223 + } 1.1224 + else if (aAttribute == nsGkAtoms::mousethrough) { 1.1225 + UpdateMouseThrough(); 1.1226 + } 1.1227 + 1.1228 + PresContext()->PresShell()-> 1.1229 + FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY); 1.1230 + } 1.1231 + else if (aAttribute == nsGkAtoms::ordinal) { 1.1232 + nsBoxLayoutState state(PresContext()); 1.1233 + nsIFrame* parent = GetParentBox(); 1.1234 + // If our parent is not a box, there's not much we can do... but in that 1.1235 + // case our ordinal doesn't matter anyway, so that's ok. 1.1236 + // Also don't bother with popup frames since they are kept on the 1.1237 + // kPopupList and RelayoutChildAtOrdinal() only handles 1.1238 + // principal children. 1.1239 + if (parent && !(GetStateBits() & NS_FRAME_OUT_OF_FLOW) && 1.1240 + StyleDisplay()->mDisplay != NS_STYLE_DISPLAY_POPUP) { 1.1241 + parent->RelayoutChildAtOrdinal(state, this); 1.1242 + // XXXldb Should this instead be a tree change on the child or parent? 1.1243 + PresContext()->PresShell()-> 1.1244 + FrameNeedsReflow(parent, nsIPresShell::eStyleChange, 1.1245 + NS_FRAME_IS_DIRTY); 1.1246 + } 1.1247 + } 1.1248 + // If the accesskey changed, register for the new value 1.1249 + // The old value has been unregistered in nsXULElement::SetAttr 1.1250 + else if (aAttribute == nsGkAtoms::accesskey) { 1.1251 + RegUnregAccessKey(true); 1.1252 + } 1.1253 + else if (aAttribute == nsGkAtoms::rows && 1.1254 + tag == nsGkAtoms::tree) { 1.1255 + // Reflow ourselves and all our children if "rows" changes, since 1.1256 + // nsTreeBodyFrame's layout reads this from its parent (this frame). 1.1257 + PresContext()->PresShell()-> 1.1258 + FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY); 1.1259 + } 1.1260 + 1.1261 + return rv; 1.1262 +} 1.1263 + 1.1264 +#ifdef DEBUG_LAYOUT 1.1265 +void 1.1266 +nsBoxFrame::GetDebugPref(nsPresContext* aPresContext) 1.1267 +{ 1.1268 + gDebug = Preferences::GetBool("xul.debug.box"); 1.1269 +} 1.1270 + 1.1271 +class nsDisplayXULDebug : public nsDisplayItem { 1.1272 +public: 1.1273 + nsDisplayXULDebug(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) : 1.1274 + nsDisplayItem(aBuilder, aFrame) { 1.1275 + MOZ_COUNT_CTOR(nsDisplayXULDebug); 1.1276 + } 1.1277 +#ifdef NS_BUILD_REFCNT_LOGGING 1.1278 + virtual ~nsDisplayXULDebug() { 1.1279 + MOZ_COUNT_DTOR(nsDisplayXULDebug); 1.1280 + } 1.1281 +#endif 1.1282 + 1.1283 + virtual void HitTest(nsDisplayListBuilder* aBuilder, nsRect aRect, 1.1284 + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) { 1.1285 + nsPoint rectCenter(aRect.x + aRect.width / 2, aRect.y + aRect.height / 2); 1.1286 + static_cast<nsBoxFrame*>(mFrame)-> 1.1287 + DisplayDebugInfoFor(this, rectCenter - ToReferenceFrame()); 1.1288 + aOutFrames->AppendElement(this); 1.1289 + } 1.1290 + virtual void Paint(nsDisplayListBuilder* aBuilder 1.1291 + nsRenderingContext* aCtx); 1.1292 + NS_DISPLAY_DECL_NAME("XULDebug", TYPE_XUL_DEBUG) 1.1293 +}; 1.1294 + 1.1295 +void 1.1296 +nsDisplayXULDebug::Paint(nsDisplayListBuilder* aBuilder, 1.1297 + nsRenderingContext* aCtx) 1.1298 +{ 1.1299 + static_cast<nsBoxFrame*>(mFrame)-> 1.1300 + PaintXULDebugOverlay(*aCtx, ToReferenceFrame()); 1.1301 +} 1.1302 + 1.1303 +static void 1.1304 +PaintXULDebugBackground(nsIFrame* aFrame, nsRenderingContext* aCtx, 1.1305 + const nsRect& aDirtyRect, nsPoint aPt) 1.1306 +{ 1.1307 + static_cast<nsBoxFrame*>(aFrame)->PaintXULDebugBackground(*aCtx, aPt); 1.1308 +} 1.1309 +#endif 1.1310 + 1.1311 +void 1.1312 +nsBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.1313 + const nsRect& aDirtyRect, 1.1314 + const nsDisplayListSet& aLists) 1.1315 +{ 1.1316 + // forcelayer is only supported on XUL elements with box layout 1.1317 + bool forceLayer = 1.1318 + GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer) && 1.1319 + GetContent()->IsXUL(); 1.1320 + 1.1321 + // Check for frames that are marked as a part of the region used 1.1322 + // in calculating glass margins on Windows. 1.1323 + if (GetContent()->IsXUL()) { 1.1324 + const nsStyleDisplay* styles = StyleDisplay(); 1.1325 + if (styles && styles->mAppearance == NS_THEME_WIN_EXCLUDE_GLASS) { 1.1326 + nsRect rect = nsRect(aBuilder->ToReferenceFrame(this), GetSize()); 1.1327 + aBuilder->AddExcludedGlassRegion(rect); 1.1328 + } 1.1329 + } 1.1330 + 1.1331 + nsDisplayListCollection tempLists; 1.1332 + const nsDisplayListSet& destination = forceLayer ? tempLists : aLists; 1.1333 + 1.1334 + DisplayBorderBackgroundOutline(aBuilder, destination); 1.1335 + 1.1336 +#ifdef DEBUG_LAYOUT 1.1337 + if (mState & NS_STATE_CURRENTLY_IN_DEBUG) { 1.1338 + destination.BorderBackground()->AppendNewToTop(new (aBuilder) 1.1339 + nsDisplayGeneric(aBuilder, this, PaintXULDebugBackground, 1.1340 + "XULDebugBackground")); 1.1341 + destination.Outlines()->AppendNewToTop(new (aBuilder) 1.1342 + nsDisplayXULDebug(aBuilder, this)); 1.1343 + } 1.1344 +#endif 1.1345 + 1.1346 + BuildDisplayListForChildren(aBuilder, aDirtyRect, destination); 1.1347 + 1.1348 + // see if we have to draw a selection frame around this container 1.1349 + DisplaySelectionOverlay(aBuilder, destination.Content()); 1.1350 + 1.1351 + if (forceLayer) { 1.1352 + // This is a bit of a hack. Collect up all descendant display items 1.1353 + // and merge them into a single Content() list. This can cause us 1.1354 + // to violate CSS stacking order, but forceLayer is a magic 1.1355 + // XUL-only extension anyway. 1.1356 + nsDisplayList masterList; 1.1357 + masterList.AppendToTop(tempLists.BorderBackground()); 1.1358 + masterList.AppendToTop(tempLists.BlockBorderBackgrounds()); 1.1359 + masterList.AppendToTop(tempLists.Floats()); 1.1360 + masterList.AppendToTop(tempLists.Content()); 1.1361 + masterList.AppendToTop(tempLists.PositionedDescendants()); 1.1362 + masterList.AppendToTop(tempLists.Outlines()); 1.1363 + // Wrap the list to make it its own layer 1.1364 + aLists.Content()->AppendNewToTop(new (aBuilder) 1.1365 + nsDisplayOwnLayer(aBuilder, this, &masterList)); 1.1366 + } 1.1367 +} 1.1368 + 1.1369 +void 1.1370 +nsBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder* aBuilder, 1.1371 + const nsRect& aDirtyRect, 1.1372 + const nsDisplayListSet& aLists) 1.1373 +{ 1.1374 + nsIFrame* kid = mFrames.FirstChild(); 1.1375 + // Put each child's background onto the BlockBorderBackgrounds list 1.1376 + // to emulate the existing two-layer XUL painting scheme. 1.1377 + nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds()); 1.1378 + // The children should be in the right order 1.1379 + while (kid) { 1.1380 + BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set); 1.1381 + kid = kid->GetNextSibling(); 1.1382 + } 1.1383 +} 1.1384 + 1.1385 +// REVIEW: PaintChildren did a few things none of which are a big deal 1.1386 +// anymore: 1.1387 +// * Paint some debugging rects for this frame. 1.1388 +// This is done by nsDisplayXULDebugBackground, which goes in the 1.1389 +// BorderBackground() layer so it isn't clipped by OVERFLOW_CLIP. 1.1390 +// * Apply OVERFLOW_CLIP to the children. 1.1391 +// This is now in nsFrame::BuildDisplayListForStackingContext/Child. 1.1392 +// * Actually paint the children. 1.1393 +// Moved to BuildDisplayList. 1.1394 +// * Paint per-kid debug information. 1.1395 +// This is done by nsDisplayXULDebug, which is in the Outlines() 1.1396 +// layer so it goes on top. This means it is not clipped by OVERFLOW_CLIP, 1.1397 +// whereas it did used to respect OVERFLOW_CLIP, but too bad. 1.1398 +#ifdef DEBUG_LAYOUT 1.1399 +void 1.1400 +nsBoxFrame::PaintXULDebugBackground(nsRenderingContext& aRenderingContext, 1.1401 + nsPoint aPt) 1.1402 +{ 1.1403 + nsMargin border; 1.1404 + GetBorder(border); 1.1405 + 1.1406 + nsMargin debugBorder; 1.1407 + nsMargin debugMargin; 1.1408 + nsMargin debugPadding; 1.1409 + 1.1410 + bool isHorizontal = IsHorizontal(); 1.1411 + 1.1412 + GetDebugBorder(debugBorder); 1.1413 + PixelMarginToTwips(GetPresContext(), debugBorder); 1.1414 + 1.1415 + GetDebugMargin(debugMargin); 1.1416 + PixelMarginToTwips(GetPresContext(), debugMargin); 1.1417 + 1.1418 + GetDebugPadding(debugPadding); 1.1419 + PixelMarginToTwips(GetPresContext(), debugPadding); 1.1420 + 1.1421 + nsRect inner(mRect); 1.1422 + inner.MoveTo(aPt); 1.1423 + inner.Deflate(debugMargin); 1.1424 + inner.Deflate(border); 1.1425 + //nsRect borderRect(inner); 1.1426 + 1.1427 + nscolor color; 1.1428 + if (isHorizontal) { 1.1429 + color = NS_RGB(0,0,255); 1.1430 + } else { 1.1431 + color = NS_RGB(255,0,0); 1.1432 + } 1.1433 + 1.1434 + aRenderingContext.SetColor(color); 1.1435 + 1.1436 + //left 1.1437 + nsRect r(inner); 1.1438 + r.width = debugBorder.left; 1.1439 + aRenderingContext.FillRect(r); 1.1440 + 1.1441 + // top 1.1442 + r = inner; 1.1443 + r.height = debugBorder.top; 1.1444 + aRenderingContext.FillRect(r); 1.1445 + 1.1446 + //right 1.1447 + r = inner; 1.1448 + r.x = r.x + r.width - debugBorder.right; 1.1449 + r.width = debugBorder.right; 1.1450 + aRenderingContext.FillRect(r); 1.1451 + 1.1452 + //bottom 1.1453 + r = inner; 1.1454 + r.y = r.y + r.height - debugBorder.bottom; 1.1455 + r.height = debugBorder.bottom; 1.1456 + aRenderingContext.FillRect(r); 1.1457 + 1.1458 + 1.1459 + // if we have dirty children or we are dirty 1.1460 + // place a green border around us. 1.1461 + if (NS_SUBTREE_DIRTY(this)) { 1.1462 + nsRect dirtyr(inner); 1.1463 + aRenderingContext.SetColor(NS_RGB(0,255,0)); 1.1464 + aRenderingContext.DrawRect(dirtyr); 1.1465 + aRenderingContext.SetColor(color); 1.1466 + } 1.1467 +} 1.1468 + 1.1469 +void 1.1470 +nsBoxFrame::PaintXULDebugOverlay(nsRenderingContext& aRenderingContext, 1.1471 + nsPoint aPt) 1.1472 + nsMargin border; 1.1473 + GetBorder(border); 1.1474 + 1.1475 + nsMargin debugMargin; 1.1476 + GetDebugMargin(debugMargin); 1.1477 + PixelMarginToTwips(GetPresContext(), debugMargin); 1.1478 + 1.1479 + nsRect inner(mRect); 1.1480 + inner.MoveTo(aPt); 1.1481 + inner.Deflate(debugMargin); 1.1482 + inner.Deflate(border); 1.1483 + 1.1484 + nscoord onePixel = GetPresContext()->IntScaledPixelsToTwips(1); 1.1485 + 1.1486 + kid = GetChildBox(); 1.1487 + while (nullptr != kid) { 1.1488 + bool isHorizontal = IsHorizontal(); 1.1489 + 1.1490 + nscoord x, y, borderSize, spacerSize; 1.1491 + 1.1492 + nsRect cr(kid->mRect); 1.1493 + nsMargin margin; 1.1494 + kid->GetMargin(margin); 1.1495 + cr.Inflate(margin); 1.1496 + 1.1497 + if (isHorizontal) 1.1498 + { 1.1499 + cr.y = inner.y; 1.1500 + x = cr.x; 1.1501 + y = cr.y + onePixel; 1.1502 + spacerSize = debugBorder.top - onePixel*4; 1.1503 + } else { 1.1504 + cr.x = inner.x; 1.1505 + x = cr.y; 1.1506 + y = cr.x + onePixel; 1.1507 + spacerSize = debugBorder.left - onePixel*4; 1.1508 + } 1.1509 + 1.1510 + nsBoxLayoutState state(GetPresContext()); 1.1511 + nscoord flex = kid->GetFlex(state); 1.1512 + 1.1513 + if (!kid->IsCollapsed()) { 1.1514 + aRenderingContext.SetColor(NS_RGB(255,255,255)); 1.1515 + 1.1516 + if (isHorizontal) 1.1517 + borderSize = cr.width; 1.1518 + else 1.1519 + borderSize = cr.height; 1.1520 + 1.1521 + DrawSpacer(GetPresContext(), aRenderingContext, isHorizontal, flex, x, y, borderSize, spacerSize); 1.1522 + } 1.1523 + 1.1524 + kid = kid->GetNextBox(); 1.1525 + } 1.1526 +} 1.1527 +#endif 1.1528 + 1.1529 +#ifdef DEBUG_LAYOUT 1.1530 +void 1.1531 +nsBoxFrame::GetBoxName(nsAutoString& aName) 1.1532 +{ 1.1533 + GetFrameName(aName); 1.1534 +} 1.1535 +#endif 1.1536 + 1.1537 +#ifdef DEBUG_FRAME_DUMP 1.1538 +nsresult 1.1539 +nsBoxFrame::GetFrameName(nsAString& aResult) const 1.1540 +{ 1.1541 + return MakeFrameName(NS_LITERAL_STRING("Box"), aResult); 1.1542 +} 1.1543 +#endif 1.1544 + 1.1545 +nsIAtom* 1.1546 +nsBoxFrame::GetType() const 1.1547 +{ 1.1548 + return nsGkAtoms::boxFrame; 1.1549 +} 1.1550 + 1.1551 +#ifdef DEBUG_LAYOUT 1.1552 +nsresult 1.1553 +nsBoxFrame::GetDebug(bool& aDebug) 1.1554 +{ 1.1555 + aDebug = (mState & NS_STATE_CURRENTLY_IN_DEBUG); 1.1556 + return NS_OK; 1.1557 +} 1.1558 +#endif 1.1559 + 1.1560 +// REVIEW: nsBoxFrame::GetFrameForPoint is a problem because of 'mousethrough' 1.1561 +// attribute support. Here's how it works: 1.1562 +// * For each child frame F, we determine the target frame T(F) by recursively 1.1563 +// invoking GetFrameForPoint on the child 1.1564 +// * Let F' be the last child frame such that T(F') doesn't have mousethrough. 1.1565 +// If F' exists, return T(F') 1.1566 +// * Otherwise let F'' be the first child frame such that T(F'') is non-null. 1.1567 +// If F'' exists, return T(F'') 1.1568 +// * Otherwise return this frame, if this frame contains the point 1.1569 +// * Otherwise return null 1.1570 +// It's not clear how this should work for more complex z-ordering situations. 1.1571 +// The basic principle seems to be that if a frame F has a descendant 1.1572 +// 'mousethrough' frame that includes the target position, then F 1.1573 +// will not receive events (unless it overrides GetFrameForPoint). 1.1574 +// A 'mousethrough' frame will only receive an event if, after applying that rule, 1.1575 +// all eligible frames are 'mousethrough'; the bottom-most inner-most 'mousethrough' 1.1576 +// frame is then chosen (the first eligible frame reached in a 1.1577 +// traversal of the frame tree --- pre/post is irrelevant since ancestors 1.1578 +// of the mousethrough frames can't be eligible). 1.1579 +// IMHO this is very bogus and adds a great deal of complexity for something 1.1580 +// that is very rarely used. So I'm redefining 'mousethrough' to the following: 1.1581 +// a frame with mousethrough is transparent to mouse events. This is compatible 1.1582 +// with the way 'mousethrough' is used in Seamonkey's navigator.xul and 1.1583 +// Firefox's browser.xul. The only other place it's used is in the 'expander' 1.1584 +// XBL binding, which in our tree is only used by Thunderbird SMIME Advanced 1.1585 +// Preferences, and I can't figure out what that does, so I'll have to test it. 1.1586 +// If it's broken I'll probably just change the binding to use it more sensibly. 1.1587 +// This new behaviour is implemented in nsDisplayList::HitTest. 1.1588 +// REVIEW: This debug-box stuff is annoying. I'm just going to put debug boxes 1.1589 +// in the outline layer and avoid GetDebugBoxAt. 1.1590 + 1.1591 +// REVIEW: GetCursor had debug-only event dumping code. I have replaced it 1.1592 +// with instrumentation in nsDisplayXULDebug. 1.1593 + 1.1594 +#ifdef DEBUG_LAYOUT 1.1595 +void 1.1596 +nsBoxFrame::DrawLine(nsRenderingContext& aRenderingContext, bool aHorizontal, nscoord x1, nscoord y1, nscoord x2, nscoord y2) 1.1597 +{ 1.1598 + if (aHorizontal) 1.1599 + aRenderingContext.DrawLine(x1,y1,x2,y2); 1.1600 + else 1.1601 + aRenderingContext.DrawLine(y1,x1,y2,x2); 1.1602 +} 1.1603 + 1.1604 +void 1.1605 +nsBoxFrame::FillRect(nsRenderingContext& aRenderingContext, bool aHorizontal, nscoord x, nscoord y, nscoord width, nscoord height) 1.1606 +{ 1.1607 + if (aHorizontal) 1.1608 + aRenderingContext.FillRect(x,y,width,height); 1.1609 + else 1.1610 + aRenderingContext.FillRect(y,x,height,width); 1.1611 +} 1.1612 + 1.1613 +void 1.1614 +nsBoxFrame::DrawSpacer(nsPresContext* aPresContext, nsRenderingContext& aRenderingContext, bool aHorizontal, int32_t flex, nscoord x, nscoord y, nscoord size, nscoord spacerSize) 1.1615 +{ 1.1616 + nscoord onePixel = aPresContext->IntScaledPixelsToTwips(1); 1.1617 + 1.1618 + // if we do draw the coils 1.1619 + int distance = 0; 1.1620 + int center = 0; 1.1621 + int offset = 0; 1.1622 + int coilSize = COIL_SIZE*onePixel; 1.1623 + int halfSpacer = spacerSize/2; 1.1624 + 1.1625 + distance = size; 1.1626 + center = y + halfSpacer; 1.1627 + offset = x; 1.1628 + 1.1629 + int coils = distance/coilSize; 1.1630 + 1.1631 + int halfCoilSize = coilSize/2; 1.1632 + 1.1633 + if (flex == 0) { 1.1634 + DrawLine(aRenderingContext, aHorizontal, x,y + spacerSize/2, x + size, y + spacerSize/2); 1.1635 + } else { 1.1636 + for (int i=0; i < coils; i++) 1.1637 + { 1.1638 + DrawLine(aRenderingContext, aHorizontal, offset, center+halfSpacer, offset+halfCoilSize, center-halfSpacer); 1.1639 + DrawLine(aRenderingContext, aHorizontal, offset+halfCoilSize, center-halfSpacer, offset+coilSize, center+halfSpacer); 1.1640 + 1.1641 + offset += coilSize; 1.1642 + } 1.1643 + } 1.1644 + 1.1645 + FillRect(aRenderingContext, aHorizontal, x + size - spacerSize/2, y, spacerSize/2, spacerSize); 1.1646 + FillRect(aRenderingContext, aHorizontal, x, y, spacerSize/2, spacerSize); 1.1647 + 1.1648 + //DrawKnob(aPresContext, aRenderingContext, x + size - spacerSize, y, spacerSize); 1.1649 +} 1.1650 + 1.1651 +void 1.1652 +nsBoxFrame::GetDebugBorder(nsMargin& aInset) 1.1653 +{ 1.1654 + aInset.SizeTo(2,2,2,2); 1.1655 + 1.1656 + if (IsHorizontal()) 1.1657 + aInset.top = 10; 1.1658 + else 1.1659 + aInset.left = 10; 1.1660 +} 1.1661 + 1.1662 +void 1.1663 +nsBoxFrame::GetDebugMargin(nsMargin& aInset) 1.1664 +{ 1.1665 + aInset.SizeTo(2,2,2,2); 1.1666 +} 1.1667 + 1.1668 +void 1.1669 +nsBoxFrame::GetDebugPadding(nsMargin& aPadding) 1.1670 +{ 1.1671 + aPadding.SizeTo(2,2,2,2); 1.1672 +} 1.1673 + 1.1674 +void 1.1675 +nsBoxFrame::PixelMarginToTwips(nsPresContext* aPresContext, nsMargin& aMarginPixels) 1.1676 +{ 1.1677 + nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); 1.1678 + aMarginPixels.left *= onePixel; 1.1679 + aMarginPixels.right *= onePixel; 1.1680 + aMarginPixels.top *= onePixel; 1.1681 + aMarginPixels.bottom *= onePixel; 1.1682 +} 1.1683 + 1.1684 +void 1.1685 +nsBoxFrame::GetValue(nsPresContext* aPresContext, const nsSize& a, const nsSize& b, char* ch) 1.1686 +{ 1.1687 + float p2t = aPresContext->ScaledPixelsToTwips(); 1.1688 + 1.1689 + char width[100]; 1.1690 + char height[100]; 1.1691 + 1.1692 + if (a.width == NS_INTRINSICSIZE) 1.1693 + sprintf(width,"%s","INF"); 1.1694 + else 1.1695 + sprintf(width,"%d", nscoord(a.width/*/p2t*/)); 1.1696 + 1.1697 + if (a.height == NS_INTRINSICSIZE) 1.1698 + sprintf(height,"%s","INF"); 1.1699 + else 1.1700 + sprintf(height,"%d", nscoord(a.height/*/p2t*/)); 1.1701 + 1.1702 + 1.1703 + sprintf(ch, "(%s%s, %s%s)", width, (b.width != NS_INTRINSICSIZE ? "[SET]" : ""), 1.1704 + height, (b.height != NS_INTRINSICSIZE ? "[SET]" : "")); 1.1705 + 1.1706 +} 1.1707 + 1.1708 +void 1.1709 +nsBoxFrame::GetValue(nsPresContext* aPresContext, int32_t a, int32_t b, char* ch) 1.1710 +{ 1.1711 + if (a == NS_INTRINSICSIZE) 1.1712 + sprintf(ch, "%d[SET]", b); 1.1713 + else 1.1714 + sprintf(ch, "%d", a); 1.1715 +} 1.1716 + 1.1717 +nsresult 1.1718 +nsBoxFrame::DisplayDebugInfoFor(nsIFrame* aBox, 1.1719 + nsPoint& aPoint) 1.1720 +{ 1.1721 + nsBoxLayoutState state(GetPresContext()); 1.1722 + 1.1723 + nscoord x = aPoint.x; 1.1724 + nscoord y = aPoint.y; 1.1725 + 1.1726 + // get the area inside our border but not our debug margins. 1.1727 + nsRect insideBorder(aBox->mRect); 1.1728 + insideBorder.MoveTo(0,0): 1.1729 + nsMargin border(0,0,0,0); 1.1730 + aBox->GetBorderAndPadding(border); 1.1731 + insideBorder.Deflate(border); 1.1732 + 1.1733 + bool isHorizontal = IsHorizontal(); 1.1734 + 1.1735 + if (!insideBorder.Contains(nsPoint(x,y))) 1.1736 + return NS_ERROR_FAILURE; 1.1737 + 1.1738 + //printf("%%%%%% inside box %%%%%%%\n"); 1.1739 + 1.1740 + int count = 0; 1.1741 + nsIFrame* child = aBox->GetChildBox(); 1.1742 + 1.1743 + nsMargin m; 1.1744 + nsMargin m2; 1.1745 + GetDebugBorder(m); 1.1746 + PixelMarginToTwips(aPresContext, m); 1.1747 + 1.1748 + GetDebugMargin(m2); 1.1749 + PixelMarginToTwips(aPresContext, m2); 1.1750 + 1.1751 + m += m2; 1.1752 + 1.1753 + if ((isHorizontal && y < insideBorder.y + m.top) || 1.1754 + (!isHorizontal && x < insideBorder.x + m.left)) { 1.1755 + //printf("**** inside debug border *******\n"); 1.1756 + while (child) 1.1757 + { 1.1758 + const nsRect& r = child->mRect; 1.1759 + 1.1760 + // if we are not in the child. But in the spacer above the child. 1.1761 + if ((isHorizontal && x >= r.x && x < r.x + r.width) || 1.1762 + (!isHorizontal && y >= r.y && y < r.y + r.height)) { 1.1763 + aCursor = NS_STYLE_CURSOR_POINTER; 1.1764 + // found it but we already showed it. 1.1765 + if (mDebugChild == child) 1.1766 + return NS_OK; 1.1767 + 1.1768 + if (aBox->GetContent()) { 1.1769 + printf("---------------\n"); 1.1770 + DumpBox(stdout); 1.1771 + printf("\n"); 1.1772 + } 1.1773 + 1.1774 + if (child->GetContent()) { 1.1775 + printf("child #%d: ", count); 1.1776 + child->DumpBox(stdout); 1.1777 + printf("\n"); 1.1778 + } 1.1779 + 1.1780 + mDebugChild = child; 1.1781 + 1.1782 + nsSize prefSizeCSS(NS_INTRINSICSIZE, NS_INTRINSICSIZE); 1.1783 + nsSize minSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE); 1.1784 + nsSize maxSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE); 1.1785 + nscoord flexCSS = NS_INTRINSICSIZE; 1.1786 + 1.1787 + bool widthSet, heightSet; 1.1788 + nsIFrame::AddCSSPrefSize(child, prefSizeCSS, widthSet, heightSet); 1.1789 + nsIFrame::AddCSSMinSize (state, child, minSizeCSS, widthSet, heightSet); 1.1790 + nsIFrame::AddCSSMaxSize (child, maxSizeCSS, widthSet, heightSet); 1.1791 + nsIFrame::AddCSSFlex (state, child, flexCSS); 1.1792 + 1.1793 + nsSize prefSize = child->GetPrefSize(state); 1.1794 + nsSize minSize = child->GetMinSize(state); 1.1795 + nsSize maxSize = child->GetMaxSize(state); 1.1796 + nscoord flexSize = child->GetFlex(state); 1.1797 + nscoord ascentSize = child->GetBoxAscent(state); 1.1798 + 1.1799 + char min[100]; 1.1800 + char pref[100]; 1.1801 + char max[100]; 1.1802 + char calc[100]; 1.1803 + char flex[100]; 1.1804 + char ascent[100]; 1.1805 + 1.1806 + nsSize actualSize; 1.1807 + GetFrameSizeWithMargin(child, actualSize); 1.1808 + nsSize actualSizeCSS (NS_INTRINSICSIZE, NS_INTRINSICSIZE); 1.1809 + 1.1810 + GetValue(aPresContext, minSize, minSizeCSS, min); 1.1811 + GetValue(aPresContext, prefSize, prefSizeCSS, pref); 1.1812 + GetValue(aPresContext, maxSize, maxSizeCSS, max); 1.1813 + GetValue(aPresContext, actualSize, actualSizeCSS, calc); 1.1814 + GetValue(aPresContext, flexSize, flexCSS, flex); 1.1815 + GetValue(aPresContext, ascentSize, NS_INTRINSICSIZE, ascent); 1.1816 + 1.1817 + 1.1818 + printf("min%s, pref%s, max%s, actual%s, flex=%s, ascent=%s\n\n", 1.1819 + min, 1.1820 + pref, 1.1821 + max, 1.1822 + calc, 1.1823 + flex, 1.1824 + ascent 1.1825 + ); 1.1826 + 1.1827 + return NS_OK; 1.1828 + } 1.1829 + 1.1830 + child = child->GetNextBox(); 1.1831 + count++; 1.1832 + } 1.1833 + } else { 1.1834 + } 1.1835 + 1.1836 + mDebugChild = nullptr; 1.1837 + 1.1838 + return NS_OK; 1.1839 +} 1.1840 + 1.1841 +void 1.1842 +nsBoxFrame::SetDebugOnChildList(nsBoxLayoutState& aState, nsIFrame* aChild, bool aDebug) 1.1843 +{ 1.1844 + nsIFrame* child = GetChildBox(); 1.1845 + while (child) 1.1846 + { 1.1847 + child->SetDebug(aState, aDebug); 1.1848 + child = child->GetNextBox(); 1.1849 + } 1.1850 +} 1.1851 + 1.1852 +nsresult 1.1853 +nsBoxFrame::GetFrameSizeWithMargin(nsIFrame* aBox, nsSize& aSize) 1.1854 +{ 1.1855 + nsRect rect(aBox->GetRect()); 1.1856 + nsMargin margin(0,0,0,0); 1.1857 + aBox->GetMargin(margin); 1.1858 + rect.Inflate(margin); 1.1859 + aSize.width = rect.width; 1.1860 + aSize.height = rect.height; 1.1861 + return NS_OK; 1.1862 +} 1.1863 +#endif 1.1864 + 1.1865 +// If you make changes to this function, check its counterparts 1.1866 +// in nsTextBoxFrame and nsXULLabelFrame 1.1867 +void 1.1868 +nsBoxFrame::RegUnregAccessKey(bool aDoReg) 1.1869 +{ 1.1870 + MOZ_ASSERT(mContent); 1.1871 + 1.1872 + // find out what type of element this is 1.1873 + nsIAtom *atom = mContent->Tag(); 1.1874 + 1.1875 + // only support accesskeys for the following elements 1.1876 + if (atom != nsGkAtoms::button && 1.1877 + atom != nsGkAtoms::toolbarbutton && 1.1878 + atom != nsGkAtoms::checkbox && 1.1879 + atom != nsGkAtoms::textbox && 1.1880 + atom != nsGkAtoms::tab && 1.1881 + atom != nsGkAtoms::radio) { 1.1882 + return; 1.1883 + } 1.1884 + 1.1885 + nsAutoString accessKey; 1.1886 + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey); 1.1887 + 1.1888 + if (accessKey.IsEmpty()) 1.1889 + return; 1.1890 + 1.1891 + // With a valid PresContext we can get the ESM 1.1892 + // and register the access key 1.1893 + EventStateManager* esm = PresContext()->EventStateManager(); 1.1894 + 1.1895 + uint32_t key = accessKey.First(); 1.1896 + if (aDoReg) 1.1897 + esm->RegisterAccessKey(mContent, key); 1.1898 + else 1.1899 + esm->UnregisterAccessKey(mContent, key); 1.1900 +} 1.1901 + 1.1902 +bool 1.1903 +nsBoxFrame::SupportsOrdinalsInChildren() 1.1904 +{ 1.1905 + return true; 1.1906 +} 1.1907 + 1.1908 +// Helper less-than-or-equal function, used in CheckBoxOrder() as a 1.1909 +// template-parameter for the sorting functions. 1.1910 +bool 1.1911 +IsBoxOrdinalLEQ(nsIFrame* aFrame1, 1.1912 + nsIFrame* aFrame2) 1.1913 +{ 1.1914 + // If we've got a placeholder frame, use its out-of-flow frame's ordinal val. 1.1915 + nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1); 1.1916 + nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2); 1.1917 + return aRealFrame1->GetOrdinal() <= aRealFrame2->GetOrdinal(); 1.1918 +} 1.1919 + 1.1920 +void 1.1921 +nsBoxFrame::CheckBoxOrder() 1.1922 +{ 1.1923 + if (SupportsOrdinalsInChildren() && 1.1924 + !nsIFrame::IsFrameListSorted<IsBoxOrdinalLEQ>(mFrames)) { 1.1925 + nsIFrame::SortFrameList<IsBoxOrdinalLEQ>(mFrames); 1.1926 + } 1.1927 +} 1.1928 + 1.1929 +nsresult 1.1930 +nsBoxFrame::LayoutChildAt(nsBoxLayoutState& aState, nsIFrame* aBox, const nsRect& aRect) 1.1931 +{ 1.1932 + // get the current rect 1.1933 + nsRect oldRect(aBox->GetRect()); 1.1934 + aBox->SetBounds(aState, aRect); 1.1935 + 1.1936 + bool layout = NS_SUBTREE_DIRTY(aBox); 1.1937 + 1.1938 + if (layout || (oldRect.width != aRect.width || oldRect.height != aRect.height)) { 1.1939 + return aBox->Layout(aState); 1.1940 + } 1.1941 + 1.1942 + return NS_OK; 1.1943 +} 1.1944 + 1.1945 +nsresult 1.1946 +nsBoxFrame::RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild) 1.1947 +{ 1.1948 + if (!SupportsOrdinalsInChildren()) 1.1949 + return NS_OK; 1.1950 + 1.1951 + uint32_t ord = aChild->GetOrdinal(); 1.1952 + 1.1953 + nsIFrame* child = mFrames.FirstChild(); 1.1954 + nsIFrame* newPrevSib = nullptr; 1.1955 + 1.1956 + while (child) { 1.1957 + if (ord < child->GetOrdinal()) { 1.1958 + break; 1.1959 + } 1.1960 + 1.1961 + if (child != aChild) { 1.1962 + newPrevSib = child; 1.1963 + } 1.1964 + 1.1965 + child = child->GetNextBox(); 1.1966 + } 1.1967 + 1.1968 + if (aChild->GetPrevSibling() == newPrevSib) { 1.1969 + // This box is not moving. 1.1970 + return NS_OK; 1.1971 + } 1.1972 + 1.1973 + // Take |aChild| out of its old position in the child list. 1.1974 + mFrames.RemoveFrame(aChild); 1.1975 + 1.1976 + // Insert it after |newPrevSib| or at the start if it's null. 1.1977 + mFrames.InsertFrame(nullptr, newPrevSib, aChild); 1.1978 + 1.1979 + return NS_OK; 1.1980 +} 1.1981 + 1.1982 +/** 1.1983 + * This wrapper class lets us redirect mouse hits from descendant frames 1.1984 + * of a menu to the menu itself, if they didn't specify 'allowevents'. 1.1985 + * 1.1986 + * The wrapper simply turns a hit on a descendant element 1.1987 + * into a hit on the menu itself, unless there is an element between the target 1.1988 + * and the menu with the "allowevents" attribute. 1.1989 + * 1.1990 + * This is used by nsMenuFrame and nsTreeColFrame. 1.1991 + * 1.1992 + * Note that turning a hit on a descendant element into nullptr, so events 1.1993 + * could fall through to the menu background, might be an appealing simplification 1.1994 + * but it would mean slightly strange behaviour in some cases, because grabber 1.1995 + * wrappers can be created for many individual lists and items, so the exact 1.1996 + * fallthrough behaviour would be complex. E.g. an element with "allowevents" 1.1997 + * on top of the Content() list could receive the event even if it was covered 1.1998 + * by a PositionedDescenants() element without "allowevents". It is best to 1.1999 + * never convert a non-null hit into null. 1.2000 + */ 1.2001 +// REVIEW: This is roughly of what nsMenuFrame::GetFrameForPoint used to do. 1.2002 +// I've made 'allowevents' affect child elements because that seems the only 1.2003 +// reasonable thing to do. 1.2004 +class nsDisplayXULEventRedirector : public nsDisplayWrapList { 1.2005 +public: 1.2006 + nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder, 1.2007 + nsIFrame* aFrame, nsDisplayItem* aItem, 1.2008 + nsIFrame* aTargetFrame) 1.2009 + : nsDisplayWrapList(aBuilder, aFrame, aItem), mTargetFrame(aTargetFrame) {} 1.2010 + nsDisplayXULEventRedirector(nsDisplayListBuilder* aBuilder, 1.2011 + nsIFrame* aFrame, nsDisplayList* aList, 1.2012 + nsIFrame* aTargetFrame) 1.2013 + : nsDisplayWrapList(aBuilder, aFrame, aList), mTargetFrame(aTargetFrame) {} 1.2014 + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 1.2015 + HitTestState* aState, 1.2016 + nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE; 1.2017 + NS_DISPLAY_DECL_NAME("XULEventRedirector", TYPE_XUL_EVENT_REDIRECTOR) 1.2018 +private: 1.2019 + nsIFrame* mTargetFrame; 1.2020 +}; 1.2021 + 1.2022 +void nsDisplayXULEventRedirector::HitTest(nsDisplayListBuilder* aBuilder, 1.2023 + const nsRect& aRect, HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) 1.2024 +{ 1.2025 + nsTArray<nsIFrame*> outFrames; 1.2026 + mList.HitTest(aBuilder, aRect, aState, &outFrames); 1.2027 + 1.2028 + bool topMostAdded = false; 1.2029 + uint32_t localLength = outFrames.Length(); 1.2030 + 1.2031 + for (uint32_t i = 0; i < localLength; i++) { 1.2032 + 1.2033 + for (nsIContent* content = outFrames.ElementAt(i)->GetContent(); 1.2034 + content && content != mTargetFrame->GetContent(); 1.2035 + content = content->GetParent()) { 1.2036 + if (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allowevents, 1.2037 + nsGkAtoms::_true, eCaseMatters)) { 1.2038 + // Events are allowed on 'frame', so let it go. 1.2039 + aOutFrames->AppendElement(outFrames.ElementAt(i)); 1.2040 + topMostAdded = true; 1.2041 + } 1.2042 + } 1.2043 + 1.2044 + // If there was no hit on the topmost frame or its ancestors, 1.2045 + // add the target frame itself as the first candidate (see bug 562554). 1.2046 + if (!topMostAdded) { 1.2047 + topMostAdded = true; 1.2048 + aOutFrames->AppendElement(mTargetFrame); 1.2049 + } 1.2050 + } 1.2051 +} 1.2052 + 1.2053 +class nsXULEventRedirectorWrapper : public nsDisplayWrapper 1.2054 +{ 1.2055 +public: 1.2056 + nsXULEventRedirectorWrapper(nsIFrame* aTargetFrame) 1.2057 + : mTargetFrame(aTargetFrame) {} 1.2058 + virtual nsDisplayItem* WrapList(nsDisplayListBuilder* aBuilder, 1.2059 + nsIFrame* aFrame, 1.2060 + nsDisplayList* aList) MOZ_OVERRIDE { 1.2061 + return new (aBuilder) 1.2062 + nsDisplayXULEventRedirector(aBuilder, aFrame, aList, mTargetFrame); 1.2063 + } 1.2064 + virtual nsDisplayItem* WrapItem(nsDisplayListBuilder* aBuilder, 1.2065 + nsDisplayItem* aItem) MOZ_OVERRIDE { 1.2066 + return new (aBuilder) 1.2067 + nsDisplayXULEventRedirector(aBuilder, aItem->Frame(), aItem, 1.2068 + mTargetFrame); 1.2069 + } 1.2070 +private: 1.2071 + nsIFrame* mTargetFrame; 1.2072 +}; 1.2073 + 1.2074 +void 1.2075 +nsBoxFrame::WrapListsInRedirector(nsDisplayListBuilder* aBuilder, 1.2076 + const nsDisplayListSet& aIn, 1.2077 + const nsDisplayListSet& aOut) 1.2078 +{ 1.2079 + nsXULEventRedirectorWrapper wrapper(this); 1.2080 + wrapper.WrapLists(aBuilder, this, aIn, aOut); 1.2081 +} 1.2082 + 1.2083 +bool 1.2084 +nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsPoint &aPoint) { 1.2085 + nsIntPoint refPoint; 1.2086 + bool res = GetEventPoint(aEvent, refPoint); 1.2087 + aPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, refPoint, this); 1.2088 + return res; 1.2089 +} 1.2090 + 1.2091 +bool 1.2092 +nsBoxFrame::GetEventPoint(WidgetGUIEvent* aEvent, nsIntPoint &aPoint) { 1.2093 + NS_ENSURE_TRUE(aEvent, false); 1.2094 + 1.2095 + WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); 1.2096 + if (touchEvent) { 1.2097 + // return false if there is more than one touch on the page, or if 1.2098 + // we can't find a touch point 1.2099 + if (touchEvent->touches.Length() != 1) { 1.2100 + return false; 1.2101 + } 1.2102 + 1.2103 + dom::Touch* touch = touchEvent->touches.SafeElementAt(0); 1.2104 + if (!touch) { 1.2105 + return false; 1.2106 + } 1.2107 + aPoint = touch->mRefPoint; 1.2108 + } else { 1.2109 + aPoint = LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint); 1.2110 + } 1.2111 + return true; 1.2112 +}