nsMathMLmtableFrame.cpp 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315
  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 "nsMathMLmtableFrame.h"
  6. #include "nsPresContext.h"
  7. #include "nsStyleContext.h"
  8. #include "nsStyleConsts.h"
  9. #include "nsNameSpaceManager.h"
  10. #include "nsRenderingContext.h"
  11. #include "nsCSSRendering.h"
  12. #include "nsMathMLElement.h"
  13. #include "nsTArray.h"
  14. #include "nsTableFrame.h"
  15. #include "celldata.h"
  16. #include "mozilla/RestyleManagerHandle.h"
  17. #include "mozilla/RestyleManagerHandleInlines.h"
  18. #include <algorithm>
  19. #include "nsIScriptError.h"
  20. #include "nsContentUtils.h"
  21. using namespace mozilla;
  22. using namespace mozilla::image;
  23. //
  24. // <mtable> -- table or matrix - implementation
  25. //
  26. static int8_t
  27. ParseStyleValue(nsIAtom* aAttribute, const nsAString& aAttributeValue)
  28. {
  29. if (aAttribute == nsGkAtoms::rowalign_) {
  30. if (aAttributeValue.EqualsLiteral("top"))
  31. return NS_STYLE_VERTICAL_ALIGN_TOP;
  32. else if (aAttributeValue.EqualsLiteral("bottom"))
  33. return NS_STYLE_VERTICAL_ALIGN_BOTTOM;
  34. else if (aAttributeValue.EqualsLiteral("center"))
  35. return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
  36. else
  37. return NS_STYLE_VERTICAL_ALIGN_BASELINE;
  38. } else if (aAttribute == nsGkAtoms::columnalign_) {
  39. if (aAttributeValue.EqualsLiteral("left"))
  40. return NS_STYLE_TEXT_ALIGN_LEFT;
  41. else if (aAttributeValue.EqualsLiteral("right"))
  42. return NS_STYLE_TEXT_ALIGN_RIGHT;
  43. else
  44. return NS_STYLE_TEXT_ALIGN_CENTER;
  45. } else if (aAttribute == nsGkAtoms::rowlines_ ||
  46. aAttribute == nsGkAtoms::columnlines_) {
  47. if (aAttributeValue.EqualsLiteral("solid"))
  48. return NS_STYLE_BORDER_STYLE_SOLID;
  49. else if (aAttributeValue.EqualsLiteral("dashed"))
  50. return NS_STYLE_BORDER_STYLE_DASHED;
  51. else
  52. return NS_STYLE_BORDER_STYLE_NONE;
  53. } else {
  54. MOZ_CRASH("Unrecognized attribute.");
  55. }
  56. return -1;
  57. }
  58. static nsTArray<int8_t>*
  59. ExtractStyleValues(const nsAString& aString,
  60. nsIAtom* aAttribute,
  61. bool aAllowMultiValues)
  62. {
  63. nsTArray<int8_t>* styleArray = nullptr;
  64. const char16_t* start = aString.BeginReading();
  65. const char16_t* end = aString.EndReading();
  66. int32_t startIndex = 0;
  67. int32_t count = 0;
  68. while (start < end) {
  69. // Skip leading spaces.
  70. while ((start < end) && nsCRT::IsAsciiSpace(*start)) {
  71. start++;
  72. startIndex++;
  73. }
  74. // Look for the end of the string, or another space.
  75. while ((start < end) && !nsCRT::IsAsciiSpace(*start)) {
  76. start++;
  77. count++;
  78. }
  79. // Grab the value found and process it.
  80. if (count > 0) {
  81. if (!styleArray)
  82. styleArray = new nsTArray<int8_t>();
  83. // We want to return a null array if an attribute gives multiple values,
  84. // but multiple values aren't allowed.
  85. if (styleArray->Length() > 1 && !aAllowMultiValues) {
  86. delete styleArray;
  87. return nullptr;
  88. }
  89. nsDependentSubstring valueString(aString, startIndex, count);
  90. int8_t styleValue = ParseStyleValue(aAttribute, valueString);
  91. styleArray->AppendElement(styleValue);
  92. startIndex += count;
  93. count = 0;
  94. }
  95. }
  96. return styleArray;
  97. }
  98. static nsresult
  99. ReportParseError(nsIFrame* aFrame,
  100. const char16_t* aAttribute,
  101. const char16_t* aValue)
  102. {
  103. nsIContent* content = aFrame->GetContent();
  104. const char16_t* params[] =
  105. { aValue, aAttribute, content->NodeInfo()->NameAtom()->GetUTF16String() };
  106. return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
  107. NS_LITERAL_CSTRING("Layout: MathML"),
  108. content->OwnerDoc(),
  109. nsContentUtils::eMATHML_PROPERTIES,
  110. "AttributeParsingError", params, 3);
  111. }
  112. // Each rowalign='top bottom' or columnalign='left right center' (from
  113. // <mtable> or <mtr>) is split once into an nsTArray<int8_t> which is
  114. // stored in the property table. Row/Cell frames query the property table
  115. // to see what values apply to them.
  116. NS_DECLARE_FRAME_PROPERTY_DELETABLE(RowAlignProperty, nsTArray<int8_t>)
  117. NS_DECLARE_FRAME_PROPERTY_DELETABLE(RowLinesProperty, nsTArray<int8_t>)
  118. NS_DECLARE_FRAME_PROPERTY_DELETABLE(ColumnAlignProperty, nsTArray<int8_t>)
  119. NS_DECLARE_FRAME_PROPERTY_DELETABLE(ColumnLinesProperty, nsTArray<int8_t>)
  120. static const FramePropertyDescriptor<nsTArray<int8_t>>*
  121. AttributeToProperty(nsIAtom* aAttribute)
  122. {
  123. if (aAttribute == nsGkAtoms::rowalign_)
  124. return RowAlignProperty();
  125. if (aAttribute == nsGkAtoms::rowlines_)
  126. return RowLinesProperty();
  127. if (aAttribute == nsGkAtoms::columnalign_)
  128. return ColumnAlignProperty();
  129. NS_ASSERTION(aAttribute == nsGkAtoms::columnlines_, "Invalid attribute");
  130. return ColumnLinesProperty();
  131. }
  132. /* This method looks for a property that applies to a cell, but it looks
  133. * recursively because some cell properties can come from the cell, a row,
  134. * a table, etc. This function searches through the hierarchy for a property
  135. * and returns its value. The function stops searching after checking a <mtable>
  136. * frame.
  137. */
  138. static nsTArray<int8_t>*
  139. FindCellProperty(const nsIFrame* aCellFrame,
  140. const FramePropertyDescriptor<nsTArray<int8_t>>* aFrameProperty)
  141. {
  142. const nsIFrame* currentFrame = aCellFrame;
  143. nsTArray<int8_t>* propertyData = nullptr;
  144. while (currentFrame) {
  145. propertyData = currentFrame->GetProperty(aFrameProperty);
  146. bool frameIsTable = (currentFrame->GetType() == nsGkAtoms::tableFrame);
  147. if (propertyData || frameIsTable)
  148. currentFrame = nullptr; // A null frame pointer exits the loop
  149. else
  150. currentFrame = currentFrame->GetParent(); // Go to the parent frame
  151. }
  152. return propertyData;
  153. }
  154. static void
  155. ApplyBorderToStyle(const nsMathMLmtdFrame* aFrame,
  156. nsStyleBorder& aStyleBorder)
  157. {
  158. uint32_t rowIndex = aFrame->RowIndex();
  159. uint32_t columnIndex = aFrame->ColIndex();
  160. nscoord borderWidth =
  161. aFrame->PresContext()->GetBorderWidthTable()[NS_STYLE_BORDER_WIDTH_THIN];
  162. nsTArray<int8_t>* rowLinesList =
  163. FindCellProperty(aFrame, RowLinesProperty());
  164. nsTArray<int8_t>* columnLinesList =
  165. FindCellProperty(aFrame, ColumnLinesProperty());
  166. // We don't place a row line on top of the first row
  167. if (rowIndex > 0 && rowLinesList) {
  168. // If the row number is greater than the number of provided rowline
  169. // values, we simply repeat the last value.
  170. uint32_t listLength = rowLinesList->Length();
  171. if (rowIndex < listLength) {
  172. aStyleBorder.SetBorderStyle(NS_SIDE_TOP,
  173. rowLinesList->ElementAt(rowIndex - 1));
  174. } else {
  175. aStyleBorder.SetBorderStyle(NS_SIDE_TOP,
  176. rowLinesList->ElementAt(listLength - 1));
  177. }
  178. aStyleBorder.SetBorderWidth(NS_SIDE_TOP, borderWidth);
  179. }
  180. // We don't place a column line on the left of the first column.
  181. if (columnIndex > 0 && columnLinesList) {
  182. // If the column number is greater than the number of provided columline
  183. // values, we simply repeat the last value.
  184. uint32_t listLength = columnLinesList->Length();
  185. if (columnIndex < listLength) {
  186. aStyleBorder.SetBorderStyle(NS_SIDE_LEFT,
  187. columnLinesList->ElementAt(columnIndex - 1));
  188. } else {
  189. aStyleBorder.SetBorderStyle(NS_SIDE_LEFT,
  190. columnLinesList->ElementAt(listLength - 1));
  191. }
  192. aStyleBorder.SetBorderWidth(NS_SIDE_LEFT, borderWidth);
  193. }
  194. }
  195. static nsMargin
  196. ComputeBorderOverflow(nsMathMLmtdFrame* aFrame,
  197. const nsStyleBorder& aStyleBorder)
  198. {
  199. nsMargin overflow;
  200. int32_t rowIndex;
  201. int32_t columnIndex;
  202. nsTableFrame* table = aFrame->GetTableFrame();
  203. aFrame->GetCellIndexes(rowIndex, columnIndex);
  204. if (!columnIndex) {
  205. overflow.left = table->GetColSpacing(-1);
  206. overflow.right = table->GetColSpacing(0) / 2;
  207. } else if (columnIndex == table->GetColCount() - 1) {
  208. overflow.left = table->GetColSpacing(columnIndex - 1) / 2;
  209. overflow.right = table->GetColSpacing(columnIndex + 1);
  210. } else {
  211. overflow.left = table->GetColSpacing(columnIndex - 1) / 2;
  212. overflow.right = table->GetColSpacing(columnIndex) / 2;
  213. }
  214. if (!rowIndex) {
  215. overflow.top = table->GetRowSpacing(-1);
  216. overflow.bottom = table->GetRowSpacing(0) / 2;
  217. } else if (rowIndex == table->GetRowCount() - 1) {
  218. overflow.top = table->GetRowSpacing(rowIndex - 1) / 2;
  219. overflow.bottom = table->GetRowSpacing(rowIndex + 1);
  220. } else {
  221. overflow.top = table->GetRowSpacing(rowIndex - 1) / 2;
  222. overflow.bottom = table->GetRowSpacing(rowIndex) / 2;
  223. }
  224. return overflow;
  225. }
  226. /*
  227. * A variant of the nsDisplayBorder contains special code to render a border
  228. * around a nsMathMLmtdFrame based on the rowline and columnline properties
  229. * set on the cell frame.
  230. */
  231. class nsDisplaymtdBorder : public nsDisplayBorder
  232. {
  233. public:
  234. nsDisplaymtdBorder(nsDisplayListBuilder* aBuilder, nsMathMLmtdFrame* aFrame)
  235. : nsDisplayBorder(aBuilder, aFrame)
  236. {
  237. }
  238. nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override
  239. {
  240. return new nsDisplayItemGenericImageGeometry(this, aBuilder);
  241. }
  242. void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
  243. const nsDisplayItemGeometry* aGeometry,
  244. nsRegion* aInvalidRegion) override
  245. {
  246. auto geometry =
  247. static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
  248. if (aBuilder->ShouldSyncDecodeImages() &&
  249. geometry->ShouldInvalidateToSyncDecodeImages()) {
  250. bool snap;
  251. aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
  252. }
  253. nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
  254. }
  255. virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
  256. {
  257. *aSnap = true;
  258. nsStyleBorder styleBorder = *mFrame->StyleBorder();
  259. nsMathMLmtdFrame* frame = static_cast<nsMathMLmtdFrame*>(mFrame);
  260. ApplyBorderToStyle(frame, styleBorder);
  261. nsRect bounds = CalculateBounds(styleBorder);
  262. nsMargin overflow = ComputeBorderOverflow(frame, styleBorder);
  263. bounds.Inflate(overflow);
  264. return bounds;
  265. }
  266. virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) override
  267. {
  268. nsStyleBorder styleBorder = *mFrame->StyleBorder();
  269. nsMathMLmtdFrame* frame = static_cast<nsMathMLmtdFrame*>(mFrame);
  270. ApplyBorderToStyle(frame, styleBorder);
  271. nsRect bounds = nsRect(ToReferenceFrame(), mFrame->GetSize());
  272. nsMargin overflow = ComputeBorderOverflow(frame, styleBorder);
  273. bounds.Inflate(overflow);
  274. PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
  275. ? PaintBorderFlags::SYNC_DECODE_IMAGES
  276. : PaintBorderFlags();
  277. DrawResult result =
  278. nsCSSRendering::PaintBorderWithStyleBorder(mFrame->PresContext(), *aCtx,
  279. mFrame, mVisibleRect,
  280. bounds,
  281. styleBorder,
  282. mFrame->StyleContext(),
  283. flags,
  284. mFrame->GetSkipSides());
  285. nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
  286. }
  287. };
  288. #ifdef DEBUG
  289. #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) \
  290. MOZ_ASSERT(mozilla::StyleDisplay::_expected == _frame->StyleDisplay()->mDisplay, \
  291. "internal error");
  292. #else
  293. #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)
  294. #endif
  295. static void
  296. ParseFrameAttribute(nsIFrame* aFrame,
  297. nsIAtom* aAttribute,
  298. bool aAllowMultiValues)
  299. {
  300. nsAutoString attrValue;
  301. nsIContent* frameContent = aFrame->GetContent();
  302. frameContent->GetAttr(kNameSpaceID_None, aAttribute, attrValue);
  303. if (!attrValue.IsEmpty()) {
  304. nsTArray<int8_t>* valueList =
  305. ExtractStyleValues(attrValue, aAttribute, aAllowMultiValues);
  306. // If valueList is null, that indicates a problem with the attribute value.
  307. // Only set properties on a valid attribute value.
  308. if (valueList) {
  309. // The code reading the property assumes that this list is nonempty.
  310. NS_ASSERTION(valueList->Length() >= 1, "valueList should not be empty!");
  311. aFrame->SetProperty(AttributeToProperty(aAttribute), valueList);
  312. } else {
  313. ReportParseError(aFrame, aAttribute->GetUTF16String(), attrValue.get());
  314. }
  315. }
  316. }
  317. // rowspacing
  318. //
  319. // Specifies the distance between successive rows in an mtable. Multiple
  320. // lengths can be specified, each corresponding to its respective position
  321. // between rows. For example:
  322. //
  323. // [ROW_0]
  324. // rowspace_0
  325. // [ROW_1]
  326. // rowspace_1
  327. // [ROW_2]
  328. //
  329. // If the number of row gaps exceeds the number of lengths specified, the final
  330. // specified length is repeated. Additional lengths are ignored.
  331. //
  332. // values: (length)+
  333. // default: 1.0ex
  334. //
  335. // Unitless values are permitted and provide a multiple of the default value
  336. // Negative values are forbidden.
  337. //
  338. // columnspacing
  339. //
  340. // Specifies the distance between successive columns in an mtable. Multiple
  341. // lengths can be specified, each corresponding to its respective position
  342. // between columns. For example:
  343. //
  344. // [COLUMN_0] columnspace_0 [COLUMN_1] columnspace_1 [COLUMN_2]
  345. //
  346. // If the number of column gaps exceeds the number of lengths specified, the
  347. // final specified length is repeated. Additional lengths are ignored.
  348. //
  349. // values: (length)+
  350. // default: 0.8em
  351. //
  352. // Unitless values are permitted and provide a multiple of the default value
  353. // Negative values are forbidden.
  354. //
  355. // framespacing
  356. //
  357. // Specifies the distance between the mtable and its frame (if any). The
  358. // first value specified provides the spacing between the left and right edge
  359. // of the table and the frame, the second value determines the spacing between
  360. // the top and bottom edges and the frame.
  361. //
  362. // An error is reported if only one length is passed. Any additional lengths
  363. // are ignored
  364. //
  365. // values: length length
  366. // default: 0em 0ex If frame attribute is "none" or not specified,
  367. // 0.4em 0.5ex otherwise
  368. //
  369. // Unitless values are permitted and provide a multiple of the default value
  370. // Negative values are forbidden.
  371. //
  372. static const float kDefaultRowspacingEx = 1.0f;
  373. static const float kDefaultColumnspacingEm = 0.8f;
  374. static const float kDefaultFramespacingArg0Em = 0.4f;
  375. static const float kDefaultFramespacingArg1Ex = 0.5f;
  376. static void
  377. ExtractSpacingValues(const nsAString& aString,
  378. nsIAtom* aAttribute,
  379. nsTArray<nscoord>& aSpacingArray,
  380. nsIFrame* aFrame,
  381. nscoord aDefaultValue0,
  382. nscoord aDefaultValue1,
  383. float aFontSizeInflation)
  384. {
  385. nsPresContext* presContext = aFrame->PresContext();
  386. nsStyleContext* styleContext = aFrame->StyleContext();
  387. const char16_t* start = aString.BeginReading();
  388. const char16_t* end = aString.EndReading();
  389. int32_t startIndex = 0;
  390. int32_t count = 0;
  391. int32_t elementNum = 0;
  392. while (start < end) {
  393. // Skip leading spaces.
  394. while ((start < end) && nsCRT::IsAsciiSpace(*start)) {
  395. start++;
  396. startIndex++;
  397. }
  398. // Look for the end of the string, or another space.
  399. while ((start < end) && !nsCRT::IsAsciiSpace(*start)) {
  400. start++;
  401. count++;
  402. }
  403. // Grab the value found and process it.
  404. if (count > 0) {
  405. const nsAString& str = Substring(aString, startIndex, count);
  406. nsAutoString valueString;
  407. valueString.Assign(str);
  408. nscoord newValue;
  409. if (aAttribute == nsGkAtoms::framespacing_ && elementNum) {
  410. newValue = aDefaultValue1;
  411. } else {
  412. newValue = aDefaultValue0;
  413. }
  414. nsMathMLFrame::ParseNumericValue(valueString, &newValue,
  415. nsMathMLElement::PARSE_ALLOW_UNITLESS,
  416. presContext, styleContext,
  417. aFontSizeInflation);
  418. aSpacingArray.AppendElement(newValue);
  419. startIndex += count;
  420. count = 0;
  421. elementNum++;
  422. }
  423. }
  424. }
  425. static void
  426. ParseSpacingAttribute(nsMathMLmtableFrame* aFrame, nsIAtom* aAttribute)
  427. {
  428. NS_ASSERTION(aAttribute == nsGkAtoms::rowspacing_ ||
  429. aAttribute == nsGkAtoms::columnspacing_ ||
  430. aAttribute == nsGkAtoms::framespacing_,
  431. "Non spacing attribute passed");
  432. nsAutoString attrValue;
  433. nsIContent* frameContent = aFrame->GetContent();
  434. frameContent->GetAttr(kNameSpaceID_None, aAttribute, attrValue);
  435. if (nsGkAtoms::framespacing_ == aAttribute) {
  436. nsAutoString frame;
  437. frameContent->GetAttr(kNameSpaceID_None, nsGkAtoms::frame, frame);
  438. if (frame.IsEmpty() || frame.EqualsLiteral("none")) {
  439. aFrame->SetFrameSpacing(0, 0);
  440. return;
  441. }
  442. }
  443. nscoord value;
  444. nscoord value2;
  445. // Set defaults
  446. float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(aFrame);
  447. RefPtr<nsFontMetrics> fm =
  448. nsLayoutUtils::GetFontMetricsForFrame(aFrame, fontSizeInflation);
  449. if (nsGkAtoms::rowspacing_ == aAttribute) {
  450. value = kDefaultRowspacingEx * fm->XHeight();
  451. value2 = 0;
  452. } else if (nsGkAtoms::columnspacing_ == aAttribute) {
  453. value = kDefaultColumnspacingEm * fm->EmHeight();
  454. value2 = 0;
  455. } else {
  456. value = kDefaultFramespacingArg0Em * fm->EmHeight();
  457. value2 = kDefaultFramespacingArg1Ex * fm->XHeight();
  458. }
  459. nsTArray<nscoord> valueList;
  460. ExtractSpacingValues(attrValue, aAttribute, valueList, aFrame, value, value2,
  461. fontSizeInflation);
  462. if (valueList.Length() == 0) {
  463. if (frameContent->HasAttr(kNameSpaceID_None, aAttribute)) {
  464. ReportParseError(aFrame, aAttribute->GetUTF16String(),
  465. attrValue.get());
  466. }
  467. valueList.AppendElement(value);
  468. }
  469. if (aAttribute == nsGkAtoms::framespacing_) {
  470. if (valueList.Length() == 1) {
  471. if(frameContent->HasAttr(kNameSpaceID_None, aAttribute)) {
  472. ReportParseError(aFrame, aAttribute->GetUTF16String(),
  473. attrValue.get());
  474. }
  475. valueList.AppendElement(value2);
  476. } else if (valueList.Length() != 2) {
  477. ReportParseError(aFrame, aAttribute->GetUTF16String(),
  478. attrValue.get());
  479. }
  480. }
  481. if (aAttribute == nsGkAtoms::rowspacing_) {
  482. aFrame->SetRowSpacingArray(valueList);
  483. } else if (aAttribute == nsGkAtoms::columnspacing_) {
  484. aFrame->SetColSpacingArray(valueList);
  485. } else {
  486. aFrame->SetFrameSpacing(valueList.ElementAt(0),
  487. valueList.ElementAt(1));
  488. }
  489. }
  490. static void ParseSpacingAttributes(nsMathMLmtableFrame* aTableFrame)
  491. {
  492. ParseSpacingAttribute(aTableFrame, nsGkAtoms::rowspacing_);
  493. ParseSpacingAttribute(aTableFrame, nsGkAtoms::columnspacing_);
  494. ParseSpacingAttribute(aTableFrame, nsGkAtoms::framespacing_);
  495. aTableFrame->SetUseCSSSpacing();
  496. }
  497. // map all attributes within a table -- requires the indices of rows and cells.
  498. // so it can only happen after they are made ready by the table base class.
  499. static void
  500. MapAllAttributesIntoCSS(nsMathMLmtableFrame* aTableFrame)
  501. {
  502. // Map mtable rowalign & rowlines.
  503. ParseFrameAttribute(aTableFrame, nsGkAtoms::rowalign_, true);
  504. ParseFrameAttribute(aTableFrame, nsGkAtoms::rowlines_, true);
  505. // Map mtable columnalign & columnlines.
  506. ParseFrameAttribute(aTableFrame, nsGkAtoms::columnalign_, true);
  507. ParseFrameAttribute(aTableFrame, nsGkAtoms::columnlines_, true);
  508. // Map mtable rowspacing, columnspacing & framespacing
  509. ParseSpacingAttributes(aTableFrame);
  510. // mtable is simple and only has one (pseudo) row-group
  511. nsIFrame* rgFrame = aTableFrame->PrincipalChildList().FirstChild();
  512. if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
  513. return;
  514. for (nsIFrame* rowFrame : rgFrame->PrincipalChildList()) {
  515. DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TableRow);
  516. if (rowFrame->GetType() == nsGkAtoms::tableRowFrame) {
  517. // Map row rowalign.
  518. ParseFrameAttribute(rowFrame, nsGkAtoms::rowalign_, false);
  519. // Map row columnalign.
  520. ParseFrameAttribute(rowFrame, nsGkAtoms::columnalign_, true);
  521. for (nsIFrame* cellFrame : rowFrame->PrincipalChildList()) {
  522. DEBUG_VERIFY_THAT_FRAME_IS(cellFrame, TableCell);
  523. if (IS_TABLE_CELL(cellFrame->GetType())) {
  524. // Map cell rowalign.
  525. ParseFrameAttribute(cellFrame, nsGkAtoms::rowalign_, false);
  526. // Map row columnalign.
  527. ParseFrameAttribute(cellFrame, nsGkAtoms::columnalign_, false);
  528. }
  529. }
  530. }
  531. }
  532. }
  533. // the align attribute of mtable can have a row number which indicates
  534. // from where to anchor the table, e.g., top 5 means anchor the table at
  535. // the top of the 5th row, axis -1 means anchor the table on the axis of
  536. // the last row
  537. // The REC says that the syntax is
  538. // '\s*(top|bottom|center|baseline|axis)(\s+-?[0-9]+)?\s*'
  539. // the parsing could have been simpler with that syntax
  540. // but for backward compatibility we make optional
  541. // the whitespaces between the alignment name and the row number
  542. enum eAlign {
  543. eAlign_top,
  544. eAlign_bottom,
  545. eAlign_center,
  546. eAlign_baseline,
  547. eAlign_axis
  548. };
  549. static void
  550. ParseAlignAttribute(nsString& aValue, eAlign& aAlign, int32_t& aRowIndex)
  551. {
  552. // by default, the table is centered about the axis
  553. aRowIndex = 0;
  554. aAlign = eAlign_axis;
  555. int32_t len = 0;
  556. // we only have to remove the leading spaces because
  557. // ToInteger ignores the whitespaces around the number
  558. aValue.CompressWhitespace(true, false);
  559. if (0 == aValue.Find("top")) {
  560. len = 3; // 3 is the length of 'top'
  561. aAlign = eAlign_top;
  562. }
  563. else if (0 == aValue.Find("bottom")) {
  564. len = 6; // 6 is the length of 'bottom'
  565. aAlign = eAlign_bottom;
  566. }
  567. else if (0 == aValue.Find("center")) {
  568. len = 6; // 6 is the length of 'center'
  569. aAlign = eAlign_center;
  570. }
  571. else if (0 == aValue.Find("baseline")) {
  572. len = 8; // 8 is the length of 'baseline'
  573. aAlign = eAlign_baseline;
  574. }
  575. else if (0 == aValue.Find("axis")) {
  576. len = 4; // 4 is the length of 'axis'
  577. aAlign = eAlign_axis;
  578. }
  579. if (len) {
  580. nsresult error;
  581. aValue.Cut(0, len); // aValue is not a const here
  582. aRowIndex = aValue.ToInteger(&error);
  583. if (NS_FAILED(error))
  584. aRowIndex = 0;
  585. }
  586. }
  587. #ifdef DEBUG_rbs_off
  588. // call ListMathMLTree(mParent) to get the big picture
  589. static void
  590. ListMathMLTree(nsIFrame* atLeast)
  591. {
  592. // climb up to <math> or <body> if <math> isn't there
  593. nsIFrame* f = atLeast;
  594. for ( ; f; f = f->GetParent()) {
  595. nsIContent* c = f->GetContent();
  596. if (!c || c->IsMathMLElement(nsGkAtoms::math) ||
  597. c->NodeInfo()->NameAtom(nsGkAtoms::body)) // XXXbaku which kind of body tag?
  598. break;
  599. }
  600. if (!f) f = atLeast;
  601. f->List(stdout, 0);
  602. }
  603. #endif
  604. // --------
  605. // implementation of nsMathMLmtableWrapperFrame
  606. NS_QUERYFRAME_HEAD(nsMathMLmtableWrapperFrame)
  607. NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
  608. NS_QUERYFRAME_TAIL_INHERITING(nsTableWrapperFrame)
  609. nsContainerFrame*
  610. NS_NewMathMLmtableOuterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
  611. {
  612. return new (aPresShell) nsMathMLmtableWrapperFrame(aContext);
  613. }
  614. NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableWrapperFrame)
  615. nsMathMLmtableWrapperFrame::~nsMathMLmtableWrapperFrame()
  616. {
  617. }
  618. nsresult
  619. nsMathMLmtableWrapperFrame::AttributeChanged(int32_t aNameSpaceID,
  620. nsIAtom* aAttribute,
  621. int32_t aModType)
  622. {
  623. // Attributes specific to <mtable>:
  624. // frame : in mathml.css
  625. // framespacing : here
  626. // groupalign : not yet supported
  627. // equalrows : not yet supported
  628. // equalcolumns : not yet supported
  629. // displaystyle : here and in mathml.css
  630. // align : in reflow
  631. // rowalign : here
  632. // rowlines : here
  633. // rowspacing : here
  634. // columnalign : here
  635. // columnlines : here
  636. // columnspacing : here
  637. // mtable is simple and only has one (pseudo) row-group inside our inner-table
  638. nsIFrame* tableFrame = mFrames.FirstChild();
  639. NS_ASSERTION(tableFrame && tableFrame->GetType() == nsGkAtoms::tableFrame,
  640. "should always have an inner table frame");
  641. nsIFrame* rgFrame = tableFrame->PrincipalChildList().FirstChild();
  642. if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
  643. return NS_OK;
  644. // align - just need to issue a dirty (resize) reflow command
  645. if (aAttribute == nsGkAtoms::align) {
  646. PresContext()->PresShell()->
  647. FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
  648. return NS_OK;
  649. }
  650. // displaystyle - may seem innocuous, but it is actually very harsh --
  651. // like changing an unit. Blow away and recompute all our automatic
  652. // presentational data, and issue a style-changed reflow request
  653. if (aAttribute == nsGkAtoms::displaystyle_) {
  654. nsMathMLContainerFrame::RebuildAutomaticDataForChildren(GetParent());
  655. // Need to reflow the parent, not us, because this can actually
  656. // affect siblings.
  657. PresContext()->PresShell()->
  658. FrameNeedsReflow(GetParent(), nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  659. return NS_OK;
  660. }
  661. // ...and the other attributes affect rows or columns in one way or another
  662. nsPresContext* presContext = tableFrame->PresContext();
  663. if (aAttribute == nsGkAtoms::rowspacing_ ||
  664. aAttribute == nsGkAtoms::columnspacing_ ||
  665. aAttribute == nsGkAtoms::framespacing_ ) {
  666. nsMathMLmtableFrame* mathMLmtableFrame = do_QueryFrame(tableFrame);
  667. if (mathMLmtableFrame) {
  668. ParseSpacingAttribute(mathMLmtableFrame, aAttribute);
  669. mathMLmtableFrame->SetUseCSSSpacing();
  670. }
  671. } else if (aAttribute == nsGkAtoms::rowalign_ ||
  672. aAttribute == nsGkAtoms::rowlines_ ||
  673. aAttribute == nsGkAtoms::columnalign_ ||
  674. aAttribute == nsGkAtoms::columnlines_) {
  675. // clear any cached property list for this table
  676. tableFrame->DeleteProperty(AttributeToProperty(aAttribute));
  677. // Reparse the new attribute on the table.
  678. ParseFrameAttribute(tableFrame, aAttribute, true);
  679. } else {
  680. // Ignore attributes that do not affect layout.
  681. return NS_OK;
  682. }
  683. // Explicitly request a reflow in our subtree to pick up any changes
  684. presContext->PresShell()->
  685. FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  686. return NS_OK;
  687. }
  688. nsIFrame*
  689. nsMathMLmtableWrapperFrame::GetRowFrameAt(int32_t aRowIndex)
  690. {
  691. int32_t rowCount = GetRowCount();
  692. // Negative indices mean to find upwards from the end.
  693. if (aRowIndex < 0) {
  694. aRowIndex = rowCount + aRowIndex;
  695. } else {
  696. // aRowIndex is 1-based, so convert it to a 0-based index
  697. --aRowIndex;
  698. }
  699. // if our inner table says that the index is valid, find the row now
  700. if (0 <= aRowIndex && aRowIndex <= rowCount) {
  701. nsIFrame* tableFrame = mFrames.FirstChild();
  702. NS_ASSERTION(tableFrame && tableFrame->GetType() == nsGkAtoms::tableFrame,
  703. "should always have an inner table frame");
  704. nsIFrame* rgFrame = tableFrame->PrincipalChildList().FirstChild();
  705. if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
  706. return nullptr;
  707. for (nsIFrame* rowFrame : rgFrame->PrincipalChildList()) {
  708. if (aRowIndex == 0) {
  709. DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TableRow);
  710. if (rowFrame->GetType() != nsGkAtoms::tableRowFrame)
  711. return nullptr;
  712. return rowFrame;
  713. }
  714. --aRowIndex;
  715. }
  716. }
  717. return nullptr;
  718. }
  719. void
  720. nsMathMLmtableWrapperFrame::Reflow(nsPresContext* aPresContext,
  721. ReflowOutput& aDesiredSize,
  722. const ReflowInput& aReflowInput,
  723. nsReflowStatus& aStatus)
  724. {
  725. nsAutoString value;
  726. // we want to return a table that is anchored according to the align attribute
  727. nsTableWrapperFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
  728. NS_ASSERTION(aDesiredSize.Height() >= 0, "illegal height for mtable");
  729. NS_ASSERTION(aDesiredSize.Width() >= 0, "illegal width for mtable");
  730. // see if the user has set the align attribute on the <mtable>
  731. int32_t rowIndex = 0;
  732. eAlign tableAlign = eAlign_axis;
  733. mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, value);
  734. if (!value.IsEmpty()) {
  735. ParseAlignAttribute(value, tableAlign, rowIndex);
  736. }
  737. // adjustments if there is a specified row from where to anchor the table
  738. // (conceptually: when there is no row of reference, picture the table as if
  739. // it is wrapped in a single big fictional row at dy = 0, this way of
  740. // doing so allows us to have a single code path for all cases).
  741. nscoord dy = 0;
  742. WritingMode wm = aDesiredSize.GetWritingMode();
  743. nscoord blockSize = aDesiredSize.BSize(wm);
  744. nsIFrame* rowFrame = nullptr;
  745. if (rowIndex) {
  746. rowFrame = GetRowFrameAt(rowIndex);
  747. if (rowFrame) {
  748. // translate the coordinates to be relative to us and in our writing mode
  749. nsIFrame* frame = rowFrame;
  750. LogicalRect rect(wm, frame->GetRect(),
  751. aReflowInput.ComputedSizeAsContainerIfConstrained());
  752. blockSize = rect.BSize(wm);
  753. do {
  754. dy += rect.BStart(wm);
  755. frame = frame->GetParent();
  756. } while (frame != this);
  757. }
  758. }
  759. switch (tableAlign) {
  760. case eAlign_top:
  761. aDesiredSize.SetBlockStartAscent(dy);
  762. break;
  763. case eAlign_bottom:
  764. aDesiredSize.SetBlockStartAscent(dy + blockSize);
  765. break;
  766. case eAlign_center:
  767. aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
  768. break;
  769. case eAlign_baseline:
  770. if (rowFrame) {
  771. // anchor the table on the baseline of the row of reference
  772. nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
  773. if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
  774. aDesiredSize.SetBlockStartAscent(dy + rowAscent);
  775. break;
  776. }
  777. }
  778. // in other situations, fallback to center
  779. aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
  780. break;
  781. case eAlign_axis:
  782. default: {
  783. // XXX should instead use style data from the row of reference here ?
  784. RefPtr<nsFontMetrics> fm =
  785. nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
  786. nscoord axisHeight;
  787. GetAxisHeight(aReflowInput.mRenderingContext->GetDrawTarget(), fm, axisHeight);
  788. if (rowFrame) {
  789. // anchor the table on the axis of the row of reference
  790. // XXX fallback to baseline because it is a hard problem
  791. // XXX need to fetch the axis of the row; would need rowalign=axis to work better
  792. nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
  793. if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
  794. aDesiredSize.SetBlockStartAscent(dy + rowAscent);
  795. break;
  796. }
  797. }
  798. // in other situations, fallback to using half of the height
  799. aDesiredSize.SetBlockStartAscent(dy + blockSize / 2 + axisHeight);
  800. }
  801. }
  802. mReference.x = 0;
  803. mReference.y = aDesiredSize.BlockStartAscent();
  804. // just make-up a bounding metrics
  805. mBoundingMetrics = nsBoundingMetrics();
  806. mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent();
  807. mBoundingMetrics.descent = aDesiredSize.Height() -
  808. aDesiredSize.BlockStartAscent();
  809. mBoundingMetrics.width = aDesiredSize.Width();
  810. mBoundingMetrics.leftBearing = 0;
  811. mBoundingMetrics.rightBearing = aDesiredSize.Width();
  812. aDesiredSize.mBoundingMetrics = mBoundingMetrics;
  813. NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
  814. }
  815. nsContainerFrame*
  816. NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  817. {
  818. return new (aPresShell) nsMathMLmtableFrame(aContext);
  819. }
  820. NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableFrame)
  821. nsMathMLmtableFrame::~nsMathMLmtableFrame()
  822. {
  823. }
  824. void
  825. nsMathMLmtableFrame::SetInitialChildList(ChildListID aListID,
  826. nsFrameList& aChildList)
  827. {
  828. nsTableFrame::SetInitialChildList(aListID, aChildList);
  829. MapAllAttributesIntoCSS(this);
  830. }
  831. void
  832. nsMathMLmtableFrame::RestyleTable()
  833. {
  834. // re-sync MathML specific style data that may have changed
  835. MapAllAttributesIntoCSS(this);
  836. // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
  837. PresContext()->RestyleManager()->
  838. PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
  839. nsChangeHint_AllReflowHints);
  840. }
  841. nscoord
  842. nsMathMLmtableFrame::GetColSpacing(int32_t aColIndex)
  843. {
  844. if (mUseCSSSpacing) {
  845. return nsTableFrame::GetColSpacing(aColIndex);
  846. }
  847. if (!mColSpacing.Length()) {
  848. NS_ERROR("mColSpacing should not be empty");
  849. return 0;
  850. }
  851. if (aColIndex < 0 || aColIndex >= GetColCount()) {
  852. NS_ASSERTION(aColIndex == -1 || aColIndex == GetColCount(),
  853. "Desired column beyond bounds of table and border");
  854. return mFrameSpacingX;
  855. }
  856. if ((uint32_t) aColIndex >= mColSpacing.Length()) {
  857. return mColSpacing.LastElement();
  858. }
  859. return mColSpacing.ElementAt(aColIndex);
  860. }
  861. nscoord
  862. nsMathMLmtableFrame::GetColSpacing(int32_t aStartColIndex,
  863. int32_t aEndColIndex)
  864. {
  865. if (mUseCSSSpacing) {
  866. return nsTableFrame::GetColSpacing(aStartColIndex, aEndColIndex);
  867. }
  868. if (aStartColIndex == aEndColIndex) {
  869. return 0;
  870. }
  871. if (!mColSpacing.Length()) {
  872. NS_ERROR("mColSpacing should not be empty");
  873. return 0;
  874. }
  875. nscoord space = 0;
  876. if (aStartColIndex < 0) {
  877. NS_ASSERTION(aStartColIndex == -1,
  878. "Desired column beyond bounds of table and border");
  879. space += mFrameSpacingX;
  880. aStartColIndex = 0;
  881. }
  882. if (aEndColIndex >= GetColCount()) {
  883. NS_ASSERTION(aEndColIndex == GetColCount(),
  884. "Desired column beyond bounds of table and border");
  885. space += mFrameSpacingX;
  886. aEndColIndex = GetColCount();
  887. }
  888. // Only iterate over column spacing when there is the potential to vary
  889. int32_t min = std::min(aEndColIndex, (int32_t) mColSpacing.Length());
  890. for (int32_t i = aStartColIndex; i < min; i++) {
  891. space += mColSpacing.ElementAt(i);
  892. }
  893. // The remaining values are constant. Note that if there are more
  894. // column spacings specified than there are columns, LastElement() will be
  895. // multiplied by 0, so it is still safe to use.
  896. space += (aEndColIndex - min) * mColSpacing.LastElement();
  897. return space;
  898. }
  899. nscoord
  900. nsMathMLmtableFrame::GetRowSpacing(int32_t aRowIndex)
  901. {
  902. if (mUseCSSSpacing) {
  903. return nsTableFrame::GetRowSpacing(aRowIndex);
  904. }
  905. if (!mRowSpacing.Length()) {
  906. NS_ERROR("mRowSpacing should not be empty");
  907. return 0;
  908. }
  909. if (aRowIndex < 0 || aRowIndex >= GetRowCount()) {
  910. NS_ASSERTION(aRowIndex == -1 || aRowIndex == GetRowCount(),
  911. "Desired row beyond bounds of table and border");
  912. return mFrameSpacingY;
  913. }
  914. if ((uint32_t) aRowIndex >= mRowSpacing.Length()) {
  915. return mRowSpacing.LastElement();
  916. }
  917. return mRowSpacing.ElementAt(aRowIndex);
  918. }
  919. nscoord
  920. nsMathMLmtableFrame::GetRowSpacing(int32_t aStartRowIndex,
  921. int32_t aEndRowIndex)
  922. {
  923. if (mUseCSSSpacing) {
  924. return nsTableFrame::GetRowSpacing(aStartRowIndex, aEndRowIndex);
  925. }
  926. if (aStartRowIndex == aEndRowIndex) {
  927. return 0;
  928. }
  929. if (!mRowSpacing.Length()) {
  930. NS_ERROR("mRowSpacing should not be empty");
  931. return 0;
  932. }
  933. nscoord space = 0;
  934. if (aStartRowIndex < 0) {
  935. NS_ASSERTION(aStartRowIndex == -1,
  936. "Desired row beyond bounds of table and border");
  937. space += mFrameSpacingY;
  938. aStartRowIndex = 0;
  939. }
  940. if (aEndRowIndex >= GetRowCount()) {
  941. NS_ASSERTION(aEndRowIndex == GetRowCount(),
  942. "Desired row beyond bounds of table and border");
  943. space += mFrameSpacingY;
  944. aEndRowIndex = GetRowCount();
  945. }
  946. // Only iterate over row spacing when there is the potential to vary
  947. int32_t min = std::min(aEndRowIndex, (int32_t) mRowSpacing.Length());
  948. for (int32_t i = aStartRowIndex; i < min; i++) {
  949. space += mRowSpacing.ElementAt(i);
  950. }
  951. // The remaining values are constant. Note that if there are more
  952. // row spacings specified than there are row, LastElement() will be
  953. // multiplied by 0, so it is still safe to use.
  954. space += (aEndRowIndex - min) * mRowSpacing.LastElement();
  955. return space;
  956. }
  957. void
  958. nsMathMLmtableFrame::SetUseCSSSpacing()
  959. {
  960. mUseCSSSpacing =
  961. !(mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::rowspacing_) ||
  962. mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::columnspacing_) ||
  963. mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::framespacing_));
  964. }
  965. NS_QUERYFRAME_HEAD(nsMathMLmtableFrame)
  966. NS_QUERYFRAME_ENTRY(nsMathMLmtableFrame)
  967. NS_QUERYFRAME_TAIL_INHERITING(nsTableFrame)
  968. // --------
  969. // implementation of nsMathMLmtrFrame
  970. nsContainerFrame*
  971. NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  972. {
  973. return new (aPresShell) nsMathMLmtrFrame(aContext);
  974. }
  975. NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtrFrame)
  976. nsMathMLmtrFrame::~nsMathMLmtrFrame()
  977. {
  978. }
  979. nsresult
  980. nsMathMLmtrFrame::AttributeChanged(int32_t aNameSpaceID,
  981. nsIAtom* aAttribute,
  982. int32_t aModType)
  983. {
  984. // Attributes specific to <mtr>:
  985. // groupalign : Not yet supported.
  986. // rowalign : Here
  987. // columnalign : Here
  988. nsPresContext* presContext = PresContext();
  989. if (aAttribute != nsGkAtoms::rowalign_ &&
  990. aAttribute != nsGkAtoms::columnalign_) {
  991. return NS_OK;
  992. }
  993. DeleteProperty(AttributeToProperty(aAttribute));
  994. bool allowMultiValues = (aAttribute == nsGkAtoms::columnalign_);
  995. // Reparse the new attribute.
  996. ParseFrameAttribute(this, aAttribute, allowMultiValues);
  997. // Explicitly request a reflow in our subtree to pick up any changes
  998. presContext->PresShell()->
  999. FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
  1000. return NS_OK;
  1001. }
  1002. // --------
  1003. // implementation of nsMathMLmtdFrame
  1004. nsContainerFrame*
  1005. NS_NewMathMLmtdFrame(nsIPresShell* aPresShell,
  1006. nsStyleContext* aContext,
  1007. nsTableFrame* aTableFrame)
  1008. {
  1009. return new (aPresShell) nsMathMLmtdFrame(aContext, aTableFrame);
  1010. }
  1011. NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdFrame)
  1012. nsMathMLmtdFrame::~nsMathMLmtdFrame()
  1013. {
  1014. }
  1015. void
  1016. nsMathMLmtdFrame::Init(nsIContent* aContent,
  1017. nsContainerFrame* aParent,
  1018. nsIFrame* aPrevInFlow)
  1019. {
  1020. nsTableCellFrame::Init(aContent, aParent, aPrevInFlow);
  1021. // We want to use the ancestor <math> element's font inflation to avoid
  1022. // individual cells having their own varying font inflation.
  1023. RemoveStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
  1024. }
  1025. nsresult
  1026. nsMathMLmtdFrame::AttributeChanged(int32_t aNameSpaceID,
  1027. nsIAtom* aAttribute,
  1028. int32_t aModType)
  1029. {
  1030. // Attributes specific to <mtd>:
  1031. // groupalign : Not yet supported
  1032. // rowalign : here
  1033. // columnalign : here
  1034. // rowspan : here
  1035. // columnspan : here
  1036. if (aAttribute == nsGkAtoms::rowalign_ ||
  1037. aAttribute == nsGkAtoms::columnalign_) {
  1038. DeleteProperty(AttributeToProperty(aAttribute));
  1039. // Reparse the attribute.
  1040. ParseFrameAttribute(this, aAttribute, false);
  1041. return NS_OK;
  1042. }
  1043. if (aAttribute == nsGkAtoms::rowspan ||
  1044. aAttribute == nsGkAtoms::columnspan_) {
  1045. // use the naming expected by the base class
  1046. if (aAttribute == nsGkAtoms::columnspan_)
  1047. aAttribute = nsGkAtoms::colspan;
  1048. return nsTableCellFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
  1049. }
  1050. return NS_OK;
  1051. }
  1052. uint8_t
  1053. nsMathMLmtdFrame::GetVerticalAlign() const
  1054. {
  1055. // Set the default alignment in case no alignment was specified
  1056. uint8_t alignment = nsTableCellFrame::GetVerticalAlign();
  1057. nsTArray<int8_t>* alignmentList = FindCellProperty(this, RowAlignProperty());
  1058. if (alignmentList) {
  1059. uint32_t rowIndex = RowIndex();
  1060. // If the row number is greater than the number of provided rowalign values,
  1061. // we simply repeat the last value.
  1062. if (rowIndex < alignmentList->Length())
  1063. alignment = alignmentList->ElementAt(rowIndex);
  1064. else
  1065. alignment = alignmentList->ElementAt(alignmentList->Length() - 1);
  1066. }
  1067. return alignment;
  1068. }
  1069. nsresult
  1070. nsMathMLmtdFrame::ProcessBorders(nsTableFrame* aFrame,
  1071. nsDisplayListBuilder* aBuilder,
  1072. const nsDisplayListSet& aLists)
  1073. {
  1074. aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
  1075. nsDisplaymtdBorder(aBuilder, this));
  1076. return NS_OK;
  1077. }
  1078. LogicalMargin
  1079. nsMathMLmtdFrame::GetBorderWidth(WritingMode aWM) const
  1080. {
  1081. nsStyleBorder styleBorder = *StyleBorder();
  1082. ApplyBorderToStyle(this, styleBorder);
  1083. return LogicalMargin(aWM, styleBorder.GetComputedBorder());
  1084. }
  1085. nsMargin
  1086. nsMathMLmtdFrame::GetBorderOverflow()
  1087. {
  1088. nsStyleBorder styleBorder = *StyleBorder();
  1089. ApplyBorderToStyle(this, styleBorder);
  1090. nsMargin overflow = ComputeBorderOverflow(this, styleBorder);
  1091. return overflow;
  1092. }
  1093. // --------
  1094. // implementation of nsMathMLmtdInnerFrame
  1095. NS_QUERYFRAME_HEAD(nsMathMLmtdInnerFrame)
  1096. NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
  1097. NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
  1098. nsContainerFrame*
  1099. NS_NewMathMLmtdInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
  1100. {
  1101. return new (aPresShell) nsMathMLmtdInnerFrame(aContext);
  1102. }
  1103. NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdInnerFrame)
  1104. nsMathMLmtdInnerFrame::nsMathMLmtdInnerFrame(nsStyleContext* aContext)
  1105. : nsBlockFrame(aContext)
  1106. {
  1107. // Make a copy of the parent nsStyleText for later modification.
  1108. mUniqueStyleText = new (PresContext()) nsStyleText(*StyleText());
  1109. }
  1110. nsMathMLmtdInnerFrame::~nsMathMLmtdInnerFrame()
  1111. {
  1112. mUniqueStyleText->Destroy(PresContext());
  1113. }
  1114. void
  1115. nsMathMLmtdInnerFrame::Reflow(nsPresContext* aPresContext,
  1116. ReflowOutput& aDesiredSize,
  1117. const ReflowInput& aReflowInput,
  1118. nsReflowStatus& aStatus)
  1119. {
  1120. // Let the base class do the reflow
  1121. nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
  1122. // more about <maligngroup/> and <malignmark/> later
  1123. // ...
  1124. }
  1125. const
  1126. nsStyleText* nsMathMLmtdInnerFrame::StyleTextForLineLayout()
  1127. {
  1128. // Set the default alignment in case nothing was specified
  1129. uint8_t alignment = StyleText()->mTextAlign;
  1130. nsTArray<int8_t>* alignmentList =
  1131. FindCellProperty(this, ColumnAlignProperty());
  1132. if (alignmentList) {
  1133. nsMathMLmtdFrame* cellFrame = (nsMathMLmtdFrame*)GetParent();
  1134. uint32_t columnIndex = cellFrame->ColIndex();
  1135. // If the column number is greater than the number of provided columalign
  1136. // values, we simply repeat the last value.
  1137. if (columnIndex < alignmentList->Length())
  1138. alignment = alignmentList->ElementAt(columnIndex);
  1139. else
  1140. alignment = alignmentList->ElementAt(alignmentList->Length() - 1);
  1141. }
  1142. mUniqueStyleText->mTextAlign = alignment;
  1143. return mUniqueStyleText;
  1144. }
  1145. /* virtual */ void
  1146. nsMathMLmtdInnerFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
  1147. {
  1148. nsBlockFrame::DidSetStyleContext(aOldStyleContext);
  1149. mUniqueStyleText->Destroy(PresContext());
  1150. mUniqueStyleText = new (PresContext()) nsStyleText(*StyleText());
  1151. }