LCOV - code coverage report
Current view: directory - layout/mathml - nsMathMLmtableFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 355 0 0.0 %
Date: 2012-06-02 Functions: 55 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla MathML Project.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * The University Of Queensland.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1999
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Roger B. Sidje <rbs@maths.uq.edu.au>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsCOMPtr.h"
      40                 : #include "nsFrame.h"
      41                 : #include "nsBlockFrame.h"
      42                 : #include "nsPresContext.h"
      43                 : #include "nsStyleContext.h"
      44                 : #include "nsStyleConsts.h"
      45                 : #include "nsINameSpaceManager.h"
      46                 : #include "nsRenderingContext.h"
      47                 : 
      48                 : #include "nsTArray.h"
      49                 : #include "nsCSSFrameConstructor.h"
      50                 : #include "nsTableOuterFrame.h"
      51                 : #include "nsTableFrame.h"
      52                 : #include "nsTableCellFrame.h"
      53                 : #include "celldata.h"
      54                 : 
      55                 : #include "nsMathMLmtableFrame.h"
      56                 : 
      57                 : using namespace mozilla;
      58                 : 
      59                 : //
      60                 : // <mtable> -- table or matrix - implementation
      61                 : //
      62                 : 
      63                 : // helper function to perform an in-place split of a space-delimited string,
      64                 : // and return an array of pointers for the beginning of each segment, i.e.,
      65                 : // aOffset[0] is the first string, aOffset[1] is the second string, etc.
      66                 : // Used to parse attributes like columnalign='left right', rowalign='top bottom'
      67                 : static void
      68               0 : SplitString(nsString&             aString, // [IN/OUT]
      69                 :             nsTArray<PRUnichar*>& aOffset) // [OUT]
      70                 : {
      71                 :   static const PRUnichar kNullCh = PRUnichar('\0');
      72                 : 
      73               0 :   aString.Append(kNullCh);  // put an extra null at the end
      74                 : 
      75               0 :   PRUnichar* start = aString.BeginWriting();
      76               0 :   PRUnichar* end   = start;
      77                 : 
      78               0 :   while (kNullCh != *start) {
      79               0 :     while ((kNullCh != *start) && nsCRT::IsAsciiSpace(*start)) {  // skip leading space
      80               0 :       start++;
      81                 :     }
      82               0 :     end = start;
      83                 : 
      84               0 :     while ((kNullCh != *end) && (false == nsCRT::IsAsciiSpace(*end))) { // look for space or end
      85               0 :       end++;
      86                 :     }
      87               0 :     *end = kNullCh; // end string here
      88                 : 
      89               0 :     if (start < end) {
      90               0 :       aOffset.AppendElement(start); // record the beginning of this segment
      91                 :     }
      92                 : 
      93               0 :     start = ++end;
      94                 :   }
      95               0 : }
      96                 : 
      97                 : struct nsValueList
      98               0 : {
      99                 :   nsString             mData;
     100                 :   nsTArray<PRUnichar*> mArray;
     101                 : 
     102               0 :   nsValueList(nsString& aData) {
     103               0 :     mData.Assign(aData);
     104               0 :     SplitString(mData, mArray);
     105               0 :   }
     106                 : };
     107                 : 
     108                 : // Each rowalign='top bottom' or columnalign='left right center' (from
     109                 : // <mtable> or <mtr>) is split once (lazily) into a nsValueList which is
     110                 : // stored in the property table. Row/Cell frames query the property table
     111                 : // to see what values apply to them.
     112                 : 
     113                 : // XXX See bug 69409 - MathML attributes are not mapped to style.
     114                 : 
     115                 : static void
     116               0 : DestroyValueList(void* aPropertyValue)
     117                 : {
     118               0 :   delete static_cast<nsValueList*>(aPropertyValue);
     119               0 : }
     120                 : 
     121               0 : NS_DECLARE_FRAME_PROPERTY(RowAlignProperty, DestroyValueList)
     122               0 : NS_DECLARE_FRAME_PROPERTY(RowLinesProperty, DestroyValueList)
     123               0 : NS_DECLARE_FRAME_PROPERTY(ColumnAlignProperty, DestroyValueList)
     124               0 : NS_DECLARE_FRAME_PROPERTY(ColumnLinesProperty, DestroyValueList)
     125                 : 
     126                 : static const FramePropertyDescriptor*
     127               0 : AttributeToProperty(nsIAtom* aAttribute)
     128                 : {
     129               0 :   if (aAttribute == nsGkAtoms::rowalign_)
     130               0 :     return RowAlignProperty();
     131               0 :   if (aAttribute == nsGkAtoms::rowlines_)
     132               0 :     return RowLinesProperty();
     133               0 :   if (aAttribute == nsGkAtoms::columnalign_)
     134               0 :     return ColumnAlignProperty();
     135               0 :   NS_ASSERTION(aAttribute == nsGkAtoms::columnlines_, "Invalid attribute");
     136               0 :   return ColumnLinesProperty();
     137                 : }
     138                 : 
     139                 : static PRUnichar*
     140               0 : GetValueAt(nsIFrame*                      aTableOrRowFrame,
     141                 :            const FramePropertyDescriptor* aProperty,
     142                 :            nsIAtom*                       aAttribute,
     143                 :            PRInt32                        aRowOrColIndex)
     144                 : {
     145               0 :   FrameProperties props = aTableOrRowFrame->Properties();
     146               0 :   nsValueList* valueList = static_cast<nsValueList*>(props.Get(aProperty));
     147               0 :   if (!valueList) {
     148                 :     // The property isn't there yet, so set it
     149               0 :     nsAutoString values;
     150               0 :     aTableOrRowFrame->GetContent()->GetAttr(kNameSpaceID_None, aAttribute, values);
     151               0 :     if (!values.IsEmpty())
     152               0 :       valueList = new nsValueList(values);
     153               0 :     if (!valueList || !valueList->mArray.Length()) {
     154               0 :       delete valueList; // ok either way, delete is null safe
     155               0 :       return nsnull;
     156                 :     }
     157               0 :     props.Set(aProperty, valueList);
     158                 :   }
     159               0 :   PRInt32 count = valueList->mArray.Length();
     160                 :   return (aRowOrColIndex < count)
     161               0 :          ? valueList->mArray[aRowOrColIndex]
     162               0 :          : valueList->mArray[count-1];
     163                 : }
     164                 : 
     165                 : #ifdef NS_DEBUG
     166                 : static bool
     167               0 : IsTable(PRUint8 aDisplay)
     168                 : {
     169               0 :   if ((aDisplay == NS_STYLE_DISPLAY_TABLE) ||
     170                 :       (aDisplay == NS_STYLE_DISPLAY_INLINE_TABLE))
     171               0 :     return true;
     172               0 :   return false;
     173                 : }
     174                 : 
     175                 : #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) \
     176                 :   NS_ASSERTION(NS_STYLE_DISPLAY_##_expected == _frame->GetStyleDisplay()->mDisplay, "internal error");
     177                 : #define DEBUG_VERIFY_THAT_FRAME_IS_TABLE(_frame) \
     178                 :   NS_ASSERTION(IsTable(_frame->GetStyleDisplay()->mDisplay), "internal error");
     179                 : #else
     180                 : #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)
     181                 : #define DEBUG_VERIFY_THAT_FRAME_IS_TABLE(_frame)
     182                 : #endif
     183                 : 
     184                 : // map attributes that depend on the index of the row:
     185                 : // rowalign, rowlines, XXX need rowspacing too
     186                 : static void
     187               0 : MapRowAttributesIntoCSS(nsIFrame* aTableFrame,
     188                 :                         nsIFrame* aRowFrame)
     189                 : {
     190               0 :   DEBUG_VERIFY_THAT_FRAME_IS_TABLE(aTableFrame);
     191               0 :   DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame, TABLE_ROW);
     192               0 :   PRInt32 rowIndex = ((nsTableRowFrame*)aRowFrame)->GetRowIndex();
     193               0 :   nsIContent* rowContent = aRowFrame->GetContent();
     194                 :   PRUnichar* attr;
     195                 : 
     196                 :   // see if the rowalign attribute is not already set
     197               0 :   if (!rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::rowalign_) &&
     198               0 :       !rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowalign_)) {
     199                 :     // see if the rowalign attribute was specified on the table
     200                 :     attr = GetValueAt(aTableFrame, RowAlignProperty(),
     201               0 :                       nsGkAtoms::rowalign_, rowIndex);
     202               0 :     if (attr) {
     203                 :       // set our special _moz attribute on the row without notifying a reflow
     204                 :       rowContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowalign_,
     205               0 :                           nsDependentString(attr), false);
     206                 :     }
     207                 :   }
     208                 : 
     209                 :   // if we are not on the first row, see if |rowlines| was specified on the table.
     210                 :   // Note that we pass 'rowIndex-1' because the CSS rule in mathml.css is associated
     211                 :   // to 'border-top', and it is as if we draw the line on behalf of the previous cell.
     212                 :   // This way of doing so allows us to handle selective lines, [row]\hline[row][row]',
     213                 :   // and cases of spanning cells without further complications.
     214               0 :   if (rowIndex > 0 &&
     215               0 :       !rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowline_)) {
     216                 :     attr = GetValueAt(aTableFrame, RowLinesProperty(),
     217               0 :                       nsGkAtoms::rowlines_, rowIndex-1);
     218               0 :     if (attr) {
     219                 :       // set our special _moz attribute on the row without notifying a reflow
     220                 :       rowContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowline_,
     221               0 :                           nsDependentString(attr), false);
     222                 :     }
     223                 :   }
     224               0 : }
     225                 : 
     226                 : // map attributes that depend on the index of the column:
     227                 : // columnalign, columnlines, XXX need columnwidth and columnspacing too
     228                 : static void
     229               0 : MapColAttributesIntoCSS(nsIFrame* aTableFrame,
     230                 :                         nsIFrame* aRowFrame,
     231                 :                         nsIFrame* aCellFrame)
     232                 : {
     233               0 :   DEBUG_VERIFY_THAT_FRAME_IS_TABLE(aTableFrame);
     234               0 :   DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame, TABLE_ROW);
     235               0 :   DEBUG_VERIFY_THAT_FRAME_IS(aCellFrame, TABLE_CELL);
     236                 :   PRInt32 rowIndex, colIndex;
     237               0 :   ((nsTableCellFrame*)aCellFrame)->GetCellIndexes(rowIndex, colIndex);
     238               0 :   nsIContent* cellContent = aCellFrame->GetContent();
     239                 :   PRUnichar* attr;
     240                 : 
     241                 :   // see if the columnalign attribute is not already set
     242               0 :   if (!cellContent->HasAttr(kNameSpaceID_None, nsGkAtoms::columnalign_) &&
     243                 :       !cellContent->HasAttr(kNameSpaceID_None,
     244               0 :                             nsGkAtoms::_moz_math_columnalign_)) {
     245                 :     // see if the columnalign attribute was specified on the row
     246                 :     attr = GetValueAt(aRowFrame, ColumnAlignProperty(),
     247               0 :                       nsGkAtoms::columnalign_, colIndex);
     248               0 :     if (!attr) {
     249                 :       // see if the columnalign attribute was specified on the table
     250                 :       attr = GetValueAt(aTableFrame, ColumnAlignProperty(),
     251               0 :                         nsGkAtoms::columnalign_, colIndex);
     252                 :     }
     253               0 :     if (attr) {
     254                 :       // set our special _moz attribute without notifying a reflow
     255                 :       cellContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_columnalign_,
     256               0 :                            nsDependentString(attr), false);
     257                 :     }
     258                 :   }
     259                 : 
     260                 :   // if we are not on the first column, see if |columnlines| was specified on
     261                 :   // the table. Note that we pass 'colIndex-1' because the CSS rule in mathml.css
     262                 :   // is associated to 'border-left', and it is as if we draw the line on behalf
     263                 :   // of the previous cell. This way of doing so allows us to handle selective lines,
     264                 :   // e.g., 'r|cl', and cases of spanning cells without further complications.
     265               0 :   if (colIndex > 0 &&
     266                 :       !cellContent->HasAttr(kNameSpaceID_None,
     267               0 :                             nsGkAtoms::_moz_math_columnline_)) {
     268                 :     attr = GetValueAt(aTableFrame, ColumnLinesProperty(),
     269               0 :                       nsGkAtoms::columnlines_, colIndex-1);
     270               0 :     if (attr) {
     271                 :       // set our special _moz attribute without notifying a reflow
     272                 :       cellContent->SetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_columnline_,
     273               0 :                            nsDependentString(attr), false);
     274                 :     }
     275                 :   }
     276               0 : }
     277                 : 
     278                 : // map all attribues within a table -- requires the indices of rows and cells.
     279                 : // so it can only happen after they are made ready by the table base class.
     280                 : static void
     281               0 : MapAllAttributesIntoCSS(nsIFrame* aTableFrame)
     282                 : {
     283                 :   // mtable is simple and only has one (pseudo) row-group
     284               0 :   nsIFrame* rgFrame = aTableFrame->GetFirstPrincipalChild();
     285               0 :   if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
     286               0 :     return;
     287                 : 
     288               0 :   nsIFrame* rowFrame = rgFrame->GetFirstPrincipalChild();
     289               0 :   for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
     290               0 :     DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW);
     291               0 :     if (rowFrame->GetType() == nsGkAtoms::tableRowFrame) {
     292               0 :       MapRowAttributesIntoCSS(aTableFrame, rowFrame);
     293               0 :       nsIFrame* cellFrame = rowFrame->GetFirstPrincipalChild();
     294               0 :       for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) {
     295               0 :         DEBUG_VERIFY_THAT_FRAME_IS(cellFrame, TABLE_CELL);
     296               0 :         if (IS_TABLE_CELL(cellFrame->GetType())) {
     297               0 :           MapColAttributesIntoCSS(aTableFrame, rowFrame, cellFrame);
     298                 :         }
     299                 :       }
     300                 :     }
     301                 :   }
     302                 : }
     303                 : 
     304                 : // the align attribute of mtable can have a row number which indicates
     305                 : // from where to anchor the table, e.g., top5 means anchor the table at
     306                 : // the top of the 5th row, axis-1 means anchor the table on the axis of
     307                 : // the last row (could have been nicer if the REC used the '#' separator,
     308                 : // e.g., top#5, or axis#-1)
     309                 : 
     310                 : enum eAlign {
     311                 :   eAlign_top,
     312                 :   eAlign_bottom,
     313                 :   eAlign_center,
     314                 :   eAlign_baseline,
     315                 :   eAlign_axis
     316                 : };
     317                 : 
     318                 : static void
     319               0 : ParseAlignAttribute(nsString& aValue, eAlign& aAlign, PRInt32& aRowIndex)
     320                 : {
     321                 :   // by default, the table is centered about the axis
     322               0 :   aRowIndex = 0;
     323               0 :   aAlign = eAlign_axis;
     324               0 :   PRInt32 len = 0;
     325               0 :   if (0 == aValue.Find("top")) {
     326               0 :     len = 3; // 3 is the length of 'top'
     327               0 :     aAlign = eAlign_top;
     328                 :   }
     329               0 :   else if (0 == aValue.Find("bottom")) {
     330               0 :     len = 6; // 6 is the length of 'bottom'
     331               0 :     aAlign = eAlign_bottom;
     332                 :   }
     333               0 :   else if (0 == aValue.Find("center")) {
     334               0 :     len = 6; // 6 is the length of 'center'
     335               0 :     aAlign = eAlign_center;
     336                 :   }
     337               0 :   else if (0 == aValue.Find("baseline")) {
     338               0 :     len = 8; // 8 is the length of 'baseline'
     339               0 :     aAlign = eAlign_baseline;
     340                 :   }
     341               0 :   else if (0 == aValue.Find("axis")) {
     342               0 :     len = 4; // 4 is the length of 'axis'
     343               0 :     aAlign = eAlign_axis;
     344                 :   }
     345               0 :   if (len) {
     346                 :     PRInt32 error;
     347               0 :     aValue.Cut(0, len); // aValue is not a const here
     348               0 :     aRowIndex = aValue.ToInteger(&error);
     349               0 :     if (error)
     350               0 :       aRowIndex = 0;
     351                 :   }
     352               0 : }
     353                 : 
     354                 : #ifdef DEBUG_rbs_off
     355                 : // call ListMathMLTree(mParent) to get the big picture
     356                 : static void
     357                 : ListMathMLTree(nsIFrame* atLeast)
     358                 : {
     359                 :   // climb up to <math> or <body> if <math> isn't there
     360                 :   nsIFrame* f = atLeast;
     361                 :   for ( ; f; f = f->GetParent()) {
     362                 :     nsIContent* c = f->GetContent();
     363                 :     if (!c || c->Tag() == nsGkAtoms::math || c->Tag() == nsGkAtoms::body)
     364                 :       break;
     365                 :   }
     366                 :   if (!f) f = atLeast;
     367                 :   f->List(stdout, 0);
     368                 : }
     369                 : #endif
     370                 : 
     371                 : // --------
     372                 : // implementation of nsMathMLmtableOuterFrame
     373                 : 
     374               0 : NS_QUERYFRAME_HEAD(nsMathMLmtableOuterFrame)
     375               0 :   NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
     376               0 : NS_QUERYFRAME_TAIL_INHERITING(nsTableOuterFrame)
     377                 : 
     378                 : nsIFrame*
     379               0 : NS_NewMathMLmtableOuterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
     380                 : {
     381               0 :   return new (aPresShell) nsMathMLmtableOuterFrame(aContext);
     382                 : }
     383                 : 
     384               0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableOuterFrame)
     385                 :  
     386               0 : nsMathMLmtableOuterFrame::~nsMathMLmtableOuterFrame()
     387                 : {
     388               0 : }
     389                 : 
     390                 : NS_IMETHODIMP
     391               0 : nsMathMLmtableOuterFrame::InheritAutomaticData(nsIFrame* aParent)
     392                 : {
     393                 :   // XXX the REC says that by default, displaystyle=false in <mtable>
     394                 : 
     395                 :   // let the base class inherit the displaystyle from our parent
     396               0 :   nsMathMLFrame::InheritAutomaticData(aParent);
     397                 : 
     398                 :   // see if the displaystyle attribute is there and let it override what we inherited
     399               0 :   if (mContent->Tag() == nsGkAtoms::mtable_)
     400               0 :     nsMathMLFrame::FindAttrDisplaystyle(mContent, mPresentationData);
     401                 : 
     402               0 :   return NS_OK;
     403                 : }
     404                 : 
     405                 : // displaystyle is special in mtable...
     406                 : // Since UpdatePresentation() and UpdatePresentationDataFromChildAt() can be called
     407                 : // by a parent, ensure that the displaystyle attribute of mtable takes precedence
     408                 : NS_IMETHODIMP
     409               0 : nsMathMLmtableOuterFrame::UpdatePresentationData(PRUint32 aFlagsValues,
     410                 :                                                  PRUint32 aWhichFlags)
     411                 : {
     412               0 :   if (NS_MATHML_HAS_EXPLICIT_DISPLAYSTYLE(mPresentationData.flags)) {
     413                 :     // our current state takes precedence, disallow updating the displastyle
     414               0 :     aWhichFlags &= ~NS_MATHML_DISPLAYSTYLE;
     415               0 :     aFlagsValues &= ~NS_MATHML_DISPLAYSTYLE;
     416                 :   }
     417                 : 
     418               0 :   return nsMathMLFrame::UpdatePresentationData(aFlagsValues, aWhichFlags);
     419                 : }
     420                 : 
     421                 : NS_IMETHODIMP
     422               0 : nsMathMLmtableOuterFrame::UpdatePresentationDataFromChildAt(PRInt32  aFirstIndex,
     423                 :                                                             PRInt32  aLastIndex,
     424                 :                                                             PRUint32 aFlagsValues,
     425                 :                                                             PRUint32 aWhichFlags)
     426                 : {
     427               0 :   if (NS_MATHML_HAS_EXPLICIT_DISPLAYSTYLE(mPresentationData.flags)) {
     428                 :     // our current state takes precedence, disallow updating the displastyle
     429               0 :     aWhichFlags &= ~NS_MATHML_DISPLAYSTYLE;
     430               0 :     aFlagsValues &= ~NS_MATHML_DISPLAYSTYLE;
     431                 :   }
     432                 : 
     433                 :   nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(this,
     434               0 :     aFirstIndex, aLastIndex, aFlagsValues, aWhichFlags);
     435                 : 
     436               0 :   return NS_OK; 
     437                 : }
     438                 : 
     439                 : NS_IMETHODIMP
     440               0 : nsMathMLmtableOuterFrame::AttributeChanged(PRInt32  aNameSpaceID,
     441                 :                                            nsIAtom* aAttribute,
     442                 :                                            PRInt32  aModType)
     443                 : {
     444                 :   // Attributes specific to <mtable>:
     445                 :   // frame         : in mathml.css
     446                 :   // framespacing  : not yet supported 
     447                 :   // groupalign    : not yet supported
     448                 :   // equalrows     : not yet supported 
     449                 :   // equalcolumns  : not yet supported 
     450                 :   // displaystyle  : here 
     451                 :   // align         : in reflow 
     452                 :   // rowalign      : here
     453                 :   // rowlines      : here 
     454                 :   // rowspacing    : not yet supported 
     455                 :   // columnalign   : here 
     456                 :   // columnlines   : here 
     457                 :   // columnspacing : not yet supported 
     458                 : 
     459                 :   // mtable is simple and only has one (pseudo) row-group inside our inner-table
     460               0 :   nsIFrame* tableFrame = mFrames.FirstChild();
     461               0 :   NS_ASSERTION(tableFrame && tableFrame->GetType() == nsGkAtoms::tableFrame,
     462                 :                "should always have an inner table frame");
     463               0 :   nsIFrame* rgFrame = tableFrame->GetFirstPrincipalChild();
     464               0 :   if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
     465               0 :     return NS_OK;
     466                 : 
     467                 :   // align - just need to issue a dirty (resize) reflow command
     468               0 :   if (aAttribute == nsGkAtoms::align) {
     469               0 :     PresContext()->PresShell()->
     470               0 :       FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
     471               0 :     return NS_OK;
     472                 :   }
     473                 : 
     474                 :   // displaystyle - may seem innocuous, but it is actually very harsh --
     475                 :   // like changing an unit. Blow away and recompute all our automatic
     476                 :   // presentational data, and issue a style-changed reflow request
     477               0 :   if (aAttribute == nsGkAtoms::displaystyle_) {
     478               0 :     nsMathMLContainerFrame::RebuildAutomaticDataForChildren(mParent);
     479                 :     // Need to reflow the parent, not us, because this can actually
     480                 :     // affect siblings.
     481               0 :     PresContext()->PresShell()->
     482               0 :       FrameNeedsReflow(mParent, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
     483               0 :     return NS_OK;
     484                 :   }
     485                 : 
     486                 :   // ...and the other attributes affect rows or columns in one way or another
     487               0 :   nsIAtom* MOZrowAtom = nsnull;
     488               0 :   nsIAtom* MOZcolAtom = nsnull;
     489               0 :   if (aAttribute == nsGkAtoms::rowalign_)
     490               0 :     MOZrowAtom = nsGkAtoms::_moz_math_rowalign_;
     491               0 :   else if (aAttribute == nsGkAtoms::rowlines_)
     492               0 :     MOZrowAtom = nsGkAtoms::_moz_math_rowline_;
     493               0 :   else if (aAttribute == nsGkAtoms::columnalign_)
     494               0 :     MOZcolAtom = nsGkAtoms::_moz_math_columnalign_;
     495               0 :   else if (aAttribute == nsGkAtoms::columnlines_)
     496               0 :     MOZcolAtom = nsGkAtoms::_moz_math_columnline_;
     497                 : 
     498               0 :   if (!MOZrowAtom && !MOZcolAtom)
     499               0 :     return NS_OK;
     500                 : 
     501               0 :   nsPresContext* presContext = tableFrame->PresContext();
     502                 :   // clear any cached nsValueList for this table
     503                 :   presContext->PropertyTable()->
     504               0 :     Delete(tableFrame, AttributeToProperty(aAttribute));
     505                 : 
     506                 :   // unset any _moz attribute that we may have set earlier, and re-sync
     507               0 :   nsIFrame* rowFrame = rgFrame->GetFirstPrincipalChild();
     508               0 :   for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
     509               0 :     if (rowFrame->GetType() == nsGkAtoms::tableRowFrame) {
     510               0 :       if (MOZrowAtom) { // let rows do the work
     511               0 :         rowFrame->GetContent()->UnsetAttr(kNameSpaceID_None, MOZrowAtom, false);
     512               0 :         MapRowAttributesIntoCSS(tableFrame, rowFrame);    
     513                 :       } else { // let cells do the work
     514               0 :         nsIFrame* cellFrame = rowFrame->GetFirstPrincipalChild();
     515               0 :         for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) {
     516               0 :           if (IS_TABLE_CELL(cellFrame->GetType())) {
     517               0 :             cellFrame->GetContent()->UnsetAttr(kNameSpaceID_None, MOZcolAtom, false);
     518               0 :             MapColAttributesIntoCSS(tableFrame, rowFrame, cellFrame);
     519                 :           }
     520                 :         }
     521                 :       }
     522                 :     }
     523                 :   }
     524                 : 
     525                 :   // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
     526                 :   presContext->PresShell()->FrameConstructor()->
     527                 :     PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
     528               0 :                      nsChangeHint_ReflowFrame);
     529                 : 
     530               0 :   return NS_OK;
     531                 : }
     532                 : 
     533                 : nsIFrame*
     534               0 : nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext,
     535                 :                                         PRInt32         aRowIndex)
     536                 : {
     537                 :   PRInt32 rowCount, colCount;
     538               0 :   GetTableSize(rowCount, colCount);
     539                 : 
     540                 :   // Negative indices mean to find upwards from the end.
     541               0 :   if (aRowIndex < 0) {
     542               0 :     aRowIndex = rowCount + aRowIndex;
     543                 :   } else {
     544                 :     // aRowIndex is 1-based, so convert it to a 0-based index
     545               0 :     --aRowIndex;
     546                 :   }
     547                 : 
     548                 :   // if our inner table says that the index is valid, find the row now
     549               0 :   if (0 <= aRowIndex && aRowIndex <= rowCount) {
     550               0 :     nsIFrame* tableFrame = mFrames.FirstChild();
     551               0 :     NS_ASSERTION(tableFrame && tableFrame->GetType() == nsGkAtoms::tableFrame,
     552                 :                  "should always have an inner table frame");
     553               0 :     nsIFrame* rgFrame = tableFrame->GetFirstPrincipalChild();
     554               0 :     if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
     555               0 :       return nsnull;
     556               0 :     nsTableIterator rowIter(*rgFrame);
     557               0 :     nsIFrame* rowFrame = rowIter.First();
     558               0 :     for ( ; rowFrame; rowFrame = rowIter.Next()) {
     559               0 :       if (aRowIndex == 0) {
     560               0 :         DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW);
     561               0 :         if (rowFrame->GetType() != nsGkAtoms::tableRowFrame)
     562               0 :           return nsnull;
     563                 : 
     564               0 :         return rowFrame;
     565                 :       }
     566               0 :       --aRowIndex;
     567                 :     }
     568                 :   }
     569               0 :   return nsnull;
     570                 : }
     571                 : 
     572                 : NS_IMETHODIMP
     573               0 : nsMathMLmtableOuterFrame::Reflow(nsPresContext*          aPresContext,
     574                 :                                  nsHTMLReflowMetrics&     aDesiredSize,
     575                 :                                  const nsHTMLReflowState& aReflowState,
     576                 :                                  nsReflowStatus&          aStatus)
     577                 : {
     578                 :   nsresult rv;
     579               0 :   nsAutoString value;
     580                 :   // we want to return a table that is anchored according to the align attribute
     581                 : 
     582                 :   rv = nsTableOuterFrame::Reflow(aPresContext, aDesiredSize, aReflowState,
     583               0 :                                  aStatus);
     584               0 :   NS_ASSERTION(aDesiredSize.height >= 0, "illegal height for mtable");
     585               0 :   NS_ASSERTION(aDesiredSize.width >= 0, "illegal width for mtable");
     586                 : 
     587                 :   // see if the user has set the align attribute on the <mtable>
     588                 :   // XXX should we also check <mstyle> ?
     589               0 :   PRInt32 rowIndex = 0;
     590               0 :   eAlign tableAlign = eAlign_axis;
     591               0 :   GetAttribute(mContent, nsnull, nsGkAtoms::align, value);
     592               0 :   if (!value.IsEmpty()) {
     593               0 :     ParseAlignAttribute(value, tableAlign, rowIndex);
     594                 :   }
     595                 : 
     596                 :   // adjustments if there is a specified row from where to anchor the table
     597                 :   // (conceptually: when there is no row of reference, picture the table as if
     598                 :   // it is wrapped in a single big fictional row at dy = 0, this way of
     599                 :   // doing so allows us to have a single code path for all cases).
     600               0 :   nscoord dy = 0;
     601               0 :   nscoord height = aDesiredSize.height;
     602               0 :   nsIFrame* rowFrame = nsnull;
     603               0 :   if (rowIndex) {
     604               0 :     rowFrame = GetRowFrameAt(aPresContext, rowIndex);
     605               0 :     if (rowFrame) {
     606                 :       // translate the coordinates to be relative to us
     607               0 :       nsIFrame* frame = rowFrame;
     608               0 :       height = frame->GetSize().height;
     609               0 :       do {
     610               0 :         dy += frame->GetPosition().y;
     611               0 :         frame = frame->GetParent();
     612                 :       } while (frame != this);
     613                 :     }
     614                 :   }
     615               0 :   switch (tableAlign) {
     616                 :     case eAlign_top:
     617               0 :       aDesiredSize.ascent = dy;
     618               0 :       break;
     619                 :     case eAlign_bottom:
     620               0 :       aDesiredSize.ascent = dy + height;
     621               0 :       break;
     622                 :     case eAlign_center:
     623               0 :       aDesiredSize.ascent = dy + height/2;
     624               0 :       break;
     625                 :     case eAlign_baseline:
     626               0 :       if (rowFrame) {
     627                 :         // anchor the table on the baseline of the row of reference
     628               0 :         nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
     629               0 :         if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
     630               0 :           aDesiredSize.ascent = dy + rowAscent;
     631               0 :           break;
     632                 :         }
     633                 :       }
     634                 :       // in other situations, fallback to center
     635               0 :       aDesiredSize.ascent = dy + height/2;
     636               0 :       break;
     637                 :     case eAlign_axis:
     638                 :     default: {
     639                 :       // XXX should instead use style data from the row of reference here ?
     640               0 :       nsRefPtr<nsFontMetrics> fm;
     641               0 :       nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
     642               0 :       aReflowState.rendContext->SetFont(fm);
     643                 :       nscoord axisHeight;
     644                 :       GetAxisHeight(*aReflowState.rendContext,
     645                 :                     aReflowState.rendContext->FontMetrics(),
     646               0 :                     axisHeight);
     647               0 :       if (rowFrame) {
     648                 :         // anchor the table on the axis of the row of reference
     649                 :         // XXX fallback to baseline because it is a hard problem
     650                 :         // XXX need to fetch the axis of the row; would need rowalign=axis to work better
     651               0 :         nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
     652               0 :         if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
     653               0 :           aDesiredSize.ascent = dy + rowAscent;
     654                 :           break;
     655                 :         }
     656                 :       }
     657                 :       // in other situations, fallback to using half of the height
     658               0 :       aDesiredSize.ascent = dy + height/2 + axisHeight;
     659                 :     }
     660                 :   }
     661                 : 
     662               0 :   mReference.x = 0;
     663               0 :   mReference.y = aDesiredSize.ascent;
     664                 : 
     665                 :   // just make-up a bounding metrics
     666               0 :   mBoundingMetrics = nsBoundingMetrics();
     667               0 :   mBoundingMetrics.ascent = aDesiredSize.ascent;
     668               0 :   mBoundingMetrics.descent = aDesiredSize.height - aDesiredSize.ascent;
     669               0 :   mBoundingMetrics.width = aDesiredSize.width;
     670               0 :   mBoundingMetrics.leftBearing = 0;
     671               0 :   mBoundingMetrics.rightBearing = aDesiredSize.width;
     672                 : 
     673               0 :   aDesiredSize.mBoundingMetrics = mBoundingMetrics;
     674               0 :   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
     675                 : 
     676               0 :   return rv;
     677                 : }
     678                 : 
     679                 : nsIFrame*
     680               0 : NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     681                 : {
     682               0 :   return new (aPresShell) nsMathMLmtableFrame(aContext);
     683                 : }
     684                 : 
     685               0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableFrame)
     686                 : 
     687               0 : nsMathMLmtableFrame::~nsMathMLmtableFrame()
     688                 : {
     689               0 : }
     690                 : 
     691                 : NS_IMETHODIMP
     692               0 : nsMathMLmtableFrame::SetInitialChildList(ChildListID  aListID,
     693                 :                                          nsFrameList& aChildList)
     694                 : {
     695               0 :   nsresult rv = nsTableFrame::SetInitialChildList(aListID, aChildList);
     696               0 :   if (NS_FAILED(rv)) return rv;
     697               0 :   MapAllAttributesIntoCSS(this);
     698               0 :   return rv;
     699                 : }
     700                 : 
     701                 : void
     702               0 : nsMathMLmtableFrame::RestyleTable()
     703                 : {
     704                 :   // re-sync MathML specific style data that may have changed
     705               0 :   MapAllAttributesIntoCSS(this);
     706                 : 
     707                 :   // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
     708                 :   PresContext()->PresShell()->FrameConstructor()->
     709                 :     PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
     710               0 :                      nsChangeHint_ReflowFrame);
     711               0 : }
     712                 : 
     713                 : // --------
     714                 : // implementation of nsMathMLmtrFrame
     715                 : 
     716                 : nsIFrame*
     717               0 : NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     718                 : {
     719               0 :   return new (aPresShell) nsMathMLmtrFrame(aContext);
     720                 : }
     721                 : 
     722               0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtrFrame)
     723                 : 
     724               0 : nsMathMLmtrFrame::~nsMathMLmtrFrame()
     725                 : {
     726               0 : }
     727                 : 
     728                 : NS_IMETHODIMP
     729               0 : nsMathMLmtrFrame::AttributeChanged(PRInt32  aNameSpaceID,
     730                 :                                    nsIAtom* aAttribute,
     731                 :                                    PRInt32  aModType)
     732                 : {
     733                 :   // Attributes specific to <mtr>:
     734                 :   // groupalign  : Not yet supported.
     735                 :   // rowalign    : Fully specified in mathml.css, and so HasAttributeDependentStyle() will
     736                 :   //               pick it up and nsCSSFrameConstructor will issue a PostRestyleEvent().
     737                 :   // columnalign : Need an explicit re-style call.
     738                 : 
     739               0 :   if (aAttribute == nsGkAtoms::rowalign_) {
     740                 :     // unset any _moz attribute that we may have set earlier, and re-sync
     741                 :     mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_rowalign_,
     742               0 :                         false);
     743               0 :     MapRowAttributesIntoCSS(nsTableFrame::GetTableFrame(this), this);
     744                 :     // That's all - see comment above.
     745               0 :     return NS_OK;
     746                 :   }
     747                 : 
     748               0 :   if (aAttribute != nsGkAtoms::columnalign_)
     749               0 :     return NS_OK;
     750                 : 
     751               0 :   nsPresContext* presContext = PresContext();
     752                 :   // Clear any cached columnalign's nsValueList for this row
     753               0 :   presContext->PropertyTable()->Delete(this, AttributeToProperty(aAttribute));
     754                 : 
     755                 :   // Clear any internal _moz attribute that we may have set earlier
     756                 :   // in our cells and re-sync their columnalign attribute
     757               0 :   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
     758               0 :   nsIFrame* cellFrame = GetFirstPrincipalChild();
     759               0 :   for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) {
     760               0 :     if (IS_TABLE_CELL(cellFrame->GetType())) {
     761               0 :       cellFrame->GetContent()->
     762                 :         UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_columnalign_,
     763               0 :                   false);
     764               0 :       MapColAttributesIntoCSS(tableFrame, this, cellFrame);
     765                 :     }
     766                 :   }
     767                 : 
     768                 :   // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
     769                 :   presContext->PresShell()->FrameConstructor()->
     770                 :     PostRestyleEvent(mContent->AsElement(), eRestyle_Subtree,
     771               0 :                      nsChangeHint_ReflowFrame);
     772                 : 
     773               0 :   return NS_OK;
     774                 : }
     775                 : 
     776                 : // --------
     777                 : // implementation of nsMathMLmtdFrame
     778                 : 
     779                 : nsIFrame*
     780               0 : NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     781                 : {
     782               0 :   return new (aPresShell) nsMathMLmtdFrame(aContext);
     783                 : }
     784                 : 
     785               0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdFrame)
     786                 : 
     787               0 : nsMathMLmtdFrame::~nsMathMLmtdFrame()
     788                 : {
     789               0 : }
     790                 : 
     791                 : PRInt32
     792               0 : nsMathMLmtdFrame::GetRowSpan()
     793                 : {
     794               0 :   PRInt32 rowspan = 1;
     795                 : 
     796                 :   // Don't look at the content's rowspan if we're not an mtd or a pseudo cell.
     797               0 :   if ((mContent->Tag() == nsGkAtoms::mtd_) && !GetStyleContext()->GetPseudo()) {
     798               0 :     nsAutoString value;
     799               0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rowspan, value);
     800               0 :     if (!value.IsEmpty()) {
     801                 :       PRInt32 error;
     802               0 :       rowspan = value.ToInteger(&error);
     803               0 :       if (error || rowspan < 0)
     804               0 :         rowspan = 1;
     805               0 :       rowspan = NS_MIN(rowspan, MAX_ROWSPAN);
     806                 :     }
     807                 :   }
     808               0 :   return rowspan;
     809                 : }
     810                 : 
     811                 : PRInt32
     812               0 : nsMathMLmtdFrame::GetColSpan()
     813                 : {
     814               0 :   PRInt32 colspan = 1;
     815                 : 
     816                 :   // Don't look at the content's colspan if we're not an mtd or a pseudo cell.
     817               0 :   if ((mContent->Tag() == nsGkAtoms::mtd_) && !GetStyleContext()->GetPseudo()) {
     818               0 :     nsAutoString value;
     819               0 :     mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::columnspan_, value);
     820               0 :     if (!value.IsEmpty()) {
     821                 :       PRInt32 error;
     822               0 :       colspan = value.ToInteger(&error);
     823               0 :       if (error || colspan < 0 || colspan > MAX_COLSPAN)
     824               0 :         colspan = 1;
     825                 :     }
     826                 :   }
     827               0 :   return colspan;
     828                 : }
     829                 : 
     830                 : NS_IMETHODIMP
     831               0 : nsMathMLmtdFrame::AttributeChanged(PRInt32  aNameSpaceID,
     832                 :                                    nsIAtom* aAttribute,
     833                 :                                    PRInt32  aModType)
     834                 : {
     835                 :   // Attributes specific to <mtd>:
     836                 :   // groupalign  : Not yet supported
     837                 :   // rowalign    : in mathml.css
     838                 :   // columnalign : here
     839                 :   // rowspan     : here
     840                 :   // columnspan  : here
     841                 : 
     842               0 :   if (aAttribute == nsGkAtoms::columnalign_) {
     843                 :     // unset any _moz attribute that we may have set earlier, and re-sync
     844                 :     mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_moz_math_columnalign_,
     845               0 :                         false);
     846               0 :     MapColAttributesIntoCSS(nsTableFrame::GetTableFrame(this), mParent, this);
     847               0 :     return NS_OK;
     848                 :   }
     849                 : 
     850               0 :   if (aAttribute == nsGkAtoms::rowspan ||
     851                 :       aAttribute == nsGkAtoms::columnspan_) {
     852                 :     // use the naming expected by the base class 
     853               0 :     if (aAttribute == nsGkAtoms::columnspan_)
     854               0 :       aAttribute = nsGkAtoms::colspan;
     855               0 :     return nsTableCellFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
     856                 :   }
     857                 : 
     858               0 :   return NS_OK;
     859                 : }
     860                 : 
     861                 : // --------
     862                 : // implementation of nsMathMLmtdInnerFrame
     863                 : 
     864               0 : NS_QUERYFRAME_HEAD(nsMathMLmtdInnerFrame)
     865               0 :   NS_QUERYFRAME_ENTRY(nsIMathMLFrame)
     866               0 : NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame)
     867                 : 
     868                 : nsIFrame*
     869               0 : NS_NewMathMLmtdInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
     870                 : {
     871               0 :   return new (aPresShell) nsMathMLmtdInnerFrame(aContext);
     872                 : }
     873                 : 
     874               0 : NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdInnerFrame)
     875                 : 
     876               0 : nsMathMLmtdInnerFrame::~nsMathMLmtdInnerFrame()
     877                 : {
     878               0 : }
     879                 : 
     880                 : NS_IMETHODIMP
     881               0 : nsMathMLmtdInnerFrame::Reflow(nsPresContext*          aPresContext,
     882                 :                               nsHTMLReflowMetrics&     aDesiredSize,
     883                 :                               const nsHTMLReflowState& aReflowState,
     884                 :                               nsReflowStatus&          aStatus)
     885                 : {
     886                 :   // Let the base class do the reflow
     887               0 :   nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
     888                 : 
     889                 :   // more about <maligngroup/> and <malignmark/> later
     890                 :   // ...
     891               0 :   return rv;
     892                 : }

Generated by: LCOV version 1.7