Backed out 2 changesets (bug 1943998) for causing wd failures @ phases.py CLOSED...
[gecko.git] / layout / mathml / nsMathMLmtableFrame.cpp
blobb1baffff228a0e2183486987ab3e1416ca486981
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "gfxContext.h"
8 #include "nsMathMLmtableFrame.h"
9 #include "nsPresContext.h"
10 #include "nsStyleConsts.h"
11 #include "nsNameSpaceManager.h"
12 #include "nsCSSRendering.h"
13 #include "mozilla/dom/MathMLElement.h"
15 #include "nsCRT.h"
16 #include "nsTArray.h"
17 #include "nsTableFrame.h"
18 #include "celldata.h"
20 #include "mozilla/PresShell.h"
21 #include "mozilla/RestyleManager.h"
22 #include <algorithm>
24 #include "nsIScriptError.h"
25 #include "nsContentUtils.h"
26 #include "nsLayoutUtils.h"
28 using namespace mozilla;
29 using namespace mozilla::image;
30 using mozilla::dom::Element;
33 // <mtable> -- table or matrix - implementation
36 static int8_t ParseStyleValue(nsAtom* aAttribute,
37 const nsAString& aAttributeValue) {
38 if (aAttribute == nsGkAtoms::rowalign_) {
39 if (aAttributeValue.EqualsLiteral("top")) {
40 return static_cast<int8_t>(StyleVerticalAlignKeyword::Top);
42 if (aAttributeValue.EqualsLiteral("bottom")) {
43 return static_cast<int8_t>(StyleVerticalAlignKeyword::Bottom);
45 if (aAttributeValue.EqualsLiteral("center")) {
46 return static_cast<int8_t>(StyleVerticalAlignKeyword::Middle);
48 return static_cast<int8_t>(StyleVerticalAlignKeyword::Baseline);
51 if (aAttribute == nsGkAtoms::columnalign_) {
52 if (aAttributeValue.EqualsLiteral("left")) {
53 return int8_t(StyleTextAlign::Left);
55 if (aAttributeValue.EqualsLiteral("right")) {
56 return int8_t(StyleTextAlign::Right);
58 return int8_t(StyleTextAlign::Center);
61 if (aAttribute == nsGkAtoms::rowlines_ ||
62 aAttribute == nsGkAtoms::columnlines_) {
63 if (aAttributeValue.EqualsLiteral("solid")) {
64 return static_cast<int8_t>(StyleBorderStyle::Solid);
66 if (aAttributeValue.EqualsLiteral("dashed")) {
67 return static_cast<int8_t>(StyleBorderStyle::Dashed);
69 return static_cast<int8_t>(StyleBorderStyle::None);
72 MOZ_CRASH("Unrecognized attribute.");
73 return -1;
76 static nsTArray<int8_t>* ExtractStyleValues(const nsAString& aString,
77 nsAtom* aAttribute,
78 bool aAllowMultiValues) {
79 nsTArray<int8_t>* styleArray = nullptr;
81 const char16_t* start = aString.BeginReading();
82 const char16_t* end = aString.EndReading();
84 int32_t startIndex = 0;
85 int32_t count = 0;
87 while (start < end) {
88 // Skip leading spaces.
89 while ((start < end) && nsCRT::IsAsciiSpace(*start)) {
90 start++;
91 startIndex++;
94 // Look for the end of the string, or another space.
95 while ((start < end) && !nsCRT::IsAsciiSpace(*start)) {
96 start++;
97 count++;
100 // Grab the value found and process it.
101 if (count > 0) {
102 if (!styleArray) {
103 styleArray = new nsTArray<int8_t>();
106 // We want to return a null array if an attribute gives multiple values,
107 // but multiple values aren't allowed.
108 if (styleArray->Length() > 1 && !aAllowMultiValues) {
109 delete styleArray;
110 return nullptr;
113 nsDependentSubstring valueString(aString, startIndex, count);
114 int8_t styleValue = ParseStyleValue(aAttribute, valueString);
115 styleArray->AppendElement(styleValue);
117 startIndex += count;
118 count = 0;
121 return styleArray;
124 static nsresult ReportParseError(nsIFrame* aFrame, const char16_t* aAttribute,
125 const char16_t* aValue) {
126 nsIContent* content = aFrame->GetContent();
128 AutoTArray<nsString, 3> params;
129 params.AppendElement(aValue);
130 params.AppendElement(aAttribute);
131 params.AppendElement(nsDependentAtomString(content->NodeInfo()->NameAtom()));
133 return nsContentUtils::ReportToConsole(
134 nsIScriptError::errorFlag, "Layout: MathML"_ns, content->OwnerDoc(),
135 nsContentUtils::eMATHML_PROPERTIES, "AttributeParsingError", params);
138 // Each rowalign='top bottom' or columnalign='left right center' (from
139 // <mtable> or <mtr>) is split once into an nsTArray<int8_t> which is
140 // stored in the property table. Row/Cell frames query the property table
141 // to see what values apply to them.
143 NS_DECLARE_FRAME_PROPERTY_DELETABLE(RowAlignProperty, nsTArray<int8_t>)
144 NS_DECLARE_FRAME_PROPERTY_DELETABLE(RowLinesProperty, nsTArray<int8_t>)
145 NS_DECLARE_FRAME_PROPERTY_DELETABLE(ColumnAlignProperty, nsTArray<int8_t>)
146 NS_DECLARE_FRAME_PROPERTY_DELETABLE(ColumnLinesProperty, nsTArray<int8_t>)
148 static const FramePropertyDescriptor<nsTArray<int8_t>>* AttributeToProperty(
149 nsAtom* aAttribute) {
150 if (aAttribute == nsGkAtoms::rowalign_) {
151 return RowAlignProperty();
153 if (aAttribute == nsGkAtoms::rowlines_) {
154 return RowLinesProperty();
156 if (aAttribute == nsGkAtoms::columnalign_) {
157 return ColumnAlignProperty();
159 NS_ASSERTION(aAttribute == nsGkAtoms::columnlines_, "Invalid attribute");
160 return ColumnLinesProperty();
163 /* This method looks for a property that applies to a cell, but it looks
164 * recursively because some cell properties can come from the cell, a row,
165 * a table, etc. This function searches through the hierarchy for a property
166 * and returns its value. The function stops searching after checking a <mtable>
167 * frame.
169 static nsTArray<int8_t>* FindCellProperty(
170 const nsIFrame* aCellFrame,
171 const FramePropertyDescriptor<nsTArray<int8_t>>* aFrameProperty) {
172 const nsIFrame* currentFrame = aCellFrame;
173 nsTArray<int8_t>* propertyData = nullptr;
175 while (currentFrame) {
176 propertyData = currentFrame->GetProperty(aFrameProperty);
177 bool frameIsTable = (currentFrame->IsTableFrame());
179 if (propertyData || frameIsTable) {
180 currentFrame = nullptr; // A null frame pointer exits the loop
181 } else {
182 currentFrame = currentFrame->GetParent(); // Go to the parent frame
186 return propertyData;
189 static void ApplyBorderToStyle(const nsMathMLmtdFrame* aFrame,
190 nsStyleBorder& aStyleBorder) {
191 uint32_t rowIndex = aFrame->RowIndex();
192 uint32_t columnIndex = aFrame->ColIndex();
194 nscoord borderWidth = nsPresContext::CSSPixelsToAppUnits(1);
196 nsTArray<int8_t>* rowLinesList = FindCellProperty(aFrame, RowLinesProperty());
198 nsTArray<int8_t>* columnLinesList =
199 FindCellProperty(aFrame, ColumnLinesProperty());
201 const auto a2d = aFrame->PresContext()->AppUnitsPerDevPixel();
203 // We don't place a row line on top of the first row
204 if (rowIndex > 0 && rowLinesList) {
205 // If the row number is greater than the number of provided rowline
206 // values, we simply repeat the last value.
207 uint32_t listLength = rowLinesList->Length();
208 if (rowIndex < listLength) {
209 aStyleBorder.SetBorderStyle(
210 eSideTop,
211 static_cast<StyleBorderStyle>(rowLinesList->ElementAt(rowIndex - 1)));
212 } else {
213 aStyleBorder.SetBorderStyle(eSideTop,
214 static_cast<StyleBorderStyle>(
215 rowLinesList->ElementAt(listLength - 1)));
217 aStyleBorder.SetBorderWidth(eSideTop, borderWidth, a2d);
220 // We don't place a column line on the left of the first column.
221 if (columnIndex > 0 && columnLinesList) {
222 // If the column number is greater than the number of provided columline
223 // values, we simply repeat the last value.
224 uint32_t listLength = columnLinesList->Length();
225 if (columnIndex < listLength) {
226 aStyleBorder.SetBorderStyle(
227 eSideLeft, static_cast<StyleBorderStyle>(
228 columnLinesList->ElementAt(columnIndex - 1)));
229 } else {
230 aStyleBorder.SetBorderStyle(
231 eSideLeft, static_cast<StyleBorderStyle>(
232 columnLinesList->ElementAt(listLength - 1)));
234 aStyleBorder.SetBorderWidth(eSideLeft, borderWidth, a2d);
238 static nsMargin ComputeBorderOverflow(nsMathMLmtdFrame* aFrame,
239 const nsStyleBorder& aStyleBorder) {
240 nsMargin overflow;
241 int32_t rowIndex;
242 int32_t columnIndex;
243 nsTableFrame* table = aFrame->GetTableFrame();
244 aFrame->GetCellIndexes(rowIndex, columnIndex);
245 if (!columnIndex) {
246 overflow.left = table->GetColSpacing(-1);
247 overflow.right = table->GetColSpacing(0) / 2;
248 } else if (columnIndex == table->GetColCount() - 1) {
249 overflow.left = table->GetColSpacing(columnIndex - 1) / 2;
250 overflow.right = table->GetColSpacing(columnIndex + 1);
251 } else {
252 overflow.left = table->GetColSpacing(columnIndex - 1) / 2;
253 overflow.right = table->GetColSpacing(columnIndex) / 2;
255 if (!rowIndex) {
256 overflow.top = table->GetRowSpacing(-1);
257 overflow.bottom = table->GetRowSpacing(0) / 2;
258 } else if (rowIndex == table->GetRowCount() - 1) {
259 overflow.top = table->GetRowSpacing(rowIndex - 1) / 2;
260 overflow.bottom = table->GetRowSpacing(rowIndex + 1);
261 } else {
262 overflow.top = table->GetRowSpacing(rowIndex - 1) / 2;
263 overflow.bottom = table->GetRowSpacing(rowIndex) / 2;
265 return overflow;
269 * A variant of the nsDisplayBorder contains special code to render a border
270 * around a nsMathMLmtdFrame based on the rowline and columnline properties
271 * set on the cell frame.
273 class nsDisplaymtdBorder final : public nsDisplayBorder {
274 public:
275 nsDisplaymtdBorder(nsDisplayListBuilder* aBuilder, nsMathMLmtdFrame* aFrame)
276 : nsDisplayBorder(aBuilder, aFrame) {}
278 nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) const override {
279 *aSnap = true;
280 nsStyleBorder styleBorder = *mFrame->StyleBorder();
281 nsMathMLmtdFrame* frame = static_cast<nsMathMLmtdFrame*>(mFrame);
282 ApplyBorderToStyle(frame, styleBorder);
283 nsRect bounds = CalculateBounds<nsRect>(styleBorder);
284 nsMargin overflow = ComputeBorderOverflow(frame, styleBorder);
285 bounds.Inflate(overflow);
286 return bounds;
289 void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) 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 PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
299 ? PaintBorderFlags::SyncDecodeImages
300 : PaintBorderFlags();
302 Unused << nsCSSRendering::PaintBorderWithStyleBorder(
303 mFrame->PresContext(), *aCtx, mFrame, GetPaintRect(aBuilder, aCtx),
304 bounds, styleBorder, mFrame->Style(), flags, mFrame->GetSkipSides());
307 bool CreateWebRenderCommands(
308 mozilla::wr::DisplayListBuilder& aBuilder,
309 mozilla::wr::IpcResourceUpdateQueue& aResources,
310 const StackingContextHelper& aSc,
311 mozilla::layers::RenderRootStateManager* aManager,
312 nsDisplayListBuilder* aDisplayListBuilder) override {
313 return false;
316 bool IsInvisibleInRect(const nsRect& aRect) const override { return false; }
319 #ifdef DEBUG
320 # define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) \
321 MOZ_ASSERT( \
322 mozilla::StyleDisplay::_expected == _frame->StyleDisplay()->mDisplay, \
323 "internal error");
324 #else
325 # define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)
326 #endif
328 static void ParseFrameAttribute(nsIFrame* aFrame, nsAtom* aAttribute,
329 bool aAllowMultiValues) {
330 nsAutoString attrValue;
332 Element* frameElement = aFrame->GetContent()->AsElement();
333 frameElement->GetAttr(aAttribute, attrValue);
335 if (!attrValue.IsEmpty()) {
336 nsTArray<int8_t>* valueList =
337 ExtractStyleValues(attrValue, aAttribute, aAllowMultiValues);
339 // If valueList is null, that indicates a problem with the attribute value.
340 // Only set properties on a valid attribute value.
341 if (valueList) {
342 // The code reading the property assumes that this list is nonempty.
343 NS_ASSERTION(valueList->Length() >= 1, "valueList should not be empty!");
344 aFrame->SetProperty(AttributeToProperty(aAttribute), valueList);
345 } else {
346 ReportParseError(aFrame, aAttribute->GetUTF16String(), attrValue.get());
351 // rowspacing
353 // Specifies the distance between successive rows in an mtable. Multiple
354 // lengths can be specified, each corresponding to its respective position
355 // between rows. For example:
357 // [ROW_0]
358 // rowspace_0
359 // [ROW_1]
360 // rowspace_1
361 // [ROW_2]
363 // If the number of row gaps exceeds the number of lengths specified, the final
364 // specified length is repeated. Additional lengths are ignored.
366 // values: (length)+
367 // default: 1.0ex
369 // Unitless values are permitted and provide a multiple of the default value
370 // Negative values are forbidden.
373 // columnspacing
375 // Specifies the distance between successive columns in an mtable. Multiple
376 // lengths can be specified, each corresponding to its respective position
377 // between columns. For example:
379 // [COLUMN_0] columnspace_0 [COLUMN_1] columnspace_1 [COLUMN_2]
381 // If the number of column gaps exceeds the number of lengths specified, the
382 // final specified length is repeated. Additional lengths are ignored.
384 // values: (length)+
385 // default: 0.8em
387 // Unitless values are permitted and provide a multiple of the default value
388 // Negative values are forbidden.
391 // framespacing
393 // Specifies the distance between the mtable and its frame (if any). The
394 // first value specified provides the spacing between the left and right edge
395 // of the table and the frame, the second value determines the spacing between
396 // the top and bottom edges and the frame.
398 // An error is reported if only one length is passed. Any additional lengths
399 // are ignored
401 // values: length length
402 // default: 0em 0ex If frame attribute is "none" or not specified,
403 // 0.4em 0.5ex otherwise
405 // Unitless values are permitted and provide a multiple of the default value
406 // Negative values are forbidden.
409 static const float kDefaultRowspacingEx = 1.0f;
410 static const float kDefaultColumnspacingEm = 0.8f;
411 static const float kDefaultFramespacingArg0Em = 0.4f;
412 static const float kDefaultFramespacingArg1Ex = 0.5f;
414 static void ExtractSpacingValues(const nsAString& aString, nsAtom* aAttribute,
415 nsTArray<nscoord>& aSpacingArray,
416 nsIFrame* aFrame, nscoord aDefaultValue0,
417 nscoord aDefaultValue1,
418 float aFontSizeInflation) {
419 nsPresContext* presContext = aFrame->PresContext();
420 ComputedStyle* computedStyle = aFrame->Style();
422 const char16_t* start = aString.BeginReading();
423 const char16_t* end = aString.EndReading();
425 int32_t startIndex = 0;
426 int32_t count = 0;
427 int32_t elementNum = 0;
429 while (start < end) {
430 // Skip leading spaces.
431 while ((start < end) && nsCRT::IsAsciiSpace(*start)) {
432 start++;
433 startIndex++;
436 // Look for the end of the string, or another space.
437 while ((start < end) && !nsCRT::IsAsciiSpace(*start)) {
438 start++;
439 count++;
442 // Grab the value found and process it.
443 if (count > 0) {
444 const nsAString& str = Substring(aString, startIndex, count);
445 nsAutoString valueString;
446 valueString.Assign(str);
447 nscoord newValue;
448 if (aAttribute == nsGkAtoms::framespacing_ && elementNum) {
449 newValue = aDefaultValue1;
450 } else {
451 newValue = aDefaultValue0;
453 nsMathMLFrame::ParseNumericValue(valueString, &newValue, 0, presContext,
454 computedStyle, aFontSizeInflation);
455 aSpacingArray.AppendElement(newValue);
457 startIndex += count;
458 count = 0;
459 elementNum++;
464 static void ParseSpacingAttribute(nsMathMLmtableFrame* aFrame,
465 nsAtom* aAttribute) {
466 NS_ASSERTION(aAttribute == nsGkAtoms::rowspacing_ ||
467 aAttribute == nsGkAtoms::columnspacing_ ||
468 aAttribute == nsGkAtoms::framespacing_,
469 "Non spacing attribute passed");
471 nsAutoString attrValue;
472 Element* frameElement = aFrame->GetContent()->AsElement();
473 frameElement->GetAttr(aAttribute, attrValue);
475 if (nsGkAtoms::framespacing_ == aAttribute) {
476 nsAutoString frame;
477 frameElement->GetAttr(nsGkAtoms::frame, frame);
478 if (frame.IsEmpty() || frame.EqualsLiteral("none")) {
479 aFrame->SetFrameSpacing(0, 0);
480 return;
484 nscoord value;
485 nscoord value2;
486 // Set defaults
487 float fontSizeInflation = nsLayoutUtils::FontSizeInflationFor(aFrame);
488 RefPtr<nsFontMetrics> fm =
489 nsLayoutUtils::GetFontMetricsForFrame(aFrame, fontSizeInflation);
490 if (nsGkAtoms::rowspacing_ == aAttribute) {
491 value = kDefaultRowspacingEx * fm->XHeight();
492 value2 = 0;
493 } else if (nsGkAtoms::columnspacing_ == aAttribute) {
494 value = kDefaultColumnspacingEm * fm->EmHeight();
495 value2 = 0;
496 } else {
497 value = kDefaultFramespacingArg0Em * fm->EmHeight();
498 value2 = kDefaultFramespacingArg1Ex * fm->XHeight();
501 nsTArray<nscoord> valueList;
502 ExtractSpacingValues(attrValue, aAttribute, valueList, aFrame, value, value2,
503 fontSizeInflation);
504 if (valueList.Length() == 0) {
505 if (frameElement->HasAttr(aAttribute)) {
506 ReportParseError(aFrame, aAttribute->GetUTF16String(), attrValue.get());
508 valueList.AppendElement(value);
510 if (aAttribute == nsGkAtoms::framespacing_) {
511 if (valueList.Length() == 1) {
512 if (frameElement->HasAttr(aAttribute)) {
513 ReportParseError(aFrame, aAttribute->GetUTF16String(), attrValue.get());
515 valueList.AppendElement(value2);
516 } else if (valueList.Length() != 2) {
517 ReportParseError(aFrame, aAttribute->GetUTF16String(), attrValue.get());
521 if (aAttribute == nsGkAtoms::rowspacing_) {
522 aFrame->SetRowSpacingArray(valueList);
523 } else if (aAttribute == nsGkAtoms::columnspacing_) {
524 aFrame->SetColSpacingArray(valueList);
525 } else {
526 aFrame->SetFrameSpacing(valueList.ElementAt(0), valueList.ElementAt(1));
530 static void ParseSpacingAttributes(nsMathMLmtableFrame* aTableFrame) {
531 ParseSpacingAttribute(aTableFrame, nsGkAtoms::rowspacing_);
532 ParseSpacingAttribute(aTableFrame, nsGkAtoms::columnspacing_);
533 ParseSpacingAttribute(aTableFrame, nsGkAtoms::framespacing_);
534 aTableFrame->SetUseCSSSpacing();
537 // map all attributes within a table -- requires the indices of rows and cells.
538 // so it can only happen after they are made ready by the table base class.
539 static void MapAllAttributesIntoCSS(nsMathMLmtableFrame* aTableFrame) {
540 // Map mtable rowalign & rowlines.
541 ParseFrameAttribute(aTableFrame, nsGkAtoms::rowalign_, true);
542 ParseFrameAttribute(aTableFrame, nsGkAtoms::rowlines_, true);
544 // Map mtable columnalign & columnlines.
545 ParseFrameAttribute(aTableFrame, nsGkAtoms::columnalign_, true);
546 ParseFrameAttribute(aTableFrame, nsGkAtoms::columnlines_, true);
548 // Map mtable rowspacing, columnspacing & framespacing
549 ParseSpacingAttributes(aTableFrame);
551 // mtable is simple and only has one (pseudo) row-group
552 nsIFrame* rgFrame = aTableFrame->PrincipalChildList().FirstChild();
553 if (!rgFrame || !rgFrame->IsTableRowGroupFrame()) {
554 return;
557 for (nsIFrame* rowFrame : rgFrame->PrincipalChildList()) {
558 DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TableRow);
559 if (rowFrame->IsTableRowFrame()) {
560 // Map row rowalign.
561 ParseFrameAttribute(rowFrame, nsGkAtoms::rowalign_, false);
562 // Map row columnalign.
563 ParseFrameAttribute(rowFrame, nsGkAtoms::columnalign_, true);
565 for (nsIFrame* cellFrame : rowFrame->PrincipalChildList()) {
566 DEBUG_VERIFY_THAT_FRAME_IS(cellFrame, TableCell);
567 if (cellFrame->IsTableCellFrame()) {
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 ParseAlignAttribute(nsString& aValue, eAlign& aAlign,
598 int32_t& aRowIndex) {
599 // by default, the table is centered about the axis
600 aRowIndex = 0;
601 aAlign = eAlign_axis;
602 int32_t len = 0;
604 // we only have to remove the leading spaces because
605 // ToInteger ignores the whitespaces around the number
606 aValue.CompressWhitespace(true, false);
608 if (0 == aValue.Find(u"top")) {
609 len = 3; // 3 is the length of 'top'
610 aAlign = eAlign_top;
611 } else if (0 == aValue.Find(u"bottom")) {
612 len = 6; // 6 is the length of 'bottom'
613 aAlign = eAlign_bottom;
614 } else if (0 == aValue.Find(u"center")) {
615 len = 6; // 6 is the length of 'center'
616 aAlign = eAlign_center;
617 } else if (0 == aValue.Find(u"baseline")) {
618 len = 8; // 8 is the length of 'baseline'
619 aAlign = eAlign_baseline;
620 } else if (0 == aValue.Find(u"axis")) {
621 len = 4; // 4 is the length of 'axis'
622 aAlign = eAlign_axis;
624 if (len) {
625 nsresult error;
626 aValue.Cut(0, len); // aValue is not a const here
627 aRowIndex = aValue.ToInteger(&error);
628 if (NS_FAILED(error)) {
629 aRowIndex = 0;
634 // --------
635 // implementation of nsMathMLmtableWrapperFrame
637 NS_QUERYFRAME_HEAD(nsMathMLmtableWrapperFrame)
638 NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
639 NS_QUERYFRAME_TAIL_INHERITING(nsTableWrapperFrame)
641 nsContainerFrame* NS_NewMathMLmtableOuterFrame(PresShell* aPresShell,
642 ComputedStyle* aStyle) {
643 return new (aPresShell)
644 nsMathMLmtableWrapperFrame(aStyle, aPresShell->GetPresContext());
647 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableWrapperFrame)
649 nsMathMLmtableWrapperFrame::~nsMathMLmtableWrapperFrame() = default;
651 nsresult nsMathMLmtableWrapperFrame::AttributeChanged(int32_t aNameSpaceID,
652 nsAtom* aAttribute,
653 int32_t aModType) {
654 // Attributes specific to <mtable>:
655 // frame : in mathml.css
656 // framespacing : here
657 // groupalign : not yet supported
658 // equalrows : not yet supported
659 // equalcolumns : not yet supported
660 // displaystyle : here and in mathml.css
661 // align : in reflow
662 // rowalign : here
663 // rowlines : here
664 // rowspacing : here
665 // columnalign : here
666 // columnlines : here
667 // columnspacing : here
669 // mtable is simple and only has one (pseudo) row-group inside our inner-table
670 nsIFrame* tableFrame = mFrames.FirstChild();
671 NS_ASSERTION(tableFrame && tableFrame->IsTableFrame(),
672 "should always have an inner table frame");
673 nsIFrame* rgFrame = tableFrame->PrincipalChildList().FirstChild();
674 if (!rgFrame || !rgFrame->IsTableRowGroupFrame()) {
675 return NS_OK;
678 // align - just need to issue a dirty (resize) reflow command
679 if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::align) {
680 PresShell()->FrameNeedsReflow(this, IntrinsicDirty::None,
681 NS_FRAME_IS_DIRTY);
682 return NS_OK;
685 // ...and the other attributes affect rows or columns in one way or another
687 if (aNameSpaceID == kNameSpaceID_None &&
688 (aAttribute == nsGkAtoms::rowspacing_ ||
689 aAttribute == nsGkAtoms::columnspacing_ ||
690 aAttribute == nsGkAtoms::framespacing_)) {
691 nsMathMLmtableFrame* mathMLmtableFrame = do_QueryFrame(tableFrame);
692 if (mathMLmtableFrame) {
693 ParseSpacingAttribute(mathMLmtableFrame, aAttribute);
694 mathMLmtableFrame->SetUseCSSSpacing();
696 PresShell()->FrameNeedsReflow(
697 this, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY);
698 return NS_OK;
701 if (aNameSpaceID == kNameSpaceID_None &&
702 (aAttribute == nsGkAtoms::rowalign_ ||
703 aAttribute == nsGkAtoms::rowlines_ ||
704 aAttribute == nsGkAtoms::columnalign_ ||
705 aAttribute == nsGkAtoms::columnlines_)) {
706 // clear any cached property list for this table
707 tableFrame->RemoveProperty(AttributeToProperty(aAttribute));
708 // Reparse the new attribute on the table.
709 ParseFrameAttribute(tableFrame, aAttribute, true);
710 PresShell()->FrameNeedsReflow(
711 this, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY);
712 return NS_OK;
715 // Skip nsTableWrapperFrame::AttributeChanged, mtable does not share more
716 // attributes with table.
717 return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
720 nsIFrame* nsMathMLmtableWrapperFrame::GetRowFrameAt(int32_t aRowIndex) {
721 int32_t rowCount = GetRowCount();
723 // Negative indices mean to find upwards from the end.
724 if (aRowIndex < 0) {
725 aRowIndex = rowCount + aRowIndex;
726 } else {
727 // aRowIndex is 1-based, so convert it to a 0-based index
728 --aRowIndex;
731 // if our inner table says that the index is valid, find the row now
732 if (0 <= aRowIndex && aRowIndex <= rowCount) {
733 nsIFrame* tableFrame = mFrames.FirstChild();
734 NS_ASSERTION(tableFrame && tableFrame->IsTableFrame(),
735 "should always have an inner table frame");
736 nsIFrame* rgFrame = tableFrame->PrincipalChildList().FirstChild();
737 if (!rgFrame || !rgFrame->IsTableRowGroupFrame()) {
738 return nullptr;
740 for (nsIFrame* rowFrame : rgFrame->PrincipalChildList()) {
741 if (aRowIndex == 0) {
742 DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TableRow);
743 if (!rowFrame->IsTableRowFrame()) {
744 return nullptr;
747 return rowFrame;
749 --aRowIndex;
752 return nullptr;
755 void nsMathMLmtableWrapperFrame::Reflow(nsPresContext* aPresContext,
756 ReflowOutput& aDesiredSize,
757 const ReflowInput& aReflowInput,
758 nsReflowStatus& aStatus) {
759 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
761 nsAutoString value;
762 // we want to return a table that is anchored according to the align attribute
764 nsTableWrapperFrame::Reflow(aPresContext, aDesiredSize, aReflowInput,
765 aStatus);
766 NS_ASSERTION(aDesiredSize.Height() >= 0, "illegal height for mtable");
767 NS_ASSERTION(aDesiredSize.Width() >= 0, "illegal width for mtable");
769 // see if the user has set the align attribute on the <mtable>
770 int32_t rowIndex = 0;
771 eAlign tableAlign = eAlign_axis;
772 mContent->AsElement()->GetAttr(nsGkAtoms::align, value);
773 if (!value.IsEmpty()) {
774 ParseAlignAttribute(value, tableAlign, rowIndex);
777 // adjustments if there is a specified row from where to anchor the table
778 // (conceptually: when there is no row of reference, picture the table as if
779 // it is wrapped in a single big fictional row at dy = 0, this way of
780 // doing so allows us to have a single code path for all cases).
781 nscoord dy = 0;
782 WritingMode wm = aDesiredSize.GetWritingMode();
783 nscoord blockSize = aDesiredSize.BSize(wm);
784 nsIFrame* rowFrame = nullptr;
785 if (rowIndex) {
786 rowFrame = GetRowFrameAt(rowIndex);
787 if (rowFrame) {
788 // translate the coordinates to be relative to us and in our writing mode
789 nsIFrame* frame = rowFrame;
790 LogicalRect rect(wm, frame->GetRect(),
791 aReflowInput.ComputedSizeAsContainerIfConstrained());
792 blockSize = rect.BSize(wm);
793 do {
794 nsIFrame* parent = frame->GetParent();
795 dy += frame->BStart(wm, parent->GetSize());
796 frame = parent;
797 } while (frame != this);
800 switch (tableAlign) {
801 case eAlign_top:
802 aDesiredSize.SetBlockStartAscent(dy);
803 break;
804 case eAlign_bottom:
805 aDesiredSize.SetBlockStartAscent(dy + blockSize);
806 break;
807 case eAlign_center:
808 aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
809 break;
810 case eAlign_baseline:
811 if (rowFrame) {
812 // anchor the table on the baseline of the row of reference
813 nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
814 if (rowAscent) { // the row has at least one cell with 'vertical-align:
815 // baseline'
816 aDesiredSize.SetBlockStartAscent(dy + rowAscent);
817 break;
820 // in other situations, fallback to center
821 aDesiredSize.SetBlockStartAscent(dy + blockSize / 2);
822 break;
823 case eAlign_axis:
824 default: {
825 // XXX should instead use style data from the row of reference here ?
826 RefPtr<nsFontMetrics> fm =
827 nsLayoutUtils::GetInflatedFontMetricsForFrame(this);
828 nscoord axisHeight;
829 GetAxisHeight(aReflowInput.mRenderingContext->GetDrawTarget(), fm,
830 axisHeight);
831 if (rowFrame) {
832 // anchor the table on the axis of the row of reference
833 // XXX fallback to baseline because it is a hard problem
834 // XXX need to fetch the axis of the row; would need rowalign=axis to
835 // work better
836 nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
837 if (rowAscent) { // the row has at least one cell with 'vertical-align:
838 // baseline'
839 aDesiredSize.SetBlockStartAscent(dy + rowAscent);
840 break;
843 // in other situations, fallback to using half of the height
844 aDesiredSize.SetBlockStartAscent(dy + blockSize / 2 + axisHeight);
848 mReference.x = 0;
849 mReference.y = aDesiredSize.BlockStartAscent();
851 // just make-up a bounding metrics
852 mBoundingMetrics = nsBoundingMetrics();
853 mBoundingMetrics.ascent = aDesiredSize.BlockStartAscent();
854 mBoundingMetrics.descent =
855 aDesiredSize.Height() - aDesiredSize.BlockStartAscent();
856 mBoundingMetrics.width = aDesiredSize.Width();
857 mBoundingMetrics.leftBearing = 0;
858 mBoundingMetrics.rightBearing = aDesiredSize.Width();
860 aDesiredSize.mBoundingMetrics = mBoundingMetrics;
863 nsContainerFrame* NS_NewMathMLmtableFrame(PresShell* aPresShell,
864 ComputedStyle* aStyle) {
865 return new (aPresShell)
866 nsMathMLmtableFrame(aStyle, aPresShell->GetPresContext());
869 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableFrame)
871 nsMathMLmtableFrame::~nsMathMLmtableFrame() = default;
873 void nsMathMLmtableFrame::SetInitialChildList(ChildListID aListID,
874 nsFrameList&& aChildList) {
875 nsTableFrame::SetInitialChildList(aListID, std::move(aChildList));
876 MapAllAttributesIntoCSS(this);
879 void nsMathMLmtableFrame::RestyleTable() {
880 // re-sync MathML specific style data that may have changed
881 MapAllAttributesIntoCSS(this);
883 // Explicitly request a re-resolve and reflow in our subtree to pick up any
884 // changes
885 PresContext()->RestyleManager()->PostRestyleEvent(
886 mContent->AsElement(), RestyleHint::RestyleSubtree(),
887 nsChangeHint_AllReflowHints);
890 nscoord nsMathMLmtableFrame::GetColSpacing(int32_t aColIndex) {
891 if (mUseCSSSpacing) {
892 return nsTableFrame::GetColSpacing(aColIndex);
894 if (!mColSpacing.Length()) {
895 NS_ERROR("mColSpacing should not be empty");
896 return 0;
898 if (aColIndex < 0 || aColIndex >= GetColCount()) {
899 NS_ASSERTION(aColIndex == -1 || aColIndex == GetColCount(),
900 "Desired column beyond bounds of table and border");
901 return mFrameSpacingX;
903 if ((uint32_t)aColIndex >= mColSpacing.Length()) {
904 return mColSpacing.LastElement();
906 return mColSpacing.ElementAt(aColIndex);
909 nscoord nsMathMLmtableFrame::GetColSpacing(int32_t aStartColIndex,
910 int32_t aEndColIndex) {
911 if (mUseCSSSpacing) {
912 return nsTableFrame::GetColSpacing(aStartColIndex, aEndColIndex);
914 if (aStartColIndex == aEndColIndex) {
915 return 0;
917 if (!mColSpacing.Length()) {
918 NS_ERROR("mColSpacing should not be empty");
919 return 0;
921 nscoord space = 0;
922 if (aStartColIndex < 0) {
923 NS_ASSERTION(aStartColIndex == -1,
924 "Desired column beyond bounds of table and border");
925 space += mFrameSpacingX;
926 aStartColIndex = 0;
928 if (aEndColIndex >= GetColCount()) {
929 NS_ASSERTION(aEndColIndex == GetColCount(),
930 "Desired column beyond bounds of table and border");
931 space += mFrameSpacingX;
932 aEndColIndex = GetColCount();
934 // Only iterate over column spacing when there is the potential to vary
935 int32_t min = std::min(aEndColIndex, (int32_t)mColSpacing.Length());
936 for (int32_t i = aStartColIndex; i < min; i++) {
937 space += mColSpacing.ElementAt(i);
939 // The remaining values are constant. Note that if there are more
940 // column spacings specified than there are columns, LastElement() will be
941 // multiplied by 0, so it is still safe to use.
942 space += (aEndColIndex - min) * mColSpacing.LastElement();
943 return space;
946 nscoord nsMathMLmtableFrame::GetRowSpacing(int32_t aRowIndex) {
947 if (mUseCSSSpacing) {
948 return nsTableFrame::GetRowSpacing(aRowIndex);
950 if (!mRowSpacing.Length()) {
951 NS_ERROR("mRowSpacing should not be empty");
952 return 0;
954 if (aRowIndex < 0 || aRowIndex >= GetRowCount()) {
955 NS_ASSERTION(aRowIndex == -1 || aRowIndex == GetRowCount(),
956 "Desired row beyond bounds of table and border");
957 return mFrameSpacingY;
959 if ((uint32_t)aRowIndex >= mRowSpacing.Length()) {
960 return mRowSpacing.LastElement();
962 return mRowSpacing.ElementAt(aRowIndex);
965 nscoord nsMathMLmtableFrame::GetRowSpacing(int32_t aStartRowIndex,
966 int32_t aEndRowIndex) {
967 if (mUseCSSSpacing) {
968 return nsTableFrame::GetRowSpacing(aStartRowIndex, aEndRowIndex);
970 if (aStartRowIndex == aEndRowIndex) {
971 return 0;
973 if (!mRowSpacing.Length()) {
974 NS_ERROR("mRowSpacing should not be empty");
975 return 0;
977 nscoord space = 0;
978 if (aStartRowIndex < 0) {
979 NS_ASSERTION(aStartRowIndex == -1,
980 "Desired row beyond bounds of table and border");
981 space += mFrameSpacingY;
982 aStartRowIndex = 0;
984 if (aEndRowIndex >= GetRowCount()) {
985 NS_ASSERTION(aEndRowIndex == GetRowCount(),
986 "Desired row beyond bounds of table and border");
987 space += mFrameSpacingY;
988 aEndRowIndex = GetRowCount();
990 // Only iterate over row spacing when there is the potential to vary
991 int32_t min = std::min(aEndRowIndex, (int32_t)mRowSpacing.Length());
992 for (int32_t i = aStartRowIndex; i < min; i++) {
993 space += mRowSpacing.ElementAt(i);
995 // The remaining values are constant. Note that if there are more
996 // row spacings specified than there are row, LastElement() will be
997 // multiplied by 0, so it is still safe to use.
998 space += (aEndRowIndex - min) * mRowSpacing.LastElement();
999 return space;
1002 void nsMathMLmtableFrame::SetUseCSSSpacing() {
1003 mUseCSSSpacing = !(mContent->AsElement()->HasAttr(nsGkAtoms::rowspacing_) ||
1004 mContent->AsElement()->HasAttr(
1005 kNameSpaceID_None, nsGkAtoms::columnspacing_) ||
1006 mContent->AsElement()->HasAttr(nsGkAtoms::framespacing_));
1009 NS_QUERYFRAME_HEAD(nsMathMLmtableFrame)
1010 NS_QUERYFRAME_ENTRY(nsMathMLmtableFrame)
1011 NS_QUERYFRAME_TAIL_INHERITING(nsTableFrame)
1013 // --------
1014 // implementation of nsMathMLmtrFrame
1016 nsContainerFrame* NS_NewMathMLmtrFrame(PresShell* aPresShell,
1017 ComputedStyle* aStyle) {
1018 return new (aPresShell)
1019 nsMathMLmtrFrame(aStyle, aPresShell->GetPresContext());
1022 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtrFrame)
1024 nsMathMLmtrFrame::~nsMathMLmtrFrame() = default;
1026 nsresult nsMathMLmtrFrame::AttributeChanged(int32_t aNameSpaceID,
1027 nsAtom* aAttribute,
1028 int32_t aModType) {
1029 // Attributes specific to <mtr>:
1030 // groupalign : Not yet supported.
1031 // rowalign : Here
1032 // columnalign : Here
1034 if (aNameSpaceID != kNameSpaceID_None ||
1035 (aAttribute != nsGkAtoms::rowalign_ &&
1036 aAttribute != nsGkAtoms::columnalign_)) {
1037 // Skip nsTableCellFrame::AttributeChanged, mtr does not share any attribute
1038 // with tr.
1039 return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
1040 aModType);
1043 RemoveProperty(AttributeToProperty(aAttribute));
1045 bool allowMultiValues = (aAttribute == nsGkAtoms::columnalign_);
1047 // Reparse the new attribute.
1048 ParseFrameAttribute(this, aAttribute, allowMultiValues);
1050 // Explicitly request a reflow in our subtree to pick up any changes
1051 PresShell()->FrameNeedsReflow(
1052 this, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY);
1054 return NS_OK;
1057 // --------
1058 // implementation of nsMathMLmtdFrame
1060 nsContainerFrame* NS_NewMathMLmtdFrame(PresShell* aPresShell,
1061 ComputedStyle* aStyle,
1062 nsTableFrame* aTableFrame) {
1063 return new (aPresShell) nsMathMLmtdFrame(aStyle, aTableFrame);
1066 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdFrame)
1068 nsMathMLmtdFrame::~nsMathMLmtdFrame() = default;
1070 void nsMathMLmtdFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
1071 nsIFrame* aPrevInFlow) {
1072 nsTableCellFrame::Init(aContent, aParent, aPrevInFlow);
1074 // We want to use the ancestor <math> element's font inflation to avoid
1075 // individual cells having their own varying font inflation.
1076 RemoveStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
1079 nsresult nsMathMLmtdFrame::AttributeChanged(int32_t aNameSpaceID,
1080 nsAtom* aAttribute,
1081 int32_t aModType) {
1082 // Attributes specific to <mtd>:
1083 // groupalign : Not yet supported
1084 // rowalign : here
1085 // columnalign : here
1086 // rowspan : here
1087 // columnspan : here
1089 if (aNameSpaceID == kNameSpaceID_None &&
1090 (aAttribute == nsGkAtoms::rowalign_ ||
1091 aAttribute == nsGkAtoms::columnalign_)) {
1092 RemoveProperty(AttributeToProperty(aAttribute));
1094 // Reparse the attribute.
1095 ParseFrameAttribute(this, aAttribute, false);
1096 return NS_OK;
1099 if (aNameSpaceID == kNameSpaceID_None &&
1100 (aAttribute == nsGkAtoms::rowspan ||
1101 aAttribute == nsGkAtoms::columnspan_)) {
1102 // nsTableCellFrame takes care of renaming columnspan to colspan.
1103 return nsTableCellFrame::AttributeChanged(aNameSpaceID, aAttribute,
1104 aModType);
1107 // Skip nsTableCellFrame::AttributeChanged, mtd does not share more attributes
1108 // with td.
1109 return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
1112 StyleVerticalAlignKeyword nsMathMLmtdFrame::GetVerticalAlign() const {
1113 // Set the default alignment in case no alignment was specified
1114 auto alignment = nsTableCellFrame::GetVerticalAlign();
1116 nsTArray<int8_t>* alignmentList = FindCellProperty(this, RowAlignProperty());
1118 if (alignmentList) {
1119 uint32_t rowIndex = RowIndex();
1121 // If the row number is greater than the number of provided rowalign values,
1122 // we simply repeat the last value.
1123 return static_cast<StyleVerticalAlignKeyword>(
1124 (rowIndex < alignmentList->Length())
1125 ? alignmentList->ElementAt(rowIndex)
1126 : alignmentList->LastElement());
1129 return alignment;
1132 void nsMathMLmtdFrame::ProcessBorders(nsTableFrame* aFrame,
1133 nsDisplayListBuilder* aBuilder,
1134 const nsDisplayListSet& aLists) {
1135 aLists.BorderBackground()->AppendNewToTop<nsDisplaymtdBorder>(aBuilder, this);
1138 LogicalMargin nsMathMLmtdFrame::GetBorderWidth(WritingMode aWM) const {
1139 nsStyleBorder styleBorder = *StyleBorder();
1140 ApplyBorderToStyle(this, styleBorder);
1141 return LogicalMargin(aWM, styleBorder.GetComputedBorder());
1144 nsMargin nsMathMLmtdFrame::GetBorderOverflow() {
1145 nsStyleBorder styleBorder = *StyleBorder();
1146 ApplyBorderToStyle(this, styleBorder);
1147 nsMargin overflow = ComputeBorderOverflow(this, styleBorder);
1148 return overflow;
1151 // --------
1152 // implementation of nsMathMLmtdInnerFrame
1154 NS_QUERYFRAME_HEAD(nsMathMLmtdInnerFrame)
1155 NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
1156 NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
1158 nsContainerFrame* NS_NewMathMLmtdInnerFrame(PresShell* aPresShell,
1159 ComputedStyle* aStyle) {
1160 return new (aPresShell)
1161 nsMathMLmtdInnerFrame(aStyle, aPresShell->GetPresContext());
1164 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdInnerFrame)
1166 nsMathMLmtdInnerFrame::nsMathMLmtdInnerFrame(ComputedStyle* aStyle,
1167 nsPresContext* aPresContext)
1168 : nsBlockFrame(aStyle, aPresContext, kClassID)
1169 // Make a copy of the parent nsStyleText for later modification.
1171 mUniqueStyleText(MakeUnique<nsStyleText>(*StyleText())) {}
1173 void nsMathMLmtdInnerFrame::Reflow(nsPresContext* aPresContext,
1174 ReflowOutput& aDesiredSize,
1175 const ReflowInput& aReflowInput,
1176 nsReflowStatus& aStatus) {
1177 // Let the base class do the reflow
1178 nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
1180 // more about <maligngroup/> and <malignmark/> later
1181 // ...
1184 const nsStyleText* nsMathMLmtdInnerFrame::StyleTextForLineLayout() {
1185 // Set the default alignment in case nothing was specified
1186 auto alignment = uint8_t(StyleText()->mTextAlign);
1188 nsTArray<int8_t>* alignmentList =
1189 FindCellProperty(this, ColumnAlignProperty());
1191 if (alignmentList) {
1192 nsMathMLmtdFrame* cellFrame = (nsMathMLmtdFrame*)GetParent();
1193 uint32_t columnIndex = cellFrame->ColIndex();
1195 // If the column number is greater than the number of provided columalign
1196 // values, we simply repeat the last value.
1197 if (columnIndex < alignmentList->Length()) {
1198 alignment = alignmentList->ElementAt(columnIndex);
1199 } else {
1200 alignment = alignmentList->ElementAt(alignmentList->Length() - 1);
1204 mUniqueStyleText->mTextAlign = StyleTextAlign(alignment);
1205 return mUniqueStyleText.get();
1208 /* virtual */
1209 void nsMathMLmtdInnerFrame::DidSetComputedStyle(
1210 ComputedStyle* aOldComputedStyle) {
1211 nsBlockFrame::DidSetComputedStyle(aOldComputedStyle);
1212 mUniqueStyleText = MakeUnique<nsStyleText>(*StyleText());