Bumping manifests a=b2g-bump
[gecko.git] / layout / mathml / nsMathMLmtableFrame.cpp
bloba53a81033895dfc52b9dfd5b793c0d5d49b47290
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/. */
6 #include "nsMathMLmtableFrame.h"
7 #include "nsPresContext.h"
8 #include "nsStyleContext.h"
9 #include "nsStyleConsts.h"
10 #include "nsNameSpaceManager.h"
11 #include "nsRenderingContext.h"
12 #include "nsCSSRendering.h"
13 #include "nsMathMLElement.h"
15 #include "nsTArray.h"
16 #include "nsTableFrame.h"
17 #include "celldata.h"
19 #include "RestyleManager.h"
20 #include <algorithm>
22 #include "nsIScriptError.h"
23 #include "nsContentUtils.h"
25 using namespace mozilla;
28 // <mtable> -- table or matrix - implementation
31 static int8_t
32 ParseStyleValue(nsIAtom* aAttribute, const nsAString& aAttributeValue)
34 if (aAttribute == nsGkAtoms::rowalign_) {
35 if (aAttributeValue.EqualsLiteral("top"))
36 return NS_STYLE_VERTICAL_ALIGN_TOP;
37 else if (aAttributeValue.EqualsLiteral("bottom"))
38 return NS_STYLE_VERTICAL_ALIGN_BOTTOM;
39 else if (aAttributeValue.EqualsLiteral("center"))
40 return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
41 else
42 return NS_STYLE_VERTICAL_ALIGN_BASELINE;
43 } else if (aAttribute == nsGkAtoms::columnalign_) {
44 if (aAttributeValue.EqualsLiteral("left"))
45 return NS_STYLE_TEXT_ALIGN_LEFT;
46 else if (aAttributeValue.EqualsLiteral("right"))
47 return NS_STYLE_TEXT_ALIGN_RIGHT;
48 else
49 return NS_STYLE_TEXT_ALIGN_CENTER;
50 } else if (aAttribute == nsGkAtoms::rowlines_ ||
51 aAttribute == nsGkAtoms::columnlines_) {
52 if (aAttributeValue.EqualsLiteral("solid"))
53 return NS_STYLE_BORDER_STYLE_SOLID;
54 else if (aAttributeValue.EqualsLiteral("dashed"))
55 return NS_STYLE_BORDER_STYLE_DASHED;
56 else
57 return NS_STYLE_BORDER_STYLE_NONE;
58 } else {
59 MOZ_CRASH("Unrecognized attribute.");
62 return -1;
65 static nsTArray<int8_t>*
66 ExtractStyleValues(const nsAString& aString, nsIAtom* aAttribute,
67 bool aAllowMultiValues)
69 nsTArray<int8_t>* styleArray = nullptr;
71 const char16_t* start = aString.BeginReading();
72 const char16_t* end = aString.EndReading();
74 int32_t startIndex = 0;
75 int32_t count = 0;
77 while (start < end) {
78 // Skip leading spaces.
79 while ((start < end) && nsCRT::IsAsciiSpace(*start)) {
80 start++;
81 startIndex++;
84 // Look for the end of the string, or another space.
85 while ((start < end) && !nsCRT::IsAsciiSpace(*start)) {
86 start++;
87 count++;
90 // Grab the value found and process it.
91 if (count > 0) {
92 if (!styleArray)
93 styleArray = new nsTArray<int8_t>();
95 // We want to return a null array if an attribute gives multiple values,
96 // but multiple values aren't allowed.
97 if (styleArray->Length() > 1 && !aAllowMultiValues) {
98 delete styleArray;
99 return nullptr;
102 nsDependentSubstring valueString(aString, startIndex, count);
103 int8_t styleValue = ParseStyleValue(aAttribute, valueString);
104 styleArray->AppendElement(styleValue);
106 startIndex += count;
107 count = 0;
110 return styleArray;
113 static nsresult ReportParseError(nsIFrame* aFrame, const char16_t* aAttribute,
114 const char16_t* aValue)
116 nsIContent* content = aFrame->GetContent();
118 const char16_t* params[] =
119 { aValue, aAttribute, content->Tag()->GetUTF16String() };
121 return nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
122 NS_LITERAL_CSTRING("Layout: MathML"),
123 content->OwnerDoc(),
124 nsContentUtils::eMATHML_PROPERTIES,
125 "AttributeParsingError", params, 3);
128 // Each rowalign='top bottom' or columnalign='left right center' (from
129 // <mtable> or <mtr>) is split once into an nsTArray<int8_t> which is
130 // stored in the property table. Row/Cell frames query the property table
131 // to see what values apply to them.
133 static void
134 DestroyStylePropertyList(void* aPropertyValue)
136 delete static_cast<nsTArray<int8_t>*>(aPropertyValue);
139 NS_DECLARE_FRAME_PROPERTY(RowAlignProperty, DestroyStylePropertyList)
140 NS_DECLARE_FRAME_PROPERTY(RowLinesProperty, DestroyStylePropertyList)
141 NS_DECLARE_FRAME_PROPERTY(ColumnAlignProperty, DestroyStylePropertyList)
142 NS_DECLARE_FRAME_PROPERTY(ColumnLinesProperty, DestroyStylePropertyList)
144 static const FramePropertyDescriptor*
145 AttributeToProperty(nsIAtom* aAttribute)
147 if (aAttribute == nsGkAtoms::rowalign_)
148 return RowAlignProperty();
149 if (aAttribute == nsGkAtoms::rowlines_)
150 return RowLinesProperty();
151 if (aAttribute == nsGkAtoms::columnalign_)
152 return ColumnAlignProperty();
153 NS_ASSERTION(aAttribute == nsGkAtoms::columnlines_, "Invalid attribute");
154 return ColumnLinesProperty();
157 /* This method looks for a property that applies to a cell, but it looks
158 * recursively because some cell properties can come from the cell, a row,
159 * a table, etc. This function searches through the heirarchy for a property
160 * and returns its value. The function stops searching after checking a <mtable>
161 * frame.
163 static nsTArray<int8_t>*
164 FindCellProperty(const nsIFrame* aCellFrame,
165 const FramePropertyDescriptor* aFrameProperty)
167 const nsIFrame* currentFrame = aCellFrame;
168 nsTArray<int8_t>* propertyData = nullptr;
170 while (currentFrame) {
171 FrameProperties props = currentFrame->Properties();
172 propertyData = static_cast<nsTArray<int8_t>*>(props.Get(aFrameProperty));
173 bool frameIsTable = (currentFrame->GetType() == nsGkAtoms::tableFrame);
175 if (propertyData || frameIsTable)
176 currentFrame = nullptr; // A null frame pointer exits the loop
177 else
178 currentFrame = currentFrame->GetParent(); // Go to the parent frame
181 return propertyData;
184 static void
185 ApplyBorderToStyle(const nsMathMLmtdFrame* aFrame,
186 nsStyleBorder& aStyleBorder)
188 int32_t rowIndex;
189 int32_t columnIndex;
190 aFrame->GetRowIndex(rowIndex);
191 aFrame->GetColIndex(columnIndex);
193 nscoord borderWidth =
194 aFrame->PresContext()->GetBorderWidthTable()[NS_STYLE_BORDER_WIDTH_THIN];
196 nsTArray<int8_t>* rowLinesList =
197 FindCellProperty(aFrame, RowLinesProperty());
199 nsTArray<int8_t>* columnLinesList =
200 FindCellProperty(aFrame, ColumnLinesProperty());
202 // We don't place a row line on top of the first row
203 if (rowIndex > 0 && rowLinesList) {
204 // If the row number is greater than the number of provided rowline
205 // values, we simply repeat the last value.
206 int32_t listLength = rowLinesList->Length();
207 if (rowIndex < listLength) {
208 aStyleBorder.SetBorderStyle(NS_SIDE_TOP,
209 rowLinesList->ElementAt(rowIndex - 1));
210 } else {
211 aStyleBorder.SetBorderStyle(NS_SIDE_TOP,
212 rowLinesList->ElementAt(listLength - 1));
214 aStyleBorder.SetBorderWidth(NS_SIDE_TOP, borderWidth);
217 // We don't place a column line on the left of the first column.
218 if (columnIndex > 0 && columnLinesList) {
219 // If the column number is greater than the number of provided columline
220 // values, we simply repeat the last value.
221 int32_t listLength = columnLinesList->Length();
222 if (columnIndex < listLength) {
223 aStyleBorder.SetBorderStyle(NS_SIDE_LEFT,
224 columnLinesList->ElementAt(columnIndex - 1));
225 } else {
226 aStyleBorder.SetBorderStyle(NS_SIDE_LEFT,
227 columnLinesList->ElementAt(listLength - 1));
229 aStyleBorder.SetBorderWidth(NS_SIDE_LEFT, borderWidth);
233 static nsMargin
234 ComputeBorderOverflow(nsMathMLmtdFrame* aFrame, nsStyleBorder aStyleBorder)
236 nsMargin overflow;
237 int32_t rowIndex;
238 int32_t columnIndex;
239 nsMathMLmtableFrame* mathMLmtableFrame =
240 static_cast<nsMathMLmtableFrame*>(nsTableFrame::GetTableFrame(aFrame));
241 aFrame->GetCellIndexes(rowIndex, columnIndex);
242 if (!columnIndex) {
243 overflow.left = mathMLmtableFrame->GetCellSpacingX(-1);
244 overflow.right = mathMLmtableFrame->GetCellSpacingX(0) / 2;
245 } else if (columnIndex == mathMLmtableFrame->GetColCount() - 1) {
246 overflow.left = mathMLmtableFrame->GetCellSpacingX(columnIndex - 1) / 2;
247 overflow.right = mathMLmtableFrame->GetCellSpacingX(columnIndex + 1);
248 } else {
249 overflow.left = mathMLmtableFrame->GetCellSpacingX(columnIndex - 1) / 2;
250 overflow.right = mathMLmtableFrame->GetCellSpacingX(columnIndex) / 2;
252 if (!rowIndex) {
253 overflow.top = mathMLmtableFrame->GetCellSpacingY(-1);
254 overflow.bottom = mathMLmtableFrame->GetCellSpacingY(0) / 2;
255 } else if (rowIndex == mathMLmtableFrame->GetRowCount() - 1) {
256 overflow.top = mathMLmtableFrame->GetCellSpacingY(rowIndex - 1) / 2;
257 overflow.bottom = mathMLmtableFrame->GetCellSpacingY(rowIndex + 1);
258 } else {
259 overflow.top = mathMLmtableFrame->GetCellSpacingY(rowIndex - 1) / 2;
260 overflow.bottom = mathMLmtableFrame->GetCellSpacingY(rowIndex) / 2;
262 return overflow;
266 * A variant of the nsDisplayBorder contains special code to render a border
267 * around a nsMathMLmtdFrame based on the rowline and columnline properties
268 * set on the cell frame.
270 class nsDisplaymtdBorder : public nsDisplayBorder {
271 public:
272 nsDisplaymtdBorder(nsDisplayListBuilder* aBuilder, nsMathMLmtdFrame* aFrame)
273 : nsDisplayBorder(aBuilder, aFrame)
277 virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE
279 nsStyleBorder styleBorder = *mFrame->StyleBorder();
280 nsMathMLmtdFrame* frame = static_cast<nsMathMLmtdFrame*>(mFrame);
281 ApplyBorderToStyle(frame, styleBorder);
282 nsRect bounds = CalculateBounds(styleBorder);
283 nsMargin overflow = ComputeBorderOverflow(frame, styleBorder);
284 bounds.Inflate(overflow);
285 return bounds;
288 virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE
290 nsStyleBorder styleBorder = *mFrame->StyleBorder();
291 nsMathMLmtdFrame* frame = static_cast<nsMathMLmtdFrame*>(mFrame);
292 ApplyBorderToStyle(frame, styleBorder);
294 nsRect bounds = nsRect(ToReferenceFrame(), mFrame->GetSize());
295 nsMargin overflow = ComputeBorderOverflow(frame, styleBorder);
296 bounds.Inflate(overflow);
298 nsCSSRendering::PaintBorderWithStyleBorder(mFrame->PresContext(), *aCtx,
299 mFrame, mVisibleRect,
300 bounds,
301 styleBorder,
302 mFrame->StyleContext(),
303 mFrame->GetSkipSides());
307 #ifdef DEBUG
308 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) \
309 NS_ASSERTION(NS_STYLE_DISPLAY_##_expected == _frame->StyleDisplay()->mDisplay, "internal error");
310 #else
311 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)
312 #endif
314 static void
315 ParseFrameAttribute(nsIFrame* aFrame, nsIAtom* aAttribute,
316 bool aAllowMultiValues)
318 nsAutoString attrValue;
320 nsIContent* frameContent = aFrame->GetContent();
321 frameContent->GetAttr(kNameSpaceID_None, aAttribute, attrValue);
323 if (!attrValue.IsEmpty()) {
324 nsTArray<int8_t>* valueList =
325 ExtractStyleValues(attrValue, aAttribute, aAllowMultiValues);
327 // If valueList is null, that indicates a problem with the attribute value.
328 // Only set properties on a valid attribute value.
329 if (valueList) {
330 // The code reading the property assumes that this list is nonempty.
331 NS_ASSERTION(valueList->Length() >= 1, "valueList should not be empty!");
332 FrameProperties props = aFrame->Properties();
333 props.Set(AttributeToProperty(aAttribute), valueList);
334 } else {
335 ReportParseError(aFrame, aAttribute->GetUTF16String(), attrValue.get());
340 // rowspacing
342 // Specifies the distance between successive rows in an mtable. Multiple
343 // lengths can be specified, each corresponding to its respective position
344 // between rows. For example:
346 // [ROW_0]
347 // rowspace_0
348 // [ROW_1]
349 // rowspace_1
350 // [ROW_2]
352 // If the number of row gaps exceeds the number of lengths specified, the final
353 // specified length is repeated. Additional lengths are ignored.
355 // values: (length)+
356 // default: 1.0ex
358 // Unitless values are permitted and provide a multiple of the default value
359 // Negative values are forbidden.
362 // columnspacing
364 // Specifies the distance between successive columns in an mtable. Multiple
365 // lengths can be specified, each corresponding to its respective position
366 // between columns. For example:
368 // [COLUMN_0] columnspace_0 [COLUMN_1] columnspace_1 [COLUMN_2]
370 // If the number of column gaps exceeds the number of lengths specified, the
371 // final specified length is repeated. Additional lengths are ignored.
373 // values: (length)+
374 // default: 0.8em
376 // Unitless values are permitted and provide a multiple of the default value
377 // Negative values are forbidden.
380 // framespacing
382 // Specifies the distance between the mtable and its frame (if any). The
383 // first value specified provides the spacing between the left and right edge
384 // of the table and the frame, the second value determines the spacing between
385 // the top and bottom edges and the frame.
387 // An error is reported if only one length is passed. Any additional lengths
388 // are ignored
390 // values: length length
391 // default: 0em 0ex If frame attribute is "none" or not specified,
392 // 0.4em 0.5ex otherwise
394 // Unitless values are permitted and provide a multiple of the default value
395 // Negative values are forbidden.
398 static const float kDefaultRowspacingEx = 1.0f;
399 static const float kDefaultColumnspacingEm = 0.8f;
400 static const float kDefaultFramespacingArg0Em = 0.4f;
401 static const float kDefaultFramespacingArg1Ex = 0.5f;
403 static void
404 ExtractSpacingValues(const nsAString& aString,
405 nsIAtom* aAttribute,
406 nsTArray<nscoord>& aSpacingArray,
407 nsIFrame* aFrame,
408 nscoord aDefaultValue0,
409 nscoord aDefaultValue1)
411 nsPresContext* presContext = aFrame->PresContext();
412 nsStyleContext* styleContext = aFrame->StyleContext();
414 const char16_t* start = aString.BeginReading();
415 const char16_t* end = aString.EndReading();
417 int32_t startIndex = 0;
418 int32_t count = 0;
419 int32_t elementNum = 0;
421 while (start < end) {
422 // Skip leading spaces.
423 while ((start < end) && nsCRT::IsAsciiSpace(*start)) {
424 start++;
425 startIndex++;
428 // Look for the end of the string, or another space.
429 while ((start < end) && !nsCRT::IsAsciiSpace(*start)) {
430 start++;
431 count++;
434 // Grab the value found and process it.
435 if (count > 0) {
436 const nsAString& str = Substring(aString, startIndex, count);
437 nsAutoString valueString;
438 valueString.Assign(str);
439 nscoord newValue;
440 if (aAttribute == nsGkAtoms::framespacing_ && elementNum) {
441 newValue = aDefaultValue1;
442 } else {
443 newValue = aDefaultValue0;
445 nsMathMLFrame::ParseNumericValue(valueString, &newValue,
446 nsMathMLElement::PARSE_ALLOW_UNITLESS,
447 presContext, styleContext);
448 aSpacingArray.AppendElement(newValue);
450 startIndex += count;
451 count = 0;
452 elementNum++;
457 static void
458 ParseSpacingAttribute(nsMathMLmtableFrame* aFrame, nsIAtom* aAttribute)
460 NS_ASSERTION(aAttribute == nsGkAtoms::rowspacing_ ||
461 aAttribute == nsGkAtoms::columnspacing_ ||
462 aAttribute == nsGkAtoms::framespacing_,
463 "Non spacing attribute passed");
465 nsAutoString attrValue;
466 nsIContent* frameContent = aFrame->GetContent();
467 frameContent->GetAttr(kNameSpaceID_None, aAttribute, attrValue);
469 if (nsGkAtoms::framespacing_ == aAttribute) {
470 nsAutoString frame;
471 frameContent->GetAttr(kNameSpaceID_None, nsGkAtoms::frame, frame);
472 if (frame.IsEmpty() || frame.EqualsLiteral("none")) {
473 aFrame->SetFrameSpacing(0, 0);
474 return;
478 nscoord value;
479 nscoord value2;
480 // Set defaults
481 nsRefPtr<nsFontMetrics> fm;
482 nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
483 if (nsGkAtoms::rowspacing_ == aAttribute) {
484 value = kDefaultRowspacingEx * fm->XHeight();
485 value2 = 0;
486 } else if (nsGkAtoms::columnspacing_ == aAttribute) {
487 value = kDefaultColumnspacingEm * fm->EmHeight();
488 value2 = 0;
489 } else {
490 value = kDefaultFramespacingArg0Em * fm->EmHeight();
491 value2 = kDefaultFramespacingArg1Ex * fm->XHeight();
494 nsTArray<nscoord> valueList;
495 ExtractSpacingValues(attrValue, aAttribute, valueList, aFrame, value, value2);
496 if (valueList.Length() == 0) {
497 if (frameContent->HasAttr(kNameSpaceID_None, aAttribute)) {
498 ReportParseError(aFrame, aAttribute->GetUTF16String(),
499 attrValue.get());
501 valueList.AppendElement(value);
503 if (aAttribute == nsGkAtoms::framespacing_) {
504 if (valueList.Length() == 1) {
505 if(frameContent->HasAttr(kNameSpaceID_None, aAttribute)) {
506 ReportParseError(aFrame, aAttribute->GetUTF16String(),
507 attrValue.get());
509 valueList.AppendElement(value2);
510 } else if (valueList.Length() != 2) {
511 ReportParseError(aFrame, aAttribute->GetUTF16String(),
512 attrValue.get());
516 if (aAttribute == nsGkAtoms::rowspacing_) {
517 aFrame->SetRowSpacingArray(valueList);
518 } else if (aAttribute == nsGkAtoms::columnspacing_) {
519 aFrame->SetColSpacingArray(valueList);
520 } else {
521 aFrame->SetFrameSpacing(valueList.ElementAt(0),
522 valueList.ElementAt(1));
526 static void ParseSpacingAttributes(nsMathMLmtableFrame* aTableFrame)
528 ParseSpacingAttribute(aTableFrame, nsGkAtoms::rowspacing_);
529 ParseSpacingAttribute(aTableFrame, nsGkAtoms::columnspacing_);
530 ParseSpacingAttribute(aTableFrame, nsGkAtoms::framespacing_);
531 aTableFrame->SetUseCSSSpacing();
534 // map all attribues within a table -- requires the indices of rows and cells.
535 // so it can only happen after they are made ready by the table base class.
536 static void
537 MapAllAttributesIntoCSS(nsMathMLmtableFrame* aTableFrame)
539 // Map mtable rowalign & rowlines.
540 ParseFrameAttribute(aTableFrame, nsGkAtoms::rowalign_, true);
541 ParseFrameAttribute(aTableFrame, nsGkAtoms::rowlines_, true);
543 // Map mtable columnalign & columnlines.
544 ParseFrameAttribute(aTableFrame, nsGkAtoms::columnalign_, true);
545 ParseFrameAttribute(aTableFrame, nsGkAtoms::columnlines_, true);
547 // Map mtable rowspacing, columnspacing & framespacing
548 ParseSpacingAttributes(aTableFrame);
550 // mtable is simple and only has one (pseudo) row-group
551 nsIFrame* rgFrame = aTableFrame->GetFirstPrincipalChild();
552 if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
553 return;
555 nsIFrame* rowFrame = rgFrame->GetFirstPrincipalChild();
556 for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
557 DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW);
558 if (rowFrame->GetType() == nsGkAtoms::tableRowFrame) {
559 // Map row rowalign.
560 ParseFrameAttribute(rowFrame, nsGkAtoms::rowalign_, false);
561 // Map row columnalign.
562 ParseFrameAttribute(rowFrame, nsGkAtoms::columnalign_, true);
564 nsIFrame* cellFrame = rowFrame->GetFirstPrincipalChild();
565 for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) {
566 DEBUG_VERIFY_THAT_FRAME_IS(cellFrame, TABLE_CELL);
567 if (IS_TABLE_CELL(cellFrame->GetType())) {
568 // Map cell rowalign.
569 ParseFrameAttribute(cellFrame, nsGkAtoms::rowalign_, false);
570 // Map row columnalign.
571 ParseFrameAttribute(cellFrame, nsGkAtoms::columnalign_, false);
578 // the align attribute of mtable can have a row number which indicates
579 // from where to anchor the table, e.g., top 5 means anchor the table at
580 // the top of the 5th row, axis -1 means anchor the table on the axis of
581 // the last row
583 // The REC says that the syntax is
584 // '\s*(top|bottom|center|baseline|axis)(\s+-?[0-9]+)?\s*'
585 // the parsing could have been simpler with that syntax
586 // but for backward compatibility we make optional
587 // the whitespaces between the alignment name and the row number
589 enum eAlign {
590 eAlign_top,
591 eAlign_bottom,
592 eAlign_center,
593 eAlign_baseline,
594 eAlign_axis
597 static void
598 ParseAlignAttribute(nsString& aValue, eAlign& aAlign, int32_t& aRowIndex)
600 // by default, the table is centered about the axis
601 aRowIndex = 0;
602 aAlign = eAlign_axis;
603 int32_t len = 0;
605 // we only have to remove the leading spaces because
606 // ToInteger ignores the whitespaces around the number
607 aValue.CompressWhitespace(true, false);
609 if (0 == aValue.Find("top")) {
610 len = 3; // 3 is the length of 'top'
611 aAlign = eAlign_top;
613 else if (0 == aValue.Find("bottom")) {
614 len = 6; // 6 is the length of 'bottom'
615 aAlign = eAlign_bottom;
617 else if (0 == aValue.Find("center")) {
618 len = 6; // 6 is the length of 'center'
619 aAlign = eAlign_center;
621 else if (0 == aValue.Find("baseline")) {
622 len = 8; // 8 is the length of 'baseline'
623 aAlign = eAlign_baseline;
625 else if (0 == aValue.Find("axis")) {
626 len = 4; // 4 is the length of 'axis'
627 aAlign = eAlign_axis;
629 if (len) {
630 nsresult error;
631 aValue.Cut(0, len); // aValue is not a const here
632 aRowIndex = aValue.ToInteger(&error);
633 if (NS_FAILED(error))
634 aRowIndex = 0;
638 #ifdef DEBUG_rbs_off
639 // call ListMathMLTree(mParent) to get the big picture
640 static void
641 ListMathMLTree(nsIFrame* atLeast)
643 // climb up to <math> or <body> if <math> isn't there
644 nsIFrame* f = atLeast;
645 for ( ; f; f = f->GetParent()) {
646 nsIContent* c = f->GetContent();
647 if (!c || c->Tag() == nsGkAtoms::math || c->Tag() == nsGkAtoms::body)
648 break;
650 if (!f) f = atLeast;
651 f->List(stdout, 0);
653 #endif
655 // --------
656 // implementation of nsMathMLmtableOuterFrame
658 NS_QUERYFRAME_HEAD(nsMathMLmtableOuterFrame)
659 NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
660 NS_QUERYFRAME_TAIL_INHERITING(nsTableOuterFrame)
662 nsContainerFrame*
663 NS_NewMathMLmtableOuterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
665 return new (aPresShell) nsMathMLmtableOuterFrame(aContext);
668 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableOuterFrame)
670 nsMathMLmtableOuterFrame::~nsMathMLmtableOuterFrame()
674 nsresult
675 nsMathMLmtableOuterFrame::AttributeChanged(int32_t aNameSpaceID,
676 nsIAtom* aAttribute,
677 int32_t aModType)
679 // Attributes specific to <mtable>:
680 // frame : in mathml.css
681 // framespacing : here
682 // groupalign : not yet supported
683 // equalrows : not yet supported
684 // equalcolumns : not yet supported
685 // displaystyle : here and in mathml.css
686 // align : in reflow
687 // rowalign : here
688 // rowlines : here
689 // rowspacing : here
690 // columnalign : here
691 // columnlines : here
692 // columnspacing : here
694 // mtable is simple and only has one (pseudo) row-group inside our inner-table
695 nsIFrame* tableFrame = mFrames.FirstChild();
696 NS_ASSERTION(tableFrame && tableFrame->GetType() == nsGkAtoms::tableFrame,
697 "should always have an inner table frame");
698 nsIFrame* rgFrame = tableFrame->GetFirstPrincipalChild();
699 if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
700 return NS_OK;
702 // align - just need to issue a dirty (resize) reflow command
703 if (aAttribute == nsGkAtoms::align) {
704 PresContext()->PresShell()->
705 FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
706 return NS_OK;
709 // displaystyle - may seem innocuous, but it is actually very harsh --
710 // like changing an unit. Blow away and recompute all our automatic
711 // presentational data, and issue a style-changed reflow request
712 if (aAttribute == nsGkAtoms::displaystyle_) {
713 nsMathMLContainerFrame::RebuildAutomaticDataForChildren(GetParent());
714 // Need to reflow the parent, not us, because this can actually
715 // affect siblings.
716 PresContext()->PresShell()->
717 FrameNeedsReflow(GetParent(), nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
718 return NS_OK;
721 // ...and the other attributes affect rows or columns in one way or another
723 nsPresContext* presContext = tableFrame->PresContext();
724 if (aAttribute == nsGkAtoms::rowspacing_ ||
725 aAttribute == nsGkAtoms::columnspacing_ ||
726 aAttribute == nsGkAtoms::framespacing_ ) {
727 nsMathMLmtableFrame* mathMLmtableFrame = do_QueryFrame(tableFrame);
728 if (mathMLmtableFrame) {
729 ParseSpacingAttribute(mathMLmtableFrame, aAttribute);
730 mathMLmtableFrame->SetUseCSSSpacing();
732 } else if (aAttribute == nsGkAtoms::rowalign_ ||
733 aAttribute == nsGkAtoms::rowlines_ ||
734 aAttribute == nsGkAtoms::columnalign_ ||
735 aAttribute == nsGkAtoms::columnlines_) {
736 // clear any cached property list for this table
737 presContext->PropertyTable()->
738 Delete(tableFrame, AttributeToProperty(aAttribute));
739 // Reparse the new attribute on the table.
740 ParseFrameAttribute(tableFrame, aAttribute, true);
741 } else {
742 // Ignore attributes that do not affect layout.
743 return NS_OK;
746 // Explicitly request a reflow in our subtree to pick up any changes
747 presContext->PresShell()->
748 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
750 return NS_OK;
753 nsIFrame*
754 nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext,
755 int32_t aRowIndex)
757 int32_t rowCount = GetRowCount();
759 // Negative indices mean to find upwards from the end.
760 if (aRowIndex < 0) {
761 aRowIndex = rowCount + aRowIndex;
762 } else {
763 // aRowIndex is 1-based, so convert it to a 0-based index
764 --aRowIndex;
767 // if our inner table says that the index is valid, find the row now
768 if (0 <= aRowIndex && aRowIndex <= rowCount) {
769 nsIFrame* tableFrame = mFrames.FirstChild();
770 NS_ASSERTION(tableFrame && tableFrame->GetType() == nsGkAtoms::tableFrame,
771 "should always have an inner table frame");
772 nsIFrame* rgFrame = tableFrame->GetFirstPrincipalChild();
773 if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
774 return nullptr;
775 nsTableIterator rowIter(*rgFrame);
776 nsIFrame* rowFrame = rowIter.First();
777 for ( ; rowFrame; rowFrame = rowIter.Next()) {
778 if (aRowIndex == 0) {
779 DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW);
780 if (rowFrame->GetType() != nsGkAtoms::tableRowFrame)
781 return nullptr;
783 return rowFrame;
785 --aRowIndex;
788 return nullptr;
791 void
792 nsMathMLmtableOuterFrame::Reflow(nsPresContext* aPresContext,
793 nsHTMLReflowMetrics& aDesiredSize,
794 const nsHTMLReflowState& aReflowState,
795 nsReflowStatus& aStatus)
797 nsAutoString value;
798 // we want to return a table that is anchored according to the align attribute
800 nsTableOuterFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
801 NS_ASSERTION(aDesiredSize.Height() >= 0, "illegal height for mtable");
802 NS_ASSERTION(aDesiredSize.Width() >= 0, "illegal width for mtable");
804 // see if the user has set the align attribute on the <mtable>
805 int32_t rowIndex = 0;
806 eAlign tableAlign = eAlign_axis;
807 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::align, value);
808 if (!value.IsEmpty()) {
809 ParseAlignAttribute(value, tableAlign, rowIndex);
812 // adjustments if there is a specified row from where to anchor the table
813 // (conceptually: when there is no row of reference, picture the table as if
814 // it is wrapped in a single big fictional row at dy = 0, this way of
815 // doing so allows us to have a single code path for all cases).
816 nscoord dy = 0;
817 WritingMode wm = aDesiredSize.GetWritingMode();
818 nscoord blockSize = aDesiredSize.BSize(wm);
819 nsIFrame* rowFrame = nullptr;
820 if (rowIndex) {
821 rowFrame = GetRowFrameAt(aPresContext, rowIndex);
822 if (rowFrame) {
823 // translate the coordinates to be relative to us and in our writing mode
824 nsIFrame* frame = rowFrame;
825 LogicalRect frameRect(wm, frame->GetRect(), aReflowState.ComputedWidth());
826 blockSize = frameRect.BSize(wm);
827 do {
828 dy += frameRect.BStart(wm);
829 frame = frame->GetParent();
830 } while (frame != this);
833 switch (tableAlign) {
834 case eAlign_top:
835 aDesiredSize.SetBlockStartAscent(dy);
836 break;
837 case eAlign_bottom:
838 aDesiredSize.SetBlockStartAscent(dy + blockSize);
839 break;
840 case eAlign_center:
841 aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
842 break;
843 case eAlign_baseline:
844 if (rowFrame) {
845 // anchor the table on the baseline of the row of reference
846 nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
847 if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
848 aDesiredSize.SetBlockStartAscent(dy + rowAscent);
849 break;
852 // in other situations, fallback to center
853 aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
854 break;
855 case eAlign_axis:
856 default: {
857 // XXX should instead use style data from the row of reference here ?
858 nsRefPtr<nsFontMetrics> fm;
859 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
860 aReflowState.rendContext->SetFont(fm);
861 nscoord axisHeight;
862 GetAxisHeight(*aReflowState.rendContext,
863 aReflowState.rendContext->FontMetrics(),
864 axisHeight);
865 if (rowFrame) {
866 // anchor the table on the axis of the row of reference
867 // XXX fallback to baseline because it is a hard problem
868 // XXX need to fetch the axis of the row; would need rowalign=axis to work better
869 nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
870 if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
871 aDesiredSize.SetBlockStartAscent(dy + rowAscent);
872 break;
875 // in other situations, fallback to using half of the height
876 aDesiredSize.SetBlockStartAscent(dy + blockSize / 2 + axisHeight);
880 mReference.x = 0;
881 mReference.y = aDesiredSize.BlockStartAscent();
883 // just make-up a bounding metrics
884 mBoundingMetrics = nsBoundingMetrics();
885 mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent();
886 mBoundingMetrics.descent = aDesiredSize.Height() -
887 aDesiredSize.BlockStartAscent();
888 mBoundingMetrics.width = aDesiredSize.Width();
889 mBoundingMetrics.leftBearing = 0;
890 mBoundingMetrics.rightBearing = aDesiredSize.Width();
892 aDesiredSize.mBoundingMetrics = mBoundingMetrics;
893 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
896 nsContainerFrame*
897 NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
899 return new (aPresShell) nsMathMLmtableFrame(aContext);
902 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableFrame)
904 nsMathMLmtableFrame::~nsMathMLmtableFrame()
908 void
909 nsMathMLmtableFrame::SetInitialChildList(ChildListID aListID,
910 nsFrameList& aChildList)
912 nsTableFrame::SetInitialChildList(aListID, aChildList);
913 MapAllAttributesIntoCSS(this);
916 void
917 nsMathMLmtableFrame::RestyleTable()
919 // re-sync MathML specific style data that may have changed
920 MapAllAttributesIntoCSS(this);
922 // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
923 PresContext()->RestyleManager()->
924 PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
925 nsChangeHint_AllReflowHints);
928 nscoord
929 nsMathMLmtableFrame::GetCellSpacingX(int32_t aColIndex)
931 if (mUseCSSSpacing) {
932 return nsTableFrame::GetCellSpacingX(aColIndex);
934 if (!mColSpacing.Length()) {
935 NS_ERROR("mColSpacing should not be empty");
936 return 0;
938 if (aColIndex < 0 || aColIndex >= GetColCount()) {
939 NS_ASSERTION(aColIndex == -1 || aColIndex == GetColCount(),
940 "Desired column beyond bounds of table and border");
941 return mFrameSpacingX;
943 if ((uint32_t) aColIndex >= mColSpacing.Length()) {
944 return mColSpacing.LastElement();
946 return mColSpacing.ElementAt(aColIndex);
949 nscoord
950 nsMathMLmtableFrame::GetCellSpacingX(int32_t aStartColIndex,
951 int32_t aEndColIndex)
953 if (mUseCSSSpacing) {
954 return nsTableFrame::GetCellSpacingX(aStartColIndex, aEndColIndex);
956 if (aStartColIndex == aEndColIndex) {
957 return 0;
959 if (!mColSpacing.Length()) {
960 NS_ERROR("mColSpacing should not be empty");
961 return 0;
963 nscoord space = 0;
964 if (aStartColIndex < 0) {
965 NS_ASSERTION(aStartColIndex == -1,
966 "Desired column beyond bounds of table and border");
967 space += mFrameSpacingX;
968 aStartColIndex = 0;
970 if (aEndColIndex >= GetColCount()) {
971 NS_ASSERTION(aEndColIndex == GetColCount(),
972 "Desired column beyond bounds of table and border");
973 space += mFrameSpacingX;
974 aEndColIndex = GetColCount();
976 // Only iterate over column spacing when there is the potential to vary
977 int32_t min = std::min(aEndColIndex, (int32_t) mColSpacing.Length());
978 for (int32_t i = aStartColIndex; i < min; i++) {
979 space += mColSpacing.ElementAt(i);
981 // The remaining values are constant. Note that if there are more
982 // column spacings specified than there are columns, LastElement() will be
983 // multiplied by 0, so it is still safe to use.
984 space += (aEndColIndex - min) * mColSpacing.LastElement();
985 return space;
988 nscoord
989 nsMathMLmtableFrame::GetCellSpacingY(int32_t aRowIndex)
991 if (mUseCSSSpacing) {
992 return nsTableFrame::GetCellSpacingY(aRowIndex);
994 if (!mRowSpacing.Length()) {
995 NS_ERROR("mRowSpacing should not be empty");
996 return 0;
998 if (aRowIndex < 0 || aRowIndex >= GetRowCount()) {
999 NS_ASSERTION(aRowIndex == -1 || aRowIndex == GetRowCount(),
1000 "Desired row beyond bounds of table and border");
1001 return mFrameSpacingY;
1003 if ((uint32_t) aRowIndex >= mRowSpacing.Length()) {
1004 return mRowSpacing.LastElement();
1006 return mRowSpacing.ElementAt(aRowIndex);
1009 nscoord
1010 nsMathMLmtableFrame::GetCellSpacingY(int32_t aStartRowIndex,
1011 int32_t aEndRowIndex)
1013 if (mUseCSSSpacing) {
1014 return nsTableFrame::GetCellSpacingY(aStartRowIndex, aEndRowIndex);
1016 if (aStartRowIndex == aEndRowIndex) {
1017 return 0;
1019 if (!mRowSpacing.Length()) {
1020 NS_ERROR("mRowSpacing should not be empty");
1021 return 0;
1023 nscoord space = 0;
1024 if (aStartRowIndex < 0) {
1025 NS_ASSERTION(aStartRowIndex == -1,
1026 "Desired row beyond bounds of table and border");
1027 space += mFrameSpacingY;
1028 aStartRowIndex = 0;
1030 if (aEndRowIndex >= GetRowCount()) {
1031 NS_ASSERTION(aEndRowIndex == GetRowCount(),
1032 "Desired row beyond bounds of table and border");
1033 space += mFrameSpacingY;
1034 aEndRowIndex = GetRowCount();
1036 // Only iterate over row spacing when there is the potential to vary
1037 int32_t min = std::min(aEndRowIndex, (int32_t) mRowSpacing.Length());
1038 for (int32_t i = aStartRowIndex; i < min; i++) {
1039 space += mRowSpacing.ElementAt(i);
1041 // The remaining values are constant. Note that if there are more
1042 // row spacings specified than there are row, LastElement() will be
1043 // multiplied by 0, so it is still safe to use.
1044 space += (aEndRowIndex - min) * mRowSpacing.LastElement();
1045 return space;
1048 void
1049 nsMathMLmtableFrame::SetUseCSSSpacing()
1051 mUseCSSSpacing =
1052 !(mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::rowspacing_) ||
1053 mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::columnspacing_) ||
1054 mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::framespacing_));
1057 NS_QUERYFRAME_HEAD(nsMathMLmtableFrame)
1058 NS_QUERYFRAME_ENTRY(nsMathMLmtableFrame)
1059 NS_QUERYFRAME_TAIL_INHERITING(nsTableFrame)
1061 // --------
1062 // implementation of nsMathMLmtrFrame
1064 nsContainerFrame*
1065 NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
1067 return new (aPresShell) nsMathMLmtrFrame(aContext);
1070 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtrFrame)
1072 nsMathMLmtrFrame::~nsMathMLmtrFrame()
1076 nsresult
1077 nsMathMLmtrFrame::AttributeChanged(int32_t aNameSpaceID,
1078 nsIAtom* aAttribute,
1079 int32_t aModType)
1081 // Attributes specific to <mtr>:
1082 // groupalign : Not yet supported.
1083 // rowalign : Here
1084 // columnalign : Here
1086 nsPresContext* presContext = PresContext();
1088 if (aAttribute != nsGkAtoms::rowalign_ &&
1089 aAttribute != nsGkAtoms::columnalign_) {
1090 return NS_OK;
1093 presContext->PropertyTable()->Delete(this, AttributeToProperty(aAttribute));
1095 bool allowMultiValues = (aAttribute == nsGkAtoms::columnalign_);
1097 // Reparse the new attribute.
1098 ParseFrameAttribute(this, aAttribute, allowMultiValues);
1100 // Explicitly request a reflow in our subtree to pick up any changes
1101 presContext->PresShell()->
1102 FrameNeedsReflow(this, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
1104 return NS_OK;
1107 // --------
1108 // implementation of nsMathMLmtdFrame
1110 nsContainerFrame*
1111 NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
1113 return new (aPresShell) nsMathMLmtdFrame(aContext);
1116 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdFrame)
1118 nsMathMLmtdFrame::~nsMathMLmtdFrame()
1122 int32_t
1123 nsMathMLmtdFrame::GetRowSpan()
1125 int32_t rowspan = 1;
1127 // Don't look at the content's rowspan if we're not an mtd or a pseudo cell.
1128 if ((mContent->Tag() == nsGkAtoms::mtd_) && !StyleContext()->GetPseudo()) {
1129 nsAutoString value;
1130 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rowspan, value);
1131 if (!value.IsEmpty()) {
1132 nsresult error;
1133 rowspan = value.ToInteger(&error);
1134 if (NS_FAILED(error) || rowspan < 0)
1135 rowspan = 1;
1136 rowspan = std::min(rowspan, MAX_ROWSPAN);
1139 return rowspan;
1142 int32_t
1143 nsMathMLmtdFrame::GetColSpan()
1145 int32_t colspan = 1;
1147 // Don't look at the content's colspan if we're not an mtd or a pseudo cell.
1148 if ((mContent->Tag() == nsGkAtoms::mtd_) && !StyleContext()->GetPseudo()) {
1149 nsAutoString value;
1150 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::columnspan_, value);
1151 if (!value.IsEmpty()) {
1152 nsresult error;
1153 colspan = value.ToInteger(&error);
1154 if (NS_FAILED(error) || colspan < 0 || colspan > MAX_COLSPAN)
1155 colspan = 1;
1158 return colspan;
1161 nsresult
1162 nsMathMLmtdFrame::AttributeChanged(int32_t aNameSpaceID,
1163 nsIAtom* aAttribute,
1164 int32_t aModType)
1166 // Attributes specific to <mtd>:
1167 // groupalign : Not yet supported
1168 // rowalign : here
1169 // columnalign : here
1170 // rowspan : here
1171 // columnspan : here
1173 if (aAttribute == nsGkAtoms::rowalign_ ||
1174 aAttribute == nsGkAtoms::columnalign_) {
1176 nsPresContext* presContext = PresContext();
1177 presContext->PropertyTable()->Delete(this, AttributeToProperty(aAttribute));
1179 // Reparse the attribute.
1180 ParseFrameAttribute(this, aAttribute, false);
1181 return NS_OK;
1184 if (aAttribute == nsGkAtoms::rowspan ||
1185 aAttribute == nsGkAtoms::columnspan_) {
1186 // use the naming expected by the base class
1187 if (aAttribute == nsGkAtoms::columnspan_)
1188 aAttribute = nsGkAtoms::colspan;
1189 return nsTableCellFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
1192 return NS_OK;
1195 uint8_t
1196 nsMathMLmtdFrame::GetVerticalAlign() const
1198 // Set the default alignment in case no alignment was specified
1199 uint8_t alignment = nsTableCellFrame::GetVerticalAlign();
1201 nsTArray<int8_t>* alignmentList = FindCellProperty(this, RowAlignProperty());
1203 if (alignmentList) {
1204 int32_t rowIndex;
1205 GetRowIndex(rowIndex);
1207 // If the row number is greater than the number of provided rowalign values,
1208 // we simply repeat the last value.
1209 if (rowIndex < (int32_t)alignmentList->Length())
1210 alignment = alignmentList->ElementAt(rowIndex);
1211 else
1212 alignment = alignmentList->ElementAt(alignmentList->Length() - 1);
1215 return alignment;
1218 nsresult
1219 nsMathMLmtdFrame::ProcessBorders(nsTableFrame* aFrame,
1220 nsDisplayListBuilder* aBuilder,
1221 const nsDisplayListSet& aLists)
1223 aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
1224 nsDisplaymtdBorder(aBuilder, this));
1225 return NS_OK;
1228 nsMargin*
1229 nsMathMLmtdFrame::GetBorderWidth(nsMargin& aBorder) const
1231 nsStyleBorder styleBorder = *StyleBorder();
1232 ApplyBorderToStyle(this, styleBorder);
1233 aBorder = styleBorder.GetComputedBorder();
1234 return &aBorder;
1237 nsMargin
1238 nsMathMLmtdFrame::GetBorderOverflow()
1240 nsStyleBorder styleBorder = *StyleBorder();
1241 ApplyBorderToStyle(this, styleBorder);
1242 nsMargin overflow = ComputeBorderOverflow(this, styleBorder);
1243 return overflow;
1246 // --------
1247 // implementation of nsMathMLmtdInnerFrame
1249 NS_QUERYFRAME_HEAD(nsMathMLmtdInnerFrame)
1250 NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
1251 NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
1253 nsContainerFrame*
1254 NS_NewMathMLmtdInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
1256 return new (aPresShell) nsMathMLmtdInnerFrame(aContext);
1259 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdInnerFrame)
1261 nsMathMLmtdInnerFrame::nsMathMLmtdInnerFrame(nsStyleContext* aContext)
1262 : nsBlockFrame(aContext)
1264 // Make a copy of the parent nsStyleText for later modificaiton.
1265 mUniqueStyleText = new (PresContext()) nsStyleText(*StyleText());
1268 nsMathMLmtdInnerFrame::~nsMathMLmtdInnerFrame()
1270 mUniqueStyleText->Destroy(PresContext());
1273 void
1274 nsMathMLmtdInnerFrame::Reflow(nsPresContext* aPresContext,
1275 nsHTMLReflowMetrics& aDesiredSize,
1276 const nsHTMLReflowState& aReflowState,
1277 nsReflowStatus& aStatus)
1279 // Let the base class do the reflow
1280 nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
1282 // more about <maligngroup/> and <malignmark/> later
1283 // ...
1286 const
1287 nsStyleText* nsMathMLmtdInnerFrame::StyleTextForLineLayout()
1289 // Set the default alignment in case nothing was specified
1290 uint8_t alignment = StyleText()->mTextAlign;
1292 nsTArray<int8_t>* alignmentList =
1293 FindCellProperty(this, ColumnAlignProperty());
1295 if (alignmentList) {
1296 nsMathMLmtdFrame* cellFrame = (nsMathMLmtdFrame*)GetParent();
1297 int32_t columnIndex;
1298 cellFrame->GetColIndex(columnIndex);
1300 // If the column number is greater than the number of provided columalign
1301 // values, we simply repeat the last value.
1302 if (columnIndex < (int32_t)alignmentList->Length())
1303 alignment = alignmentList->ElementAt(columnIndex);
1304 else
1305 alignment = alignmentList->ElementAt(alignmentList->Length() - 1);
1308 mUniqueStyleText->mTextAlign = alignment;
1309 return mUniqueStyleText;
1312 /* virtual */ void
1313 nsMathMLmtdInnerFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
1315 nsBlockFrame::DidSetStyleContext(aOldStyleContext);
1316 mUniqueStyleText->Destroy(PresContext());
1317 mUniqueStyleText = new (PresContext()) nsStyleText(*StyleText());