nsMathMLContainerFrame.cpp 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605
  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 "nsMathMLContainerFrame.h"
  6. #include "gfxUtils.h"
  7. #include "mozilla/gfx/2D.h"
  8. #include "nsLayoutUtils.h"
  9. #include "nsPresContext.h"
  10. #include "nsIPresShell.h"
  11. #include "nsStyleContext.h"
  12. #include "nsNameSpaceManager.h"
  13. #include "nsRenderingContext.h"
  14. #include "nsIDOMMutationEvent.h"
  15. #include "nsGkAtoms.h"
  16. #include "nsDisplayList.h"
  17. #include "nsIReflowCallback.h"
  18. #include "mozilla/Likely.h"
  19. #include "nsIScriptError.h"
  20. #include "nsContentUtils.h"
  21. #include "nsMathMLElement.h"
  22. using namespace mozilla;
  23. using namespace mozilla::gfx;
  24. //
  25. // nsMathMLContainerFrame implementation
  26. //
  27. NS_QUERYFRAME_HEAD(nsMathMLContainerFrame)
  28. NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
  29. NS_QUERYFRAME_ENTRY(nsMathMLContainerFrame)
  30. NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
  31. // =============================================================================
  32. // error handlers
  33. // provide a feedback to the user when a frame with bad markup can not be rendered
  34. nsresult
  35. nsMathMLContainerFrame::ReflowError(DrawTarget* aDrawTarget,
  36. ReflowOutput& aDesiredSize)
  37. {
  38. // clear all other flags and record that there is an error with this frame
  39. mEmbellishData.flags = 0;
  40. mPresentationData.flags = NS_MATHML_ERROR;
  41. ///////////////
  42. // Set font
  43. RefPtr<nsFontMetrics> fm =
  44. nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
  45. // bounding metrics
  46. nsAutoString errorMsg; errorMsg.AssignLiteral("invalid-markup");
  47. mBoundingMetrics =
  48. nsLayoutUtils::AppUnitBoundsOfString(errorMsg.get(), errorMsg.Length(),
  49. *fm, aDrawTarget);
  50. // reflow metrics
  51. WritingMode wm = aDesiredSize.GetWritingMode();
  52. aDesiredSize.SetBlockStartAscent(fm->MaxAscent());
  53. nscoord descent = fm->MaxDescent();
  54. aDesiredSize.BSize(wm) = aDesiredSize.BlockStartAscent() + descent;
  55. aDesiredSize.ISize(wm) = mBoundingMetrics.width;
  56. // Also return our bounding metrics
  57. aDesiredSize.mBoundingMetrics = mBoundingMetrics;
  58. return NS_OK;
  59. }
  60. class nsDisplayMathMLError : public nsDisplayItem {
  61. public:
  62. nsDisplayMathMLError(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
  63. : nsDisplayItem(aBuilder, aFrame) {
  64. MOZ_COUNT_CTOR(nsDisplayMathMLError);
  65. }
  66. #ifdef NS_BUILD_REFCNT_LOGGING
  67. virtual ~nsDisplayMathMLError() {
  68. MOZ_COUNT_DTOR(nsDisplayMathMLError);
  69. }
  70. #endif
  71. virtual void Paint(nsDisplayListBuilder* aBuilder,
  72. nsRenderingContext* aCtx) override;
  73. NS_DISPLAY_DECL_NAME("MathMLError", TYPE_MATHML_ERROR)
  74. };
  75. void nsDisplayMathMLError::Paint(nsDisplayListBuilder* aBuilder,
  76. nsRenderingContext* aCtx)
  77. {
  78. // Set color and font ...
  79. RefPtr<nsFontMetrics> fm =
  80. nsLayoutUtils::GetFontMetricsForFrame(mFrame, 1.0f);
  81. nsPoint pt = ToReferenceFrame();
  82. int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
  83. DrawTarget* drawTarget = aCtx->GetDrawTarget();
  84. Rect rect = NSRectToSnappedRect(nsRect(pt, mFrame->GetSize()),
  85. appUnitsPerDevPixel,
  86. *drawTarget);
  87. ColorPattern red(ToDeviceColor(Color(1.f, 0.f, 0.f, 1.f)));
  88. drawTarget->FillRect(rect, red);
  89. aCtx->ThebesContext()->SetColor(Color(1.f, 1.f, 1.f));
  90. nscoord ascent = fm->MaxAscent();
  91. NS_NAMED_LITERAL_STRING(errorMsg, "invalid-markup");
  92. nsLayoutUtils::DrawUniDirString(errorMsg.get(), uint32_t(errorMsg.Length()),
  93. nsPoint(pt.x, pt.y + ascent), *fm, *aCtx);
  94. }
  95. /* /////////////
  96. * nsIMathMLFrame - support methods for stretchy elements
  97. * =============================================================================
  98. */
  99. static bool
  100. IsForeignChild(const nsIFrame* aFrame)
  101. {
  102. // This counts nsMathMLmathBlockFrame as a foreign child, because it
  103. // uses block reflow
  104. return !(aFrame->IsFrameOfType(nsIFrame::eMathML)) ||
  105. aFrame->GetType() == nsGkAtoms::blockFrame;
  106. }
  107. NS_DECLARE_FRAME_PROPERTY_DELETABLE(HTMLReflowOutputProperty,
  108. ReflowOutput)
  109. /* static */ void
  110. nsMathMLContainerFrame::SaveReflowAndBoundingMetricsFor(nsIFrame* aFrame,
  111. const ReflowOutput& aReflowOutput,
  112. const nsBoundingMetrics& aBoundingMetrics)
  113. {
  114. ReflowOutput* reflowOutput = new ReflowOutput(aReflowOutput);
  115. reflowOutput->mBoundingMetrics = aBoundingMetrics;
  116. aFrame->SetProperty(HTMLReflowOutputProperty(), reflowOutput);
  117. }
  118. // helper method to facilitate getting the reflow and bounding metrics
  119. /* static */ void
  120. nsMathMLContainerFrame::GetReflowAndBoundingMetricsFor(nsIFrame* aFrame,
  121. ReflowOutput& aReflowOutput,
  122. nsBoundingMetrics& aBoundingMetrics,
  123. eMathMLFrameType* aMathMLFrameType)
  124. {
  125. NS_PRECONDITION(aFrame, "null arg");
  126. ReflowOutput* reflowOutput =
  127. aFrame->GetProperty(HTMLReflowOutputProperty());
  128. // IMPORTANT: This function is only meant to be called in Place() methods
  129. // where it is assumed that SaveReflowAndBoundingMetricsFor has recorded the
  130. // information.
  131. NS_ASSERTION(reflowOutput, "Didn't SaveReflowAndBoundingMetricsFor frame!");
  132. if (reflowOutput) {
  133. aReflowOutput = *reflowOutput;
  134. aBoundingMetrics = reflowOutput->mBoundingMetrics;
  135. }
  136. if (aMathMLFrameType) {
  137. if (!IsForeignChild(aFrame)) {
  138. nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame);
  139. if (mathMLFrame) {
  140. *aMathMLFrameType = mathMLFrame->GetMathMLFrameType();
  141. return;
  142. }
  143. }
  144. *aMathMLFrameType = eMathMLFrameType_UNKNOWN;
  145. }
  146. }
  147. void
  148. nsMathMLContainerFrame::ClearSavedChildMetrics()
  149. {
  150. nsIFrame* childFrame = mFrames.FirstChild();
  151. while (childFrame) {
  152. childFrame->DeleteProperty(HTMLReflowOutputProperty());
  153. childFrame = childFrame->GetNextSibling();
  154. }
  155. }
  156. // helper to get the preferred size that a container frame should use to fire
  157. // the stretch on its stretchy child frames.
  158. void
  159. nsMathMLContainerFrame::GetPreferredStretchSize(DrawTarget* aDrawTarget,
  160. uint32_t aOptions,
  161. nsStretchDirection aStretchDirection,
  162. nsBoundingMetrics& aPreferredStretchSize)
  163. {
  164. if (aOptions & STRETCH_CONSIDER_ACTUAL_SIZE) {
  165. // when our actual size is ok, just use it
  166. aPreferredStretchSize = mBoundingMetrics;
  167. }
  168. else if (aOptions & STRETCH_CONSIDER_EMBELLISHMENTS) {
  169. // compute our up-to-date size using Place()
  170. ReflowOutput reflowOutput(GetWritingMode());
  171. Place(aDrawTarget, false, reflowOutput);
  172. aPreferredStretchSize = reflowOutput.mBoundingMetrics;
  173. }
  174. else {
  175. // compute a size that includes embellishments iff the container stretches
  176. // in the same direction as the embellished operator.
  177. bool stretchAll = aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL ?
  178. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) :
  179. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
  180. NS_ASSERTION(aStretchDirection == NS_STRETCH_DIRECTION_HORIZONTAL ||
  181. aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL,
  182. "You must specify a direction in which to stretch");
  183. NS_ASSERTION(NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
  184. stretchAll,
  185. "invalid call to GetPreferredStretchSize");
  186. bool firstTime = true;
  187. nsBoundingMetrics bm, bmChild;
  188. nsIFrame* childFrame =
  189. stretchAll ? PrincipalChildList().FirstChild() : mPresentationData.baseFrame;
  190. while (childFrame) {
  191. // initializations in case this child happens not to be a MathML frame
  192. nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
  193. if (mathMLFrame) {
  194. nsEmbellishData embellishData;
  195. nsPresentationData presentationData;
  196. mathMLFrame->GetEmbellishData(embellishData);
  197. mathMLFrame->GetPresentationData(presentationData);
  198. if (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags) &&
  199. embellishData.direction == aStretchDirection &&
  200. presentationData.baseFrame) {
  201. // embellishements are not included, only consider the inner first child itself
  202. // XXXkt Does that mean the core descendent frame should be used
  203. // instead of the base child?
  204. nsIMathMLFrame* mathMLchildFrame = do_QueryFrame(presentationData.baseFrame);
  205. if (mathMLchildFrame) {
  206. mathMLFrame = mathMLchildFrame;
  207. }
  208. }
  209. mathMLFrame->GetBoundingMetrics(bmChild);
  210. }
  211. else {
  212. ReflowOutput unused(GetWritingMode());
  213. GetReflowAndBoundingMetricsFor(childFrame, unused, bmChild);
  214. }
  215. if (firstTime) {
  216. firstTime = false;
  217. bm = bmChild;
  218. if (!stretchAll) {
  219. // we may get here for cases such as <msup><mo>...</mo> ... </msup>,
  220. // or <maction>...<mo>...</mo></maction>.
  221. break;
  222. }
  223. }
  224. else {
  225. if (aStretchDirection == NS_STRETCH_DIRECTION_HORIZONTAL) {
  226. // if we get here, it means this is container that will stack its children
  227. // vertically and fire an horizontal stretch on each them. This is the case
  228. // for \munder, \mover, \munderover. We just sum-up the size vertically.
  229. bm.descent += bmChild.ascent + bmChild.descent;
  230. // Sometimes non-spacing marks (when width is zero) are positioned
  231. // to the left of the origin, but it is the distance between left
  232. // and right bearing that is important rather than the offsets from
  233. // the origin.
  234. if (bmChild.width == 0) {
  235. bmChild.rightBearing -= bmChild.leftBearing;
  236. bmChild.leftBearing = 0;
  237. }
  238. if (bm.leftBearing > bmChild.leftBearing)
  239. bm.leftBearing = bmChild.leftBearing;
  240. if (bm.rightBearing < bmChild.rightBearing)
  241. bm.rightBearing = bmChild.rightBearing;
  242. }
  243. else if (aStretchDirection == NS_STRETCH_DIRECTION_VERTICAL) {
  244. // just sum-up the sizes horizontally.
  245. bm += bmChild;
  246. }
  247. else {
  248. NS_ERROR("unexpected case in GetPreferredStretchSize");
  249. break;
  250. }
  251. }
  252. childFrame = childFrame->GetNextSibling();
  253. }
  254. aPreferredStretchSize = bm;
  255. }
  256. }
  257. NS_IMETHODIMP
  258. nsMathMLContainerFrame::Stretch(DrawTarget* aDrawTarget,
  259. nsStretchDirection aStretchDirection,
  260. nsBoundingMetrics& aContainerSize,
  261. ReflowOutput& aDesiredStretchSize)
  262. {
  263. if (NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags)) {
  264. if (NS_MATHML_STRETCH_WAS_DONE(mPresentationData.flags)) {
  265. NS_WARNING("it is wrong to fire stretch more than once on a frame");
  266. return NS_OK;
  267. }
  268. mPresentationData.flags |= NS_MATHML_STRETCH_DONE;
  269. if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
  270. NS_WARNING("it is wrong to fire stretch on a erroneous frame");
  271. return NS_OK;
  272. }
  273. // Pass the stretch to the base child ...
  274. nsIFrame* baseFrame = mPresentationData.baseFrame;
  275. if (baseFrame) {
  276. nsIMathMLFrame* mathMLFrame = do_QueryFrame(baseFrame);
  277. NS_ASSERTION(mathMLFrame, "Something is wrong somewhere");
  278. if (mathMLFrame) {
  279. // And the trick is that the child's rect.x is still holding the descent,
  280. // and rect.y is still holding the ascent ...
  281. ReflowOutput childSize(aDesiredStretchSize);
  282. GetReflowAndBoundingMetricsFor(baseFrame, childSize, childSize.mBoundingMetrics);
  283. // See if we should downsize and confine the stretch to us...
  284. // XXX there may be other cases where we can downsize the stretch,
  285. // e.g., the first &Sum; might appear big in the following situation
  286. // <math xmlns='http://www.w3.org/1998/Math/MathML'>
  287. // <mstyle>
  288. // <msub>
  289. // <msub><mo>&Sum;</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub>
  290. // <msub><mo>&Sum;</mo><mfrac><mi>a</mi><mi>b</mi></mfrac></msub>
  291. // </msub>
  292. // </mstyle>
  293. // </math>
  294. nsBoundingMetrics containerSize = aContainerSize;
  295. if (aStretchDirection != mEmbellishData.direction &&
  296. mEmbellishData.direction != NS_STRETCH_DIRECTION_UNSUPPORTED) {
  297. NS_ASSERTION(mEmbellishData.direction != NS_STRETCH_DIRECTION_DEFAULT,
  298. "Stretches may have a default direction, operators can not.");
  299. if (mEmbellishData.direction == NS_STRETCH_DIRECTION_VERTICAL ?
  300. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) :
  301. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags)) {
  302. GetPreferredStretchSize(aDrawTarget, 0,
  303. mEmbellishData.direction, containerSize);
  304. // Stop further recalculations
  305. aStretchDirection = mEmbellishData.direction;
  306. } else {
  307. // We aren't going to stretch the child, so just use the child metrics.
  308. containerSize = childSize.mBoundingMetrics;
  309. }
  310. }
  311. // do the stretching...
  312. mathMLFrame->Stretch(aDrawTarget,
  313. aStretchDirection, containerSize, childSize);
  314. // store the updated metrics
  315. SaveReflowAndBoundingMetricsFor(baseFrame, childSize,
  316. childSize.mBoundingMetrics);
  317. // Remember the siblings which were _deferred_.
  318. // Now that this embellished child may have changed, we need to
  319. // fire the stretch on its siblings using our updated size
  320. if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
  321. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags)) {
  322. nsStretchDirection stretchDir =
  323. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ?
  324. NS_STRETCH_DIRECTION_VERTICAL : NS_STRETCH_DIRECTION_HORIZONTAL;
  325. GetPreferredStretchSize(aDrawTarget, STRETCH_CONSIDER_EMBELLISHMENTS,
  326. stretchDir, containerSize);
  327. nsIFrame* childFrame = mFrames.FirstChild();
  328. while (childFrame) {
  329. if (childFrame != mPresentationData.baseFrame) {
  330. mathMLFrame = do_QueryFrame(childFrame);
  331. if (mathMLFrame) {
  332. // retrieve the metrics that was stored at the previous pass
  333. GetReflowAndBoundingMetricsFor(childFrame,
  334. childSize, childSize.mBoundingMetrics);
  335. // do the stretching...
  336. mathMLFrame->Stretch(aDrawTarget, stretchDir,
  337. containerSize, childSize);
  338. // store the updated metrics
  339. SaveReflowAndBoundingMetricsFor(childFrame, childSize,
  340. childSize.mBoundingMetrics);
  341. }
  342. }
  343. childFrame = childFrame->GetNextSibling();
  344. }
  345. }
  346. // re-position all our children
  347. nsresult rv = Place(aDrawTarget, true, aDesiredStretchSize);
  348. if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
  349. // Make sure the child frames get their DidReflow() calls.
  350. DidReflowChildren(mFrames.FirstChild());
  351. }
  352. // If our parent is not embellished, it means we are the outermost embellished
  353. // container and so we put the spacing, otherwise we don't include the spacing,
  354. // the outermost embellished container will take care of it.
  355. nsEmbellishData parentData;
  356. GetEmbellishDataFrom(GetParent(), parentData);
  357. // ensure that we are the embellished child, not just a sibling
  358. // (need to test coreFrame since <mfrac> resets other things)
  359. if (parentData.coreFrame != mEmbellishData.coreFrame) {
  360. // (we fetch values from the core since they may use units that depend
  361. // on style data, and style changes could have occurred in the core since
  362. // our last visit there)
  363. nsEmbellishData coreData;
  364. GetEmbellishDataFrom(mEmbellishData.coreFrame, coreData);
  365. mBoundingMetrics.width +=
  366. coreData.leadingSpace + coreData.trailingSpace;
  367. aDesiredStretchSize.Width() = mBoundingMetrics.width;
  368. aDesiredStretchSize.mBoundingMetrics.width = mBoundingMetrics.width;
  369. nscoord dx = (StyleVisibility()->mDirection ?
  370. coreData.trailingSpace : coreData.leadingSpace);
  371. if (dx != 0) {
  372. mBoundingMetrics.leftBearing += dx;
  373. mBoundingMetrics.rightBearing += dx;
  374. aDesiredStretchSize.mBoundingMetrics.leftBearing += dx;
  375. aDesiredStretchSize.mBoundingMetrics.rightBearing += dx;
  376. nsIFrame* childFrame = mFrames.FirstChild();
  377. while (childFrame) {
  378. childFrame->SetPosition(childFrame->GetPosition()
  379. + nsPoint(dx, 0));
  380. childFrame = childFrame->GetNextSibling();
  381. }
  382. }
  383. }
  384. // Finished with these:
  385. ClearSavedChildMetrics();
  386. // Set our overflow area
  387. GatherAndStoreOverflow(&aDesiredStretchSize);
  388. }
  389. }
  390. }
  391. return NS_OK;
  392. }
  393. nsresult
  394. nsMathMLContainerFrame::FinalizeReflow(DrawTarget* aDrawTarget,
  395. ReflowOutput& aDesiredSize)
  396. {
  397. // During reflow, we use rect.x and rect.y as placeholders for the child's ascent
  398. // and descent in expectation of a stretch command. Hence we need to ensure that
  399. // a stretch command will actually be fired later on, after exiting from our
  400. // reflow. If the stretch is not fired, the rect.x, and rect.y will remain
  401. // with inappropriate data causing children to be improperly positioned.
  402. // This helper method checks to see if our parent will fire a stretch command
  403. // targeted at us. If not, we go ahead and fire an involutive stretch on
  404. // ourselves. This will clear all the rect.x and rect.y, and return our
  405. // desired size.
  406. // First, complete the post-reflow hook.
  407. // We use the information in our children rectangles to position them.
  408. // If placeOrigin==false, then Place() will not touch rect.x, and rect.y.
  409. // They will still be holding the ascent and descent for each child.
  410. // The first clause caters for any non-embellished container.
  411. // The second clause is for a container which won't fire stretch even though it is
  412. // embellished, e.g., as in <mfrac><mo>...</mo> ... </mfrac>, the test is convoluted
  413. // because it excludes the particular case of the core <mo>...</mo> itself.
  414. // (<mo> needs to fire stretch on its MathMLChar in any case to initialize it)
  415. bool placeOrigin = !NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) ||
  416. (mEmbellishData.coreFrame != this && !mPresentationData.baseFrame &&
  417. mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED);
  418. nsresult rv = Place(aDrawTarget, placeOrigin, aDesiredSize);
  419. // Place() will call FinishReflowChild() when placeOrigin is true but if
  420. // it returns before reaching FinishReflowChild() due to errors we need
  421. // to fulfill the reflow protocol by calling DidReflow for the child frames
  422. // that still needs it here (or we may crash - bug 366012).
  423. // If placeOrigin is false we should reach Place() with aPlaceOrigin == true
  424. // through Stretch() eventually.
  425. if (NS_MATHML_HAS_ERROR(mPresentationData.flags) || NS_FAILED(rv)) {
  426. GatherAndStoreOverflow(&aDesiredSize);
  427. DidReflowChildren(PrincipalChildList().FirstChild());
  428. return rv;
  429. }
  430. bool parentWillFireStretch = false;
  431. if (!placeOrigin) {
  432. // This means the rect.x and rect.y of our children were not set!!
  433. // Don't go without checking to see if our parent will later fire a Stretch() command
  434. // targeted at us. The Stretch() will cause the rect.x and rect.y to clear...
  435. nsIMathMLFrame* mathMLFrame = do_QueryFrame(GetParent());
  436. if (mathMLFrame) {
  437. nsEmbellishData embellishData;
  438. nsPresentationData presentationData;
  439. mathMLFrame->GetEmbellishData(embellishData);
  440. mathMLFrame->GetPresentationData(presentationData);
  441. if (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(presentationData.flags) ||
  442. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(presentationData.flags) ||
  443. (NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)
  444. && presentationData.baseFrame == this))
  445. {
  446. parentWillFireStretch = true;
  447. }
  448. }
  449. if (!parentWillFireStretch) {
  450. // There is nobody who will fire the stretch for us, we do it ourselves!
  451. bool stretchAll =
  452. /* NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) || */
  453. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags);
  454. nsStretchDirection stretchDir;
  455. if (mEmbellishData.coreFrame == this || /* case of a bare <mo>...</mo> itself */
  456. (mEmbellishData.direction == NS_STRETCH_DIRECTION_HORIZONTAL &&
  457. stretchAll) || /* or <mover><mo>...</mo>...</mover>, or friends */
  458. mEmbellishData.direction == NS_STRETCH_DIRECTION_UNSUPPORTED) { /* Doesn't stretch */
  459. stretchDir = mEmbellishData.direction;
  460. } else {
  461. // Let the Stretch() call decide the direction.
  462. stretchDir = NS_STRETCH_DIRECTION_DEFAULT;
  463. }
  464. // Use our current size as computed earlier by Place()
  465. // The stretch call will detect if this is incorrect and recalculate the size.
  466. nsBoundingMetrics defaultSize = aDesiredSize.mBoundingMetrics;
  467. Stretch(aDrawTarget, stretchDir, defaultSize, aDesiredSize);
  468. #ifdef DEBUG
  469. {
  470. // The Place() call above didn't request FinishReflowChild(),
  471. // so let's check that we eventually did through Stretch().
  472. for (nsIFrame* childFrame : PrincipalChildList()) {
  473. NS_ASSERTION(!(childFrame->GetStateBits() & NS_FRAME_IN_REFLOW),
  474. "DidReflow() was never called");
  475. }
  476. }
  477. #endif
  478. }
  479. }
  480. // Also return our bounding metrics
  481. aDesiredSize.mBoundingMetrics = mBoundingMetrics;
  482. // see if we should fix the spacing
  483. FixInterFrameSpacing(aDesiredSize);
  484. if (!parentWillFireStretch) {
  485. // Not expecting a stretch.
  486. // Finished with these:
  487. ClearSavedChildMetrics();
  488. // Set our overflow area.
  489. GatherAndStoreOverflow(&aDesiredSize);
  490. }
  491. return NS_OK;
  492. }
  493. /* /////////////
  494. * nsIMathMLFrame - support methods for scripting elements (nested frames
  495. * within msub, msup, msubsup, munder, mover, munderover, mmultiscripts,
  496. * mfrac, mroot, mtable).
  497. * =============================================================================
  498. */
  499. // helper to let the update of presentation data pass through
  500. // a subtree that may contain non-mathml container frames
  501. /* static */ void
  502. nsMathMLContainerFrame::PropagatePresentationDataFor(nsIFrame* aFrame,
  503. uint32_t aFlagsValues,
  504. uint32_t aFlagsToUpdate)
  505. {
  506. if (!aFrame || !aFlagsToUpdate)
  507. return;
  508. nsIMathMLFrame* mathMLFrame = do_QueryFrame(aFrame);
  509. if (mathMLFrame) {
  510. // update
  511. mathMLFrame->UpdatePresentationData(aFlagsValues,
  512. aFlagsToUpdate);
  513. // propagate using the base method to make sure that the control
  514. // is passed on to MathML frames that may be overloading the method
  515. mathMLFrame->UpdatePresentationDataFromChildAt(0, -1,
  516. aFlagsValues, aFlagsToUpdate);
  517. }
  518. else {
  519. // propagate down the subtrees
  520. for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
  521. PropagatePresentationDataFor(childFrame,
  522. aFlagsValues, aFlagsToUpdate);
  523. }
  524. }
  525. }
  526. /* static */ void
  527. nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(nsIFrame* aParentFrame,
  528. int32_t aFirstChildIndex,
  529. int32_t aLastChildIndex,
  530. uint32_t aFlagsValues,
  531. uint32_t aFlagsToUpdate)
  532. {
  533. if (!aParentFrame || !aFlagsToUpdate)
  534. return;
  535. int32_t index = 0;
  536. for (nsIFrame* childFrame : aParentFrame->PrincipalChildList()) {
  537. if ((index >= aFirstChildIndex) &&
  538. ((aLastChildIndex <= 0) || ((aLastChildIndex > 0) &&
  539. (index <= aLastChildIndex)))) {
  540. PropagatePresentationDataFor(childFrame,
  541. aFlagsValues, aFlagsToUpdate);
  542. }
  543. index++;
  544. }
  545. }
  546. /* //////////////////
  547. * Frame construction
  548. * =============================================================================
  549. */
  550. void
  551. nsMathMLContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
  552. const nsDisplayListSet& aLists)
  553. {
  554. // report an error if something wrong was found in this frame
  555. if (NS_MATHML_HAS_ERROR(mPresentationData.flags)) {
  556. if (!IsVisibleForPainting(aBuilder))
  557. return;
  558. aLists.Content()->AppendNewToTop(
  559. new (aBuilder) nsDisplayMathMLError(aBuilder, this));
  560. return;
  561. }
  562. DisplayBorderBackgroundOutline(aBuilder, aLists);
  563. BuildDisplayListForNonBlockChildren(aBuilder, aLists, DISPLAY_CHILD_INLINE);
  564. #if defined(DEBUG) && defined(SHOW_BOUNDING_BOX)
  565. // for visual debug
  566. // ----------------
  567. // if you want to see your bounding box, make sure to properly fill
  568. // your mBoundingMetrics and mReference point, and set
  569. // mPresentationData.flags |= NS_MATHML_SHOW_BOUNDING_METRICS
  570. // in the Init() of your sub-class
  571. DisplayBoundingMetrics(aBuilder, this, mReference, mBoundingMetrics, aLists);
  572. #endif
  573. }
  574. // Note that this method re-builds the automatic data in the children -- not
  575. // in aParentFrame itself (except for those particular operations that the
  576. // parent frame may do in its TransmitAutomaticData()).
  577. /* static */ void
  578. nsMathMLContainerFrame::RebuildAutomaticDataForChildren(nsIFrame* aParentFrame)
  579. {
  580. // 1. As we descend the tree, make each child frame inherit data from
  581. // the parent
  582. // 2. As we ascend the tree, transmit any specific change that we want
  583. // down the subtrees
  584. for (nsIFrame* childFrame : aParentFrame->PrincipalChildList()) {
  585. nsIMathMLFrame* childMathMLFrame = do_QueryFrame(childFrame);
  586. if (childMathMLFrame) {
  587. childMathMLFrame->InheritAutomaticData(aParentFrame);
  588. }
  589. RebuildAutomaticDataForChildren(childFrame);
  590. }
  591. nsIMathMLFrame* mathMLFrame = do_QueryFrame(aParentFrame);
  592. if (mathMLFrame) {
  593. mathMLFrame->TransmitAutomaticData();
  594. }
  595. }
  596. /* static */ nsresult
  597. nsMathMLContainerFrame::ReLayoutChildren(nsIFrame* aParentFrame)
  598. {
  599. if (!aParentFrame)
  600. return NS_OK;
  601. // walk-up to the first frame that is a MathML frame, stop if we reach <math>
  602. nsIFrame* frame = aParentFrame;
  603. while (1) {
  604. nsIFrame* parent = frame->GetParent();
  605. if (!parent || !parent->GetContent())
  606. break;
  607. // stop if it is a MathML frame
  608. nsIMathMLFrame* mathMLFrame = do_QueryFrame(frame);
  609. if (mathMLFrame)
  610. break;
  611. // stop if we reach the root <math> tag
  612. nsIContent* content = frame->GetContent();
  613. NS_ASSERTION(content, "dangling frame without a content node");
  614. if (!content)
  615. break;
  616. if (content->IsMathMLElement(nsGkAtoms::math))
  617. break;
  618. frame = parent;
  619. }
  620. // re-sync the presentation data and embellishment data of our children
  621. RebuildAutomaticDataForChildren(frame);
  622. // Ask our parent frame to reflow us
  623. nsIFrame* parent = frame->GetParent();
  624. NS_ASSERTION(parent, "No parent to pass the reflow request up to");
  625. if (!parent)
  626. return NS_OK;
  627. frame->PresContext()->PresShell()->
  628. FrameNeedsReflow(frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  629. return NS_OK;
  630. }
  631. // There are precise rules governing children of a MathML frame,
  632. // and properties such as the scriptlevel depends on those rules.
  633. // Hence for things to work, callers must use Append/Insert/etc wisely.
  634. nsresult
  635. nsMathMLContainerFrame::ChildListChanged(int32_t aModType)
  636. {
  637. // If this is an embellished frame we need to rebuild the
  638. // embellished hierarchy by walking-up to the parent of the
  639. // outermost embellished container.
  640. nsIFrame* frame = this;
  641. if (mEmbellishData.coreFrame) {
  642. nsIFrame* parent = GetParent();
  643. nsEmbellishData embellishData;
  644. for ( ; parent; frame = parent, parent = parent->GetParent()) {
  645. GetEmbellishDataFrom(parent, embellishData);
  646. if (embellishData.coreFrame != mEmbellishData.coreFrame)
  647. break;
  648. }
  649. }
  650. return ReLayoutChildren(frame);
  651. }
  652. void
  653. nsMathMLContainerFrame::AppendFrames(ChildListID aListID,
  654. nsFrameList& aFrameList)
  655. {
  656. MOZ_ASSERT(aListID == kPrincipalList);
  657. mFrames.AppendFrames(this, aFrameList);
  658. ChildListChanged(nsIDOMMutationEvent::ADDITION);
  659. }
  660. void
  661. nsMathMLContainerFrame::InsertFrames(ChildListID aListID,
  662. nsIFrame* aPrevFrame,
  663. nsFrameList& aFrameList)
  664. {
  665. MOZ_ASSERT(aListID == kPrincipalList);
  666. mFrames.InsertFrames(this, aPrevFrame, aFrameList);
  667. ChildListChanged(nsIDOMMutationEvent::ADDITION);
  668. }
  669. void
  670. nsMathMLContainerFrame::RemoveFrame(ChildListID aListID,
  671. nsIFrame* aOldFrame)
  672. {
  673. MOZ_ASSERT(aListID == kPrincipalList);
  674. mFrames.DestroyFrame(aOldFrame);
  675. ChildListChanged(nsIDOMMutationEvent::REMOVAL);
  676. }
  677. nsresult
  678. nsMathMLContainerFrame::AttributeChanged(int32_t aNameSpaceID,
  679. nsIAtom* aAttribute,
  680. int32_t aModType)
  681. {
  682. // XXX Since they are numerous MathML attributes that affect layout, and
  683. // we can't check all of them here, play safe by requesting a reflow.
  684. // XXXldb This should only do work for attributes that cause changes!
  685. PresContext()->PresShell()->
  686. FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  687. return NS_OK;
  688. }
  689. void
  690. nsMathMLContainerFrame::GatherAndStoreOverflow(ReflowOutput* aMetrics)
  691. {
  692. mBlockStartAscent = aMetrics->BlockStartAscent();
  693. // nsIFrame::FinishAndStoreOverflow likes the overflow area to include the
  694. // frame rectangle.
  695. aMetrics->SetOverflowAreasToDesiredBounds();
  696. ComputeCustomOverflow(aMetrics->mOverflowAreas);
  697. // mBoundingMetrics does not necessarily include content of <mpadded>
  698. // elements whose mBoundingMetrics may not be representative of the true
  699. // bounds, and doesn't include the CSS2 outline rectangles of children, so
  700. // make such to include child overflow areas.
  701. UnionChildOverflow(aMetrics->mOverflowAreas);
  702. FinishAndStoreOverflow(aMetrics);
  703. }
  704. bool
  705. nsMathMLContainerFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas)
  706. {
  707. // All non-child-frame content such as nsMathMLChars (and most child-frame
  708. // content) is included in mBoundingMetrics.
  709. nsRect boundingBox(mBoundingMetrics.leftBearing,
  710. mBlockStartAscent - mBoundingMetrics.ascent,
  711. mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing,
  712. mBoundingMetrics.ascent + mBoundingMetrics.descent);
  713. // REVIEW: Maybe this should contribute only to visual overflow
  714. // and not scrollable?
  715. aOverflowAreas.UnionAllWith(boundingBox);
  716. return nsContainerFrame::ComputeCustomOverflow(aOverflowAreas);
  717. }
  718. void
  719. nsMathMLContainerFrame::ReflowChild(nsIFrame* aChildFrame,
  720. nsPresContext* aPresContext,
  721. ReflowOutput& aDesiredSize,
  722. const ReflowInput& aReflowInput,
  723. nsReflowStatus& aStatus)
  724. {
  725. // Having foreign/hybrid children, e.g., from html markups, is not defined by
  726. // the MathML spec. But it can happen in practice, e.g., <html:img> allows us
  727. // to do some cool demos... or we may have a child that is an nsInlineFrame
  728. // from a generated content such as :before { content: open-quote } or
  729. // :after { content: close-quote }. Unfortunately, the other frames out-there
  730. // may expect their own invariants that are not met when we mix things.
  731. // Hence we do not claim their support, but we will nevertheless attempt to keep
  732. // them in the flow, if we can get their desired size. We observed that most
  733. // frames may be reflowed generically, but nsInlineFrames need extra care.
  734. #ifdef DEBUG
  735. nsInlineFrame* inlineFrame = do_QueryFrame(aChildFrame);
  736. NS_ASSERTION(!inlineFrame, "Inline frames should be wrapped in blocks");
  737. #endif
  738. nsContainerFrame::
  739. ReflowChild(aChildFrame, aPresContext, aDesiredSize, aReflowInput,
  740. 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus);
  741. if (aDesiredSize.BlockStartAscent() == ReflowOutput::ASK_FOR_BASELINE) {
  742. // This will be suitable for inline frames, which are wrapped in a block.
  743. nscoord ascent;
  744. WritingMode wm = aDesiredSize.GetWritingMode();
  745. if (!nsLayoutUtils::GetLastLineBaseline(wm, aChildFrame, &ascent)) {
  746. // We don't expect any other block children so just place the frame on
  747. // the baseline instead of going through DidReflow() and
  748. // GetBaseline(). This is what nsFrame::GetBaseline() will do anyway.
  749. aDesiredSize.SetBlockStartAscent(aDesiredSize.BSize(wm));
  750. } else {
  751. aDesiredSize.SetBlockStartAscent(ascent);
  752. }
  753. }
  754. if (IsForeignChild(aChildFrame)) {
  755. // use ComputeTightBounds API as aDesiredSize.mBoundingMetrics is not set.
  756. nsRect r = aChildFrame->ComputeTightBounds(aReflowInput.mRenderingContext->GetDrawTarget());
  757. aDesiredSize.mBoundingMetrics.leftBearing = r.x;
  758. aDesiredSize.mBoundingMetrics.rightBearing = r.XMost();
  759. aDesiredSize.mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent() - r.y;
  760. aDesiredSize.mBoundingMetrics.descent = r.YMost() - aDesiredSize.BlockStartAscent();
  761. aDesiredSize.mBoundingMetrics.width = aDesiredSize.Width();
  762. }
  763. }
  764. void
  765. nsMathMLContainerFrame::Reflow(nsPresContext* aPresContext,
  766. ReflowOutput& aDesiredSize,
  767. const ReflowInput& aReflowInput,
  768. nsReflowStatus& aStatus)
  769. {
  770. MarkInReflow();
  771. mPresentationData.flags &= ~NS_MATHML_ERROR;
  772. aDesiredSize.Width() = aDesiredSize.Height() = 0;
  773. aDesiredSize.SetBlockStartAscent(0);
  774. aDesiredSize.mBoundingMetrics = nsBoundingMetrics();
  775. /////////////
  776. // Reflow children
  777. // Asking each child to cache its bounding metrics
  778. nsReflowStatus childStatus;
  779. nsIFrame* childFrame = mFrames.FirstChild();
  780. while (childFrame) {
  781. ReflowOutput childDesiredSize(aReflowInput, // ???
  782. aDesiredSize.mFlags);
  783. WritingMode wm = childFrame->GetWritingMode();
  784. LogicalSize availSize = aReflowInput.ComputedSize(wm);
  785. availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
  786. ReflowInput childReflowInput(aPresContext, aReflowInput,
  787. childFrame, availSize);
  788. ReflowChild(childFrame, aPresContext, childDesiredSize,
  789. childReflowInput, childStatus);
  790. //NS_ASSERTION(NS_FRAME_IS_COMPLETE(childStatus), "bad status");
  791. SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
  792. childDesiredSize.mBoundingMetrics);
  793. childFrame = childFrame->GetNextSibling();
  794. }
  795. /////////////
  796. // If we are a container which is entitled to stretch its children, then we
  797. // ask our stretchy children to stretch themselves
  798. // The stretching of siblings of an embellished child is _deferred_ until
  799. // after finishing the stretching of the embellished child - bug 117652
  800. DrawTarget* drawTarget = aReflowInput.mRenderingContext->GetDrawTarget();
  801. if (!NS_MATHML_IS_EMBELLISH_OPERATOR(mEmbellishData.flags) &&
  802. (NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags) ||
  803. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_HORIZONTALLY(mPresentationData.flags))) {
  804. // get the stretchy direction
  805. nsStretchDirection stretchDir =
  806. NS_MATHML_WILL_STRETCH_ALL_CHILDREN_VERTICALLY(mPresentationData.flags)
  807. ? NS_STRETCH_DIRECTION_VERTICAL
  808. : NS_STRETCH_DIRECTION_HORIZONTAL;
  809. // what size should we use to stretch our stretchy children
  810. // We don't use STRETCH_CONSIDER_ACTUAL_SIZE -- because our size is not known yet
  811. // We don't use STRETCH_CONSIDER_EMBELLISHMENTS -- because we don't want to
  812. // include them in the caculations of the size of stretchy elements
  813. nsBoundingMetrics containerSize;
  814. GetPreferredStretchSize(drawTarget, 0, stretchDir, containerSize);
  815. // fire the stretch on each child
  816. childFrame = mFrames.FirstChild();
  817. while (childFrame) {
  818. nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
  819. if (mathMLFrame) {
  820. // retrieve the metrics that was stored at the previous pass
  821. ReflowOutput childDesiredSize(aReflowInput);
  822. GetReflowAndBoundingMetricsFor(childFrame,
  823. childDesiredSize, childDesiredSize.mBoundingMetrics);
  824. mathMLFrame->Stretch(drawTarget, stretchDir,
  825. containerSize, childDesiredSize);
  826. // store the updated metrics
  827. SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
  828. childDesiredSize.mBoundingMetrics);
  829. }
  830. childFrame = childFrame->GetNextSibling();
  831. }
  832. }
  833. /////////////
  834. // Place children now by re-adjusting the origins to align the baselines
  835. FinalizeReflow(drawTarget, aDesiredSize);
  836. aStatus = NS_FRAME_COMPLETE;
  837. NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
  838. }
  839. static nscoord AddInterFrameSpacingToSize(ReflowOutput& aDesiredSize,
  840. nsMathMLContainerFrame* aFrame);
  841. /* virtual */ void
  842. nsMathMLContainerFrame::MarkIntrinsicISizesDirty()
  843. {
  844. mIntrinsicWidth = NS_INTRINSIC_WIDTH_UNKNOWN;
  845. nsContainerFrame::MarkIntrinsicISizesDirty();
  846. }
  847. void
  848. nsMathMLContainerFrame::UpdateIntrinsicWidth(nsRenderingContext* aRenderingContext)
  849. {
  850. if (mIntrinsicWidth == NS_INTRINSIC_WIDTH_UNKNOWN) {
  851. ReflowOutput desiredSize(GetWritingMode());
  852. GetIntrinsicISizeMetrics(aRenderingContext, desiredSize);
  853. // Include the additional width added by FixInterFrameSpacing to ensure
  854. // consistent width calculations.
  855. AddInterFrameSpacingToSize(desiredSize, this);
  856. mIntrinsicWidth = desiredSize.ISize(GetWritingMode());
  857. }
  858. }
  859. /* virtual */ nscoord
  860. nsMathMLContainerFrame::GetMinISize(nsRenderingContext* aRenderingContext)
  861. {
  862. nscoord result;
  863. DISPLAY_MIN_WIDTH(this, result);
  864. UpdateIntrinsicWidth(aRenderingContext);
  865. result = mIntrinsicWidth;
  866. return result;
  867. }
  868. /* virtual */ nscoord
  869. nsMathMLContainerFrame::GetPrefISize(nsRenderingContext* aRenderingContext)
  870. {
  871. nscoord result;
  872. DISPLAY_PREF_WIDTH(this, result);
  873. UpdateIntrinsicWidth(aRenderingContext);
  874. result = mIntrinsicWidth;
  875. return result;
  876. }
  877. /* virtual */ void
  878. nsMathMLContainerFrame::GetIntrinsicISizeMetrics(nsRenderingContext* aRenderingContext,
  879. ReflowOutput& aDesiredSize)
  880. {
  881. // Get child widths
  882. nsIFrame* childFrame = mFrames.FirstChild();
  883. while (childFrame) {
  884. ReflowOutput childDesiredSize(GetWritingMode()); // ???
  885. nsMathMLContainerFrame* containerFrame = do_QueryFrame(childFrame);
  886. if (containerFrame) {
  887. containerFrame->GetIntrinsicISizeMetrics(aRenderingContext,
  888. childDesiredSize);
  889. } else {
  890. // XXX This includes margin while Reflow currently doesn't consider
  891. // margin, so we may end up with too much space, but, with stretchy
  892. // characters, this is an approximation anyway.
  893. nscoord width =
  894. nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
  895. nsLayoutUtils::PREF_ISIZE);
  896. childDesiredSize.Width() = width;
  897. childDesiredSize.mBoundingMetrics.width = width;
  898. childDesiredSize.mBoundingMetrics.leftBearing = 0;
  899. childDesiredSize.mBoundingMetrics.rightBearing = width;
  900. nscoord x, xMost;
  901. if (NS_SUCCEEDED(childFrame->GetPrefWidthTightBounds(aRenderingContext,
  902. &x, &xMost))) {
  903. childDesiredSize.mBoundingMetrics.leftBearing = x;
  904. childDesiredSize.mBoundingMetrics.rightBearing = xMost;
  905. }
  906. }
  907. SaveReflowAndBoundingMetricsFor(childFrame, childDesiredSize,
  908. childDesiredSize.mBoundingMetrics);
  909. childFrame = childFrame->GetNextSibling();
  910. }
  911. // Measure
  912. nsresult rv = MeasureForWidth(aRenderingContext->GetDrawTarget(), aDesiredSize);
  913. if (NS_FAILED(rv)) {
  914. ReflowError(aRenderingContext->GetDrawTarget(), aDesiredSize);
  915. }
  916. ClearSavedChildMetrics();
  917. }
  918. /* virtual */ nsresult
  919. nsMathMLContainerFrame::MeasureForWidth(DrawTarget* aDrawTarget,
  920. ReflowOutput& aDesiredSize)
  921. {
  922. return Place(aDrawTarget, false, aDesiredSize);
  923. }
  924. // see spacing table in Chapter 18, TeXBook (p.170)
  925. // Our table isn't quite identical to TeX because operators have
  926. // built-in values for lspace & rspace in the Operator Dictionary.
  927. static int32_t kInterFrameSpacingTable[eMathMLFrameType_COUNT][eMathMLFrameType_COUNT] =
  928. {
  929. // in units of muspace.
  930. // upper half of the byte is set if the
  931. // spacing is not to be used for scriptlevel > 0
  932. /* Ord OpOrd OpInv OpUsr Inner Italic Upright */
  933. /*Ord */ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00},
  934. /*OpOrd*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  935. /*OpInv*/ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  936. /*OpUsr*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01},
  937. /*Inner*/ {0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01},
  938. /*Italic*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01},
  939. /*Upright*/ {0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00}
  940. };
  941. #define GET_INTERSPACE(scriptlevel_, frametype1_, frametype2_, space_) \
  942. /* no space if there is a frame that we know nothing about */ \
  943. if (frametype1_ == eMathMLFrameType_UNKNOWN || \
  944. frametype2_ == eMathMLFrameType_UNKNOWN) \
  945. space_ = 0; \
  946. else { \
  947. space_ = kInterFrameSpacingTable[frametype1_][frametype2_]; \
  948. space_ = (scriptlevel_ > 0 && (space_ & 0xF0)) \
  949. ? 0 /* spacing is disabled */ \
  950. : space_ & 0x0F; \
  951. } \
  952. // This function computes the inter-space between two frames. However,
  953. // since invisible operators need special treatment, the inter-space may
  954. // be delayed when an invisible operator is encountered. In this case,
  955. // the function will carry the inter-space forward until it is determined
  956. // that it can be applied properly (i.e., until we encounter a visible
  957. // frame where to decide whether to accept or reject the inter-space).
  958. // aFromFrameType: remembers the frame when the carry-forward initiated.
  959. // aCarrySpace: keeps track of the inter-space that is delayed.
  960. // @returns: current inter-space (which is 0 when the true inter-space is
  961. // delayed -- and thus has no effect since the frame is invisible anyway).
  962. static nscoord
  963. GetInterFrameSpacing(int32_t aScriptLevel,
  964. eMathMLFrameType aFirstFrameType,
  965. eMathMLFrameType aSecondFrameType,
  966. eMathMLFrameType* aFromFrameType, // IN/OUT
  967. int32_t* aCarrySpace) // IN/OUT
  968. {
  969. eMathMLFrameType firstType = aFirstFrameType;
  970. eMathMLFrameType secondType = aSecondFrameType;
  971. int32_t space;
  972. GET_INTERSPACE(aScriptLevel, firstType, secondType, space);
  973. // feedback control to avoid the inter-space to be added when not necessary
  974. if (secondType == eMathMLFrameType_OperatorInvisible) {
  975. // see if we should start to carry the space forward until we
  976. // encounter a visible frame
  977. if (*aFromFrameType == eMathMLFrameType_UNKNOWN) {
  978. *aFromFrameType = firstType;
  979. *aCarrySpace = space;
  980. }
  981. // keep carrying *aCarrySpace forward, while returning 0 for this stage
  982. space = 0;
  983. }
  984. else if (*aFromFrameType != eMathMLFrameType_UNKNOWN) {
  985. // no carry-forward anymore, get the real inter-space between
  986. // the two frames of interest
  987. firstType = *aFromFrameType;
  988. // But... the invisible operator that we encountered earlier could
  989. // be sitting between italic and upright identifiers, e.g.,
  990. //
  991. // 1. <mi>sin</mi> <mo>&ApplyFunction;</mo> <mi>x</mi>
  992. // 2. <mi>x</mi> <mo>&InvisibileTime;</mo> <mi>sin</mi>
  993. //
  994. // the trick to get the inter-space in either situation
  995. // is to promote "<mi>sin</mi><mo>&ApplyFunction;</mo>" and
  996. // "<mo>&InvisibileTime;</mo><mi>sin</mi>" to user-defined operators...
  997. if (firstType == eMathMLFrameType_UprightIdentifier) {
  998. firstType = eMathMLFrameType_OperatorUserDefined;
  999. }
  1000. else if (secondType == eMathMLFrameType_UprightIdentifier) {
  1001. secondType = eMathMLFrameType_OperatorUserDefined;
  1002. }
  1003. GET_INTERSPACE(aScriptLevel, firstType, secondType, space);
  1004. // Now, we have two values: the computed space and the space that
  1005. // has been carried forward until now. Which value do we pick?
  1006. // If the second type is an operator (e.g., fence), it already has
  1007. // built-in lspace & rspace, so we let them win. Otherwise we pick
  1008. // the max between the two values that we have.
  1009. if (secondType != eMathMLFrameType_OperatorOrdinary &&
  1010. space < *aCarrySpace)
  1011. space = *aCarrySpace;
  1012. // reset everything now that the carry-forward is done
  1013. *aFromFrameType = eMathMLFrameType_UNKNOWN;
  1014. *aCarrySpace = 0;
  1015. }
  1016. return space;
  1017. }
  1018. static nscoord GetThinSpace(const nsStyleFont* aStyleFont)
  1019. {
  1020. return NSToCoordRound(float(aStyleFont->mFont.size)*float(3) / float(18));
  1021. }
  1022. class nsMathMLContainerFrame::RowChildFrameIterator {
  1023. public:
  1024. explicit RowChildFrameIterator(nsMathMLContainerFrame* aParentFrame) :
  1025. mParentFrame(aParentFrame),
  1026. mReflowOutput(aParentFrame->GetWritingMode()),
  1027. mX(0),
  1028. mCarrySpace(0),
  1029. mFromFrameType(eMathMLFrameType_UNKNOWN),
  1030. mRTL(aParentFrame->StyleVisibility()->mDirection)
  1031. {
  1032. if (!mRTL) {
  1033. mChildFrame = aParentFrame->mFrames.FirstChild();
  1034. } else {
  1035. mChildFrame = aParentFrame->mFrames.LastChild();
  1036. }
  1037. if (!mChildFrame)
  1038. return;
  1039. InitMetricsForChild();
  1040. }
  1041. RowChildFrameIterator& operator++()
  1042. {
  1043. // add child size + italic correction
  1044. mX += mReflowOutput.mBoundingMetrics.width + mItalicCorrection;
  1045. if (!mRTL) {
  1046. mChildFrame = mChildFrame->GetNextSibling();
  1047. } else {
  1048. mChildFrame = mChildFrame->GetPrevSibling();
  1049. }
  1050. if (!mChildFrame)
  1051. return *this;
  1052. eMathMLFrameType prevFrameType = mChildFrameType;
  1053. InitMetricsForChild();
  1054. // add inter frame spacing
  1055. const nsStyleFont* font = mParentFrame->StyleFont();
  1056. nscoord space =
  1057. GetInterFrameSpacing(font->mScriptLevel,
  1058. prevFrameType, mChildFrameType,
  1059. &mFromFrameType, &mCarrySpace);
  1060. mX += space * GetThinSpace(font);
  1061. return *this;
  1062. }
  1063. nsIFrame* Frame() const { return mChildFrame; }
  1064. nscoord X() const { return mX; }
  1065. const ReflowOutput& GetReflowOutput() const { return mReflowOutput; }
  1066. nscoord Ascent() const { return mReflowOutput.BlockStartAscent(); }
  1067. nscoord Descent() const { return mReflowOutput.Height() - mReflowOutput.BlockStartAscent(); }
  1068. const nsBoundingMetrics& BoundingMetrics() const {
  1069. return mReflowOutput.mBoundingMetrics;
  1070. }
  1071. private:
  1072. const nsMathMLContainerFrame* mParentFrame;
  1073. nsIFrame* mChildFrame;
  1074. ReflowOutput mReflowOutput;
  1075. nscoord mX;
  1076. nscoord mItalicCorrection;
  1077. eMathMLFrameType mChildFrameType;
  1078. int32_t mCarrySpace;
  1079. eMathMLFrameType mFromFrameType;
  1080. bool mRTL;
  1081. void InitMetricsForChild()
  1082. {
  1083. GetReflowAndBoundingMetricsFor(mChildFrame, mReflowOutput, mReflowOutput.mBoundingMetrics,
  1084. &mChildFrameType);
  1085. nscoord leftCorrection, rightCorrection;
  1086. GetItalicCorrection(mReflowOutput.mBoundingMetrics,
  1087. leftCorrection, rightCorrection);
  1088. if (!mChildFrame->GetPrevSibling() &&
  1089. mParentFrame->GetContent()->IsMathMLElement(nsGkAtoms::msqrt_)) {
  1090. // Remove leading correction in <msqrt> because the sqrt glyph itself is
  1091. // there first.
  1092. if (!mRTL) {
  1093. leftCorrection = 0;
  1094. } else {
  1095. rightCorrection = 0;
  1096. }
  1097. }
  1098. // add left correction -- this fixes the problem of the italic 'f'
  1099. // e.g., <mo>q</mo> <mi>f</mi> <mo>I</mo>
  1100. mX += leftCorrection;
  1101. mItalicCorrection = rightCorrection;
  1102. }
  1103. };
  1104. /* virtual */ nsresult
  1105. nsMathMLContainerFrame::Place(DrawTarget* aDrawTarget,
  1106. bool aPlaceOrigin,
  1107. ReflowOutput& aDesiredSize)
  1108. {
  1109. // This is needed in case this frame is empty (i.e., no child frames)
  1110. mBoundingMetrics = nsBoundingMetrics();
  1111. RowChildFrameIterator child(this);
  1112. nscoord ascent = 0, descent = 0;
  1113. while (child.Frame()) {
  1114. if (descent < child.Descent())
  1115. descent = child.Descent();
  1116. if (ascent < child.Ascent())
  1117. ascent = child.Ascent();
  1118. // add the child size
  1119. mBoundingMetrics.width = child.X();
  1120. mBoundingMetrics += child.BoundingMetrics();
  1121. ++child;
  1122. }
  1123. // Add the italic correction at the end (including the last child).
  1124. // This gives a nice gap between math and non-math frames, and still
  1125. // gives the same math inter-spacing in case this frame connects to
  1126. // another math frame
  1127. mBoundingMetrics.width = child.X();
  1128. aDesiredSize.Width() = std::max(0, mBoundingMetrics.width);
  1129. aDesiredSize.Height() = ascent + descent;
  1130. aDesiredSize.SetBlockStartAscent(ascent);
  1131. aDesiredSize.mBoundingMetrics = mBoundingMetrics;
  1132. mReference.x = 0;
  1133. mReference.y = aDesiredSize.BlockStartAscent();
  1134. //////////////////
  1135. // Place Children
  1136. if (aPlaceOrigin) {
  1137. PositionRowChildFrames(0, aDesiredSize.BlockStartAscent());
  1138. }
  1139. return NS_OK;
  1140. }
  1141. void
  1142. nsMathMLContainerFrame::PositionRowChildFrames(nscoord aOffsetX,
  1143. nscoord aBaseline)
  1144. {
  1145. RowChildFrameIterator child(this);
  1146. while (child.Frame()) {
  1147. nscoord dx = aOffsetX + child.X();
  1148. nscoord dy = aBaseline - child.Ascent();
  1149. FinishReflowChild(child.Frame(), PresContext(), child.GetReflowOutput(),
  1150. nullptr, dx, dy, 0);
  1151. ++child;
  1152. }
  1153. }
  1154. class ForceReflow : public nsIReflowCallback {
  1155. public:
  1156. virtual bool ReflowFinished() override {
  1157. return true;
  1158. }
  1159. virtual void ReflowCallbackCanceled() override {}
  1160. };
  1161. // We only need one of these so we just make it a static global, no need
  1162. // to dynamically allocate/destroy it.
  1163. static ForceReflow gForceReflow;
  1164. void
  1165. nsMathMLContainerFrame::SetIncrementScriptLevel(int32_t aChildIndex, bool aIncrement)
  1166. {
  1167. nsIFrame* child = PrincipalChildList().FrameAt(aChildIndex);
  1168. if (!child)
  1169. return;
  1170. nsIContent* content = child->GetContent();
  1171. if (!content->IsMathMLElement())
  1172. return;
  1173. nsMathMLElement* element = static_cast<nsMathMLElement*>(content);
  1174. if (element->GetIncrementScriptLevel() == aIncrement)
  1175. return;
  1176. // XXXroc this does a ContentStatesChanged, is it safe to call here? If
  1177. // not we should do it in a post-reflow callback.
  1178. element->SetIncrementScriptLevel(aIncrement, true);
  1179. PresContext()->PresShell()->PostReflowCallback(&gForceReflow);
  1180. }
  1181. // helpers to fix the inter-spacing when <math> is the only parent
  1182. // e.g., it fixes <math> <mi>f</mi> <mo>q</mo> <mi>f</mi> <mo>I</mo> </math>
  1183. static nscoord
  1184. GetInterFrameSpacingFor(int32_t aScriptLevel,
  1185. nsIFrame* aParentFrame,
  1186. nsIFrame* aChildFrame)
  1187. {
  1188. nsIFrame* childFrame = aParentFrame->PrincipalChildList().FirstChild();
  1189. if (!childFrame || aChildFrame == childFrame)
  1190. return 0;
  1191. int32_t carrySpace = 0;
  1192. eMathMLFrameType fromFrameType = eMathMLFrameType_UNKNOWN;
  1193. eMathMLFrameType prevFrameType = eMathMLFrameType_UNKNOWN;
  1194. eMathMLFrameType childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame);
  1195. childFrame = childFrame->GetNextSibling();
  1196. while (childFrame) {
  1197. prevFrameType = childFrameType;
  1198. childFrameType = nsMathMLFrame::GetMathMLFrameTypeFor(childFrame);
  1199. nscoord space = GetInterFrameSpacing(aScriptLevel,
  1200. prevFrameType, childFrameType, &fromFrameType, &carrySpace);
  1201. if (aChildFrame == childFrame) {
  1202. // get thinspace
  1203. nsStyleContext* parentContext = aParentFrame->StyleContext();
  1204. nscoord thinSpace = GetThinSpace(parentContext->StyleFont());
  1205. // we are done
  1206. return space * thinSpace;
  1207. }
  1208. childFrame = childFrame->GetNextSibling();
  1209. }
  1210. NS_NOTREACHED("child not in the childlist of its parent");
  1211. return 0;
  1212. }
  1213. static nscoord
  1214. AddInterFrameSpacingToSize(ReflowOutput& aDesiredSize,
  1215. nsMathMLContainerFrame* aFrame)
  1216. {
  1217. nscoord gap = 0;
  1218. nsIFrame* parent = aFrame->GetParent();
  1219. nsIContent* parentContent = parent->GetContent();
  1220. if (MOZ_UNLIKELY(!parentContent)) {
  1221. return 0;
  1222. }
  1223. if (parentContent->IsAnyOfMathMLElements(nsGkAtoms::math,
  1224. nsGkAtoms::mtd_)) {
  1225. gap = GetInterFrameSpacingFor(aFrame->StyleFont()->mScriptLevel,
  1226. parent, aFrame);
  1227. // add our own italic correction
  1228. nscoord leftCorrection = 0, italicCorrection = 0;
  1229. aFrame->GetItalicCorrection(aDesiredSize.mBoundingMetrics,
  1230. leftCorrection, italicCorrection);
  1231. gap += leftCorrection;
  1232. if (gap) {
  1233. aDesiredSize.mBoundingMetrics.leftBearing += gap;
  1234. aDesiredSize.mBoundingMetrics.rightBearing += gap;
  1235. aDesiredSize.mBoundingMetrics.width += gap;
  1236. aDesiredSize.Width() += gap;
  1237. }
  1238. aDesiredSize.mBoundingMetrics.width += italicCorrection;
  1239. aDesiredSize.Width() += italicCorrection;
  1240. }
  1241. return gap;
  1242. }
  1243. nscoord
  1244. nsMathMLContainerFrame::FixInterFrameSpacing(ReflowOutput& aDesiredSize)
  1245. {
  1246. nscoord gap = 0;
  1247. gap = AddInterFrameSpacingToSize(aDesiredSize, this);
  1248. if (gap) {
  1249. // Shift our children to account for the correction
  1250. nsIFrame* childFrame = mFrames.FirstChild();
  1251. while (childFrame) {
  1252. childFrame->SetPosition(childFrame->GetPosition() + nsPoint(gap, 0));
  1253. childFrame = childFrame->GetNextSibling();
  1254. }
  1255. }
  1256. return gap;
  1257. }
  1258. /* static */ void
  1259. nsMathMLContainerFrame::DidReflowChildren(nsIFrame* aFirst, nsIFrame* aStop)
  1260. {
  1261. if (MOZ_UNLIKELY(!aFirst))
  1262. return;
  1263. for (nsIFrame* frame = aFirst;
  1264. frame != aStop;
  1265. frame = frame->GetNextSibling()) {
  1266. NS_ASSERTION(frame, "aStop isn't a sibling");
  1267. if (frame->GetStateBits() & NS_FRAME_IN_REFLOW) {
  1268. // finish off principal descendants, too
  1269. nsIFrame* grandchild = frame->PrincipalChildList().FirstChild();
  1270. if (grandchild)
  1271. DidReflowChildren(grandchild, nullptr);
  1272. frame->DidReflow(frame->PresContext(), nullptr,
  1273. nsDidReflowStatus::FINISHED);
  1274. }
  1275. }
  1276. }
  1277. // helper used by mstyle, mphantom, mpadded and mrow in their implementations
  1278. // of TransmitAutomaticData().
  1279. nsresult
  1280. nsMathMLContainerFrame::TransmitAutomaticDataForMrowLikeElement()
  1281. {
  1282. //
  1283. // One loop to check both conditions below:
  1284. //
  1285. // 1) whether all the children of the mrow-like element are space-like.
  1286. //
  1287. // The REC defines the following elements to be "space-like":
  1288. // * an mstyle, mphantom, or mpadded element, all of whose direct
  1289. // sub-expressions are space-like;
  1290. // * an mrow all of whose direct sub-expressions are space-like.
  1291. //
  1292. // 2) whether all but one child of the mrow-like element are space-like and
  1293. // this non-space-like child is an embellished operator.
  1294. //
  1295. // The REC defines the following elements to be embellished operators:
  1296. // * one of the elements mstyle, mphantom, or mpadded, such that an mrow
  1297. // containing the same arguments would be an embellished operator;
  1298. // * an mrow whose arguments consist (in any order) of one embellished
  1299. // operator and zero or more space-like elements.
  1300. //
  1301. nsIFrame *childFrame, *baseFrame;
  1302. bool embellishedOpFound = false;
  1303. nsEmbellishData embellishData;
  1304. for (childFrame = PrincipalChildList().FirstChild();
  1305. childFrame;
  1306. childFrame = childFrame->GetNextSibling()) {
  1307. nsIMathMLFrame* mathMLFrame = do_QueryFrame(childFrame);
  1308. if (!mathMLFrame) break;
  1309. if (!mathMLFrame->IsSpaceLike()) {
  1310. if (embellishedOpFound) break;
  1311. baseFrame = childFrame;
  1312. GetEmbellishDataFrom(baseFrame, embellishData);
  1313. if (!NS_MATHML_IS_EMBELLISH_OPERATOR(embellishData.flags)) break;
  1314. embellishedOpFound = true;
  1315. }
  1316. }
  1317. if (!childFrame) {
  1318. // we successfully went to the end of the loop. This means that one of
  1319. // condition 1) or 2) holds.
  1320. if (!embellishedOpFound) {
  1321. // the mrow-like element is space-like.
  1322. mPresentationData.flags |= NS_MATHML_SPACE_LIKE;
  1323. } else {
  1324. // the mrow-like element is an embellished operator.
  1325. // let the state of the embellished operator found bubble to us.
  1326. mPresentationData.baseFrame = baseFrame;
  1327. mEmbellishData = embellishData;
  1328. }
  1329. }
  1330. if (childFrame || !embellishedOpFound) {
  1331. // The element is not embellished operator
  1332. mPresentationData.baseFrame = nullptr;
  1333. mEmbellishData.flags = 0;
  1334. mEmbellishData.coreFrame = nullptr;
  1335. mEmbellishData.direction = NS_STRETCH_DIRECTION_UNSUPPORTED;
  1336. mEmbellishData.leadingSpace = 0;
  1337. mEmbellishData.trailingSpace = 0;
  1338. }
  1339. if (childFrame || embellishedOpFound) {
  1340. // The element is not space-like
  1341. mPresentationData.flags &= ~NS_MATHML_SPACE_LIKE;
  1342. }
  1343. return NS_OK;
  1344. }
  1345. /*static*/ void
  1346. nsMathMLContainerFrame::PropagateFrameFlagFor(nsIFrame* aFrame,
  1347. nsFrameState aFlags)
  1348. {
  1349. if (!aFrame || !aFlags)
  1350. return;
  1351. aFrame->AddStateBits(aFlags);
  1352. for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
  1353. PropagateFrameFlagFor(childFrame, aFlags);
  1354. }
  1355. }
  1356. nsresult
  1357. nsMathMLContainerFrame::ReportErrorToConsole(const char* errorMsgId,
  1358. const char16_t** aParams,
  1359. uint32_t aParamCount)
  1360. {
  1361. return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
  1362. NS_LITERAL_CSTRING("Layout: MathML"), mContent->OwnerDoc(),
  1363. nsContentUtils::eMATHML_PROPERTIES,
  1364. errorMsgId, aParams, aParamCount);
  1365. }
  1366. nsresult
  1367. nsMathMLContainerFrame::ReportParseError(const char16_t* aAttribute,
  1368. const char16_t* aValue)
  1369. {
  1370. const char16_t* argv[] =
  1371. { aValue, aAttribute, mContent->NodeInfo()->NameAtom()->GetUTF16String() };
  1372. return ReportErrorToConsole("AttributeParsingError", argv, 3);
  1373. }
  1374. nsresult
  1375. nsMathMLContainerFrame::ReportChildCountError()
  1376. {
  1377. const char16_t* arg = mContent->NodeInfo()->NameAtom()->GetUTF16String();
  1378. return ReportErrorToConsole("ChildCountIncorrect", &arg, 1);
  1379. }
  1380. nsresult
  1381. nsMathMLContainerFrame::ReportInvalidChildError(nsIAtom* aChildTag)
  1382. {
  1383. const char16_t* argv[] =
  1384. { aChildTag->GetUTF16String(),
  1385. mContent->NodeInfo()->NameAtom()->GetUTF16String() };
  1386. return ReportErrorToConsole("InvalidChild", argv, 2);
  1387. }
  1388. //==========================
  1389. nsContainerFrame*
  1390. NS_NewMathMLmathBlockFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  1391. {
  1392. return new (aPresShell) nsMathMLmathBlockFrame(aContext);
  1393. }
  1394. NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathBlockFrame)
  1395. NS_QUERYFRAME_HEAD(nsMathMLmathBlockFrame)
  1396. NS_QUERYFRAME_ENTRY(nsMathMLmathBlockFrame)
  1397. NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
  1398. nsContainerFrame*
  1399. NS_NewMathMLmathInlineFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  1400. {
  1401. return new (aPresShell) nsMathMLmathInlineFrame(aContext);
  1402. }
  1403. NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmathInlineFrame)
  1404. NS_QUERYFRAME_HEAD(nsMathMLmathInlineFrame)
  1405. NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
  1406. NS_QUERYFRAME_TAIL_INHERITING(nsInlineFrame)