layout/tables/nsTableCellFrame.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "nsTableFrame.h"
     6 #include "nsTableColFrame.h"
     7 #include "nsTableCellFrame.h"
     8 #include "nsTableRowFrame.h"
     9 #include "nsTableRowGroupFrame.h"
    10 #include "nsTablePainter.h"
    11 #include "nsStyleContext.h"
    12 #include "nsStyleConsts.h"
    13 #include "nsPresContext.h"
    14 #include "nsRenderingContext.h"
    15 #include "nsCSSRendering.h"
    16 #include "nsIContent.h"
    17 #include "nsGenericHTMLElement.h"
    18 #include "nsAttrValueInlines.h"
    19 #include "nsHTMLParts.h"
    20 #include "nsGkAtoms.h"
    21 #include "nsIPresShell.h"
    22 #include "nsCOMPtr.h"
    23 #include "nsIServiceManager.h"
    24 #include "nsIDOMNode.h"
    25 #include "nsNameSpaceManager.h"
    26 #include "nsDisplayList.h"
    27 #include "nsLayoutUtils.h"
    28 #include "nsTextFrame.h"
    29 #include "FrameLayerBuilder.h"
    30 #include <algorithm>
    32 //TABLECELL SELECTION
    33 #include "nsFrameSelection.h"
    34 #include "mozilla/LookAndFeel.h"
    36 using namespace mozilla;
    39 nsTableCellFrame::nsTableCellFrame(nsStyleContext* aContext) :
    40   nsContainerFrame(aContext)
    41 {
    42   mColIndex = 0;
    43   mPriorAvailWidth = 0;
    45   SetContentEmpty(false);
    46   SetHasPctOverHeight(false);
    47 }
    49 nsTableCellFrame::~nsTableCellFrame()
    50 {
    51 }
    53 NS_IMPL_FRAMEARENA_HELPERS(nsTableCellFrame)
    55 nsTableCellFrame*
    56 nsTableCellFrame::GetNextCell() const
    57 {
    58   nsIFrame* childFrame = GetNextSibling();
    59   while (childFrame) {
    60     nsTableCellFrame *cellFrame = do_QueryFrame(childFrame);
    61     if (cellFrame) {
    62       return cellFrame;
    63     }
    64     childFrame = childFrame->GetNextSibling();
    65   }
    66   return nullptr;
    67 }
    69 void
    70 nsTableCellFrame::Init(nsIContent*      aContent,
    71                        nsIFrame*        aParent,
    72                        nsIFrame*        aPrevInFlow)
    73 {
    74   // Let the base class do its initialization
    75   nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
    77   if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) {
    78     AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
    79   }
    81   if (aPrevInFlow) {
    82     // Set the column index
    83     nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow;
    84     int32_t           colIndex;
    85     cellFrame->GetColIndex(colIndex);
    86     SetColIndex(colIndex);
    87   }
    88 }
    90 void
    91 nsTableCellFrame::DestroyFrom(nsIFrame* aDestructRoot)
    92 {
    93   if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) {
    94     nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot);
    95   }
    97   nsContainerFrame::DestroyFrom(aDestructRoot);
    98 }
   100 // nsIPercentHeightObserver methods
   102 void
   103 nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState)
   104 {
   105   // nsHTMLReflowState ensures the mCBReflowState of blocks inside a
   106   // cell is the cell frame, not the inner-cell block, and that the
   107   // containing block of an inner table is the containing block of its
   108   // outer table.
   109   // XXXldb Given the now-stricter |NeedsToObserve|, many if not all of
   110   // these tests are probably unnecessary.
   112   // Maybe the cell reflow state; we sure if we're inside the |if|.
   113   const nsHTMLReflowState *cellRS = aReflowState.mCBReflowState;
   115   if (cellRS && cellRS->frame == this &&
   116       (cellRS->ComputedHeight() == NS_UNCONSTRAINEDSIZE ||
   117        cellRS->ComputedHeight() == 0)) { // XXXldb Why 0?
   118     // This is a percentage height on a frame whose percentage heights
   119     // are based on the height of the cell, since its containing block
   120     // is the inner cell frame.
   122     // We'll only honor the percent height if sibling-cells/ancestors
   123     // have specified/pct height. (Also, siblings only count for this if
   124     // both this cell and the sibling cell span exactly 1 row.)
   126     if (nsTableFrame::AncestorsHaveStyleHeight(*cellRS) ||
   127         (nsTableFrame::GetTableFrame(this)->GetEffectiveRowSpan(*this) == 1 &&
   128          (cellRS->parentReflowState->frame->GetStateBits() &
   129           NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT))) {
   131       for (const nsHTMLReflowState *rs = aReflowState.parentReflowState;
   132            rs != cellRS;
   133            rs = rs->parentReflowState) {
   134         rs->frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT);
   135       }
   137       nsTableFrame::RequestSpecialHeightReflow(*cellRS);
   138     }
   139   }
   140 }
   142 // The cell needs to observe its block and things inside its block but nothing below that
   143 bool
   144 nsTableCellFrame::NeedsToObserve(const nsHTMLReflowState& aReflowState)
   145 {
   146   const nsHTMLReflowState *rs = aReflowState.parentReflowState;
   147   if (!rs)
   148     return false;
   149   if (rs->frame == this) {
   150     // We always observe the child block.  It will never send any
   151     // notifications, but we need this so that the observer gets
   152     // propagated to its kids.
   153     return true;
   154   }
   155   rs = rs->parentReflowState;
   156   if (!rs) {
   157     return false;
   158   }
   160   // We always need to let the percent height observer be propagated
   161   // from an outer table frame to an inner table frame.
   162   nsIAtom *fType = aReflowState.frame->GetType();
   163   if (fType == nsGkAtoms::tableFrame) {
   164     return true;
   165   }
   167   // We need the observer to be propagated to all children of the cell
   168   // (i.e., children of the child block) in quirks mode, but only to
   169   // tables in standards mode.
   170   return rs->frame == this &&
   171          (PresContext()->CompatibilityMode() == eCompatibility_NavQuirks ||
   172           fType == nsGkAtoms::tableOuterFrame);
   173 }
   175 nsresult
   176 nsTableCellFrame::GetRowIndex(int32_t &aRowIndex) const
   177 {
   178   nsresult result;
   179   nsTableRowFrame* row = static_cast<nsTableRowFrame*>(GetParent());
   180   if (row) {
   181     aRowIndex = row->GetRowIndex();
   182     result = NS_OK;
   183   }
   184   else {
   185     aRowIndex = 0;
   186     result = NS_ERROR_NOT_INITIALIZED;
   187   }
   188   return result;
   189 }
   191 nsresult
   192 nsTableCellFrame::GetColIndex(int32_t &aColIndex) const
   193 {
   194   if (GetPrevInFlow()) {
   195     return static_cast<nsTableCellFrame*>(FirstInFlow())->GetColIndex(aColIndex);
   196   }
   197   else {
   198     aColIndex = mColIndex;
   199     return  NS_OK;
   200   }
   201 }
   203 nsresult
   204 nsTableCellFrame::AttributeChanged(int32_t         aNameSpaceID,
   205                                    nsIAtom*        aAttribute,
   206                                    int32_t         aModType)
   207 {
   208   // We need to recalculate in this case because of the nowrap quirk in
   209   // BasicTableLayoutStrategy
   210   if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::nowrap &&
   211       PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
   212     PresContext()->PresShell()->
   213       FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY);
   214   }
   215   // let the table frame decide what to do
   216   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   217   tableFrame->AttributeChangedFor(this, mContent, aAttribute);
   218   return NS_OK;
   219 }
   221 /* virtual */ void
   222 nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
   223 {
   224   nsContainerFrame::DidSetStyleContext(aOldStyleContext);
   226   if (!aOldStyleContext) //avoid this on init
   227     return;
   229   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   230   if (tableFrame->IsBorderCollapse() &&
   231       tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
   232     int32_t colIndex, rowIndex;
   233     GetColIndex(colIndex);
   234     GetRowIndex(rowIndex);
   235     // row span needs to be clamped as we do not create rows in the cellmap
   236     // which do not have cells originating in them
   237     nsIntRect damageArea(colIndex, rowIndex, GetColSpan(),
   238       std::min(GetRowSpan(), tableFrame->GetRowCount() - rowIndex));
   239     tableFrame->AddBCDamageArea(damageArea);
   240   }
   241 }
   244 nsresult
   245 nsTableCellFrame::AppendFrames(ChildListID     aListID,
   246                                nsFrameList&    aFrameList)
   247 {
   248   NS_PRECONDITION(false, "unsupported operation");
   249   return NS_ERROR_NOT_IMPLEMENTED;
   250 }
   252 nsresult
   253 nsTableCellFrame::InsertFrames(ChildListID     aListID,
   254                                nsIFrame*       aPrevFrame,
   255                                nsFrameList&    aFrameList)
   256 {
   257   NS_PRECONDITION(false, "unsupported operation");
   258   return NS_ERROR_NOT_IMPLEMENTED;
   259 }
   261 nsresult
   262 nsTableCellFrame::RemoveFrame(ChildListID     aListID,
   263                               nsIFrame*       aOldFrame)
   264 {
   265   NS_PRECONDITION(false, "unsupported operation");
   266   return NS_ERROR_NOT_IMPLEMENTED;
   267 }
   269 void nsTableCellFrame::SetColIndex(int32_t aColIndex)
   270 {
   271   mColIndex = aColIndex;
   272 }
   274 /* virtual */ nsMargin
   275 nsTableCellFrame::GetUsedMargin() const
   276 {
   277   return nsMargin(0,0,0,0);
   278 }
   280 //ASSURE DIFFERENT COLORS for selection
   281 inline nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB)
   282 {
   283     if (colorA == colorB)
   284     {
   285       nscolor res;
   286       res = NS_RGB(NS_GET_R(colorA) ^ 0xff,
   287                    NS_GET_G(colorA) ^ 0xff,
   288                    NS_GET_B(colorA) ^ 0xff);
   289       return res;
   290     }
   291     return colorA;
   292 }
   294 void
   295 nsTableCellFrame::DecorateForSelection(nsRenderingContext& aRenderingContext,
   296                                        nsPoint aPt)
   297 {
   298   NS_ASSERTION(IsSelected(), "Should only be called for selected cells");
   299   int16_t displaySelection;
   300   nsPresContext* presContext = PresContext();
   301   displaySelection = DisplaySelection(presContext);
   302   if (displaySelection) {
   303     nsRefPtr<nsFrameSelection> frameSelection =
   304       presContext->PresShell()->FrameSelection();
   306     if (frameSelection->GetTableCellSelection()) {
   307       nscolor       bordercolor;
   308       if (displaySelection == nsISelectionController::SELECTION_DISABLED) {
   309         bordercolor = NS_RGB(176,176,176);// disabled color
   310       }
   311       else {
   312         bordercolor =
   313           LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectBackground);
   314       }
   315       nscoord threePx = nsPresContext::CSSPixelsToAppUnits(3);
   316       if ((mRect.width > threePx) && (mRect.height > threePx))
   317       {
   318         //compare bordercolor to ((nsStyleColor *)myColor)->mBackgroundColor)
   319         bordercolor = EnsureDifferentColors(bordercolor,
   320                                             StyleBackground()->mBackgroundColor);
   321         nsRenderingContext::AutoPushTranslation
   322             translate(&aRenderingContext, aPt);
   323         nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1);
   325         aRenderingContext.SetColor(bordercolor);
   326         aRenderingContext.DrawLine(onePixel, 0, mRect.width, 0);
   327         aRenderingContext.DrawLine(0, onePixel, 0, mRect.height);
   328         aRenderingContext.DrawLine(onePixel, mRect.height, mRect.width, mRect.height);
   329         aRenderingContext.DrawLine(mRect.width, onePixel, mRect.width, mRect.height);
   330         //middle
   331         aRenderingContext.DrawRect(onePixel, onePixel, mRect.width-onePixel,
   332                                    mRect.height-onePixel);
   333         //shading
   334         aRenderingContext.DrawLine(2*onePixel, mRect.height-2*onePixel,
   335                                    mRect.width-onePixel, mRect.height- (2*onePixel));
   336         aRenderingContext.DrawLine(mRect.width - (2*onePixel), 2*onePixel,
   337                                    mRect.width - (2*onePixel), mRect.height-onePixel);
   338       }
   339     }
   340   }
   341 }
   343 void
   344 nsTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
   345                                   const nsRect&        aDirtyRect,
   346                                   nsPoint              aPt,
   347                                   uint32_t             aFlags)
   348 {
   349   nsRect rect(aPt, GetSize());
   350   nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this,
   351                                   aDirtyRect, rect, aFlags);
   352 }
   354 // Called by nsTablePainter
   355 void
   356 nsTableCellFrame::PaintCellBackground(nsRenderingContext& aRenderingContext,
   357                                       const nsRect& aDirtyRect, nsPoint aPt,
   358                                       uint32_t aFlags)
   359 {
   360   if (!StyleVisibility()->IsVisible())
   361     return;
   363   PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags);
   364 }
   366 nsresult
   367 nsTableCellFrame::ProcessBorders(nsTableFrame* aFrame,
   368                                  nsDisplayListBuilder* aBuilder,
   369                                  const nsDisplayListSet& aLists)
   370 {
   371   const nsStyleBorder* borderStyle = StyleBorder();
   372   if (aFrame->IsBorderCollapse() || !borderStyle->HasBorder())
   373     return NS_OK;
   375   if (!GetContentEmpty() ||
   376       StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW) {
   377     aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
   378                                               nsDisplayBorder(aBuilder, this));
   379   }
   381   return NS_OK;
   382 }
   384 class nsDisplayTableCellBackground : public nsDisplayTableItem {
   385 public:
   386   nsDisplayTableCellBackground(nsDisplayListBuilder* aBuilder,
   387                                nsTableCellFrame* aFrame) :
   388     nsDisplayTableItem(aBuilder, aFrame) {
   389     MOZ_COUNT_CTOR(nsDisplayTableCellBackground);
   390   }
   391 #ifdef NS_BUILD_REFCNT_LOGGING
   392   virtual ~nsDisplayTableCellBackground() {
   393     MOZ_COUNT_DTOR(nsDisplayTableCellBackground);
   394   }
   395 #endif
   397   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
   398                        HitTestState* aState,
   399                        nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE {
   400     aOutFrames->AppendElement(mFrame);
   401   }
   402   virtual void Paint(nsDisplayListBuilder* aBuilder,
   403                      nsRenderingContext* aCtx) MOZ_OVERRIDE;
   404   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
   405                            bool* aSnap) MOZ_OVERRIDE;
   406   virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   407                                          const nsDisplayItemGeometry* aGeometry,
   408                                          nsRegion *aInvalidRegion) MOZ_OVERRIDE;
   410   NS_DISPLAY_DECL_NAME("TableCellBackground", TYPE_TABLE_CELL_BACKGROUND)
   411 };
   413 void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder,
   414                                          nsRenderingContext* aCtx)
   415 {
   416   static_cast<nsTableCellFrame*>(mFrame)->
   417     PaintBackground(*aCtx, mVisibleRect, ToReferenceFrame(),
   418                     aBuilder->GetBackgroundPaintFlags());
   419 }
   421 nsRect
   422 nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder,
   423                                         bool* aSnap)
   424 {
   425   // revert from nsDisplayTableItem's implementation ... cell backgrounds
   426   // don't overflow the cell
   427   return nsDisplayItem::GetBounds(aBuilder, aSnap);
   428 }
   430 void
   431 nsDisplayTableCellBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
   432                                                         const nsDisplayItemGeometry* aGeometry,
   433                                                         nsRegion *aInvalidRegion)
   434 {
   435   if (aBuilder->ShouldSyncDecodeImages()) {
   436     if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame)) {
   437       bool snap;
   438       aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
   439     }
   440   }
   442   nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
   443 }
   445 void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey)
   446 {
   447   nsIFrame::InvalidateFrame(aDisplayItemKey);
   448   GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
   449 }
   451 void nsTableCellFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
   452 {
   453   nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
   454   // If we have filters applied that would affects our bounds, then
   455   // we get an inactive layer created and this is computed
   456   // within FrameLayerBuilder
   457   GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
   458 }
   460 static void
   461 PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx,
   462                         const nsRect& aRect, nsPoint aPt)
   463 {
   464   static_cast<nsTableCellFrame*>(aFrame)->DecorateForSelection(*aCtx, aPt);
   465 }
   467 void
   468 nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   469                                    const nsRect&           aDirtyRect,
   470                                    const nsDisplayListSet& aLists)
   471 {
   472   DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame");
   473   if (IsVisibleInSelection(aBuilder)) {
   474     nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   475     int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ?
   476                                 StyleTableBorder()->mEmptyCells
   477                                 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
   478     // take account of 'empty-cells'
   479     if (StyleVisibility()->IsVisible() &&
   480         (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) {
   483       bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext();
   484       if (!isRoot) {
   485         nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem();
   486         if (currentItem) {
   487           currentItem->UpdateForFrameBackground(this);
   488         }
   489       }
   491       // display outset box-shadows if we need to.
   492       const nsStyleBorder* borderStyle = StyleBorder();
   493       bool hasBoxShadow = !!borderStyle->mBoxShadow;
   494       if (hasBoxShadow) {
   495         aLists.BorderBackground()->AppendNewToTop(
   496           new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this));
   497       }
   499       // display background if we need to.
   500       if (aBuilder->IsForEventDelivery() ||
   501           (((!tableFrame->IsBorderCollapse() || isRoot) &&
   502           (!StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance)))) {
   503         // The cell background was not painted by the nsTablePainter,
   504         // so we need to do it. We have special background processing here
   505         // so we need to duplicate some code from nsFrame::DisplayBorderBackgroundOutline
   506         nsDisplayTableItem* item =
   507           new (aBuilder) nsDisplayTableCellBackground(aBuilder, this);
   508         aLists.BorderBackground()->AppendNewToTop(item);
   509         item->UpdateForFrameBackground(this);
   510       }
   512       // display inset box-shadows if we need to.
   513       if (hasBoxShadow) {
   514         aLists.BorderBackground()->AppendNewToTop(
   515           new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this));
   516       }
   518       // display borders if we need to
   519       ProcessBorders(tableFrame, aBuilder, aLists);
   521       // and display the selection border if we need to
   522       if (IsSelected()) {
   523         aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
   524           nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection,
   525                            "TableCellSelection",
   526                            nsDisplayItem::TYPE_TABLE_CELL_SELECTION));
   527       }
   528     }
   530     // the 'empty-cells' property has no effect on 'outline'
   531     DisplayOutline(aBuilder, aLists);
   532   }
   534   // Push a null 'current table item' so that descendant tables can't
   535   // accidentally mess with our table
   536   nsAutoPushCurrentTableItem pushTableItem;
   537   pushTableItem.Push(aBuilder, nullptr);
   539   nsIFrame* kid = mFrames.FirstChild();
   540   NS_ASSERTION(kid && !kid->GetNextSibling(), "Table cells should have just one child");
   541   // The child's background will go in our BorderBackground() list.
   542   // This isn't a problem since it won't have a real background except for
   543   // event handling. We do not call BuildDisplayListForNonBlockChildren
   544   // because that/ would put the child's background in the Content() list
   545   // which isn't right (e.g., would end up on top of our child floats for
   546   // event handling).
   547   BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists);
   548 }
   550 int
   551 nsTableCellFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
   552 {
   553   int skip = 0;
   554   if (nullptr != GetPrevInFlow()) {
   555     skip |= LOGICAL_SIDE_B_START;
   556   }
   557   if (nullptr != GetNextInFlow()) {
   558     skip |= LOGICAL_SIDE_B_END;
   559   }
   560   return skip;
   561 }
   563 /* virtual */ nsMargin
   564 nsTableCellFrame::GetBorderOverflow()
   565 {
   566   return nsMargin(0, 0, 0, 0);
   567 }
   569 // Align the cell's child frame within the cell
   571 void nsTableCellFrame::VerticallyAlignChild(nscoord aMaxAscent)
   572 {
   573   /* It's the 'border-collapse' on the table that matters */
   574   nsMargin borderPadding = GetUsedBorderAndPadding();
   576   nscoord topInset = borderPadding.top;
   577   nscoord bottomInset = borderPadding.bottom;
   579   uint8_t verticalAlignFlags = GetVerticalAlign();
   581   nscoord height = mRect.height;
   582   nsIFrame* firstKid = mFrames.FirstChild();
   583   NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
   584   nsRect kidRect = firstKid->GetRect();
   585   nscoord childHeight = kidRect.height;
   587   // Vertically align the child
   588   nscoord kidYTop = 0;
   589   switch (verticalAlignFlags)
   590   {
   591     case NS_STYLE_VERTICAL_ALIGN_BASELINE:
   592       // Align the baselines of the child frame with the baselines of
   593       // other children in the same row which have 'vertical-align: baseline'
   594       kidYTop = topInset + aMaxAscent - GetCellBaseline();
   595     break;
   597     case NS_STYLE_VERTICAL_ALIGN_TOP:
   598       // Align the top of the child frame with the top of the content area,
   599       kidYTop = topInset;
   600     break;
   602     case NS_STYLE_VERTICAL_ALIGN_BOTTOM:
   603       // Align the bottom of the child frame with the bottom of the content area,
   604       kidYTop = height - childHeight - bottomInset;
   605     break;
   607     default:
   608     case NS_STYLE_VERTICAL_ALIGN_MIDDLE:
   609       // Align the middle of the child frame with the middle of the content area,
   610       kidYTop = (height - childHeight - bottomInset + topInset) / 2;
   611   }
   612   // if the content is larger than the cell height align from top
   613   kidYTop = std::max(0, kidYTop);
   615   if (kidYTop != kidRect.y) {
   616     // Invalidate at the old position first
   617     firstKid->InvalidateFrameSubtree();
   618   }
   620   firstKid->SetPosition(nsPoint(kidRect.x, kidYTop));
   621   nsHTMLReflowMetrics desiredSize(GetWritingMode()); // ???
   622   desiredSize.Width() = mRect.width;
   623   desiredSize.Height() = mRect.height;
   625   nsRect overflow(nsPoint(0,0), GetSize());
   626   overflow.Inflate(GetBorderOverflow());
   627   desiredSize.mOverflowAreas.SetAllTo(overflow);
   628   ConsiderChildOverflow(desiredSize.mOverflowAreas, firstKid);
   629   FinishAndStoreOverflow(&desiredSize);
   630   if (kidYTop != kidRect.y) {
   631     // Make sure any child views are correctly positioned. We know the inner table
   632     // cell won't have a view
   633     nsContainerFrame::PositionChildViews(firstKid);
   635     // Invalidate new overflow rect
   636     firstKid->InvalidateFrameSubtree();
   637   }
   638   if (HasView()) {
   639     nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this,
   640                                                GetView(),
   641                                                desiredSize.VisualOverflow(), 0);
   642   }
   643 }
   645 bool
   646 nsTableCellFrame::UpdateOverflow()
   647 {
   648   nsRect bounds(nsPoint(0,0), GetSize());
   649   bounds.Inflate(GetBorderOverflow());
   650   nsOverflowAreas overflowAreas(bounds, bounds);
   652   nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
   654   return FinishAndStoreOverflow(overflowAreas, GetSize());
   655 }
   657 // Per CSS 2.1, we map 'sub', 'super', 'text-top', 'text-bottom',
   658 // length, percentage, and calc() values to 'baseline'.
   659 uint8_t
   660 nsTableCellFrame::GetVerticalAlign() const
   661 {
   662   const nsStyleCoord& verticalAlign = StyleTextReset()->mVerticalAlign;
   663   if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
   664     uint8_t value = verticalAlign.GetIntValue();
   665     if (value == NS_STYLE_VERTICAL_ALIGN_TOP ||
   666         value == NS_STYLE_VERTICAL_ALIGN_MIDDLE ||
   667         value == NS_STYLE_VERTICAL_ALIGN_BOTTOM) {
   668       return value;
   669     }
   670   }
   671   return NS_STYLE_VERTICAL_ALIGN_BASELINE;
   672 }
   674 bool
   675 nsTableCellFrame::CellHasVisibleContent(nscoord       height,
   676                                         nsTableFrame* tableFrame,
   677                                         nsIFrame*     kidFrame)
   678 {
   679   // see  http://www.w3.org/TR/CSS21/tables.html#empty-cells
   680   if (height > 0)
   681     return true;
   682   if (tableFrame->IsBorderCollapse())
   683     return true;
   684   nsIFrame* innerFrame = kidFrame->GetFirstPrincipalChild();
   685   while(innerFrame) {
   686     nsIAtom* frameType = innerFrame->GetType();
   687     if (nsGkAtoms::textFrame == frameType) {
   688        nsTextFrame* textFrame = static_cast<nsTextFrame*>(innerFrame);
   689        if (textFrame->HasNoncollapsedCharacters())
   690          return true;
   691     }
   692     else if (nsGkAtoms::placeholderFrame != frameType) {
   693       return true;
   694     }
   695     else {
   696       nsIFrame *floatFrame = nsLayoutUtils::GetFloatFromPlaceholder(innerFrame);
   697       if (floatFrame)
   698         return true;
   699     }
   700     innerFrame = innerFrame->GetNextSibling();
   701   }	
   702   return false;
   703 }
   705 nscoord
   706 nsTableCellFrame::GetCellBaseline() const
   707 {
   708   // Ignore the position of the inner frame relative to the cell frame
   709   // since we want the position as though the inner were top-aligned.
   710   nsIFrame *inner = mFrames.FirstChild();
   711   nscoord borderPadding = GetUsedBorderAndPadding().top;
   712   nscoord result;
   713   if (nsLayoutUtils::GetFirstLineBaseline(inner, &result))
   714     return result + borderPadding;
   715   return inner->GetContentRect().YMost() - inner->GetPosition().y +
   716          borderPadding;
   717 }
   719 int32_t nsTableCellFrame::GetRowSpan()
   720 {
   721   int32_t rowSpan=1;
   722   nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
   724   // Don't look at the content's rowspan if we're a pseudo cell
   725   if (hc && !StyleContext()->GetPseudo()) {
   726     const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::rowspan);
   727     // Note that we don't need to check the tag name, because only table cells
   728     // and table headers parse the "rowspan" attribute into an integer.
   729     if (attr && attr->Type() == nsAttrValue::eInteger) {
   730        rowSpan = attr->GetIntegerValue();
   731     }
   732   }
   733   return rowSpan;
   734 }
   736 int32_t nsTableCellFrame::GetColSpan()
   737 {
   738   int32_t colSpan=1;
   739   nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent);
   741   // Don't look at the content's colspan if we're a pseudo cell
   742   if (hc && !StyleContext()->GetPseudo()) {
   743     const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::colspan);
   744     // Note that we don't need to check the tag name, because only table cells
   745     // and table headers parse the "colspan" attribute into an integer.
   746     if (attr && attr->Type() == nsAttrValue::eInteger) {
   747        colSpan = attr->GetIntegerValue();
   748     }
   749   }
   750   return colSpan;
   751 }
   753 /* virtual */ nscoord
   754 nsTableCellFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
   755 {
   756   nscoord result = 0;
   757   DISPLAY_MIN_WIDTH(this, result);
   759   nsIFrame *inner = mFrames.FirstChild();
   760   result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
   761                                                     nsLayoutUtils::MIN_WIDTH);
   762   return result;
   763 }
   765 /* virtual */ nscoord
   766 nsTableCellFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
   767 {
   768   nscoord result = 0;
   769   DISPLAY_PREF_WIDTH(this, result);
   771   nsIFrame *inner = mFrames.FirstChild();
   772   result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
   773                                                 nsLayoutUtils::PREF_WIDTH);
   774   return result;
   775 }
   777 /* virtual */ nsIFrame::IntrinsicWidthOffsetData
   778 nsTableCellFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext)
   779 {
   780   IntrinsicWidthOffsetData result =
   781     nsContainerFrame::IntrinsicWidthOffsets(aRenderingContext);
   783   result.hMargin = 0;
   784   result.hPctMargin = 0;
   786   nsMargin border;
   787   GetBorderWidth(border);
   788   result.hBorder = border.LeftRight();
   790   return result;
   791 }
   793 #ifdef DEBUG
   794 #define PROBABLY_TOO_LARGE 1000000
   795 static
   796 void DebugCheckChildSize(nsIFrame*            aChild,
   797                          nsHTMLReflowMetrics& aMet,
   798                          nsSize&              aAvailSize)
   799 {
   800   if ((aMet.Width() < 0) || (aMet.Width() > PROBABLY_TOO_LARGE)) {
   801     printf("WARNING: cell content %p has large width %d \n",
   802            static_cast<void*>(aChild), int32_t(aMet.Width()));
   803   }
   804 }
   805 #endif
   807 // the computed height for the cell, which descendants use for percent height calculations
   808 // it is the height (minus border, padding) of the cell's first in flow during its final
   809 // reflow without an unconstrained height.
   810 static nscoord
   811 CalcUnpaginagedHeight(nsPresContext*        aPresContext,
   812                       nsTableCellFrame&     aCellFrame,
   813                       nsTableFrame&         aTableFrame,
   814                       nscoord               aVerticalBorderPadding)
   815 {
   816   const nsTableCellFrame* firstCellInFlow =
   817     static_cast<nsTableCellFrame*>(aCellFrame.FirstInFlow());
   818   nsTableFrame* firstTableInFlow  =
   819     static_cast<nsTableFrame*>(aTableFrame.FirstInFlow());
   820   nsTableRowFrame* row =
   821     static_cast<nsTableRowFrame*>(firstCellInFlow->GetParent());
   822   nsTableRowGroupFrame* firstRGInFlow =
   823     static_cast<nsTableRowGroupFrame*>(row->GetParent());
   825   int32_t rowIndex;
   826   firstCellInFlow->GetRowIndex(rowIndex);
   827   int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow);
   828   nscoord cellSpacing = firstTableInFlow->GetCellSpacingX();
   830   nscoord computedHeight = ((rowSpan - 1) * cellSpacing) - aVerticalBorderPadding;
   831   int32_t rowX;
   832   for (row = firstRGInFlow->GetFirstRow(), rowX = 0; row; row = row->GetNextRow(), rowX++) {
   833     if (rowX > rowIndex + rowSpan - 1) {
   834       break;
   835     }
   836     else if (rowX >= rowIndex) {
   837       computedHeight += row->GetUnpaginatedHeight(aPresContext);
   838     }
   839   }
   840   return computedHeight;
   841 }
   843 nsresult nsTableCellFrame::Reflow(nsPresContext*           aPresContext,
   844                                    nsHTMLReflowMetrics&     aDesiredSize,
   845                                    const nsHTMLReflowState& aReflowState,
   846                                    nsReflowStatus&          aStatus)
   847 {
   848   DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame");
   849   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   851   if (aReflowState.mFlags.mSpecialHeightReflow) {
   852     FirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW);
   853   }
   855   // see if a special height reflow needs to occur due to having a pct height
   856   nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
   858   aStatus = NS_FRAME_COMPLETE;
   859   nsSize availSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight());
   861   nsMargin borderPadding = aReflowState.ComputedPhysicalPadding();
   862   nsMargin border;
   863   GetBorderWidth(border);
   864   borderPadding += border;
   866   nscoord topInset    = borderPadding.top;
   867   nscoord rightInset  = borderPadding.right;
   868   nscoord bottomInset = borderPadding.bottom;
   869   nscoord leftInset   = borderPadding.left;
   871   // reduce available space by insets, if we're in a constrained situation
   872   availSize.width -= leftInset + rightInset;
   873   if (NS_UNCONSTRAINEDSIZE != availSize.height)
   874     availSize.height -= topInset + bottomInset;
   876   // Try to reflow the child into the available space. It might not
   877   // fit or might need continuing.
   878   if (availSize.height < 0)
   879     availSize.height = 1;
   881   nsHTMLReflowMetrics kidSize(aReflowState.GetWritingMode(), aDesiredSize.mFlags);
   882   kidSize.Width() = kidSize.Height() = 0;
   883   SetPriorAvailWidth(aReflowState.AvailableWidth());
   884   nsIFrame* firstKid = mFrames.FirstChild();
   885   NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
   886   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   888   if (aReflowState.mFlags.mSpecialHeightReflow) {
   889     const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(mRect.height - topInset - bottomInset);
   890     DISPLAY_REFLOW_CHANGE();
   891   }
   892   else if (aPresContext->IsPaginated()) {
   893     nscoord computedUnpaginatedHeight =
   894       CalcUnpaginagedHeight(aPresContext, (nsTableCellFrame&)*this,
   895                             *tableFrame, topInset + bottomInset);
   896     if (computedUnpaginatedHeight > 0) {
   897       const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(computedUnpaginatedHeight);
   898       DISPLAY_REFLOW_CHANGE();
   899     }
   900   }
   901   else {
   902     SetHasPctOverHeight(false);
   903   }
   905   nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid,
   906                                    availSize);
   908   // Don't be a percent height observer if we're in the middle of
   909   // special-height reflow, in case we get an accidental NotifyPercentHeight()
   910   // call (which we shouldn't honor during special-height reflow)
   911   if (!aReflowState.mFlags.mSpecialHeightReflow) {
   912     // mPercentHeightObserver is for children of cells in quirks mode,
   913     // but only those than are tables in standards mode.  NeedsToObserve
   914     // will determine how far this is propagated to descendants.
   915     kidReflowState.mPercentHeightObserver = this;
   916   }
   917   // Don't propagate special height reflow state to our kids
   918   kidReflowState.mFlags.mSpecialHeightReflow = false;
   920   if (aReflowState.mFlags.mSpecialHeightReflow ||
   921       (FirstInFlow()->GetStateBits() & NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) {
   922     // We need to force the kid to have mVResize set if we've had a
   923     // special reflow in the past, since the non-special reflow needs to
   924     // resize back to what it was without the special height reflow.
   925     kidReflowState.mFlags.mVResize = true;
   926   }
   928   nsPoint kidOrigin(leftInset, topInset);
   929   nsRect origRect = firstKid->GetRect();
   930   nsRect origVisualOverflow = firstKid->GetVisualOverflowRect();
   931   bool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0;
   933   ReflowChild(firstKid, aPresContext, kidSize, kidReflowState,
   934               kidOrigin.x, kidOrigin.y, 0, aStatus);
   935   if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
   936     // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it
   937     //XXX should paginate overflow as overflow, but not in this patch (bug 379349)
   938     NS_FRAME_SET_INCOMPLETE(aStatus);
   939     printf("Set table cell incomplete %p\n", static_cast<void*>(this));
   940   }
   942   // XXXbz is this invalidate actually needed, really?
   943   if (GetStateBits() & NS_FRAME_IS_DIRTY) {
   944     InvalidateFrameSubtree();
   945   }
   947 #ifdef DEBUG
   948   DebugCheckChildSize(firstKid, kidSize, availSize);
   949 #endif
   951   // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode
   952   // see testcase "emptyCells.html"
   953   nsIFrame* prevInFlow = GetPrevInFlow();
   954   bool isEmpty;
   955   if (prevInFlow) {
   956     isEmpty = static_cast<nsTableCellFrame*>(prevInFlow)->GetContentEmpty();
   957   } else {
   958     isEmpty = !CellHasVisibleContent(kidSize.Height(), tableFrame, firstKid);
   959   }
   960   SetContentEmpty(isEmpty);
   962   // Place the child
   963   FinishReflowChild(firstKid, aPresContext, kidSize, &kidReflowState,
   964                     kidOrigin.x, kidOrigin.y, 0);
   966   nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow,
   967                                      firstReflow);
   969   // first, compute the height which can be set w/o being restricted by aMaxSize.height
   970   nscoord cellHeight = kidSize.Height();
   972   if (NS_UNCONSTRAINEDSIZE != cellHeight) {
   973     cellHeight += topInset + bottomInset;
   974   }
   976   // next determine the cell's width
   977   nscoord cellWidth = kidSize.Width();      // at this point, we've factored in the cell's style attributes
   979   // factor in border and padding
   980   if (NS_UNCONSTRAINEDSIZE != cellWidth) {
   981     cellWidth += leftInset + rightInset;
   982   }
   984   // set the cell's desired size and max element size
   985   aDesiredSize.Width() = cellWidth;
   986   aDesiredSize.Height() = cellHeight;
   988   // the overflow area will be computed when the child will be vertically aligned
   990   if (aReflowState.mFlags.mSpecialHeightReflow) {
   991     if (aDesiredSize.Height() > mRect.height) {
   992       // set a bit indicating that the pct height contents exceeded
   993       // the height that they could honor in the pass 2 reflow
   994       SetHasPctOverHeight(true);
   995     }
   996     if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) {
   997       aDesiredSize.Height() = mRect.height;
   998     }
   999   }
  1001   // If our parent is in initial reflow, it'll handle invalidating our
  1002   // entire overflow rect.
  1003   if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
  1004       nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) {
  1005     InvalidateFrame();
  1008   // remember the desired size for this reflow
  1009   SetDesiredSize(aDesiredSize);
  1011   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
  1012   return NS_OK;
  1015 /* ----- global methods ----- */
  1017 NS_QUERYFRAME_HEAD(nsTableCellFrame)
  1018   NS_QUERYFRAME_ENTRY(nsTableCellFrame)
  1019   NS_QUERYFRAME_ENTRY(nsITableCellLayout)
  1020   NS_QUERYFRAME_ENTRY(nsIPercentHeightObserver)
  1021 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
  1023 #ifdef ACCESSIBILITY
  1024 a11y::AccType
  1025 nsTableCellFrame::AccessibleType()
  1027   return a11y::eHTMLTableCellType;
  1029 #endif
  1031 /* This is primarily for editor access via nsITableLayout */
  1032 NS_IMETHODIMP
  1033 nsTableCellFrame::GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex)
  1035   nsresult res = GetRowIndex(aRowIndex);
  1036   if (NS_FAILED(res))
  1038     aColIndex = 0;
  1039     return res;
  1041   aColIndex = mColIndex;
  1042   return  NS_OK;
  1045 nsIFrame*
  1046 NS_NewTableCellFrame(nsIPresShell*   aPresShell,
  1047                      nsStyleContext* aContext,
  1048                      bool            aIsBorderCollapse)
  1050   if (aIsBorderCollapse)
  1051     return new (aPresShell) nsBCTableCellFrame(aContext);
  1052   else
  1053     return new (aPresShell) nsTableCellFrame(aContext);
  1056 NS_IMPL_FRAMEARENA_HELPERS(nsBCTableCellFrame)
  1058 nsMargin*
  1059 nsTableCellFrame::GetBorderWidth(nsMargin&  aBorder) const
  1061   aBorder = StyleBorder()->GetComputedBorder();
  1062   return &aBorder;
  1065 nsIAtom*
  1066 nsTableCellFrame::GetType() const
  1068   return nsGkAtoms::tableCellFrame;
  1071 #ifdef DEBUG_FRAME_DUMP
  1072 nsresult
  1073 nsTableCellFrame::GetFrameName(nsAString& aResult) const
  1075   return MakeFrameName(NS_LITERAL_STRING("TableCell"), aResult);
  1077 #endif
  1079 // nsBCTableCellFrame
  1081 nsBCTableCellFrame::nsBCTableCellFrame(nsStyleContext* aContext)
  1082 :nsTableCellFrame(aContext)
  1084   mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0;
  1087 nsBCTableCellFrame::~nsBCTableCellFrame()
  1091 nsIAtom*
  1092 nsBCTableCellFrame::GetType() const
  1094   return nsGkAtoms::bcTableCellFrame;
  1097 /* virtual */ nsMargin
  1098 nsBCTableCellFrame::GetUsedBorder() const
  1100   nsMargin result;
  1101   GetBorderWidth(result);
  1102   return result;
  1105 /* virtual */ bool
  1106 nsBCTableCellFrame::GetBorderRadii(nscoord aRadii[8]) const
  1108   NS_FOR_CSS_HALF_CORNERS(corner) {
  1109     aRadii[corner] = 0;
  1111   return false;
  1114 #ifdef DEBUG_FRAME_DUMP
  1115 nsresult
  1116 nsBCTableCellFrame::GetFrameName(nsAString& aResult) const
  1118   return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
  1120 #endif
  1122 nsMargin*
  1123 nsBCTableCellFrame::GetBorderWidth(nsMargin&  aBorder) const
  1125   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
  1126   aBorder.top    = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, mTopBorder);
  1127   aBorder.right  = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, mRightBorder);
  1128   aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mBottomBorder);
  1129   aBorder.left   = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mLeftBorder);
  1130   return &aBorder;
  1133 BCPixelSize
  1134 nsBCTableCellFrame::GetBorderWidth(mozilla::css::Side aSide) const
  1136   switch(aSide) {
  1137   case NS_SIDE_TOP:
  1138     return BC_BORDER_BOTTOM_HALF(mTopBorder);
  1139   case NS_SIDE_RIGHT:
  1140     return BC_BORDER_LEFT_HALF(mRightBorder);
  1141   case NS_SIDE_BOTTOM:
  1142     return BC_BORDER_TOP_HALF(mBottomBorder);
  1143   default:
  1144     return BC_BORDER_RIGHT_HALF(mLeftBorder);
  1148 void
  1149 nsBCTableCellFrame::SetBorderWidth(mozilla::css::Side aSide,
  1150                                    BCPixelSize aValue)
  1152   switch(aSide) {
  1153   case NS_SIDE_TOP:
  1154     mTopBorder = aValue;
  1155     break;
  1156   case NS_SIDE_RIGHT:
  1157     mRightBorder = aValue;
  1158     break;
  1159   case NS_SIDE_BOTTOM:
  1160     mBottomBorder = aValue;
  1161     break;
  1162   default:
  1163     mLeftBorder = aValue;
  1167 /* virtual */ nsMargin
  1168 nsBCTableCellFrame::GetBorderOverflow()
  1170   nsMargin halfBorder;
  1171   int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
  1172   halfBorder.top = BC_BORDER_TOP_HALF_COORD(p2t, mTopBorder);
  1173   halfBorder.right = BC_BORDER_RIGHT_HALF_COORD(p2t, mRightBorder);
  1174   halfBorder.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, mBottomBorder);
  1175   halfBorder.left = BC_BORDER_LEFT_HALF_COORD(p2t, mLeftBorder);
  1176   return halfBorder;
  1180 void
  1181 nsBCTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
  1182                                     const nsRect&        aDirtyRect,
  1183                                     nsPoint              aPt,
  1184                                     uint32_t             aFlags)
  1186   // make border-width reflect the half of the border-collapse
  1187   // assigned border that's inside the cell
  1188   nsMargin borderWidth;
  1189   GetBorderWidth(borderWidth);
  1191   nsStyleBorder myBorder(*StyleBorder());
  1193   NS_FOR_CSS_SIDES(side) {
  1194     myBorder.SetBorderWidth(side, borderWidth.Side(side));
  1197   nsRect rect(aPt, GetSize());
  1198   // bypassing nsCSSRendering::PaintBackground is safe because this kind
  1199   // of frame cannot be used for the root element
  1200   nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext, this,
  1201                                         aDirtyRect, rect,
  1202                                         StyleContext(), myBorder,
  1203                                         aFlags, nullptr);

mercurial