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
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/
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
15 * The Original Code is Mozilla MathML Project.
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.
23 * Roger B. Sidje <rbs@maths.uq.edu.au>
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.
37 * ***** END LICENSE BLOCK ***** */
41 #include "nsBlockFrame.h"
42 #include "nsPresContext.h"
43 #include "nsStyleContext.h"
44 #include "nsStyleConsts.h"
45 #include "nsINameSpaceManager.h"
46 #include "nsIRenderingContext.h"
47 #include "nsIFontMetrics.h"
50 #include "nsCSSFrameConstructor.h"
51 #include "nsTableOuterFrame.h"
52 #include "nsTableFrame.h"
53 #include "nsTableCellFrame.h"
56 #include "nsMathMLmtableFrame.h"
58 using namespace mozilla
;
61 // <mtable> -- table or matrix - implementation
64 // helper function to perform an in-place split of a space-delimited string,
65 // and return an array of pointers for the beginning of each segment, i.e.,
66 // aOffset[0] is the first string, aOffset[1] is the second string, etc.
67 // Used to parse attributes like columnalign='left right', rowalign='top bottom'
69 SplitString(nsString
& aString
, // [IN/OUT]
70 nsTArray
<PRUnichar
*>& aOffset
) // [OUT]
72 static const PRUnichar kNullCh
= PRUnichar('\0');
74 aString
.Append(kNullCh
); // put an extra null at the end
76 PRUnichar
* start
= aString
.BeginWriting();
77 PRUnichar
* end
= start
;
79 while (kNullCh
!= *start
) {
80 while ((kNullCh
!= *start
) && nsCRT::IsAsciiSpace(*start
)) { // skip leading space
85 while ((kNullCh
!= *end
) && (PR_FALSE
== nsCRT::IsAsciiSpace(*end
))) { // look for space or end
88 *end
= kNullCh
; // end string here
91 aOffset
.AppendElement(start
); // record the beginning of this segment
101 nsTArray
<PRUnichar
*> mArray
;
103 nsValueList(nsString
& aData
) {
105 SplitString(mData
, mArray
);
109 // Each rowalign='top bottom' or columnalign='left right center' (from
110 // <mtable> or <mtr>) is split once (lazily) into a nsValueList which is
111 // stored in the property table. Row/Cell frames query the property table
112 // to see what values apply to them.
114 // XXX See bug 69409 - MathML attributes are not mapped to style.
117 DestroyValueList(void* aPropertyValue
)
119 delete static_cast<nsValueList
*>(aPropertyValue
);
122 NS_DECLARE_FRAME_PROPERTY(RowAlignProperty
, DestroyValueList
)
123 NS_DECLARE_FRAME_PROPERTY(RowLinesProperty
, DestroyValueList
)
124 NS_DECLARE_FRAME_PROPERTY(ColumnAlignProperty
, DestroyValueList
)
125 NS_DECLARE_FRAME_PROPERTY(ColumnLinesProperty
, DestroyValueList
)
127 static const FramePropertyDescriptor
*
128 AttributeToProperty(nsIAtom
* aAttribute
)
130 if (aAttribute
== nsGkAtoms::rowalign_
)
131 return RowAlignProperty();
132 if (aAttribute
== nsGkAtoms::rowlines_
)
133 return RowLinesProperty();
134 if (aAttribute
== nsGkAtoms::columnalign_
)
135 return ColumnAlignProperty();
136 NS_ASSERTION(aAttribute
== nsGkAtoms::columnlines_
, "Invalid attribute");
137 return ColumnLinesProperty();
141 GetValueAt(nsIFrame
* aTableOrRowFrame
,
142 const FramePropertyDescriptor
* aProperty
,
144 PRInt32 aRowOrColIndex
)
146 FrameProperties props
= aTableOrRowFrame
->Properties();
147 nsValueList
* valueList
= static_cast<nsValueList
*>(props
.Get(aProperty
));
149 // The property isn't there yet, so set it
151 aTableOrRowFrame
->GetContent()->GetAttr(kNameSpaceID_None
, aAttribute
, values
);
152 if (!values
.IsEmpty())
153 valueList
= new nsValueList(values
);
154 if (!valueList
|| !valueList
->mArray
.Length()) {
155 delete valueList
; // ok either way, delete is null safe
158 props
.Set(aProperty
, valueList
);
160 PRInt32 count
= valueList
->mArray
.Length();
161 return (aRowOrColIndex
< count
)
162 ? valueList
->mArray
[aRowOrColIndex
]
163 : valueList
->mArray
[count
-1];
168 IsTable(PRUint8 aDisplay
)
170 if ((aDisplay
== NS_STYLE_DISPLAY_TABLE
) ||
171 (aDisplay
== NS_STYLE_DISPLAY_INLINE_TABLE
))
176 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) \
177 NS_ASSERTION(NS_STYLE_DISPLAY_##_expected == _frame->GetStyleDisplay()->mDisplay, "internal error");
178 #define DEBUG_VERIFY_THAT_FRAME_IS_TABLE(_frame) \
179 NS_ASSERTION(IsTable(_frame->GetStyleDisplay()->mDisplay), "internal error");
181 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)
182 #define DEBUG_VERIFY_THAT_FRAME_IS_TABLE(_frame)
185 // map attributes that depend on the index of the row:
186 // rowalign, rowlines, XXX need rowspacing too
188 MapRowAttributesIntoCSS(nsIFrame
* aTableFrame
,
191 DEBUG_VERIFY_THAT_FRAME_IS_TABLE(aTableFrame
);
192 DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame
, TABLE_ROW
);
193 PRInt32 rowIndex
= ((nsTableRowFrame
*)aRowFrame
)->GetRowIndex();
194 nsIContent
* rowContent
= aRowFrame
->GetContent();
197 // see if the rowalign attribute is not already set
198 if (!rowContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::rowalign_
) &&
199 !rowContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_rowalign_
)) {
200 // see if the rowalign attribute was specified on the table
201 attr
= GetValueAt(aTableFrame
, RowAlignProperty(),
202 nsGkAtoms::rowalign_
, rowIndex
);
204 // set our special _moz attribute on the row without notifying a reflow
205 rowContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_rowalign_
,
206 nsDependentString(attr
), PR_FALSE
);
210 // if we are not on the first row, see if |rowlines| was specified on the table.
211 // Note that we pass 'rowIndex-1' because the CSS rule in mathml.css is associated
212 // to 'border-top', and it is as if we draw the line on behalf of the previous cell.
213 // This way of doing so allows us to handle selective lines, [row]\hline[row][row]',
214 // and cases of spanning cells without further complications.
216 !rowContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_rowline_
)) {
217 attr
= GetValueAt(aTableFrame
, RowLinesProperty(),
218 nsGkAtoms::rowlines_
, rowIndex
-1);
220 // set our special _moz attribute on the row without notifying a reflow
221 rowContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_rowline_
,
222 nsDependentString(attr
), PR_FALSE
);
227 // map attributes that depend on the index of the column:
228 // columnalign, columnlines, XXX need columnwidth and columnspacing too
230 MapColAttributesIntoCSS(nsIFrame
* aTableFrame
,
232 nsIFrame
* aCellFrame
)
234 DEBUG_VERIFY_THAT_FRAME_IS_TABLE(aTableFrame
);
235 DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame
, TABLE_ROW
);
236 DEBUG_VERIFY_THAT_FRAME_IS(aCellFrame
, TABLE_CELL
);
237 PRInt32 rowIndex
, colIndex
;
238 ((nsTableCellFrame
*)aCellFrame
)->GetCellIndexes(rowIndex
, colIndex
);
239 nsIContent
* cellContent
= aCellFrame
->GetContent();
242 // see if the columnalign attribute is not already set
243 if (!cellContent
->HasAttr(kNameSpaceID_None
, nsGkAtoms::columnalign_
) &&
244 !cellContent
->HasAttr(kNameSpaceID_None
,
245 nsGkAtoms::_moz_math_columnalign_
)) {
246 // see if the columnalign attribute was specified on the row
247 attr
= GetValueAt(aRowFrame
, ColumnAlignProperty(),
248 nsGkAtoms::columnalign_
, colIndex
);
250 // see if the columnalign attribute was specified on the table
251 attr
= GetValueAt(aTableFrame
, ColumnAlignProperty(),
252 nsGkAtoms::columnalign_
, colIndex
);
255 // set our special _moz attribute without notifying a reflow
256 cellContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_columnalign_
,
257 nsDependentString(attr
), PR_FALSE
);
261 // if we are not on the first column, see if |columnlines| was specified on
262 // the table. Note that we pass 'colIndex-1' because the CSS rule in mathml.css
263 // is associated to 'border-left', and it is as if we draw the line on behalf
264 // of the previous cell. This way of doing so allows us to handle selective lines,
265 // e.g., 'r|cl', and cases of spanning cells without further complications.
267 !cellContent
->HasAttr(kNameSpaceID_None
,
268 nsGkAtoms::_moz_math_columnline_
)) {
269 attr
= GetValueAt(aTableFrame
, ColumnLinesProperty(),
270 nsGkAtoms::columnlines_
, colIndex
-1);
272 // set our special _moz attribute without notifying a reflow
273 cellContent
->SetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_columnline_
,
274 nsDependentString(attr
), PR_FALSE
);
279 // map all attribues within a table -- requires the indices of rows and cells.
280 // so it can only happen after they are made ready by the table base class.
282 MapAllAttributesIntoCSS(nsIFrame
* aTableFrame
)
284 // mtable is simple and only has one (pseudo) row-group
285 nsIFrame
* rgFrame
= aTableFrame
->GetFirstChild(nsnull
);
286 if (!rgFrame
|| rgFrame
->GetType() != nsGkAtoms::tableRowGroupFrame
)
289 nsIFrame
* rowFrame
= rgFrame
->GetFirstChild(nsnull
);
290 for ( ; rowFrame
; rowFrame
= rowFrame
->GetNextSibling()) {
291 DEBUG_VERIFY_THAT_FRAME_IS(rowFrame
, TABLE_ROW
);
292 if (rowFrame
->GetType() == nsGkAtoms::tableRowFrame
) {
293 MapRowAttributesIntoCSS(aTableFrame
, rowFrame
);
294 nsIFrame
* cellFrame
= rowFrame
->GetFirstChild(nsnull
);
295 for ( ; cellFrame
; cellFrame
= cellFrame
->GetNextSibling()) {
296 DEBUG_VERIFY_THAT_FRAME_IS(cellFrame
, TABLE_CELL
);
297 if (IS_TABLE_CELL(cellFrame
->GetType())) {
298 MapColAttributesIntoCSS(aTableFrame
, rowFrame
, cellFrame
);
305 // the align attribute of mtable can have a row number which indicates
306 // from where to anchor the table, e.g., top5 means anchor the table at
307 // the top of the 5th row, axis-1 means anchor the table on the axis of
308 // the last row (could have been nicer if the REC used the '#' separator,
309 // e.g., top#5, or axis#-1)
320 ParseAlignAttribute(nsString
& aValue
, eAlign
& aAlign
, PRInt32
& aRowIndex
)
322 // by default, the table is centered about the axis
324 aAlign
= eAlign_axis
;
326 if (0 == aValue
.Find("top")) {
327 len
= 3; // 3 is the length of 'top'
330 else if (0 == aValue
.Find("bottom")) {
331 len
= 6; // 6 is the length of 'bottom'
332 aAlign
= eAlign_bottom
;
334 else if (0 == aValue
.Find("center")) {
335 len
= 6; // 6 is the length of 'center'
336 aAlign
= eAlign_center
;
338 else if (0 == aValue
.Find("baseline")) {
339 len
= 8; // 8 is the length of 'baseline'
340 aAlign
= eAlign_baseline
;
342 else if (0 == aValue
.Find("axis")) {
343 len
= 4; // 4 is the length of 'axis'
344 aAlign
= eAlign_axis
;
348 aValue
.Cut(0, len
); // aValue is not a const here
349 aRowIndex
= aValue
.ToInteger(&error
);
356 // call ListMathMLTree(mParent) to get the big picture
358 ListMathMLTree(nsIFrame
* atLeast
)
360 // climb up to <math> or <body> if <math> isn't there
361 nsIFrame
* f
= atLeast
;
362 for ( ; f
; f
= f
->GetParent()) {
363 nsIContent
* c
= f
->GetContent();
364 if (!c
|| c
->Tag() == nsGkAtoms::math
|| c
->Tag() == nsGkAtoms::body
)
373 // implementation of nsMathMLmtableOuterFrame
375 NS_QUERYFRAME_HEAD(nsMathMLmtableOuterFrame
)
376 NS_QUERYFRAME_ENTRY(nsIMathMLFrame
)
377 NS_QUERYFRAME_TAIL_INHERITING(nsTableOuterFrame
)
380 NS_NewMathMLmtableOuterFrame (nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
382 return new (aPresShell
) nsMathMLmtableOuterFrame(aContext
);
385 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableOuterFrame
)
387 nsMathMLmtableOuterFrame::~nsMathMLmtableOuterFrame()
392 nsMathMLmtableOuterFrame::InheritAutomaticData(nsIFrame
* aParent
)
394 // XXX the REC says that by default, displaystyle=false in <mtable>
396 // let the base class inherit the displaystyle from our parent
397 nsMathMLFrame::InheritAutomaticData(aParent
);
399 // see if the displaystyle attribute is there and let it override what we inherited
400 if (mContent
->Tag() == nsGkAtoms::mtable_
)
401 nsMathMLFrame::FindAttrDisplaystyle(mContent
, mPresentationData
);
406 // displaystyle is special in mtable...
407 // Since UpdatePresentation() and UpdatePresentationDataFromChildAt() can be called
408 // by a parent, ensure that the displaystyle attribute of mtable takes precedence
410 nsMathMLmtableOuterFrame::UpdatePresentationData(PRUint32 aFlagsValues
,
411 PRUint32 aWhichFlags
)
413 if (NS_MATHML_HAS_EXPLICIT_DISPLAYSTYLE(mPresentationData
.flags
)) {
414 // our current state takes precedence, disallow updating the displastyle
415 aWhichFlags
&= ~NS_MATHML_DISPLAYSTYLE
;
416 aFlagsValues
&= ~NS_MATHML_DISPLAYSTYLE
;
419 return nsMathMLFrame::UpdatePresentationData(aFlagsValues
, aWhichFlags
);
423 nsMathMLmtableOuterFrame::UpdatePresentationDataFromChildAt(PRInt32 aFirstIndex
,
425 PRUint32 aFlagsValues
,
426 PRUint32 aWhichFlags
)
428 if (NS_MATHML_HAS_EXPLICIT_DISPLAYSTYLE(mPresentationData
.flags
)) {
429 // our current state takes precedence, disallow updating the displastyle
430 aWhichFlags
&= ~NS_MATHML_DISPLAYSTYLE
;
431 aFlagsValues
&= ~NS_MATHML_DISPLAYSTYLE
;
434 nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(this,
435 aFirstIndex
, aLastIndex
, aFlagsValues
, aWhichFlags
);
441 nsMathMLmtableOuterFrame::AttributeChanged(PRInt32 aNameSpaceID
,
445 // Attributes specific to <mtable>:
446 // frame : in mathml.css
447 // framespacing : not yet supported
448 // groupalign : not yet supported
449 // equalrows : not yet supported
450 // equalcolumns : not yet supported
451 // displaystyle : here
455 // rowspacing : not yet supported
456 // columnalign : here
457 // columnlines : here
458 // columnspacing : not yet supported
460 // mtable is simple and only has one (pseudo) row-group inside our inner-table
461 nsIFrame
* tableFrame
= mFrames
.FirstChild();
462 if (!tableFrame
|| tableFrame
->GetType() != nsGkAtoms::tableFrame
)
464 nsIFrame
* rgFrame
= tableFrame
->GetFirstChild(nsnull
);
465 if (!rgFrame
|| rgFrame
->GetType() != nsGkAtoms::tableRowGroupFrame
)
468 // align - just need to issue a dirty (resize) reflow command
469 if (aAttribute
== nsGkAtoms::align
) {
470 PresContext()->PresShell()->
471 FrameNeedsReflow(this, nsIPresShell::eResize
, NS_FRAME_IS_DIRTY
);
475 // displaystyle - may seem innocuous, but it is actually very harsh --
476 // like changing an unit. Blow away and recompute all our automatic
477 // presentational data, and issue a style-changed reflow request
478 if (aAttribute
== nsGkAtoms::displaystyle_
) {
479 nsMathMLContainerFrame::RebuildAutomaticDataForChildren(mParent
);
480 // Need to reflow the parent, not us, because this can actually
482 PresContext()->PresShell()->
483 FrameNeedsReflow(mParent
, nsIPresShell::eStyleChange
, NS_FRAME_IS_DIRTY
);
487 // ...and the other attributes affect rows or columns in one way or another
488 nsIAtom
* MOZrowAtom
= nsnull
;
489 nsIAtom
* MOZcolAtom
= nsnull
;
490 if (aAttribute
== nsGkAtoms::rowalign_
)
491 MOZrowAtom
= nsGkAtoms::_moz_math_rowalign_
;
492 else if (aAttribute
== nsGkAtoms::rowlines_
)
493 MOZrowAtom
= nsGkAtoms::_moz_math_rowline_
;
494 else if (aAttribute
== nsGkAtoms::columnalign_
)
495 MOZcolAtom
= nsGkAtoms::_moz_math_columnalign_
;
496 else if (aAttribute
== nsGkAtoms::columnlines_
)
497 MOZcolAtom
= nsGkAtoms::_moz_math_columnline_
;
499 if (!MOZrowAtom
&& !MOZcolAtom
)
502 nsPresContext
* presContext
= tableFrame
->PresContext();
503 // clear any cached nsValueList for this table
504 presContext
->PropertyTable()->
505 Delete(tableFrame
, AttributeToProperty(aAttribute
));
507 // unset any _moz attribute that we may have set earlier, and re-sync
508 nsIFrame
* rowFrame
= rgFrame
->GetFirstChild(nsnull
);
509 for ( ; rowFrame
; rowFrame
= rowFrame
->GetNextSibling()) {
510 if (rowFrame
->GetType() == nsGkAtoms::tableRowFrame
) {
511 if (MOZrowAtom
) { // let rows do the work
512 rowFrame
->GetContent()->UnsetAttr(kNameSpaceID_None
, MOZrowAtom
, PR_FALSE
);
513 MapRowAttributesIntoCSS(tableFrame
, rowFrame
);
514 } else { // let cells do the work
515 nsIFrame
* cellFrame
= rowFrame
->GetFirstChild(nsnull
);
516 for ( ; cellFrame
; cellFrame
= cellFrame
->GetNextSibling()) {
517 if (IS_TABLE_CELL(cellFrame
->GetType())) {
518 cellFrame
->GetContent()->UnsetAttr(kNameSpaceID_None
, MOZcolAtom
, PR_FALSE
);
519 MapColAttributesIntoCSS(tableFrame
, rowFrame
, cellFrame
);
526 // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
527 presContext
->PresShell()->FrameConstructor()->
528 PostRestyleEvent(mContent
->AsElement(), eRestyle_Subtree
,
529 nsChangeHint_ReflowFrame
);
535 nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext
* aPresContext
,
538 PRInt32 rowCount
, colCount
;
539 GetTableSize(rowCount
, colCount
);
541 // Negative indices mean to find upwards from the end.
543 aRowIndex
= rowCount
+ aRowIndex
;
545 // aRowIndex is 1-based, so convert it to a 0-based index
548 // if our inner table says that the index is valid, find the row now
549 if (0 <= aRowIndex
&& aRowIndex
<= rowCount
) {
550 nsIFrame
* tableFrame
= mFrames
.FirstChild();
551 if (!tableFrame
|| tableFrame
->GetType() != nsGkAtoms::tableFrame
)
553 nsIFrame
* rgFrame
= tableFrame
->GetFirstChild(nsnull
);
554 if (!rgFrame
|| rgFrame
->GetType() != nsGkAtoms::tableRowGroupFrame
)
556 nsTableIterator
rowIter(*rgFrame
);
557 nsIFrame
* rowFrame
= rowIter
.First();
558 for ( ; rowFrame
; rowFrame
= rowIter
.Next()) {
559 if (aRowIndex
== 0) {
560 DEBUG_VERIFY_THAT_FRAME_IS(rowFrame
, TABLE_ROW
);
561 if (rowFrame
->GetType() != nsGkAtoms::tableRowFrame
)
573 nsMathMLmtableOuterFrame::Reflow(nsPresContext
* aPresContext
,
574 nsHTMLReflowMetrics
& aDesiredSize
,
575 const nsHTMLReflowState
& aReflowState
,
576 nsReflowStatus
& aStatus
)
580 // we want to return a table that is anchored according to the align attribute
582 rv
= nsTableOuterFrame::Reflow(aPresContext
, aDesiredSize
, aReflowState
,
584 NS_ASSERTION(aDesiredSize
.height
>= 0, "illegal height for mtable");
585 NS_ASSERTION(aDesiredSize
.width
>= 0, "illegal width for mtable");
587 // see if the user has set the align attribute on the <mtable>
588 // XXX should we also check <mstyle> ?
589 PRInt32 rowIndex
= 0;
590 eAlign tableAlign
= eAlign_axis
;
591 GetAttribute(mContent
, nsnull
, nsGkAtoms::align
, value
);
592 if (!value
.IsEmpty()) {
593 ParseAlignAttribute(value
, tableAlign
, rowIndex
);
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).
601 nscoord height
= aDesiredSize
.height
;
602 nsIFrame
* rowFrame
= nsnull
;
604 rowFrame
= GetRowFrameAt(aPresContext
, rowIndex
);
606 // translate the coordinates to be relative to us
607 nsIFrame
* frame
= rowFrame
;
608 height
= frame
->GetSize().height
;
610 dy
+= frame
->GetPosition().y
;
611 frame
= frame
->GetParent();
612 } while (frame
!= this);
615 switch (tableAlign
) {
617 aDesiredSize
.ascent
= dy
;
620 aDesiredSize
.ascent
= dy
+ height
;
623 aDesiredSize
.ascent
= dy
+ height
/2;
625 case eAlign_baseline
:
627 // anchor the table on the baseline of the row of reference
628 nscoord rowAscent
= ((nsTableRowFrame
*)rowFrame
)->GetMaxCellAscent();
629 if (rowAscent
) { // the row has at least one cell with 'vertical-align: baseline'
630 aDesiredSize
.ascent
= dy
+ rowAscent
;
634 // in other situations, fallback to center
635 aDesiredSize
.ascent
= dy
+ height
/2;
639 // XXX should instead use style data from the row of reference here ?
640 aReflowState
.rendContext
->SetFont(GetStyleFont()->mFont
,
641 aPresContext
->GetUserFontSet());
642 nsCOMPtr
<nsIFontMetrics
> fm
;
643 aReflowState
.rendContext
->GetFontMetrics(*getter_AddRefs(fm
));
645 GetAxisHeight(*aReflowState
.rendContext
, fm
, axisHeight
);
647 // anchor the table on the axis of the row of reference
648 // XXX fallback to baseline because it is a hard problem
649 // XXX need to fetch the axis of the row; would need rowalign=axis to work better
650 nscoord rowAscent
= ((nsTableRowFrame
*)rowFrame
)->GetMaxCellAscent();
651 if (rowAscent
) { // the row has at least one cell with 'vertical-align: baseline'
652 aDesiredSize
.ascent
= dy
+ rowAscent
;
656 // in other situations, fallback to using half of the height
657 aDesiredSize
.ascent
= dy
+ height
/2 + axisHeight
;
662 mReference
.y
= aDesiredSize
.ascent
;
664 // just make-up a bounding metrics
665 mBoundingMetrics
.Clear();
666 mBoundingMetrics
.ascent
= aDesiredSize
.ascent
;
667 mBoundingMetrics
.descent
= aDesiredSize
.height
- aDesiredSize
.ascent
;
668 mBoundingMetrics
.width
= aDesiredSize
.width
;
669 mBoundingMetrics
.leftBearing
= 0;
670 mBoundingMetrics
.rightBearing
= aDesiredSize
.width
;
672 aDesiredSize
.mBoundingMetrics
= mBoundingMetrics
;
673 NS_FRAME_SET_TRUNCATION(aStatus
, aReflowState
, aDesiredSize
);
679 NS_NewMathMLmtableFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
681 return new (aPresShell
) nsMathMLmtableFrame(aContext
);
684 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtableFrame
)
686 nsMathMLmtableFrame::~nsMathMLmtableFrame()
691 nsMathMLmtableFrame::SetInitialChildList(nsIAtom
* aListName
,
692 nsFrameList
& aChildList
)
694 nsresult rv
= nsTableFrame::SetInitialChildList(aListName
, aChildList
);
695 if (NS_FAILED(rv
)) return rv
;
696 MapAllAttributesIntoCSS(this);
701 nsMathMLmtableFrame::RestyleTable()
703 // re-sync MathML specific style data that may have changed
704 MapAllAttributesIntoCSS(this);
706 // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
707 PresContext()->PresShell()->FrameConstructor()->
708 PostRestyleEvent(mContent
->AsElement(), eRestyle_Subtree
,
709 nsChangeHint_ReflowFrame
);
713 // implementation of nsMathMLmtrFrame
716 NS_NewMathMLmtrFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
718 return new (aPresShell
) nsMathMLmtrFrame(aContext
);
721 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtrFrame
)
723 nsMathMLmtrFrame::~nsMathMLmtrFrame()
728 nsMathMLmtrFrame::AttributeChanged(PRInt32 aNameSpaceID
,
732 // Attributes specific to <mtr>:
733 // groupalign : Not yet supported.
734 // rowalign : Fully specified in mathml.css, and so HasAttributeDependentStyle() will
735 // pick it up and nsCSSFrameConstructor will issue a PostRestyleEvent().
736 // columnalign : Need an explicit re-style call.
738 if (aAttribute
== nsGkAtoms::rowalign_
) {
739 // unset any _moz attribute that we may have set earlier, and re-sync
740 mContent
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_rowalign_
,
742 MapRowAttributesIntoCSS(nsTableFrame::GetTableFrame(this), this);
743 // That's all - see comment above.
747 if (aAttribute
!= nsGkAtoms::columnalign_
)
750 nsPresContext
* presContext
= PresContext();
751 // Clear any cached columnalign's nsValueList for this row
752 presContext
->PropertyTable()->Delete(this, AttributeToProperty(aAttribute
));
754 // Clear any internal _moz attribute that we may have set earlier
755 // in our cells and re-sync their columnalign attribute
756 nsTableFrame
* tableFrame
= nsTableFrame::GetTableFrame(this);
757 nsIFrame
* cellFrame
= GetFirstChild(nsnull
);
758 for ( ; cellFrame
; cellFrame
= cellFrame
->GetNextSibling()) {
759 if (IS_TABLE_CELL(cellFrame
->GetType())) {
760 cellFrame
->GetContent()->
761 UnsetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_columnalign_
,
763 MapColAttributesIntoCSS(tableFrame
, this, cellFrame
);
767 // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
768 presContext
->PresShell()->FrameConstructor()->
769 PostRestyleEvent(mContent
->AsElement(), eRestyle_Subtree
,
770 nsChangeHint_ReflowFrame
);
776 // implementation of nsMathMLmtdFrame
779 NS_NewMathMLmtdFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
781 return new (aPresShell
) nsMathMLmtdFrame(aContext
);
784 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdFrame
)
786 nsMathMLmtdFrame::~nsMathMLmtdFrame()
791 nsMathMLmtdFrame::GetRowSpan()
795 // Don't look at the content's rowspan if we're not an mtd or a pseudo cell.
796 if ((mContent
->Tag() == nsGkAtoms::mtd_
) && !GetStyleContext()->GetPseudo()) {
798 mContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::rowspan
, value
);
799 if (!value
.IsEmpty()) {
801 rowspan
= value
.ToInteger(&error
);
802 if (error
|| rowspan
< 0)
804 rowspan
= NS_MIN(rowspan
, MAX_ROWSPAN
);
811 nsMathMLmtdFrame::GetColSpan()
815 // Don't look at the content's colspan if we're not an mtd or a pseudo cell.
816 if ((mContent
->Tag() == nsGkAtoms::mtd_
) && !GetStyleContext()->GetPseudo()) {
818 mContent
->GetAttr(kNameSpaceID_None
, nsGkAtoms::columnspan_
, value
);
819 if (!value
.IsEmpty()) {
821 colspan
= value
.ToInteger(&error
);
822 if (error
|| colspan
< 0 || colspan
> MAX_COLSPAN
)
830 nsMathMLmtdFrame::AttributeChanged(PRInt32 aNameSpaceID
,
834 // Attributes specific to <mtd>:
835 // groupalign : Not yet supported
836 // rowalign : in mathml.css
837 // columnalign : here
841 if (aAttribute
== nsGkAtoms::columnalign_
) {
842 // unset any _moz attribute that we may have set earlier, and re-sync
843 mContent
->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::_moz_math_columnalign_
,
845 MapColAttributesIntoCSS(nsTableFrame::GetTableFrame(this), mParent
, this);
849 if (aAttribute
== nsGkAtoms::rowspan
||
850 aAttribute
== nsGkAtoms::columnspan_
) {
851 // use the naming expected by the base class
852 if (aAttribute
== nsGkAtoms::columnspan_
)
853 aAttribute
= nsGkAtoms::colspan
;
854 return nsTableCellFrame::AttributeChanged(aNameSpaceID
, aAttribute
, aModType
);
861 // implementation of nsMathMLmtdInnerFrame
863 NS_QUERYFRAME_HEAD(nsMathMLmtdInnerFrame
)
864 NS_QUERYFRAME_ENTRY(nsIMathMLFrame
)
865 NS_QUERYFRAME_TAIL_INHERITING(nsBlockFrame
)
868 NS_NewMathMLmtdInnerFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
870 return new (aPresShell
) nsMathMLmtdInnerFrame(aContext
);
873 NS_IMPL_FRAMEARENA_HELPERS(nsMathMLmtdInnerFrame
)
875 nsMathMLmtdInnerFrame::~nsMathMLmtdInnerFrame()
880 nsMathMLmtdInnerFrame::Reflow(nsPresContext
* aPresContext
,
881 nsHTMLReflowMetrics
& aDesiredSize
,
882 const nsHTMLReflowState
& aReflowState
,
883 nsReflowStatus
& aStatus
)
885 // Let the base class do the reflow
886 nsresult rv
= nsBlockFrame::Reflow(aPresContext
, aDesiredSize
, aReflowState
, aStatus
);
888 // more about <maligngroup/> and <malignmark/> later