nsLeafBoxFrame.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. //
  6. // Eric Vaughan
  7. // Netscape Communications
  8. //
  9. // See documentation in associated header file
  10. //
  11. #include "nsLeafBoxFrame.h"
  12. #include "nsBoxFrame.h"
  13. #include "nsCOMPtr.h"
  14. #include "nsGkAtoms.h"
  15. #include "nsPresContext.h"
  16. #include "nsStyleContext.h"
  17. #include "nsIContent.h"
  18. #include "nsNameSpaceManager.h"
  19. #include "nsBoxLayoutState.h"
  20. #include "nsWidgetsCID.h"
  21. #include "nsViewManager.h"
  22. #include "nsContainerFrame.h"
  23. #include "nsDisplayList.h"
  24. #include <algorithm>
  25. using namespace mozilla;
  26. //
  27. // NS_NewLeafBoxFrame
  28. //
  29. // Creates a new Toolbar frame and returns it
  30. //
  31. nsIFrame*
  32. NS_NewLeafBoxFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
  33. {
  34. return new (aPresShell) nsLeafBoxFrame(aContext);
  35. }
  36. NS_IMPL_FRAMEARENA_HELPERS(nsLeafBoxFrame)
  37. nsLeafBoxFrame::nsLeafBoxFrame(nsStyleContext* aContext)
  38. : nsLeafFrame(aContext)
  39. {
  40. }
  41. #ifdef DEBUG_LAYOUT
  42. void
  43. nsLeafBoxFrame::GetBoxName(nsAutoString& aName)
  44. {
  45. GetFrameName(aName);
  46. }
  47. #endif
  48. /**
  49. * Initialize us. This is a good time to get the alignment of the box
  50. */
  51. void
  52. nsLeafBoxFrame::Init(nsIContent* aContent,
  53. nsContainerFrame* aParent,
  54. nsIFrame* aPrevInFlow)
  55. {
  56. nsLeafFrame::Init(aContent, aParent, aPrevInFlow);
  57. if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) {
  58. AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
  59. }
  60. UpdateMouseThrough();
  61. }
  62. nsresult
  63. nsLeafBoxFrame::AttributeChanged(int32_t aNameSpaceID,
  64. nsIAtom* aAttribute,
  65. int32_t aModType)
  66. {
  67. nsresult rv = nsLeafFrame::AttributeChanged(aNameSpaceID, aAttribute,
  68. aModType);
  69. if (aAttribute == nsGkAtoms::mousethrough)
  70. UpdateMouseThrough();
  71. return rv;
  72. }
  73. void nsLeafBoxFrame::UpdateMouseThrough()
  74. {
  75. if (mContent) {
  76. static nsIContent::AttrValuesArray strings[] =
  77. {&nsGkAtoms::never, &nsGkAtoms::always, nullptr};
  78. switch (mContent->FindAttrValueIn(kNameSpaceID_None,
  79. nsGkAtoms::mousethrough,
  80. strings, eCaseMatters)) {
  81. case 0: AddStateBits(NS_FRAME_MOUSE_THROUGH_NEVER); break;
  82. case 1: AddStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS); break;
  83. case 2: {
  84. RemoveStateBits(NS_FRAME_MOUSE_THROUGH_ALWAYS);
  85. RemoveStateBits(NS_FRAME_MOUSE_THROUGH_NEVER);
  86. break;
  87. }
  88. }
  89. }
  90. }
  91. void
  92. nsLeafBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  93. const nsDisplayListSet& aLists)
  94. {
  95. // REVIEW: GetFrameForPoint used to not report events for the background
  96. // layer, whereas this code will put an event receiver for this frame in the
  97. // BlockBorderBackground() list. But I don't see any need to preserve
  98. // that anomalous behaviour. The important thing I'm preserving is that
  99. // leaf boxes continue to receive events in the foreground layer.
  100. DisplayBorderBackgroundOutline(aBuilder, aLists);
  101. if (!aBuilder->IsForEventDelivery() || !IsVisibleForPainting(aBuilder))
  102. return;
  103. aLists.Content()->AppendNewToTop(new (aBuilder)
  104. nsDisplayEventReceiver(aBuilder, this));
  105. }
  106. /* virtual */ nscoord
  107. nsLeafBoxFrame::GetMinISize(nsRenderingContext *aRenderingContext)
  108. {
  109. nscoord result;
  110. DISPLAY_MIN_WIDTH(this, result);
  111. nsBoxLayoutState state(PresContext(), aRenderingContext);
  112. WritingMode wm = GetWritingMode();
  113. LogicalSize minSize(wm, GetXULMinSize(state));
  114. // GetXULMinSize returns border-box size, and we want to return content
  115. // inline-size. Since Reflow uses the reflow state's border and padding, we
  116. // actually just want to subtract what GetXULMinSize added, which is the
  117. // result of GetXULBorderAndPadding.
  118. nsMargin bp;
  119. GetXULBorderAndPadding(bp);
  120. result = minSize.ISize(wm) - LogicalMargin(wm, bp).IStartEnd(wm);
  121. return result;
  122. }
  123. /* virtual */ nscoord
  124. nsLeafBoxFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
  125. {
  126. nscoord result;
  127. DISPLAY_PREF_WIDTH(this, result);
  128. nsBoxLayoutState state(PresContext(), aRenderingContext);
  129. WritingMode wm = GetWritingMode();
  130. LogicalSize prefSize(wm, GetXULPrefSize(state));
  131. // GetXULPrefSize returns border-box size, and we want to return content
  132. // inline-size. Since Reflow uses the reflow state's border and padding, we
  133. // actually just want to subtract what GetXULPrefSize added, which is the
  134. // result of GetXULBorderAndPadding.
  135. nsMargin bp;
  136. GetXULBorderAndPadding(bp);
  137. result = prefSize.ISize(wm) - LogicalMargin(wm, bp).IStartEnd(wm);
  138. return result;
  139. }
  140. nscoord
  141. nsLeafBoxFrame::GetIntrinsicISize()
  142. {
  143. // No intrinsic width
  144. return 0;
  145. }
  146. LogicalSize
  147. nsLeafBoxFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
  148. WritingMode aWM,
  149. const LogicalSize& aCBSize,
  150. nscoord aAvailableISize,
  151. const LogicalSize& aMargin,
  152. const LogicalSize& aBorder,
  153. const LogicalSize& aPadding,
  154. ComputeSizeFlags aFlags)
  155. {
  156. // Important: NOT calling our direct superclass here!
  157. return nsFrame::ComputeAutoSize(aRenderingContext, aWM,
  158. aCBSize, aAvailableISize,
  159. aMargin, aBorder, aPadding, aFlags);
  160. }
  161. void
  162. nsLeafBoxFrame::Reflow(nsPresContext* aPresContext,
  163. ReflowOutput& aDesiredSize,
  164. const ReflowInput& aReflowInput,
  165. nsReflowStatus& aStatus)
  166. {
  167. // This is mostly a copy of nsBoxFrame::Reflow().
  168. // We aren't able to share an implementation because of the frame
  169. // class hierarchy. If you make changes here, please keep
  170. // nsBoxFrame::Reflow in sync.
  171. MarkInReflow();
  172. DO_GLOBAL_REFLOW_COUNT("nsLeafBoxFrame");
  173. DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
  174. NS_ASSERTION(aReflowInput.ComputedWidth() >=0 &&
  175. aReflowInput.ComputedHeight() >= 0, "Computed Size < 0");
  176. #ifdef DO_NOISY_REFLOW
  177. printf("\n-------------Starting LeafBoxFrame Reflow ----------------------------\n");
  178. printf("%p ** nsLBF::Reflow %d R: ", this, myCounter++);
  179. switch (aReflowInput.reason) {
  180. case eReflowReason_Initial:
  181. printf("Ini");break;
  182. case eReflowReason_Incremental:
  183. printf("Inc");break;
  184. case eReflowReason_Resize:
  185. printf("Rsz");break;
  186. case eReflowReason_StyleChange:
  187. printf("Sty");break;
  188. case eReflowReason_Dirty:
  189. printf("Drt ");
  190. break;
  191. default:printf("<unknown>%d", aReflowInput.reason);break;
  192. }
  193. printSize("AW", aReflowInput.AvailableWidth());
  194. printSize("AH", aReflowInput.AvailableHeight());
  195. printSize("CW", aReflowInput.ComputedWidth());
  196. printSize("CH", aReflowInput.ComputedHeight());
  197. printf(" *\n");
  198. #endif
  199. aStatus = NS_FRAME_COMPLETE;
  200. // create the layout state
  201. nsBoxLayoutState state(aPresContext, aReflowInput.mRenderingContext);
  202. nsSize computedSize(aReflowInput.ComputedWidth(),aReflowInput.ComputedHeight());
  203. nsMargin m;
  204. m = aReflowInput.ComputedPhysicalBorderPadding();
  205. //GetXULBorderAndPadding(m);
  206. // this happens sometimes. So lets handle it gracefully.
  207. if (aReflowInput.ComputedHeight() == 0) {
  208. nsSize minSize = GetXULMinSize(state);
  209. computedSize.height = minSize.height - m.top - m.bottom;
  210. }
  211. nsSize prefSize(0,0);
  212. // if we are told to layout intrinic then get our preferred size.
  213. if (computedSize.width == NS_INTRINSICSIZE || computedSize.height == NS_INTRINSICSIZE) {
  214. prefSize = GetXULPrefSize(state);
  215. nsSize minSize = GetXULMinSize(state);
  216. nsSize maxSize = GetXULMaxSize(state);
  217. prefSize = BoundsCheck(minSize, prefSize, maxSize);
  218. }
  219. // get our desiredSize
  220. if (aReflowInput.ComputedWidth() == NS_INTRINSICSIZE) {
  221. computedSize.width = prefSize.width;
  222. } else {
  223. computedSize.width += m.left + m.right;
  224. }
  225. if (aReflowInput.ComputedHeight() == NS_INTRINSICSIZE) {
  226. computedSize.height = prefSize.height;
  227. } else {
  228. computedSize.height += m.top + m.bottom;
  229. }
  230. // handle reflow state min and max sizes
  231. // XXXbz the width handling here seems to be wrong, since
  232. // mComputedMin/MaxWidth is a content-box size, whole
  233. // computedSize.width is a border-box size...
  234. if (computedSize.width > aReflowInput.ComputedMaxWidth())
  235. computedSize.width = aReflowInput.ComputedMaxWidth();
  236. if (computedSize.width < aReflowInput.ComputedMinWidth())
  237. computedSize.width = aReflowInput.ComputedMinWidth();
  238. // Now adjust computedSize.height for our min and max computed
  239. // height. The only problem is that those are content-box sizes,
  240. // while computedSize.height is a border-box size. So subtract off
  241. // m.TopBottom() before adjusting, then readd it.
  242. computedSize.height = std::max(0, computedSize.height - m.TopBottom());
  243. computedSize.height = NS_CSS_MINMAX(computedSize.height,
  244. aReflowInput.ComputedMinHeight(),
  245. aReflowInput.ComputedMaxHeight());
  246. computedSize.height += m.TopBottom();
  247. nsRect r(mRect.x, mRect.y, computedSize.width, computedSize.height);
  248. SetXULBounds(state, r);
  249. // layout our children
  250. XULLayout(state);
  251. // ok our child could have gotten bigger. So lets get its bounds
  252. aDesiredSize.Width() = mRect.width;
  253. aDesiredSize.Height() = mRect.height;
  254. aDesiredSize.SetBlockStartAscent(GetXULBoxAscent(state));
  255. // the overflow rect is set in SetXULBounds() above
  256. aDesiredSize.mOverflowAreas = GetOverflowAreas();
  257. #ifdef DO_NOISY_REFLOW
  258. {
  259. printf("%p ** nsLBF(done) W:%d H:%d ", this, aDesiredSize.Width(), aDesiredSize.Height());
  260. if (maxElementWidth) {
  261. printf("MW:%d\n", *maxElementWidth);
  262. } else {
  263. printf("MW:?\n");
  264. }
  265. }
  266. #endif
  267. }
  268. #ifdef DEBUG_FRAME_DUMP
  269. nsresult
  270. nsLeafBoxFrame::GetFrameName(nsAString& aResult) const
  271. {
  272. return MakeFrameName(NS_LITERAL_STRING("LeafBox"), aResult);
  273. }
  274. #endif
  275. nsIAtom*
  276. nsLeafBoxFrame::GetType() const
  277. {
  278. return nsGkAtoms::leafBoxFrame;
  279. }
  280. nsresult
  281. nsLeafBoxFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
  282. {
  283. MarkIntrinsicISizesDirty();
  284. return nsLeafFrame::CharacterDataChanged(aInfo);
  285. }
  286. /* virtual */ nsSize
  287. nsLeafBoxFrame::GetXULPrefSize(nsBoxLayoutState& aState)
  288. {
  289. return nsBox::GetXULPrefSize(aState);
  290. }
  291. /* virtual */ nsSize
  292. nsLeafBoxFrame::GetXULMinSize(nsBoxLayoutState& aState)
  293. {
  294. return nsBox::GetXULMinSize(aState);
  295. }
  296. /* virtual */ nsSize
  297. nsLeafBoxFrame::GetXULMaxSize(nsBoxLayoutState& aState)
  298. {
  299. return nsBox::GetXULMaxSize(aState);
  300. }
  301. /* virtual */ nscoord
  302. nsLeafBoxFrame::GetXULFlex()
  303. {
  304. return nsBox::GetXULFlex();
  305. }
  306. /* virtual */ nscoord
  307. nsLeafBoxFrame::GetXULBoxAscent(nsBoxLayoutState& aState)
  308. {
  309. return nsBox::GetXULBoxAscent(aState);
  310. }
  311. /* virtual */ void
  312. nsLeafBoxFrame::MarkIntrinsicISizesDirty()
  313. {
  314. // Don't call base class method, since everything it does is within an
  315. // IsXULBoxWrapped check.
  316. }
  317. NS_IMETHODIMP
  318. nsLeafBoxFrame::DoXULLayout(nsBoxLayoutState& aState)
  319. {
  320. return nsBox::DoXULLayout(aState);
  321. }