nsBox.cpp 25 KB

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