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.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Pierre Phaneuf <pp@ludusdesign.com>
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 ***** */
38 #include "nsTableOuterFrame.h"
39 #include "nsTableFrame.h"
40 #include "nsStyleContext.h"
41 #include "nsStyleConsts.h"
42 #include "nsPresContext.h"
43 #include "nsIRenderingContext.h"
44 #include "nsCSSRendering.h"
45 #include "nsIContent.h"
47 #include "nsGkAtoms.h"
48 #include "nsHTMLParts.h"
49 #include "nsIPresShell.h"
51 #include "nsIAccessibilityService.h"
53 #include "nsIServiceManager.h"
54 #include "nsIDOMNode.h"
55 #include "nsDisplayList.h"
56 #include "nsLayoutUtils.h"
58 /* ----------- nsTableCaptionFrame ---------- */
60 #define NS_TABLE_FRAME_CAPTION_LIST_INDEX 0
64 nsTableCaptionFrame::nsTableCaptionFrame(nsStyleContext
* aContext
):
65 nsBlockFrame(aContext
)
68 SetFlags(NS_BLOCK_SPACE_MGR
);
71 nsTableCaptionFrame::~nsTableCaptionFrame()
76 nsTableCaptionFrame::GetType() const
78 return nsGkAtoms::tableCaptionFrame
;
82 nsTableOuterFrame::GetBaseline() const
84 nsIFrame
* kid
= mFrames
.FirstChild();
86 NS_NOTREACHED("no inner table");
87 return nsHTMLContainerFrame::GetBaseline();
90 return kid
->GetBaseline() + kid
->GetPosition().y
;
94 nsTableCaptionFrame::ComputeAutoSize(nsIRenderingContext
*aRenderingContext
,
95 nsSize aCBSize
, nscoord aAvailableWidth
,
96 nsSize aMargin
, nsSize aBorder
,
97 nsSize aPadding
, PRBool aShrinkWrap
)
99 nsSize result
= nsBlockFrame::ComputeAutoSize(aRenderingContext
, aCBSize
,
100 aAvailableWidth
, aMargin
, aBorder
, aPadding
, aShrinkWrap
);
101 PRUint8 captionSide
= GetStyleTableBorder()->mCaptionSide
;
102 if (captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
103 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
) {
104 result
.width
= GetMinWidth(aRenderingContext
);
105 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
106 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
107 // The outer frame constrains our available width to the width of
108 // the table. Grow if our min-width is bigger than that, but not
109 // larger than the containing block width. (It would really be nice
110 // to transmit that information another way, so we could grow up to
111 // the table's available width, but that's harder.)
112 nscoord min
= GetMinWidth(aRenderingContext
);
113 if (min
> aCBSize
.width
)
115 if (min
> result
.width
)
122 nsTableCaptionFrame::GetParentStyleContextFrame(nsPresContext
* aPresContext
,
123 nsIFrame
** aProviderFrame
,
126 NS_PRECONDITION(mContent
->GetParent(),
127 "How could we not have a parent here?");
129 // The caption's style context parent is the inner frame, unless
131 nsIFrame
* outerFrame
= GetParent();
132 if (outerFrame
&& outerFrame
->GetType() == nsGkAtoms::tableOuterFrame
) {
133 nsIFrame
* innerFrame
= outerFrame
->GetFirstChild(nsnull
);
136 nsFrame::CorrectStyleParentFrame(innerFrame
,
137 GetStyleContext()->GetPseudoType());
138 *aIsChild
= PR_FALSE
;
143 NS_NOTREACHED("Where is our inner table frame?");
144 return nsBlockFrame::GetParentStyleContextFrame(aPresContext
, aProviderFrame
,
149 NS_IMETHODIMP
nsTableCaptionFrame::GetAccessible(nsIAccessible
** aAccessible
)
151 *aAccessible
= nsnull
;
152 if (!GetRect().IsEmpty()) {
153 nsCOMPtr
<nsIAccessibilityService
> accService
= do_GetService("@mozilla.org/accessibilityService;1");
155 return accService
->CreateHTMLCaptionAccessible(static_cast<nsIFrame
*>(this), aAccessible
);
159 return NS_ERROR_FAILURE
;
165 nsTableCaptionFrame::GetFrameName(nsAString
& aResult
) const
167 return MakeFrameName(NS_LITERAL_STRING("Caption"), aResult
);
172 NS_NewTableCaptionFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
174 return new (aPresShell
) nsTableCaptionFrame(aContext
);
177 /* ----------- nsTableOuterFrame ---------- */
179 NS_IMPL_ADDREF_INHERITED(nsTableOuterFrame
, nsHTMLContainerFrame
)
180 NS_IMPL_RELEASE_INHERITED(nsTableOuterFrame
, nsHTMLContainerFrame
)
182 nsTableOuterFrame::nsTableOuterFrame(nsStyleContext
* aContext
):
183 nsHTMLContainerFrame(aContext
)
187 nsTableOuterFrame::~nsTableOuterFrame()
192 nsTableOuterFrame::QueryInterface(const nsIID
& aIID
, void** aInstancePtr
)
194 NS_PRECONDITION(aInstancePtr
, "null out param");
196 if (aIID
.Equals(NS_GET_IID(nsITableLayout
))) {
197 *aInstancePtr
= static_cast<nsITableLayout
*>(this);
201 return nsHTMLContainerFrame::QueryInterface(aIID
, aInstancePtr
);
205 NS_IMETHODIMP
nsTableOuterFrame::GetAccessible(nsIAccessible
** aAccessible
)
207 nsCOMPtr
<nsIAccessibilityService
> accService
= do_GetService("@mozilla.org/accessibilityService;1");
210 return accService
->CreateHTMLTableAccessible(static_cast<nsIFrame
*>(this), aAccessible
);
213 return NS_ERROR_FAILURE
;
218 nsTableOuterFrame::IsContainingBlock() const
224 nsTableOuterFrame::Destroy()
226 mCaptionFrames
.DestroyFrames();
227 nsHTMLContainerFrame::Destroy();
231 nsTableOuterFrame::GetFirstChild(nsIAtom
* aListName
) const
233 if (nsGkAtoms::captionList
== aListName
) {
234 return mCaptionFrames
.FirstChild();
237 return mFrames
.FirstChild();
243 nsTableOuterFrame::GetAdditionalChildListName(PRInt32 aIndex
) const
245 if (aIndex
== NS_TABLE_FRAME_CAPTION_LIST_INDEX
) {
246 return nsGkAtoms::captionList
;
252 nsTableOuterFrame::SetInitialChildList(nsIAtom
* aListName
,
253 nsIFrame
* aChildList
)
255 if (nsGkAtoms::captionList
== aListName
) {
256 // the frame constructor already checked for table-caption display type
257 mCaptionFrames
.SetFrames(aChildList
);
258 mCaptionFrame
= mCaptionFrames
.FirstChild();
261 NS_ASSERTION(!aListName
, "wrong childlist");
262 NS_ASSERTION(mFrames
.IsEmpty(), "Frame leak!");
263 mFrames
.SetFrames(aChildList
);
264 mInnerTableFrame
= nsnull
;
266 if (nsGkAtoms::tableFrame
== aChildList
->GetType()) {
267 mInnerTableFrame
= (nsTableFrame
*)aChildList
;
270 NS_ERROR("expected a table frame");
271 return NS_ERROR_INVALID_ARG
;
280 nsTableOuterFrame::AppendFrames(nsIAtom
* aListName
,
281 nsIFrame
* aFrameList
)
285 // We only have two child frames: the inner table and a caption frame.
286 // The inner frame is provided when we're initialized, and it cannot change
287 if (nsGkAtoms::captionList
== aListName
) {
288 NS_ASSERTION(!aFrameList
||
289 aFrameList
->GetType() == nsGkAtoms::tableCaptionFrame
,
290 "appending non-caption frame to captionList");
291 mCaptionFrames
.AppendFrames(this, aFrameList
);
292 mCaptionFrame
= mCaptionFrames
.FirstChild();
295 // Reflow the new caption frame. It's already marked dirty, so
296 // just tell the pres shell.
297 PresContext()->PresShell()->
298 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
299 NS_FRAME_HAS_DIRTY_CHILDREN
);
302 NS_PRECONDITION(PR_FALSE
, "unexpected child list");
303 rv
= NS_ERROR_UNEXPECTED
;
310 nsTableOuterFrame::InsertFrames(nsIAtom
* aListName
,
311 nsIFrame
* aPrevFrame
,
312 nsIFrame
* aFrameList
)
314 if (nsGkAtoms::captionList
== aListName
) {
315 NS_ASSERTION(!aPrevFrame
|| aPrevFrame
->GetParent() == this,
316 "inserting after sibling frame with different parent");
317 NS_ASSERTION(!aFrameList
||
318 aFrameList
->GetType() == nsGkAtoms::tableCaptionFrame
,
319 "inserting non-caption frame into captionList");
320 mCaptionFrames
.InsertFrames(nsnull
, aPrevFrame
, aFrameList
);
321 mCaptionFrame
= mCaptionFrames
.FirstChild();
323 // Reflow the new caption frame. It's already marked dirty, so
324 // just tell the pres shell.
325 PresContext()->PresShell()->
326 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
327 NS_FRAME_HAS_DIRTY_CHILDREN
);
331 NS_PRECONDITION(!aPrevFrame
, "invalid previous frame");
332 return AppendFrames(aListName
, aFrameList
);
337 nsTableOuterFrame::RemoveFrame(nsIAtom
* aListName
,
340 // We only have two child frames: the inner table and one caption frame.
341 // The inner frame can't be removed so this should be the caption
342 NS_PRECONDITION(nsGkAtoms::captionList
== aListName
, "can't remove inner frame");
344 if (HasSideCaption()) {
345 // The old caption width had an effect on the inner table width so
346 // we're going to need to reflow it. Mark it dirty
347 mInnerTableFrame
->AddStateBits(NS_FRAME_IS_DIRTY
);
350 // Remove the frame and destroy it
351 mCaptionFrames
.DestroyFrame(aOldFrame
);
352 mCaptionFrame
= mCaptionFrames
.FirstChild();
354 PresContext()->PresShell()->
355 FrameNeedsReflow(this, nsIPresShell::eTreeChange
,
356 NS_FRAME_HAS_DIRTY_CHILDREN
); // also means child removed
362 nsTableOuterFrame::BuildDisplayList(nsDisplayListBuilder
* aBuilder
,
363 const nsRect
& aDirtyRect
,
364 const nsDisplayListSet
& aLists
)
366 // No border, background or outline are painted because they all belong
367 // to the inner table.
368 if (!IsVisibleInSelection(aBuilder
))
371 // If there's no caption, take a short cut to avoid having to create
372 // the special display list set and then sort it.
374 return BuildDisplayListForInnerTable(aBuilder
, aDirtyRect
, aLists
);
376 nsDisplayListCollection set
;
377 nsresult rv
= BuildDisplayListForInnerTable(aBuilder
, aDirtyRect
, set
);
378 NS_ENSURE_SUCCESS(rv
, rv
);
380 nsDisplayListSet
captionSet(set
, set
.BlockBorderBackgrounds());
381 rv
= BuildDisplayListForChild(aBuilder
, mCaptionFrame
, aDirtyRect
, captionSet
);
382 NS_ENSURE_SUCCESS(rv
, rv
);
384 // Now we have to sort everything by content order, since the caption
385 // may be somewhere inside the table
386 set
.SortAllByContentOrder(aBuilder
, GetContent());
392 nsTableOuterFrame::BuildDisplayListForInnerTable(nsDisplayListBuilder
* aBuilder
,
393 const nsRect
& aDirtyRect
,
394 const nsDisplayListSet
& aLists
)
396 // Just paint the regular children, but the children's background is our
397 // true background (there should only be one, the real table)
398 nsIFrame
* kid
= mFrames
.FirstChild();
399 // The children should be in content order
401 nsresult rv
= BuildDisplayListForChild(aBuilder
, kid
, aDirtyRect
, aLists
);
402 NS_ENSURE_SUCCESS(rv
, rv
);
403 kid
= kid
->GetNextSibling();
408 NS_IMETHODIMP
nsTableOuterFrame::SetSelected(nsPresContext
* aPresContext
,
414 nsresult result
= nsFrame::SetSelected(aPresContext
, aRange
,aSelected
, aSpread
, aType
);
415 if (NS_SUCCEEDED(result
) && mInnerTableFrame
)
416 return mInnerTableFrame
->SetSelected(aPresContext
, aRange
,aSelected
, aSpread
, aType
);
421 nsTableOuterFrame::GetParentStyleContextFrame(nsPresContext
* aPresContext
,
422 nsIFrame
** aProviderFrame
,
425 // The table outer frame and the (inner) table frame split the style
426 // data by giving the table frame the style context associated with
427 // the table content node and creating a style context for the outer
428 // frame that is a *child* of the table frame's style context,
429 // matching the ::-moz-table-outer pseudo-element. html.css has a
430 // rule that causes that pseudo-element (and thus the outer table)
431 // to inherit *some* style properties from the table frame. The
432 // children of the table inherit directly from the inner table, and
433 // the outer table's style context is a leaf.
435 if (!mInnerTableFrame
) {
436 *aProviderFrame
= this;
437 *aIsChild
= PR_FALSE
;
438 return NS_ERROR_FAILURE
;
440 *aProviderFrame
= mInnerTableFrame
;
445 // INCREMENTAL REFLOW HELPER FUNCTIONS
448 nsTableOuterFrame::InitChildReflowState(nsPresContext
& aPresContext
,
449 nsHTMLReflowState
& aReflowState
)
452 nsMargin collapseBorder
;
453 nsMargin
collapsePadding(0,0,0,0);
454 nsMargin
* pCollapseBorder
= nsnull
;
455 nsMargin
* pCollapsePadding
= nsnull
;
456 if ((aReflowState
.frame
== mInnerTableFrame
) && (mInnerTableFrame
->IsBorderCollapse())) {
457 collapseBorder
= mInnerTableFrame
->GetIncludedOuterBCBorder();
458 pCollapseBorder
= &collapseBorder
;
459 pCollapsePadding
= &collapsePadding
;
461 aReflowState
.Init(&aPresContext
, -1, -1, pCollapseBorder
, pCollapsePadding
);
464 // get the margin and padding data. nsHTMLReflowState doesn't handle the
465 // case of auto margins
467 nsTableOuterFrame::GetMargin(nsPresContext
* aPresContext
,
468 const nsHTMLReflowState
& aOuterRS
,
469 nsIFrame
* aChildFrame
,
473 // construct a reflow state to compute margin and padding. Auto margins
474 // will not be computed at this time.
476 // create and init the child reflow state
477 // XXX We really shouldn't construct a reflow state to do this.
478 nsHTMLReflowState
childRS(aPresContext
, aOuterRS
, aChildFrame
,
479 nsSize(aAvailWidth
, aOuterRS
.availableHeight
),
481 InitChildReflowState(*aPresContext
, childRS
);
483 aMargin
= childRS
.mComputedMargin
;
487 nscoord
CalcAutoMargin(nscoord aAutoMargin
,
488 nscoord aOppositeMargin
,
489 nscoord aContainBlockSize
,
493 if (NS_AUTOMARGIN
== aOppositeMargin
)
494 margin
= (aContainBlockSize
- aFrameSize
) / 2;
496 margin
= aContainBlockSize
- aFrameSize
- aOppositeMargin
;
498 return PR_MAX(0, margin
);
502 GetContainingBlockSize(const nsHTMLReflowState
& aOuterRS
)
505 const nsHTMLReflowState
* containRS
=
506 aOuterRS
.mCBReflowState
;
509 size
.width
= containRS
->ComputedWidth();
510 if (NS_UNCONSTRAINEDSIZE
== size
.width
) {
513 size
.height
= containRS
->ComputedHeight();
514 if (NS_UNCONSTRAINEDSIZE
== size
.height
) {
521 /* virtual */ nscoord
522 nsTableOuterFrame::GetMinWidth(nsIRenderingContext
*aRenderingContext
)
524 nscoord width
= nsLayoutUtils::IntrinsicForContainer(aRenderingContext
,
525 mInnerTableFrame
, nsLayoutUtils::MIN_WIDTH
);
526 DISPLAY_MIN_WIDTH(this, width
);
529 nsLayoutUtils::IntrinsicForContainer(aRenderingContext
, mCaptionFrame
,
530 nsLayoutUtils::MIN_WIDTH
);
531 if (HasSideCaption()) {
534 if (capWidth
> width
) {
542 /* virtual */ nscoord
543 nsTableOuterFrame::GetPrefWidth(nsIRenderingContext
*aRenderingContext
)
546 DISPLAY_PREF_WIDTH(this, maxWidth
);
548 maxWidth
= nsLayoutUtils::IntrinsicForContainer(aRenderingContext
,
549 mInnerTableFrame
, nsLayoutUtils::PREF_WIDTH
);
551 PRUint8 captionSide
= GetCaptionSide();
552 switch(captionSide
) {
553 case NS_STYLE_CAPTION_SIDE_LEFT
:
554 case NS_STYLE_CAPTION_SIDE_RIGHT
:
557 nsLayoutUtils::IntrinsicForContainer(aRenderingContext
, mCaptionFrame
,
558 nsLayoutUtils::MIN_WIDTH
);
564 nsLayoutUtils::IntrinsicWidthType iwt
;
565 if (captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
566 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
567 // Don't let the caption's pref width expand the table's pref
569 iwt
= nsLayoutUtils::MIN_WIDTH
;
571 NS_ASSERTION(captionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
||
572 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
,
573 "unexpected caption side");
574 iwt
= nsLayoutUtils::PREF_WIDTH
;
577 nsLayoutUtils::IntrinsicForContainer(aRenderingContext
, mCaptionFrame
,
579 maxWidth
= PR_MAX(maxWidth
, capPref
);
587 // Compute the margin-box width of aChildFrame given the inputs. If
588 // aMarginResult is non-null, fill it with the part of the margin-width
589 // that was contributed by the margin.
591 ChildShrinkWrapWidth(nsIRenderingContext
*aRenderingContext
,
592 nsIFrame
*aChildFrame
,
593 nsSize aCBSize
, nscoord aAvailableWidth
,
594 nscoord
*aMarginResult
= nsnull
)
596 // The outer table's children do not use it as a containing block.
597 nsCSSOffsetState
offsets(aChildFrame
, aRenderingContext
, aCBSize
.width
);
598 nsSize size
= aChildFrame
->ComputeSize(aRenderingContext
, aCBSize
,
600 nsSize(offsets
.mComputedMargin
.LeftRight(),
601 offsets
.mComputedMargin
.TopBottom()),
602 nsSize(offsets
.mComputedBorderPadding
.LeftRight() -
603 offsets
.mComputedPadding
.LeftRight(),
604 offsets
.mComputedBorderPadding
.TopBottom() -
605 offsets
.mComputedPadding
.TopBottom()),
606 nsSize(offsets
.mComputedPadding
.LeftRight(),
607 offsets
.mComputedPadding
.TopBottom()),
610 *aMarginResult
= offsets
.mComputedMargin
.LeftRight();
611 return size
.width
+ offsets
.mComputedMargin
.LeftRight() +
612 offsets
.mComputedBorderPadding
.LeftRight();
616 nsTableOuterFrame::ComputeAutoSize(nsIRenderingContext
*aRenderingContext
,
617 nsSize aCBSize
, nscoord aAvailableWidth
,
618 nsSize aMargin
, nsSize aBorder
,
619 nsSize aPadding
, PRBool aShrinkWrap
)
622 return nsHTMLContainerFrame::ComputeAutoSize(aRenderingContext
, aCBSize
,
623 aAvailableWidth
, aMargin
, aBorder
, aPadding
, aShrinkWrap
);
625 // When we're shrink-wrapping, our auto size needs to wrap around the
626 // actual size of the table, which (if it is specified as a percent)
627 // could be something that is not reflected in our GetMinWidth and
628 // GetPrefWidth. See bug 349457 for an example.
630 // Match the availableWidth logic in Reflow.
631 PRUint8 captionSide
= GetCaptionSide();
633 if (captionSide
== NO_SIDE
) {
634 width
= ChildShrinkWrapWidth(aRenderingContext
, mInnerTableFrame
,
635 aCBSize
, aAvailableWidth
);
636 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
637 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
) {
638 nscoord capWidth
= ChildShrinkWrapWidth(aRenderingContext
, mCaptionFrame
,
639 aCBSize
, aAvailableWidth
);
640 width
= capWidth
+ ChildShrinkWrapWidth(aRenderingContext
,
641 mInnerTableFrame
, aCBSize
,
642 aAvailableWidth
- capWidth
);
643 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
644 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
646 width
= ChildShrinkWrapWidth(aRenderingContext
, mInnerTableFrame
,
647 aCBSize
, aAvailableWidth
, &margin
);
648 nscoord capWidth
= ChildShrinkWrapWidth(aRenderingContext
,
649 mCaptionFrame
, aCBSize
,
651 if (capWidth
> width
)
654 NS_ASSERTION(captionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
||
655 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
,
656 "unexpected caption-side");
657 width
= ChildShrinkWrapWidth(aRenderingContext
, mInnerTableFrame
,
658 aCBSize
, aAvailableWidth
);
659 nscoord capWidth
= ChildShrinkWrapWidth(aRenderingContext
,
660 mCaptionFrame
, aCBSize
,
662 if (capWidth
> width
)
666 return nsSize(width
, NS_UNCONSTRAINEDSIZE
);
670 nsTableOuterFrame::GetCaptionSide()
673 return mCaptionFrame
->GetStyleTableBorder()->mCaptionSide
;
676 return NO_SIDE
; // no caption
681 nsTableOuterFrame::GetCaptionVerticalAlign()
683 const nsStyleCoord
& va
= mCaptionFrame
->GetStyleTextReset()->mVerticalAlign
;
684 return (va
.GetUnit() == eStyleUnit_Enumerated
)
686 : NS_STYLE_VERTICAL_ALIGN_TOP
;
690 nsTableOuterFrame::SetDesiredSize(PRUint8 aCaptionSide
,
691 const nsMargin
& aInnerMargin
,
692 const nsMargin
& aCaptionMargin
,
696 aWidth
= aHeight
= 0;
698 nsRect innerRect
= mInnerTableFrame
->GetRect();
699 nscoord innerWidth
= innerRect
.width
;
701 nsRect
captionRect(0,0,0,0);
702 nscoord captionWidth
= 0;
704 captionRect
= mCaptionFrame
->GetRect();
705 captionWidth
= captionRect
.width
;
707 switch(aCaptionSide
) {
708 case NS_STYLE_CAPTION_SIDE_LEFT
:
709 aWidth
= PR_MAX(aInnerMargin
.left
, aCaptionMargin
.left
+ captionWidth
+ aCaptionMargin
.right
) +
710 innerWidth
+ aInnerMargin
.right
;
712 case NS_STYLE_CAPTION_SIDE_RIGHT
:
713 aWidth
= PR_MAX(aInnerMargin
.right
, aCaptionMargin
.left
+ captionWidth
+ aCaptionMargin
.right
) +
714 innerWidth
+ aInnerMargin
.left
;
717 aWidth
= aInnerMargin
.left
+ innerWidth
+ aInnerMargin
.right
;
718 aWidth
= PR_MAX(aWidth
, captionRect
.XMost() + aCaptionMargin
.right
);
720 aHeight
= innerRect
.YMost() + aInnerMargin
.bottom
;
721 aHeight
= PR_MAX(aHeight
, captionRect
.YMost() + aCaptionMargin
.bottom
);
725 // XXX This is now unused, but it probably should be used!
727 nsTableOuterFrame::BalanceLeftRightCaption(PRUint8 aCaptionSide
,
728 const nsMargin
& aInnerMargin
,
729 const nsMargin
& aCaptionMargin
,
730 nscoord
& aInnerWidth
,
731 nscoord
& aCaptionWidth
)
734 /* balance the caption and inner table widths to ensure space for percent widths
735 * Percent widths for captions or the inner table frame can determine how much of the
736 * available width is used and how the available width is distributed between those frames
737 * The inner table frame has already a quite sophisticated treatment of percentage widths
738 * (see BasicTableLayoutStrategy.cpp). So it acts as master in the below computations.
739 * There are four possible scenarios
740 * a) None of the frames have a percentage width - then the aInnerWidth and aCaptionwidth will not change
741 * b) Only the inner frame has a percentage width - this is handled in BasicTableLayoutStrategy.cpp,
742 * both widths will not change
743 * c) Only the caption has a percentage width - then the overall width (ow) will be different depending on
744 * the caption side. For the left side
745 * ow = aCaptionMargin.left + aCaptionWidth + aCaptionMargin.right + aInnerwidth + aInnerMargin.right
746 * aCaptionWidth = capPercent * ow
747 * solving this equation for aCaptionWidth gives:
748 * aCaptionWidth = capPercent/(1-capPercent) *
749 * (aCaptionMargin.left + aCaptionMargin.right + aInnerwidth + aInnerMargin.right)
750 * this result will cause problems for capPercent >= 1, in these cases the algorithm will now bail out
751 * a similar expression can be found for the right case
752 * d) both frames have percent widths in this case the caption width will be the inner width multiplied
753 * by the weight capPercent/innerPercent
757 float capPercent
= -1.0;
758 float innerPercent
= -1.0;
759 const nsStylePosition
* position
= mCaptionFrame
->GetStylePosition();
760 if (eStyleUnit_Percent
== position
->mWidth
.GetUnit()) {
761 capPercent
= position
->mWidth
.GetPercentValue();
762 if (capPercent
>= 1.0)
766 position
= mInnerTableFrame
->GetStylePosition();
767 if (eStyleUnit_Percent
== position
->mWidth
.GetUnit()) {
768 innerPercent
= position
->mWidth
.GetPercentValue();
769 if (innerPercent
>= 1.0)
773 if ((capPercent
<= 0.0) && (innerPercent
<= 0.0))
777 if (innerPercent
<= 0.0) {
778 if (NS_STYLE_CAPTION_SIDE_LEFT
== aCaptionSide
)
779 aCaptionWidth
= (nscoord
) ((capPercent
/ (1.0 - capPercent
)) * (aCaptionMargin
.left
+ aCaptionMargin
.right
+
780 aInnerWidth
+ aInnerMargin
.right
));
782 aCaptionWidth
= (nscoord
) ((capPercent
/ (1.0 - capPercent
)) * (aCaptionMargin
.left
+ aCaptionMargin
.right
+
783 aInnerWidth
+ aInnerMargin
.left
));
786 aCaptionWidth
= (nscoord
) ((capPercent
/ innerPercent
) * aInnerWidth
);
791 nsTableOuterFrame::GetCaptionOrigin(PRUint32 aCaptionSide
,
792 const nsSize
& aContainBlockSize
,
793 const nsSize
& aInnerSize
,
794 const nsMargin
& aInnerMargin
,
795 const nsSize
& aCaptionSize
,
796 nsMargin
& aCaptionMargin
,
799 // FIXME: This function expects computed margin values to be
800 // NS_AUTOMARGIN, but this is no longer the case.
801 aOrigin
.x
= aOrigin
.y
= 0;
802 if ((NS_UNCONSTRAINEDSIZE
== aInnerSize
.width
) || (NS_UNCONSTRAINEDSIZE
== aInnerSize
.height
) ||
803 (NS_UNCONSTRAINEDSIZE
== aCaptionSize
.width
) || (NS_UNCONSTRAINEDSIZE
== aCaptionSize
.height
)) {
806 if (!mCaptionFrame
) return NS_OK
;
808 // FIXME: Have two separate switch statements so we can coalesce the
809 // horizontal computation for top and bottom.
810 switch(aCaptionSide
) {
811 case NS_STYLE_CAPTION_SIDE_BOTTOM
:
812 case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
: {
813 if (NS_AUTOMARGIN
== aCaptionMargin
.left
) {
814 aCaptionMargin
.left
= CalcAutoMargin(aCaptionMargin
.left
, aCaptionMargin
.right
,
815 aContainBlockSize
.width
, aCaptionSize
.width
);
817 aOrigin
.x
= aCaptionMargin
.left
;
818 if (aCaptionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
819 // We placed the caption using only the table's width as available
820 // width, and we should position it this way as well.
821 aOrigin
.x
+= aInnerMargin
.left
;
823 if (NS_AUTOMARGIN
== aCaptionMargin
.top
) {
824 aCaptionMargin
.top
= 0;
826 // FIXME: Position relative to right edge for RTL. (Based on table
827 // direction or table parent direction?)
828 nsCollapsingMargin marg
;
829 marg
.Include(aCaptionMargin
.top
);
830 marg
.Include(aInnerMargin
.bottom
);
831 nscoord collapseMargin
= marg
.get();
832 if (NS_AUTOMARGIN
== aCaptionMargin
.bottom
) {
833 nscoord height
= aInnerSize
.height
+ collapseMargin
+ aCaptionSize
.height
;
834 aCaptionMargin
.bottom
= CalcAutoMargin(aCaptionMargin
.bottom
, aInnerMargin
.top
,
835 aContainBlockSize
.height
, height
);
837 aOrigin
.y
= aInnerMargin
.top
+ aInnerSize
.height
+ collapseMargin
;
839 case NS_STYLE_CAPTION_SIDE_LEFT
: {
840 if (NS_AUTOMARGIN
== aCaptionMargin
.left
) {
841 if (NS_AUTOMARGIN
!= aInnerMargin
.left
) {
842 aCaptionMargin
.left
= CalcAutoMargin(aCaptionMargin
.left
, aCaptionMargin
.right
,
843 aInnerMargin
.left
, aCaptionSize
.width
);
847 aCaptionMargin
.left
= 0;
850 aOrigin
.x
= aCaptionMargin
.left
;
851 aOrigin
.y
= aInnerMargin
.top
;
852 switch(GetCaptionVerticalAlign()) {
853 case NS_STYLE_VERTICAL_ALIGN_MIDDLE
:
854 aOrigin
.y
= PR_MAX(0, aInnerMargin
.top
+ ((aInnerSize
.height
- aCaptionSize
.height
) / 2));
856 case NS_STYLE_VERTICAL_ALIGN_BOTTOM
:
857 aOrigin
.y
= PR_MAX(0, aInnerMargin
.top
+ aInnerSize
.height
- aCaptionSize
.height
);
863 case NS_STYLE_CAPTION_SIDE_RIGHT
: {
864 if (NS_AUTOMARGIN
== aCaptionMargin
.left
) {
865 if (NS_AUTOMARGIN
!= aInnerMargin
.right
) {
866 aCaptionMargin
.left
= CalcAutoMargin(aCaptionMargin
.left
, aCaptionMargin
.right
,
867 aInnerMargin
.right
, aCaptionSize
.width
);
871 aCaptionMargin
.left
= 0;
874 aOrigin
.x
= aInnerMargin
.left
+ aInnerSize
.width
+ aCaptionMargin
.left
;
875 aOrigin
.y
= aInnerMargin
.top
;
876 switch(GetCaptionVerticalAlign()) {
877 case NS_STYLE_VERTICAL_ALIGN_MIDDLE
:
878 aOrigin
.y
+= PR_MAX(0, (aInnerSize
.height
- aCaptionSize
.height
) / 2);
880 case NS_STYLE_VERTICAL_ALIGN_BOTTOM
:
881 aOrigin
.y
+= PR_MAX(0, aInnerSize
.height
- aCaptionSize
.height
);
888 NS_ASSERTION(aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
889 aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
,
890 "unexpected caption side");
891 if (NS_AUTOMARGIN
== aCaptionMargin
.left
) {
892 aCaptionMargin
.left
= CalcAutoMargin(aCaptionMargin
.left
, aCaptionMargin
.right
,
893 aContainBlockSize
.width
, aCaptionSize
.width
);
895 aOrigin
.x
= aCaptionMargin
.left
;
896 if (aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP
) {
897 // We placed the caption using only the table's width as available
898 // width, and we should position it this way as well.
899 aOrigin
.x
+= aInnerMargin
.left
;
901 // FIXME: Position relative to right edge for RTL. (Based on table
902 // direction or table parent direction?)
903 if (NS_AUTOMARGIN
== aCaptionMargin
.bottom
) {
904 aCaptionMargin
.bottom
= 0;
906 if (NS_AUTOMARGIN
== aCaptionMargin
.top
) {
907 nsCollapsingMargin marg
;
908 marg
.Include(aCaptionMargin
.bottom
);
909 marg
.Include(aInnerMargin
.top
);
910 nscoord collapseMargin
= marg
.get();
911 nscoord height
= aCaptionSize
.height
+ collapseMargin
+ aInnerSize
.height
;
912 aCaptionMargin
.top
= CalcAutoMargin(aCaptionMargin
.top
, aInnerMargin
.bottom
,
913 aContainBlockSize
.height
, height
);
915 aOrigin
.y
= aCaptionMargin
.top
;
922 nsTableOuterFrame::GetInnerOrigin(PRUint32 aCaptionSide
,
923 const nsSize
& aContainBlockSize
,
924 const nsSize
& aCaptionSize
,
925 const nsMargin
& aCaptionMargin
,
926 const nsSize
& aInnerSize
,
927 nsMargin
& aInnerMargin
,
930 // FIXME: This function expects computed margin values to be
931 // NS_AUTOMARGIN, but this is no longer the case.
932 aOrigin
.x
= aOrigin
.y
= 0;
933 if ((NS_UNCONSTRAINEDSIZE
== aInnerSize
.width
) || (NS_UNCONSTRAINEDSIZE
== aInnerSize
.height
) ||
934 (NS_UNCONSTRAINEDSIZE
== aCaptionSize
.width
) || (NS_UNCONSTRAINEDSIZE
== aCaptionSize
.height
)) {
938 nscoord minCapWidth
= aCaptionSize
.width
;
939 if (NS_AUTOMARGIN
!= aCaptionMargin
.left
)
940 minCapWidth
+= aCaptionMargin
.left
;
941 if (NS_AUTOMARGIN
!= aCaptionMargin
.right
)
942 minCapWidth
+= aCaptionMargin
.right
;
944 switch(aCaptionSide
) {
945 case NS_STYLE_CAPTION_SIDE_BOTTOM
:
946 case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
: {
947 if (NS_AUTOMARGIN
== aInnerMargin
.left
) {
948 aInnerMargin
.left
= CalcAutoMargin(aInnerMargin
.left
, aInnerMargin
.right
,
949 aContainBlockSize
.width
, aInnerSize
.width
);
951 aOrigin
.x
= aInnerMargin
.left
;
952 if (NS_AUTOMARGIN
== aInnerMargin
.bottom
) {
953 aInnerMargin
.bottom
= 0;
955 if (NS_AUTOMARGIN
== aInnerMargin
.top
) {
956 nsCollapsingMargin marg
;
957 marg
.Include(aInnerMargin
.bottom
);
958 marg
.Include(aCaptionMargin
.top
);
959 nscoord collapseMargin
= marg
.get();
960 nscoord height
= aInnerSize
.height
+ collapseMargin
+ aCaptionSize
.height
;
961 aInnerMargin
.top
= CalcAutoMargin(aInnerMargin
.top
, aCaptionMargin
.bottom
,
962 aContainBlockSize
.height
, height
);
964 aOrigin
.y
= aInnerMargin
.top
;
966 case NS_STYLE_CAPTION_SIDE_LEFT
: {
968 if (NS_AUTOMARGIN
== aInnerMargin
.left
) {
969 aInnerMargin
.left
= CalcAutoMargin(aInnerMargin
.left
, aInnerMargin
.right
,
970 aContainBlockSize
.width
, aInnerSize
.width
);
973 if (aInnerMargin
.left
< minCapWidth
) {
974 // shift the inner table to get some place for the caption
975 aInnerMargin
.right
+= aInnerMargin
.left
- minCapWidth
;
976 aInnerMargin
.right
= PR_MAX(0, aInnerMargin
.right
);
977 aInnerMargin
.left
= minCapWidth
;
979 aOrigin
.x
= aInnerMargin
.left
;
980 if (NS_AUTOMARGIN
== aInnerMargin
.top
) {
981 aInnerMargin
.top
= 0;
983 aOrigin
.y
= aInnerMargin
.top
;
984 switch(GetCaptionVerticalAlign()) {
985 case NS_STYLE_VERTICAL_ALIGN_MIDDLE
:
986 aOrigin
.y
= PR_MAX(aInnerMargin
.top
, (aCaptionSize
.height
- aInnerSize
.height
) / 2);
988 case NS_STYLE_VERTICAL_ALIGN_BOTTOM
:
989 aOrigin
.y
= PR_MAX(aInnerMargin
.top
, aCaptionSize
.height
- aInnerSize
.height
);
995 case NS_STYLE_CAPTION_SIDE_RIGHT
: {
996 if (NS_AUTOMARGIN
== aInnerMargin
.right
) {
997 aInnerMargin
.right
= CalcAutoMargin(aInnerMargin
.left
, aInnerMargin
.right
,
998 aContainBlockSize
.width
, aInnerSize
.width
);
999 if (aInnerMargin
.right
< minCapWidth
) {
1000 // shift the inner table to get some place for the caption
1001 aInnerMargin
.left
-= aInnerMargin
.right
- minCapWidth
;
1002 aInnerMargin
.left
= PR_MAX(0, aInnerMargin
.left
);
1003 aInnerMargin
.right
= minCapWidth
;
1006 aOrigin
.x
= aInnerMargin
.left
;
1007 if (NS_AUTOMARGIN
== aInnerMargin
.top
) {
1008 aInnerMargin
.top
= 0;
1010 aOrigin
.y
= aInnerMargin
.top
;
1011 switch(GetCaptionVerticalAlign()) {
1012 case NS_STYLE_VERTICAL_ALIGN_MIDDLE
:
1013 aOrigin
.y
= PR_MAX(aInnerMargin
.top
, (aCaptionSize
.height
- aInnerSize
.height
) / 2);
1015 case NS_STYLE_VERTICAL_ALIGN_BOTTOM
:
1016 aOrigin
.y
= PR_MAX(aInnerMargin
.top
, aCaptionSize
.height
- aInnerSize
.height
);
1023 NS_ASSERTION(aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
1024 aCaptionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
||
1025 aCaptionSide
== NO_SIDE
,
1026 "unexpected caption side");
1027 if (NS_AUTOMARGIN
== aInnerMargin
.left
) {
1028 aInnerMargin
.left
= CalcAutoMargin(aInnerMargin
.left
, aInnerMargin
.right
,
1029 aContainBlockSize
.width
, aInnerSize
.width
);
1031 aOrigin
.x
= aInnerMargin
.left
;
1032 if (NS_AUTOMARGIN
== aInnerMargin
.top
) {
1033 aInnerMargin
.top
= 0;
1035 nsCollapsingMargin marg
;
1036 marg
.Include(aCaptionMargin
.bottom
);
1037 marg
.Include(aInnerMargin
.top
);
1038 nscoord collapseMargin
= marg
.get();
1039 if (NS_AUTOMARGIN
== aInnerMargin
.bottom
) {
1040 nscoord height
= aCaptionSize
.height
+ collapseMargin
+ aInnerSize
.height
;
1041 aInnerMargin
.bottom
= CalcAutoMargin(aCaptionMargin
.bottom
, aInnerMargin
.top
,
1042 aContainBlockSize
.height
, height
);
1044 aOrigin
.y
= aCaptionMargin
.top
+ aCaptionSize
.height
+ collapseMargin
;
1051 nsTableOuterFrame::OuterBeginReflowChild(nsPresContext
* aPresContext
,
1052 nsIFrame
* aChildFrame
,
1053 const nsHTMLReflowState
& aOuterRS
,
1054 void* aChildRSSpace
,
1055 nscoord aAvailWidth
)
1057 // work around pixel rounding errors, round down to ensure we don't exceed the avail height in
1058 nscoord availHeight
= aOuterRS
.availableHeight
;
1059 if (NS_UNCONSTRAINEDSIZE
!= availHeight
) {
1060 if (mCaptionFrame
== aChildFrame
) {
1061 availHeight
= NS_UNCONSTRAINEDSIZE
;
1064 GetMargin(aPresContext
, aOuterRS
, aChildFrame
, aOuterRS
.availableWidth
,
1067 NS_ASSERTION(NS_UNCONSTRAINEDSIZE
!= margin
.top
, "No unconstrainedsize arithmetic, please");
1068 availHeight
-= margin
.top
;
1070 NS_ASSERTION(NS_UNCONSTRAINEDSIZE
!= margin
.bottom
, "No unconstrainedsize arithmetic, please");
1071 availHeight
-= margin
.bottom
;
1074 nsSize
availSize(aAvailWidth
, availHeight
);
1075 // create and init the child reflow state, using placement new on
1076 // stack space allocated by the caller, so that the caller can destroy
1078 nsHTMLReflowState
&childRS
= * new (aChildRSSpace
)
1079 nsHTMLReflowState(aPresContext
, aOuterRS
, aChildFrame
, availSize
,
1081 InitChildReflowState(*aPresContext
, childRS
);
1083 // see if we need to reset top of page due to a caption
1084 if (mCaptionFrame
) {
1085 PRUint8 captionSide
= GetCaptionSide();
1086 if (((captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
||
1087 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
) &&
1088 mCaptionFrame
== aChildFrame
) ||
1089 ((captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
1090 captionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
) &&
1091 mInnerTableFrame
== aChildFrame
)) {
1092 childRS
.mFlags
.mIsTopOfPage
= PR_FALSE
;
1098 nsTableOuterFrame::OuterDoReflowChild(nsPresContext
* aPresContext
,
1099 nsIFrame
* aChildFrame
,
1100 const nsHTMLReflowState
& aChildRS
,
1101 nsHTMLReflowMetrics
& aMetrics
,
1102 nsReflowStatus
& aStatus
)
1105 // use the current position as a best guess for placement
1106 nsPoint childPt
= aChildFrame
->GetPosition();
1107 return ReflowChild(aChildFrame
, aPresContext
, aMetrics
, aChildRS
,
1108 childPt
.x
, childPt
.y
, NS_FRAME_NO_MOVE_FRAME
, aStatus
);
1112 nsTableOuterFrame::UpdateReflowMetrics(PRUint8 aCaptionSide
,
1113 nsHTMLReflowMetrics
& aMet
,
1114 const nsMargin
& aInnerMargin
,
1115 const nsMargin
& aCaptionMargin
)
1117 SetDesiredSize(aCaptionSide
, aInnerMargin
, aCaptionMargin
,
1118 aMet
.width
, aMet
.height
);
1120 aMet
.mOverflowArea
= nsRect(0, 0, aMet
.width
, aMet
.height
);
1121 ConsiderChildOverflow(aMet
.mOverflowArea
, mInnerTableFrame
);
1122 if (mCaptionFrame
) {
1123 ConsiderChildOverflow(aMet
.mOverflowArea
, mCaptionFrame
);
1125 FinishAndStoreOverflow(&aMet
);
1128 NS_METHOD
nsTableOuterFrame::Reflow(nsPresContext
* aPresContext
,
1129 nsHTMLReflowMetrics
& aDesiredSize
,
1130 const nsHTMLReflowState
& aOuterRS
,
1131 nsReflowStatus
& aStatus
)
1133 DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame");
1134 DISPLAY_REFLOW(aPresContext
, this, aOuterRS
, aDesiredSize
, aStatus
);
1136 // We desperately need an inner table frame,
1137 // if this fails fix the frame constructor
1138 if (mFrames
.IsEmpty() || !mInnerTableFrame
) {
1139 NS_ERROR("incomplete children");
1140 return NS_ERROR_FAILURE
;
1142 nsresult rv
= NS_OK
;
1143 PRUint8 captionSide
= GetCaptionSide();
1145 // Initialize out parameters
1146 aDesiredSize
.width
= aDesiredSize
.height
= 0;
1147 aStatus
= NS_FRAME_COMPLETE
;
1149 if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW
)) {
1150 // Set up our kids. They're already present, on an overflow list,
1151 // or there are none so we'll create them now
1152 MoveOverflowToChildList(aPresContext
);
1155 // Use longs to get more-aligned space.
1156 #define LONGS_IN_HTMLRS \
1157 ((sizeof(nsHTMLReflowState) + sizeof(long) - 1) / sizeof(long))
1158 long captionRSSpace
[LONGS_IN_HTMLRS
];
1159 nsHTMLReflowState
*captionRS
=
1160 static_cast<nsHTMLReflowState
*>((void*)captionRSSpace
);
1161 long innerRSSpace
[LONGS_IN_HTMLRS
];
1162 nsHTMLReflowState
*innerRS
=
1163 static_cast<nsHTMLReflowState
*>((void*) innerRSSpace
);
1165 nsRect origInnerRect
= mInnerTableFrame
->GetRect();
1166 nsRect origInnerOverflowRect
= mInnerTableFrame
->GetOverflowRect();
1167 PRBool innerFirstReflow
=
1168 (mInnerTableFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) != 0;
1169 nsRect origCaptionRect
;
1170 nsRect origCaptionOverflowRect
;
1171 PRBool captionFirstReflow
;
1172 if (mCaptionFrame
) {
1173 origCaptionRect
= mCaptionFrame
->GetRect();
1174 origCaptionOverflowRect
= mCaptionFrame
->GetOverflowRect();
1175 captionFirstReflow
=
1176 (mCaptionFrame
->GetStateBits() & NS_FRAME_FIRST_REFLOW
) != 0;
1179 // ComputeAutoSize has to match this logic.
1180 if (captionSide
== NO_SIDE
) {
1181 // We don't have a caption.
1182 OuterBeginReflowChild(aPresContext
, mInnerTableFrame
, aOuterRS
,
1183 innerRSSpace
, aOuterRS
.ComputedWidth());
1184 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_LEFT
||
1185 captionSide
== NS_STYLE_CAPTION_SIDE_RIGHT
) {
1186 // nsTableCaptionFrame::ComputeAutoSize takes care of making side
1187 // captions small. Compute the caption's size first, and tell the
1188 // table to fit in what's left.
1189 OuterBeginReflowChild(aPresContext
, mCaptionFrame
, aOuterRS
,
1190 captionRSSpace
, aOuterRS
.ComputedWidth());
1191 nscoord innerAvailWidth
= aOuterRS
.ComputedWidth() -
1192 (captionRS
->ComputedWidth() + captionRS
->mComputedMargin
.LeftRight() +
1193 captionRS
->mComputedBorderPadding
.LeftRight());
1194 OuterBeginReflowChild(aPresContext
, mInnerTableFrame
, aOuterRS
,
1195 innerRSSpace
, innerAvailWidth
);
1197 } else if (captionSide
== NS_STYLE_CAPTION_SIDE_TOP
||
1198 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM
) {
1199 // Compute the table's size first, and then prevent the caption from
1200 // being wider unless it has to be.
1202 // Note that CSS 2.1 (but not 2.0) says:
1203 // The width of the anonymous box is the border-edge width of the
1204 // table box inside it
1205 // We don't actually make our anonymous box that width (if we did,
1206 // it would break 'auto' margins), but this effectively does that.
1207 OuterBeginReflowChild(aPresContext
, mInnerTableFrame
, aOuterRS
,
1208 innerRSSpace
, aOuterRS
.ComputedWidth());
1209 // It's good that CSS 2.1 says not to include margins, since we
1210 // can't, since they already been converted so they exactly
1211 // fill the available width (ignoring the margin on one side if
1212 // neither are auto). (We take advantage of that later when we call
1213 // GetCaptionOrigin, though.)
1214 nscoord innerBorderWidth
= innerRS
->ComputedWidth() +
1215 innerRS
->mComputedBorderPadding
.LeftRight();
1216 OuterBeginReflowChild(aPresContext
, mCaptionFrame
, aOuterRS
,
1217 captionRSSpace
, innerBorderWidth
);
1219 NS_ASSERTION(captionSide
== NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE
||
1220 captionSide
== NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE
,
1221 "unexpected caption-side");
1222 // Size the table and the caption independently.
1223 OuterBeginReflowChild(aPresContext
, mCaptionFrame
, aOuterRS
,
1224 captionRSSpace
, aOuterRS
.ComputedWidth());
1225 OuterBeginReflowChild(aPresContext
, mInnerTableFrame
, aOuterRS
,
1226 innerRSSpace
, aOuterRS
.ComputedWidth());
1229 // First reflow the caption.
1230 nsHTMLReflowMetrics captionMet
;
1232 nsMargin captionMargin
;
1233 if (mCaptionFrame
) {
1234 nsReflowStatus capStatus
; // don't let the caption cause incomplete
1235 rv
= OuterDoReflowChild(aPresContext
, mCaptionFrame
, *captionRS
,
1236 captionMet
, capStatus
);
1237 if (NS_FAILED(rv
)) return rv
;
1238 captionSize
.width
= captionMet
.width
;
1239 captionSize
.height
= captionMet
.height
;
1240 captionMargin
= captionRS
->mComputedMargin
;
1242 captionSize
.SizeTo(0,0);
1243 captionMargin
.SizeTo(0,0,0,0);
1246 // Then, now that we know how much to reduce the width of the inner
1247 // table to account for side captions, reflow the inner table.
1248 nsHTMLReflowMetrics innerMet
;
1249 rv
= OuterDoReflowChild(aPresContext
, mInnerTableFrame
, *innerRS
,
1251 if (NS_FAILED(rv
)) return rv
;
1253 innerSize
.width
= innerMet
.width
;
1254 innerSize
.height
= innerMet
.height
;
1255 nsMargin innerMargin
= innerRS
->mComputedMargin
;
1257 nsSize containSize
= GetContainingBlockSize(aOuterRS
);
1259 // Now that we've reflowed both we can place them.
1260 // XXXldb Most of the input variables here are now uninitialized!
1262 // XXX Need to recompute inner table's auto margins for the case of side
1263 // captions. (Caption's are broken too, but that should be fixed earlier.)
1265 if (mCaptionFrame
) {
1266 nsPoint captionOrigin
;
1267 GetCaptionOrigin(captionSide
, containSize
, innerSize
,
1268 innerMargin
, captionSize
, captionMargin
, captionOrigin
);
1269 FinishReflowChild(mCaptionFrame
, aPresContext
, captionRS
, captionMet
,
1270 captionOrigin
.x
, captionOrigin
.y
, 0);
1271 captionRS
->~nsHTMLReflowState();
1273 // XXX If the height is constrained then we need to check whether
1274 // everything still fits...
1276 nsPoint innerOrigin
;
1277 GetInnerOrigin(captionSide
, containSize
, captionSize
,
1278 captionMargin
, innerSize
, innerMargin
, innerOrigin
);
1279 FinishReflowChild(mInnerTableFrame
, aPresContext
, innerRS
, innerMet
,
1280 innerOrigin
.x
, innerOrigin
.y
, 0);
1281 innerRS
->~nsHTMLReflowState();
1283 nsTableFrame::InvalidateFrame(mInnerTableFrame
, origInnerRect
,
1284 origInnerOverflowRect
, innerFirstReflow
);
1285 if (mCaptionFrame
) {
1286 nsTableFrame::InvalidateFrame(mCaptionFrame
, origCaptionRect
,
1287 origCaptionOverflowRect
, captionFirstReflow
);
1290 UpdateReflowMetrics(captionSide
, aDesiredSize
, innerMargin
, captionMargin
);
1292 // Return our desired rect
1294 NS_FRAME_SET_TRUNCATION(aStatus
, aOuterRS
, aDesiredSize
);
1299 NS_METHOD
nsTableOuterFrame::VerifyTree() const
1306 nsTableOuterFrame::GetType() const
1308 return nsGkAtoms::tableOuterFrame
;
1311 /* ----- global methods ----- */
1313 /*------------------ nsITableLayout methods ------------------------------*/
1315 nsTableOuterFrame::GetCellDataAt(PRInt32 aRowIndex
, PRInt32 aColIndex
,
1316 nsIDOMElement
* &aCell
, //out params
1317 PRInt32
& aStartRowIndex
, PRInt32
& aStartColIndex
,
1318 PRInt32
& aRowSpan
, PRInt32
& aColSpan
,
1319 PRInt32
& aActualRowSpan
, PRInt32
& aActualColSpan
,
1320 PRBool
& aIsSelected
)
1322 NS_ASSERTION(mInnerTableFrame
, "no inner table frame yet?");
1324 return mInnerTableFrame
->GetCellDataAt(aRowIndex
, aColIndex
, aCell
,
1325 aStartRowIndex
, aStartColIndex
,
1326 aRowSpan
, aColSpan
, aActualRowSpan
,
1327 aActualColSpan
, aIsSelected
);
1331 nsTableOuterFrame::GetTableSize(PRInt32
& aRowCount
, PRInt32
& aColCount
)
1333 NS_ASSERTION(mInnerTableFrame
, "no inner table frame yet?");
1335 return mInnerTableFrame
->GetTableSize(aRowCount
, aColCount
);
1339 nsTableOuterFrame::GetIndexByRowAndColumn(PRInt32 aRow
, PRInt32 aColumn
,
1342 NS_ENSURE_ARG_POINTER(aIndex
);
1344 NS_ASSERTION(mInnerTableFrame
, "no inner table frame yet?");
1345 return mInnerTableFrame
->GetIndexByRowAndColumn(aRow
, aColumn
, aIndex
);
1349 nsTableOuterFrame::GetRowAndColumnByIndex(PRInt32 aIndex
,
1350 PRInt32
*aRow
, PRInt32
*aColumn
)
1352 NS_ENSURE_ARG_POINTER(aRow
);
1353 NS_ENSURE_ARG_POINTER(aColumn
);
1355 NS_ASSERTION(mInnerTableFrame
, "no inner table frame yet?");
1356 return mInnerTableFrame
->GetRowAndColumnByIndex(aIndex
, aRow
, aColumn
);
1359 /*---------------- end of nsITableLayout implementation ------------------*/
1363 NS_NewTableOuterFrame(nsIPresShell
* aPresShell
, nsStyleContext
* aContext
)
1365 return new (aPresShell
) nsTableOuterFrame(aContext
);
1370 nsTableOuterFrame::GetFrameName(nsAString
& aResult
) const
1372 return MakeFrameName(NS_LITERAL_STRING("TableOuter"), aResult
);