Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / layout / mathml / base / src / nsMathMLmtableFrame.cpp
blob7dfd23751321a80a78c9b6d00b04e66e95257def
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
13 * License.
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.
22 * Contributor(s):
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 ***** */
39 #include "nsCOMPtr.h"
40 #include "nsFrame.h"
41 #include "nsAreaFrame.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"
49 #include "nsVoidArray.h"
50 #include "nsCSSFrameConstructor.h"
51 #include "nsTableOuterFrame.h"
52 #include "nsTableFrame.h"
53 #include "nsTableCellFrame.h"
54 #include "celldata.h"
56 #include "nsMathMLmtableFrame.h"
59 // <mtable> -- table or matrix - implementation
62 // helper function to perform an in-place split of a space-delimited string,
63 // and return an array of pointers for the beginning of each segment, i.e.,
64 // aOffset[0] is the first string, aOffset[1] is the second string, etc.
65 // Used to parse attributes like columnalign='left right', rowalign='top bottom'
66 static void
67 SplitString(nsString& aString, // [IN/OUT]
68 nsVoidArray& aOffset) // [OUT]
70 static const PRUnichar kNullCh = PRUnichar('\0');
72 aString.Append(kNullCh); // put an extra null at the end
74 PRUnichar* start = aString.BeginWriting();
75 PRUnichar* end = start;
77 while (kNullCh != *start) {
78 while ((kNullCh != *start) && nsCRT::IsAsciiSpace(*start)) { // skip leading space
79 start++;
81 end = start;
83 while ((kNullCh != *end) && (PR_FALSE == nsCRT::IsAsciiSpace(*end))) { // look for space or end
84 end++;
86 *end = kNullCh; // end string here
88 if (start < end) {
89 aOffset.AppendElement(start); // record the beginning of this segment
92 start = ++end;
96 struct nsValueList
98 nsString mData;
99 nsVoidArray mArray;
101 nsValueList(nsString& aData) {
102 mData.Assign(aData);
103 SplitString(mData, mArray);
107 // Each rowalign='top bottom' or columnalign='left right center' (from
108 // <mtable> or <mtr>) is split once (lazily) into a nsValueList which is
109 // stored in the property table. Row/Cell frames query the property table
110 // to see what values apply to them.
112 // XXX See bug 69409 - MathML attributes are not mapped to style.
114 static void
115 DestroyValueListFunc(void* aFrame,
116 nsIAtom* aPropertyName,
117 void* aPropertyValue,
118 void* aDtorData)
120 delete static_cast<nsValueList*>(aPropertyValue);
123 static PRUnichar*
124 GetValueAt(nsIFrame* aTableOrRowFrame,
125 nsIAtom* aAttribute,
126 PRInt32 aRowOrColIndex)
128 nsValueList* valueList = static_cast<nsValueList*>
129 (aTableOrRowFrame->GetProperty(aAttribute));
130 if (!valueList) {
131 // The property isn't there yet, so set it
132 nsAutoString values;
133 aTableOrRowFrame->GetContent()->GetAttr(kNameSpaceID_None, aAttribute, values);
134 if (!values.IsEmpty())
135 valueList = new nsValueList(values);
136 if (!valueList || !valueList->mArray.Count()) {
137 delete valueList; // ok either way, delete is null safe
138 return nsnull;
140 aTableOrRowFrame->SetProperty(aAttribute, valueList, DestroyValueListFunc);
142 PRInt32 count = valueList->mArray.Count();
143 return (aRowOrColIndex < count)
144 ? (PRUnichar*)(valueList->mArray[aRowOrColIndex])
145 : (PRUnichar*)(valueList->mArray[count-1]);
148 #ifdef NS_DEBUG
149 static PRBool
150 IsTable(PRUint8 aDisplay)
152 if ((aDisplay == NS_STYLE_DISPLAY_TABLE) ||
153 (aDisplay == NS_STYLE_DISPLAY_INLINE_TABLE))
154 return PR_TRUE;
155 return PR_FALSE;
158 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected) \
159 NS_ASSERTION(NS_STYLE_DISPLAY_##_expected == _frame->GetStyleDisplay()->mDisplay, "internal error");
160 #define DEBUG_VERIFY_THAT_FRAME_IS_TABLE(_frame) \
161 NS_ASSERTION(IsTable(_frame->GetStyleDisplay()->mDisplay), "internal error");
162 #else
163 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)
164 #define DEBUG_VERIFY_THAT_FRAME_IS_TABLE(_frame)
165 #endif
167 // map attributes that depend on the index of the row:
168 // rowalign, rowlines, XXX need rowspacing too
169 static void
170 MapRowAttributesIntoCSS(nsIFrame* aTableFrame,
171 nsIFrame* aRowFrame)
173 DEBUG_VERIFY_THAT_FRAME_IS_TABLE(aTableFrame);
174 DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame, TABLE_ROW);
175 PRInt32 rowIndex = ((nsTableRowFrame*)aRowFrame)->GetRowIndex();
176 nsIContent* rowContent = aRowFrame->GetContent();
177 PRUnichar* attr;
179 // see if the rowalign attribute is not already set
180 if (!rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::rowalign_) &&
181 !rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::MOZrowalign)) {
182 // see if the rowalign attribute was specified on the table
183 attr = GetValueAt(aTableFrame, nsGkAtoms::rowalign_, rowIndex);
184 if (attr) {
185 // set our special -moz attribute on the row without notifying a reflow
186 rowContent->SetAttr(kNameSpaceID_None, nsGkAtoms::MOZrowalign,
187 nsDependentString(attr), PR_FALSE);
191 // if we are not on the first row, see if |rowlines| was specified on the table.
192 // Note that we pass 'rowIndex-1' because the CSS rule in mathml.css is associated
193 // to 'border-top', and it is as if we draw the line on behalf of the previous cell.
194 // This way of doing so allows us to handle selective lines, [row]\hline[row][row]',
195 // and cases of spanning cells without further complications.
196 if (rowIndex > 0 &&
197 !rowContent->HasAttr(kNameSpaceID_None, nsGkAtoms::MOZrowline)) {
198 attr = GetValueAt(aTableFrame, nsGkAtoms::rowlines_, rowIndex-1);
199 if (attr) {
200 // set our special -moz attribute on the row without notifying a reflow
201 rowContent->SetAttr(kNameSpaceID_None, nsGkAtoms::MOZrowline,
202 nsDependentString(attr), PR_FALSE);
207 // map attributes that depend on the index of the column:
208 // columnalign, columnlines, XXX need columnwidth and columnspacing too
209 static void
210 MapColAttributesIntoCSS(nsIFrame* aTableFrame,
211 nsIFrame* aRowFrame,
212 nsIFrame* aCellFrame)
214 DEBUG_VERIFY_THAT_FRAME_IS_TABLE(aTableFrame);
215 DEBUG_VERIFY_THAT_FRAME_IS(aRowFrame, TABLE_ROW);
216 DEBUG_VERIFY_THAT_FRAME_IS(aCellFrame, TABLE_CELL);
217 PRInt32 rowIndex, colIndex;
218 ((nsTableCellFrame*)aCellFrame)->GetCellIndexes(rowIndex, colIndex);
219 nsIContent* cellContent = aCellFrame->GetContent();
220 PRUnichar* attr;
222 // see if the columnalign attribute is not already set
223 if (!cellContent->HasAttr(kNameSpaceID_None, nsGkAtoms::columnalign_) &&
224 !cellContent->HasAttr(kNameSpaceID_None, nsGkAtoms::MOZcolumnalign)) {
225 // see if the columnalign attribute was specified on the row
226 attr = GetValueAt(aRowFrame, nsGkAtoms::columnalign_, colIndex);
227 if (!attr) {
228 // see if the columnalign attribute was specified on the table
229 attr = GetValueAt(aTableFrame, nsGkAtoms::columnalign_, colIndex);
231 if (attr) {
232 // set our special -moz attribute without notifying a reflow
233 cellContent->SetAttr(kNameSpaceID_None, nsGkAtoms::MOZcolumnalign,
234 nsDependentString(attr), PR_FALSE);
238 // if we are not on the first column, see if |columnlines| was specified on
239 // the table. Note that we pass 'colIndex-1' because the CSS rule in mathml.css
240 // is associated to 'border-left', and it is as if we draw the line on behalf
241 // of the previous cell. This way of doing so allows us to handle selective lines,
242 // e.g., 'r|cl', and cases of spanning cells without further complications.
243 if (colIndex > 0 &&
244 !cellContent->HasAttr(kNameSpaceID_None, nsGkAtoms::MOZcolumnline)) {
245 attr = GetValueAt(aTableFrame, nsGkAtoms::columnlines_, colIndex-1);
246 if (attr) {
247 // set our special -moz attribute without notifying a reflow
248 cellContent->SetAttr(kNameSpaceID_None, nsGkAtoms::MOZcolumnline,
249 nsDependentString(attr), PR_FALSE);
254 // map all attribues within a table -- requires the indices of rows and cells.
255 // so it can only happen after they are made ready by the table base class.
256 static void
257 MapAllAttributesIntoCSS(nsIFrame* aTableFrame)
259 // mtable is simple and only has one (pseudo) row-group
260 nsIFrame* rgFrame = aTableFrame->GetFirstChild(nsnull);
261 if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
262 return;
264 nsIFrame* rowFrame = rgFrame->GetFirstChild(nsnull);
265 for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
266 DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW);
267 if (rowFrame->GetType() == nsGkAtoms::tableRowFrame) {
268 MapRowAttributesIntoCSS(aTableFrame, rowFrame);
269 nsIFrame* cellFrame = rowFrame->GetFirstChild(nsnull);
270 for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) {
271 DEBUG_VERIFY_THAT_FRAME_IS(cellFrame, TABLE_CELL);
272 if (IS_TABLE_CELL(cellFrame->GetType())) {
273 MapColAttributesIntoCSS(aTableFrame, rowFrame, cellFrame);
280 // the align attribute of mtable can have a row number which indicates
281 // from where to anchor the table, e.g., top5 means anchor the table at
282 // the top of the 5th row, axis-1 means anchor the table on the axis of
283 // the last row (could have been nicer if the REC used the '#' separator,
284 // e.g., top#5, or axis#-1)
286 enum eAlign {
287 eAlign_top,
288 eAlign_bottom,
289 eAlign_center,
290 eAlign_baseline,
291 eAlign_axis
294 static void
295 ParseAlignAttribute(nsString& aValue, eAlign& aAlign, PRInt32& aRowIndex)
297 // by default, the table is centered about the axis
298 aRowIndex = 0;
299 aAlign = eAlign_axis;
300 PRInt32 len = 0;
301 if (0 == aValue.Find("top")) {
302 len = 3; // 3 is the length of 'top'
303 aAlign = eAlign_top;
305 else if (0 == aValue.Find("bottom")) {
306 len = 6; // 6 is the length of 'bottom'
307 aAlign = eAlign_bottom;
309 else if (0 == aValue.Find("center")) {
310 len = 6; // 6 is the length of 'center'
311 aAlign = eAlign_center;
313 else if (0 == aValue.Find("baseline")) {
314 len = 8; // 8 is the length of 'baseline'
315 aAlign = eAlign_baseline;
317 else if (0 == aValue.Find("axis")) {
318 len = 4; // 4 is the length of 'axis'
319 aAlign = eAlign_axis;
321 if (len) {
322 PRInt32 error;
323 aValue.Cut(0, len); // aValue is not a const here
324 aRowIndex = aValue.ToInteger(&error);
325 if (error)
326 aRowIndex = 0;
330 #ifdef DEBUG_rbs_off
331 // call ListMathMLTree(mParent) to get the big picture
332 static void
333 ListMathMLTree(nsIFrame* atLeast)
335 // climb up to <math> or <body> if <math> isn't there
336 nsIFrame* f = atLeast;
337 for ( ; f; f = f->GetParent()) {
338 nsIContent* c = f->GetContent();
339 if (!c || c->Tag() == nsGkAtoms::math || c->Tag() == nsGkAtoms::body)
340 break;
342 if (!f) f = atLeast;
343 nsIFrameDebug* fdbg;
344 CallQueryInterface(f, &fdbg);
345 fdbg->List(stdout, 0);
347 #endif
349 // --------
350 // implementation of nsMathMLmtableOuterFrame
352 NS_IMPL_ADDREF_INHERITED(nsMathMLmtableOuterFrame, nsMathMLFrame)
353 NS_IMPL_RELEASE_INHERITED(nsMathMLmtableOuterFrame, nsMathMLFrame)
354 NS_IMPL_QUERY_INTERFACE_INHERITED1(nsMathMLmtableOuterFrame, nsTableOuterFrame, nsMathMLFrame)
356 nsIFrame*
357 NS_NewMathMLmtableOuterFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
359 return new (aPresShell) nsMathMLmtableOuterFrame(aContext);
362 nsMathMLmtableOuterFrame::~nsMathMLmtableOuterFrame()
366 NS_IMETHODIMP
367 nsMathMLmtableOuterFrame::InheritAutomaticData(nsIFrame* aParent)
369 // XXX the REC says that by default, displaystyle=false in <mtable>
371 // let the base class inherit the displaystyle from our parent
372 nsMathMLFrame::InheritAutomaticData(aParent);
374 // see if the displaystyle attribute is there and let it override what we inherited
375 if (mContent->Tag() == nsGkAtoms::mtable_)
376 nsMathMLFrame::FindAttrDisplaystyle(mContent, mPresentationData);
378 return NS_OK;
381 // displaystyle is special in mtable...
382 // Since UpdatePresentation() and UpdatePresentationDataFromChildAt() can be called
383 // by a parent, ensure that the displaystyle attribute of mtable takes precedence
384 NS_IMETHODIMP
385 nsMathMLmtableOuterFrame::UpdatePresentationData(PRUint32 aFlagsValues,
386 PRUint32 aWhichFlags)
388 if (NS_MATHML_HAS_EXPLICIT_DISPLAYSTYLE(mPresentationData.flags)) {
389 // our current state takes precedence, disallow updating the displastyle
390 aWhichFlags &= ~NS_MATHML_DISPLAYSTYLE;
391 aFlagsValues &= ~NS_MATHML_DISPLAYSTYLE;
394 return nsMathMLFrame::UpdatePresentationData(aFlagsValues, aWhichFlags);
397 NS_IMETHODIMP
398 nsMathMLmtableOuterFrame::UpdatePresentationDataFromChildAt(PRInt32 aFirstIndex,
399 PRInt32 aLastIndex,
400 PRUint32 aFlagsValues,
401 PRUint32 aWhichFlags)
403 if (NS_MATHML_HAS_EXPLICIT_DISPLAYSTYLE(mPresentationData.flags)) {
404 // our current state takes precedence, disallow updating the displastyle
405 aWhichFlags &= ~NS_MATHML_DISPLAYSTYLE;
406 aFlagsValues &= ~NS_MATHML_DISPLAYSTYLE;
409 nsMathMLContainerFrame::PropagatePresentationDataFromChildAt(this,
410 aFirstIndex, aLastIndex, aFlagsValues, aWhichFlags);
412 return NS_OK;
415 NS_IMETHODIMP
416 nsMathMLmtableOuterFrame::AttributeChanged(PRInt32 aNameSpaceID,
417 nsIAtom* aAttribute,
418 PRInt32 aModType)
420 // Attributes specific to <mtable>:
421 // frame : in mathml.css
422 // framespacing : not yet supported
423 // groupalign : not yet supported
424 // equalrows : not yet supported
425 // equalcolumns : not yet supported
426 // displaystyle : here
427 // align : in reflow
428 // rowalign : here
429 // rowlines : here
430 // rowspacing : not yet supported
431 // columnalign : here
432 // columnlines : here
433 // columnspacing : not yet supported
435 // mtable is simple and only has one (pseudo) row-group inside our inner-table
436 nsIFrame* tableFrame = mFrames.FirstChild();
437 if (!tableFrame || tableFrame->GetType() != nsGkAtoms::tableFrame)
438 return NS_OK;
439 nsIFrame* rgFrame = tableFrame->GetFirstChild(nsnull);
440 if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
441 return NS_OK;
443 // align - just need to issue a dirty (resize) reflow command
444 if (aAttribute == nsGkAtoms::align) {
445 PresContext()->PresShell()->
446 FrameNeedsReflow(this, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
447 return NS_OK;
450 // displaystyle - may seem innocuous, but it is actually very harsh --
451 // like changing an unit. Blow away and recompute all our automatic
452 // presentational data, and issue a style-changed reflow request
453 if (aAttribute == nsGkAtoms::displaystyle_) {
454 nsMathMLContainerFrame::RebuildAutomaticDataForChildren(mParent);
455 // Need to reflow the parent, not us, because this can actually
456 // affect siblings.
457 PresContext()->PresShell()->
458 FrameNeedsReflow(mParent, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
459 return NS_OK;
462 // ...and the other attributes affect rows or columns in one way or another
463 nsIAtom* MOZrowAtom = nsnull;
464 nsIAtom* MOZcolAtom = nsnull;
465 if (aAttribute == nsGkAtoms::rowalign_)
466 MOZrowAtom = nsGkAtoms::MOZrowalign;
467 else if (aAttribute == nsGkAtoms::rowlines_)
468 MOZrowAtom = nsGkAtoms::MOZrowline;
469 else if (aAttribute == nsGkAtoms::columnalign_)
470 MOZcolAtom = nsGkAtoms::MOZcolumnalign;
471 else if (aAttribute == nsGkAtoms::columnlines_)
472 MOZcolAtom = nsGkAtoms::MOZcolumnline;
474 if (!MOZrowAtom && !MOZcolAtom)
475 return NS_OK;
477 // clear any cached nsValueList for this table
478 tableFrame->DeleteProperty(aAttribute);
480 // unset any -moz attribute that we may have set earlier, and re-sync
481 nsIFrame* rowFrame = rgFrame->GetFirstChild(nsnull);
482 for ( ; rowFrame; rowFrame = rowFrame->GetNextSibling()) {
483 if (rowFrame->GetType() == nsGkAtoms::tableRowFrame) {
484 if (MOZrowAtom) { // let rows do the work
485 rowFrame->GetContent()->UnsetAttr(kNameSpaceID_None, MOZrowAtom, PR_FALSE);
486 MapRowAttributesIntoCSS(tableFrame, rowFrame);
487 } else { // let cells do the work
488 nsIFrame* cellFrame = rowFrame->GetFirstChild(nsnull);
489 for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) {
490 if (IS_TABLE_CELL(cellFrame->GetType())) {
491 cellFrame->GetContent()->UnsetAttr(kNameSpaceID_None, MOZcolAtom, PR_FALSE);
492 MapColAttributesIntoCSS(tableFrame, rowFrame, cellFrame);
499 // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
500 PresContext()->PresShell()->FrameConstructor()->
501 PostRestyleEvent(mContent, eReStyle_Self, nsChangeHint_ReflowFrame);
503 return NS_OK;
506 nsIFrame*
507 nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext,
508 PRInt32 aRowIndex)
510 PRInt32 rowCount, colCount;
511 GetTableSize(rowCount, colCount);
513 // Negative indices mean to find upwards from the end.
514 if (aRowIndex < 0) {
515 aRowIndex = rowCount + aRowIndex;
517 // aRowIndex is 1-based, so convert it to a 0-based index
518 --aRowIndex;
520 // if our inner table says that the index is valid, find the row now
521 if (0 <= aRowIndex && aRowIndex <= rowCount) {
522 nsIFrame* tableFrame = mFrames.FirstChild();
523 if (!tableFrame || tableFrame->GetType() != nsGkAtoms::tableFrame)
524 return nsnull;
525 nsIFrame* rgFrame = tableFrame->GetFirstChild(nsnull);
526 if (!rgFrame || rgFrame->GetType() != nsGkAtoms::tableRowGroupFrame)
527 return nsnull;
528 nsTableIterator rowIter(*rgFrame);
529 nsIFrame* rowFrame = rowIter.First();
530 for ( ; rowFrame; rowFrame = rowIter.Next()) {
531 if (aRowIndex == 0) {
532 DEBUG_VERIFY_THAT_FRAME_IS(rowFrame, TABLE_ROW);
533 if (rowFrame->GetType() != nsGkAtoms::tableRowFrame)
534 return nsnull;
536 return rowFrame;
538 --aRowIndex;
541 return nsnull;
544 NS_IMETHODIMP
545 nsMathMLmtableOuterFrame::Reflow(nsPresContext* aPresContext,
546 nsHTMLReflowMetrics& aDesiredSize,
547 const nsHTMLReflowState& aReflowState,
548 nsReflowStatus& aStatus)
550 nsresult rv;
551 nsAutoString value;
552 // we want to return a table that is anchored according to the align attribute
554 rv = nsTableOuterFrame::Reflow(aPresContext, aDesiredSize, aReflowState,
555 aStatus);
556 NS_ASSERTION(aDesiredSize.height >= 0, "illegal height for mtable");
557 NS_ASSERTION(aDesiredSize.width >= 0, "illegal width for mtable");
559 // see if the user has set the align attribute on the <mtable>
560 // XXX should we also check <mstyle> ?
561 PRInt32 rowIndex = 0;
562 eAlign tableAlign = eAlign_axis;
563 GetAttribute(mContent, nsnull, nsGkAtoms::align, value);
564 if (!value.IsEmpty()) {
565 ParseAlignAttribute(value, tableAlign, rowIndex);
568 // adjustments if there is a specified row from where to anchor the table
569 // (conceptually: when there is no row of reference, picture the table as if
570 // it is wrapped in a single big fictional row at dy = 0, this way of
571 // doing so allows us to have a single code path for all cases).
572 nscoord dy = 0;
573 nscoord height = aDesiredSize.height;
574 nsIFrame* rowFrame = nsnull;
575 if (rowIndex) {
576 rowFrame = GetRowFrameAt(aPresContext, rowIndex);
577 if (rowFrame) {
578 // translate the coordinates to be relative to us
579 nsIFrame* frame = rowFrame;
580 height = frame->GetSize().height;
581 do {
582 dy += frame->GetPosition().y;
583 frame = frame->GetParent();
584 } while (frame != this);
587 switch (tableAlign) {
588 case eAlign_top:
589 aDesiredSize.ascent = dy;
590 break;
591 case eAlign_bottom:
592 aDesiredSize.ascent = dy + height;
593 break;
594 case eAlign_center:
595 aDesiredSize.ascent = dy + height/2;
596 break;
597 case eAlign_baseline:
598 if (rowFrame) {
599 // anchor the table on the baseline of the row of reference
600 nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
601 if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
602 aDesiredSize.ascent = dy + rowAscent;
603 break;
606 // in other situations, fallback to center
607 aDesiredSize.ascent = dy + height/2;
608 break;
609 case eAlign_axis:
610 default: {
611 // XXX should instead use style data from the row of reference here ?
612 aReflowState.rendContext->SetFont(GetStyleFont()->mFont, nsnull,
613 aPresContext->GetUserFontSet());
614 nsCOMPtr<nsIFontMetrics> fm;
615 aReflowState.rendContext->GetFontMetrics(*getter_AddRefs(fm));
616 nscoord axisHeight;
617 GetAxisHeight(*aReflowState.rendContext, fm, axisHeight);
618 if (rowFrame) {
619 // anchor the table on the axis of the row of reference
620 // XXX fallback to baseline because it is a hard problem
621 // XXX need to fetch the axis of the row; would need rowalign=axis to work better
622 nscoord rowAscent = ((nsTableRowFrame*)rowFrame)->GetMaxCellAscent();
623 if (rowAscent) { // the row has at least one cell with 'vertical-align: baseline'
624 aDesiredSize.ascent = dy + rowAscent;
625 break;
628 // in other situations, fallback to using half of the height
629 aDesiredSize.ascent = dy + height/2 + axisHeight;
633 mReference.x = 0;
634 mReference.y = aDesiredSize.ascent;
636 // just make-up a bounding metrics
637 mBoundingMetrics.Clear();
638 mBoundingMetrics.ascent = aDesiredSize.ascent;
639 mBoundingMetrics.descent = aDesiredSize.height - aDesiredSize.ascent;
640 mBoundingMetrics.width = aDesiredSize.width;
641 mBoundingMetrics.leftBearing = 0;
642 mBoundingMetrics.rightBearing = aDesiredSize.width;
644 aDesiredSize.mBoundingMetrics = mBoundingMetrics;
645 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
647 return rv;
650 // --------
651 // implementation of nsMathMLmtableFrame
653 NS_IMPL_ADDREF_INHERITED(nsMathMLmtableFrame, nsTableFrame)
654 NS_IMPL_RELEASE_INHERITED(nsMathMLmtableFrame, nsTableFrame)
655 NS_IMPL_QUERY_INTERFACE_INHERITED0(nsMathMLmtableFrame, nsTableFrame)
657 nsIFrame*
658 NS_NewMathMLmtableFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
660 return new (aPresShell) nsMathMLmtableFrame(aContext);
663 nsMathMLmtableFrame::~nsMathMLmtableFrame()
667 NS_IMETHODIMP
668 nsMathMLmtableFrame::SetInitialChildList(nsIAtom* aListName,
669 nsIFrame* aChildList)
671 nsresult rv = nsTableFrame::SetInitialChildList(aListName, aChildList);
672 if (NS_FAILED(rv)) return rv;
673 MapAllAttributesIntoCSS(this);
674 return rv;
677 void
678 nsMathMLmtableFrame::RestyleTable()
680 // re-sync MathML specific style data that may have changed
681 MapAllAttributesIntoCSS(this);
683 // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
684 PresContext()->PresShell()->FrameConstructor()->
685 PostRestyleEvent(mContent, eReStyle_Self, nsChangeHint_ReflowFrame);
688 // --------
689 // implementation of nsMathMLmtrFrame
691 NS_IMPL_ADDREF_INHERITED(nsMathMLmtrFrame, nsTableRowFrame)
692 NS_IMPL_RELEASE_INHERITED(nsMathMLmtrFrame, nsTableRowFrame)
693 NS_IMPL_QUERY_INTERFACE_INHERITED0(nsMathMLmtrFrame, nsTableRowFrame)
695 nsIFrame*
696 NS_NewMathMLmtrFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
698 return new (aPresShell) nsMathMLmtrFrame(aContext);
701 nsMathMLmtrFrame::~nsMathMLmtrFrame()
705 NS_IMETHODIMP
706 nsMathMLmtrFrame::AttributeChanged(PRInt32 aNameSpaceID,
707 nsIAtom* aAttribute,
708 PRInt32 aModType)
710 // Attributes specific to <mtr>:
711 // groupalign : Not yet supported.
712 // rowalign : Fully specified in mathml.css, and so HasAttributeDependentStyle() will
713 // pick it up and nsCSSFrameConstructor will issue a PostRestyleEvent().
714 // columnalign : Need an explicit re-style call.
716 if (aAttribute == nsGkAtoms::rowalign_) {
717 // unset any -moz attribute that we may have set earlier, and re-sync
718 mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::MOZrowalign, PR_FALSE);
719 MapRowAttributesIntoCSS(nsTableFrame::GetTableFrame(this), this);
720 // That's all - see comment above.
721 return NS_OK;
724 if (aAttribute != nsGkAtoms::columnalign_)
725 return NS_OK;
727 // Clear any cached columnalign's nsValueList for this row
728 DeleteProperty(aAttribute);
730 // Clear any internal -moz attribute that we may have set earlier
731 // in our cells and re-sync their columnalign attribute
732 nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
733 nsIFrame* cellFrame = GetFirstChild(nsnull);
734 for ( ; cellFrame; cellFrame = cellFrame->GetNextSibling()) {
735 if (IS_TABLE_CELL(cellFrame->GetType())) {
736 cellFrame->GetContent()->
737 UnsetAttr(kNameSpaceID_None, nsGkAtoms::MOZcolumnalign, PR_FALSE);
738 MapColAttributesIntoCSS(tableFrame, this, cellFrame);
742 // Explicitly request a re-resolve and reflow in our subtree to pick up any changes
743 PresContext()->PresShell()->FrameConstructor()->
744 PostRestyleEvent(mContent, eReStyle_Self, nsChangeHint_ReflowFrame);
746 return NS_OK;
749 // --------
750 // implementation of nsMathMLmtdFrame
752 NS_IMPL_ADDREF_INHERITED(nsMathMLmtdFrame, nsTableCellFrame)
753 NS_IMPL_RELEASE_INHERITED(nsMathMLmtdFrame, nsTableCellFrame)
754 NS_IMPL_QUERY_INTERFACE_INHERITED0(nsMathMLmtdFrame, nsTableCellFrame)
756 nsIFrame*
757 NS_NewMathMLmtdFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
759 return new (aPresShell) nsMathMLmtdFrame(aContext);
762 nsMathMLmtdFrame::~nsMathMLmtdFrame()
766 PRInt32
767 nsMathMLmtdFrame::GetRowSpan()
769 PRInt32 rowspan = 1;
771 // Don't look at the content's rowspan if we're not an mtd or a pseudo cell.
772 if ((mContent->Tag() == nsGkAtoms::mtd_) && !GetStyleContext()->GetPseudoType()) {
773 nsAutoString value;
774 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rowspan, value);
775 if (!value.IsEmpty()) {
776 PRInt32 error;
777 rowspan = value.ToInteger(&error);
778 if (error || rowspan < 0)
779 rowspan = 1;
780 rowspan = PR_MIN(rowspan, MAX_ROWSPAN);
783 return rowspan;
786 PRInt32
787 nsMathMLmtdFrame::GetColSpan()
789 PRInt32 colspan = 1;
791 // Don't look at the content's colspan if we're not an mtd or a pseudo cell.
792 if ((mContent->Tag() == nsGkAtoms::mtd_) && !GetStyleContext()->GetPseudoType()) {
793 nsAutoString value;
794 mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::columnspan_, value);
795 if (!value.IsEmpty()) {
796 PRInt32 error;
797 colspan = value.ToInteger(&error);
798 if (error || colspan < 0 || colspan > MAX_COLSPAN)
799 colspan = 1;
802 return colspan;
805 NS_IMETHODIMP
806 nsMathMLmtdFrame::AttributeChanged(PRInt32 aNameSpaceID,
807 nsIAtom* aAttribute,
808 PRInt32 aModType)
810 // Attributes specific to <mtd>:
811 // groupalign : Not yet supported
812 // rowalign : in mathml.css
813 // columnalign : here
814 // rowspan : here
815 // columnspan : here
817 if (aAttribute == nsGkAtoms::columnalign_) {
818 // unset any -moz attribute that we may have set earlier, and re-sync
819 mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::MOZcolumnalign, PR_FALSE);
820 MapColAttributesIntoCSS(nsTableFrame::GetTableFrame(this), mParent, this);
821 return NS_OK;
824 if (aAttribute == nsGkAtoms::rowspan ||
825 aAttribute == nsGkAtoms::columnspan_) {
826 // use the naming expected by the base class
827 if (aAttribute == nsGkAtoms::columnspan_)
828 aAttribute = nsGkAtoms::colspan;
829 return nsTableCellFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
832 return NS_OK;
835 // --------
836 // implementation of nsMathMLmtdInnerFrame
838 NS_IMPL_ADDREF_INHERITED(nsMathMLmtdInnerFrame, nsMathMLFrame)
839 NS_IMPL_RELEASE_INHERITED(nsMathMLmtdInnerFrame, nsMathMLFrame)
840 NS_IMPL_QUERY_INTERFACE_INHERITED1(nsMathMLmtdInnerFrame, nsBlockFrame, nsMathMLFrame)
842 nsIFrame*
843 NS_NewMathMLmtdInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
845 return new (aPresShell) nsMathMLmtdInnerFrame(aContext);
848 nsMathMLmtdInnerFrame::~nsMathMLmtdInnerFrame()
852 NS_IMETHODIMP
853 nsMathMLmtdInnerFrame::Reflow(nsPresContext* aPresContext,
854 nsHTMLReflowMetrics& aDesiredSize,
855 const nsHTMLReflowState& aReflowState,
856 nsReflowStatus& aStatus)
858 // Let the base class do the reflow
859 nsresult rv = nsBlockFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus);
861 // more about <maligngroup/> and <malignmark/> later
862 // ...
863 return rv;