LCOV - code coverage report
Current view: top level - layout/mathml - nsMathMLmtableFrame.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 595 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 68 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13