nsBoxFrame.cpp 63 KB

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