1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/tables/nsTableCellFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1204 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +#include "nsTableFrame.h" 1.9 +#include "nsTableColFrame.h" 1.10 +#include "nsTableCellFrame.h" 1.11 +#include "nsTableRowFrame.h" 1.12 +#include "nsTableRowGroupFrame.h" 1.13 +#include "nsTablePainter.h" 1.14 +#include "nsStyleContext.h" 1.15 +#include "nsStyleConsts.h" 1.16 +#include "nsPresContext.h" 1.17 +#include "nsRenderingContext.h" 1.18 +#include "nsCSSRendering.h" 1.19 +#include "nsIContent.h" 1.20 +#include "nsGenericHTMLElement.h" 1.21 +#include "nsAttrValueInlines.h" 1.22 +#include "nsHTMLParts.h" 1.23 +#include "nsGkAtoms.h" 1.24 +#include "nsIPresShell.h" 1.25 +#include "nsCOMPtr.h" 1.26 +#include "nsIServiceManager.h" 1.27 +#include "nsIDOMNode.h" 1.28 +#include "nsNameSpaceManager.h" 1.29 +#include "nsDisplayList.h" 1.30 +#include "nsLayoutUtils.h" 1.31 +#include "nsTextFrame.h" 1.32 +#include "FrameLayerBuilder.h" 1.33 +#include <algorithm> 1.34 + 1.35 +//TABLECELL SELECTION 1.36 +#include "nsFrameSelection.h" 1.37 +#include "mozilla/LookAndFeel.h" 1.38 + 1.39 +using namespace mozilla; 1.40 + 1.41 + 1.42 +nsTableCellFrame::nsTableCellFrame(nsStyleContext* aContext) : 1.43 + nsContainerFrame(aContext) 1.44 +{ 1.45 + mColIndex = 0; 1.46 + mPriorAvailWidth = 0; 1.47 + 1.48 + SetContentEmpty(false); 1.49 + SetHasPctOverHeight(false); 1.50 +} 1.51 + 1.52 +nsTableCellFrame::~nsTableCellFrame() 1.53 +{ 1.54 +} 1.55 + 1.56 +NS_IMPL_FRAMEARENA_HELPERS(nsTableCellFrame) 1.57 + 1.58 +nsTableCellFrame* 1.59 +nsTableCellFrame::GetNextCell() const 1.60 +{ 1.61 + nsIFrame* childFrame = GetNextSibling(); 1.62 + while (childFrame) { 1.63 + nsTableCellFrame *cellFrame = do_QueryFrame(childFrame); 1.64 + if (cellFrame) { 1.65 + return cellFrame; 1.66 + } 1.67 + childFrame = childFrame->GetNextSibling(); 1.68 + } 1.69 + return nullptr; 1.70 +} 1.71 + 1.72 +void 1.73 +nsTableCellFrame::Init(nsIContent* aContent, 1.74 + nsIFrame* aParent, 1.75 + nsIFrame* aPrevInFlow) 1.76 +{ 1.77 + // Let the base class do its initialization 1.78 + nsContainerFrame::Init(aContent, aParent, aPrevInFlow); 1.79 + 1.80 + if (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER) { 1.81 + AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); 1.82 + } 1.83 + 1.84 + if (aPrevInFlow) { 1.85 + // Set the column index 1.86 + nsTableCellFrame* cellFrame = (nsTableCellFrame*)aPrevInFlow; 1.87 + int32_t colIndex; 1.88 + cellFrame->GetColIndex(colIndex); 1.89 + SetColIndex(colIndex); 1.90 + } 1.91 +} 1.92 + 1.93 +void 1.94 +nsTableCellFrame::DestroyFrom(nsIFrame* aDestructRoot) 1.95 +{ 1.96 + if (GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN) { 1.97 + nsTableFrame::UnregisterPositionedTablePart(this, aDestructRoot); 1.98 + } 1.99 + 1.100 + nsContainerFrame::DestroyFrom(aDestructRoot); 1.101 +} 1.102 + 1.103 +// nsIPercentHeightObserver methods 1.104 + 1.105 +void 1.106 +nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState) 1.107 +{ 1.108 + // nsHTMLReflowState ensures the mCBReflowState of blocks inside a 1.109 + // cell is the cell frame, not the inner-cell block, and that the 1.110 + // containing block of an inner table is the containing block of its 1.111 + // outer table. 1.112 + // XXXldb Given the now-stricter |NeedsToObserve|, many if not all of 1.113 + // these tests are probably unnecessary. 1.114 + 1.115 + // Maybe the cell reflow state; we sure if we're inside the |if|. 1.116 + const nsHTMLReflowState *cellRS = aReflowState.mCBReflowState; 1.117 + 1.118 + if (cellRS && cellRS->frame == this && 1.119 + (cellRS->ComputedHeight() == NS_UNCONSTRAINEDSIZE || 1.120 + cellRS->ComputedHeight() == 0)) { // XXXldb Why 0? 1.121 + // This is a percentage height on a frame whose percentage heights 1.122 + // are based on the height of the cell, since its containing block 1.123 + // is the inner cell frame. 1.124 + 1.125 + // We'll only honor the percent height if sibling-cells/ancestors 1.126 + // have specified/pct height. (Also, siblings only count for this if 1.127 + // both this cell and the sibling cell span exactly 1 row.) 1.128 + 1.129 + if (nsTableFrame::AncestorsHaveStyleHeight(*cellRS) || 1.130 + (nsTableFrame::GetTableFrame(this)->GetEffectiveRowSpan(*this) == 1 && 1.131 + (cellRS->parentReflowState->frame->GetStateBits() & 1.132 + NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT))) { 1.133 + 1.134 + for (const nsHTMLReflowState *rs = aReflowState.parentReflowState; 1.135 + rs != cellRS; 1.136 + rs = rs->parentReflowState) { 1.137 + rs->frame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_HEIGHT); 1.138 + } 1.139 + 1.140 + nsTableFrame::RequestSpecialHeightReflow(*cellRS); 1.141 + } 1.142 + } 1.143 +} 1.144 + 1.145 +// The cell needs to observe its block and things inside its block but nothing below that 1.146 +bool 1.147 +nsTableCellFrame::NeedsToObserve(const nsHTMLReflowState& aReflowState) 1.148 +{ 1.149 + const nsHTMLReflowState *rs = aReflowState.parentReflowState; 1.150 + if (!rs) 1.151 + return false; 1.152 + if (rs->frame == this) { 1.153 + // We always observe the child block. It will never send any 1.154 + // notifications, but we need this so that the observer gets 1.155 + // propagated to its kids. 1.156 + return true; 1.157 + } 1.158 + rs = rs->parentReflowState; 1.159 + if (!rs) { 1.160 + return false; 1.161 + } 1.162 + 1.163 + // We always need to let the percent height observer be propagated 1.164 + // from an outer table frame to an inner table frame. 1.165 + nsIAtom *fType = aReflowState.frame->GetType(); 1.166 + if (fType == nsGkAtoms::tableFrame) { 1.167 + return true; 1.168 + } 1.169 + 1.170 + // We need the observer to be propagated to all children of the cell 1.171 + // (i.e., children of the child block) in quirks mode, but only to 1.172 + // tables in standards mode. 1.173 + return rs->frame == this && 1.174 + (PresContext()->CompatibilityMode() == eCompatibility_NavQuirks || 1.175 + fType == nsGkAtoms::tableOuterFrame); 1.176 +} 1.177 + 1.178 +nsresult 1.179 +nsTableCellFrame::GetRowIndex(int32_t &aRowIndex) const 1.180 +{ 1.181 + nsresult result; 1.182 + nsTableRowFrame* row = static_cast<nsTableRowFrame*>(GetParent()); 1.183 + if (row) { 1.184 + aRowIndex = row->GetRowIndex(); 1.185 + result = NS_OK; 1.186 + } 1.187 + else { 1.188 + aRowIndex = 0; 1.189 + result = NS_ERROR_NOT_INITIALIZED; 1.190 + } 1.191 + return result; 1.192 +} 1.193 + 1.194 +nsresult 1.195 +nsTableCellFrame::GetColIndex(int32_t &aColIndex) const 1.196 +{ 1.197 + if (GetPrevInFlow()) { 1.198 + return static_cast<nsTableCellFrame*>(FirstInFlow())->GetColIndex(aColIndex); 1.199 + } 1.200 + else { 1.201 + aColIndex = mColIndex; 1.202 + return NS_OK; 1.203 + } 1.204 +} 1.205 + 1.206 +nsresult 1.207 +nsTableCellFrame::AttributeChanged(int32_t aNameSpaceID, 1.208 + nsIAtom* aAttribute, 1.209 + int32_t aModType) 1.210 +{ 1.211 + // We need to recalculate in this case because of the nowrap quirk in 1.212 + // BasicTableLayoutStrategy 1.213 + if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::nowrap && 1.214 + PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) { 1.215 + PresContext()->PresShell()-> 1.216 + FrameNeedsReflow(this, nsIPresShell::eTreeChange, NS_FRAME_IS_DIRTY); 1.217 + } 1.218 + // let the table frame decide what to do 1.219 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.220 + tableFrame->AttributeChangedFor(this, mContent, aAttribute); 1.221 + return NS_OK; 1.222 +} 1.223 + 1.224 +/* virtual */ void 1.225 +nsTableCellFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) 1.226 +{ 1.227 + nsContainerFrame::DidSetStyleContext(aOldStyleContext); 1.228 + 1.229 + if (!aOldStyleContext) //avoid this on init 1.230 + return; 1.231 + 1.232 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.233 + if (tableFrame->IsBorderCollapse() && 1.234 + tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) { 1.235 + int32_t colIndex, rowIndex; 1.236 + GetColIndex(colIndex); 1.237 + GetRowIndex(rowIndex); 1.238 + // row span needs to be clamped as we do not create rows in the cellmap 1.239 + // which do not have cells originating in them 1.240 + nsIntRect damageArea(colIndex, rowIndex, GetColSpan(), 1.241 + std::min(GetRowSpan(), tableFrame->GetRowCount() - rowIndex)); 1.242 + tableFrame->AddBCDamageArea(damageArea); 1.243 + } 1.244 +} 1.245 + 1.246 + 1.247 +nsresult 1.248 +nsTableCellFrame::AppendFrames(ChildListID aListID, 1.249 + nsFrameList& aFrameList) 1.250 +{ 1.251 + NS_PRECONDITION(false, "unsupported operation"); 1.252 + return NS_ERROR_NOT_IMPLEMENTED; 1.253 +} 1.254 + 1.255 +nsresult 1.256 +nsTableCellFrame::InsertFrames(ChildListID aListID, 1.257 + nsIFrame* aPrevFrame, 1.258 + nsFrameList& aFrameList) 1.259 +{ 1.260 + NS_PRECONDITION(false, "unsupported operation"); 1.261 + return NS_ERROR_NOT_IMPLEMENTED; 1.262 +} 1.263 + 1.264 +nsresult 1.265 +nsTableCellFrame::RemoveFrame(ChildListID aListID, 1.266 + nsIFrame* aOldFrame) 1.267 +{ 1.268 + NS_PRECONDITION(false, "unsupported operation"); 1.269 + return NS_ERROR_NOT_IMPLEMENTED; 1.270 +} 1.271 + 1.272 +void nsTableCellFrame::SetColIndex(int32_t aColIndex) 1.273 +{ 1.274 + mColIndex = aColIndex; 1.275 +} 1.276 + 1.277 +/* virtual */ nsMargin 1.278 +nsTableCellFrame::GetUsedMargin() const 1.279 +{ 1.280 + return nsMargin(0,0,0,0); 1.281 +} 1.282 + 1.283 +//ASSURE DIFFERENT COLORS for selection 1.284 +inline nscolor EnsureDifferentColors(nscolor colorA, nscolor colorB) 1.285 +{ 1.286 + if (colorA == colorB) 1.287 + { 1.288 + nscolor res; 1.289 + res = NS_RGB(NS_GET_R(colorA) ^ 0xff, 1.290 + NS_GET_G(colorA) ^ 0xff, 1.291 + NS_GET_B(colorA) ^ 0xff); 1.292 + return res; 1.293 + } 1.294 + return colorA; 1.295 +} 1.296 + 1.297 +void 1.298 +nsTableCellFrame::DecorateForSelection(nsRenderingContext& aRenderingContext, 1.299 + nsPoint aPt) 1.300 +{ 1.301 + NS_ASSERTION(IsSelected(), "Should only be called for selected cells"); 1.302 + int16_t displaySelection; 1.303 + nsPresContext* presContext = PresContext(); 1.304 + displaySelection = DisplaySelection(presContext); 1.305 + if (displaySelection) { 1.306 + nsRefPtr<nsFrameSelection> frameSelection = 1.307 + presContext->PresShell()->FrameSelection(); 1.308 + 1.309 + if (frameSelection->GetTableCellSelection()) { 1.310 + nscolor bordercolor; 1.311 + if (displaySelection == nsISelectionController::SELECTION_DISABLED) { 1.312 + bordercolor = NS_RGB(176,176,176);// disabled color 1.313 + } 1.314 + else { 1.315 + bordercolor = 1.316 + LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectBackground); 1.317 + } 1.318 + nscoord threePx = nsPresContext::CSSPixelsToAppUnits(3); 1.319 + if ((mRect.width > threePx) && (mRect.height > threePx)) 1.320 + { 1.321 + //compare bordercolor to ((nsStyleColor *)myColor)->mBackgroundColor) 1.322 + bordercolor = EnsureDifferentColors(bordercolor, 1.323 + StyleBackground()->mBackgroundColor); 1.324 + nsRenderingContext::AutoPushTranslation 1.325 + translate(&aRenderingContext, aPt); 1.326 + nscoord onePixel = nsPresContext::CSSPixelsToAppUnits(1); 1.327 + 1.328 + aRenderingContext.SetColor(bordercolor); 1.329 + aRenderingContext.DrawLine(onePixel, 0, mRect.width, 0); 1.330 + aRenderingContext.DrawLine(0, onePixel, 0, mRect.height); 1.331 + aRenderingContext.DrawLine(onePixel, mRect.height, mRect.width, mRect.height); 1.332 + aRenderingContext.DrawLine(mRect.width, onePixel, mRect.width, mRect.height); 1.333 + //middle 1.334 + aRenderingContext.DrawRect(onePixel, onePixel, mRect.width-onePixel, 1.335 + mRect.height-onePixel); 1.336 + //shading 1.337 + aRenderingContext.DrawLine(2*onePixel, mRect.height-2*onePixel, 1.338 + mRect.width-onePixel, mRect.height- (2*onePixel)); 1.339 + aRenderingContext.DrawLine(mRect.width - (2*onePixel), 2*onePixel, 1.340 + mRect.width - (2*onePixel), mRect.height-onePixel); 1.341 + } 1.342 + } 1.343 + } 1.344 +} 1.345 + 1.346 +void 1.347 +nsTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext, 1.348 + const nsRect& aDirtyRect, 1.349 + nsPoint aPt, 1.350 + uint32_t aFlags) 1.351 +{ 1.352 + nsRect rect(aPt, GetSize()); 1.353 + nsCSSRendering::PaintBackground(PresContext(), aRenderingContext, this, 1.354 + aDirtyRect, rect, aFlags); 1.355 +} 1.356 + 1.357 +// Called by nsTablePainter 1.358 +void 1.359 +nsTableCellFrame::PaintCellBackground(nsRenderingContext& aRenderingContext, 1.360 + const nsRect& aDirtyRect, nsPoint aPt, 1.361 + uint32_t aFlags) 1.362 +{ 1.363 + if (!StyleVisibility()->IsVisible()) 1.364 + return; 1.365 + 1.366 + PaintBackground(aRenderingContext, aDirtyRect, aPt, aFlags); 1.367 +} 1.368 + 1.369 +nsresult 1.370 +nsTableCellFrame::ProcessBorders(nsTableFrame* aFrame, 1.371 + nsDisplayListBuilder* aBuilder, 1.372 + const nsDisplayListSet& aLists) 1.373 +{ 1.374 + const nsStyleBorder* borderStyle = StyleBorder(); 1.375 + if (aFrame->IsBorderCollapse() || !borderStyle->HasBorder()) 1.376 + return NS_OK; 1.377 + 1.378 + if (!GetContentEmpty() || 1.379 + StyleTableBorder()->mEmptyCells == NS_STYLE_TABLE_EMPTY_CELLS_SHOW) { 1.380 + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) 1.381 + nsDisplayBorder(aBuilder, this)); 1.382 + } 1.383 + 1.384 + return NS_OK; 1.385 +} 1.386 + 1.387 +class nsDisplayTableCellBackground : public nsDisplayTableItem { 1.388 +public: 1.389 + nsDisplayTableCellBackground(nsDisplayListBuilder* aBuilder, 1.390 + nsTableCellFrame* aFrame) : 1.391 + nsDisplayTableItem(aBuilder, aFrame) { 1.392 + MOZ_COUNT_CTOR(nsDisplayTableCellBackground); 1.393 + } 1.394 +#ifdef NS_BUILD_REFCNT_LOGGING 1.395 + virtual ~nsDisplayTableCellBackground() { 1.396 + MOZ_COUNT_DTOR(nsDisplayTableCellBackground); 1.397 + } 1.398 +#endif 1.399 + 1.400 + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 1.401 + HitTestState* aState, 1.402 + nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE { 1.403 + aOutFrames->AppendElement(mFrame); 1.404 + } 1.405 + virtual void Paint(nsDisplayListBuilder* aBuilder, 1.406 + nsRenderingContext* aCtx) MOZ_OVERRIDE; 1.407 + virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, 1.408 + bool* aSnap) MOZ_OVERRIDE; 1.409 + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.410 + const nsDisplayItemGeometry* aGeometry, 1.411 + nsRegion *aInvalidRegion) MOZ_OVERRIDE; 1.412 + 1.413 + NS_DISPLAY_DECL_NAME("TableCellBackground", TYPE_TABLE_CELL_BACKGROUND) 1.414 +}; 1.415 + 1.416 +void nsDisplayTableCellBackground::Paint(nsDisplayListBuilder* aBuilder, 1.417 + nsRenderingContext* aCtx) 1.418 +{ 1.419 + static_cast<nsTableCellFrame*>(mFrame)-> 1.420 + PaintBackground(*aCtx, mVisibleRect, ToReferenceFrame(), 1.421 + aBuilder->GetBackgroundPaintFlags()); 1.422 +} 1.423 + 1.424 +nsRect 1.425 +nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder, 1.426 + bool* aSnap) 1.427 +{ 1.428 + // revert from nsDisplayTableItem's implementation ... cell backgrounds 1.429 + // don't overflow the cell 1.430 + return nsDisplayItem::GetBounds(aBuilder, aSnap); 1.431 +} 1.432 + 1.433 +void 1.434 +nsDisplayTableCellBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.435 + const nsDisplayItemGeometry* aGeometry, 1.436 + nsRegion *aInvalidRegion) 1.437 +{ 1.438 + if (aBuilder->ShouldSyncDecodeImages()) { 1.439 + if (!nsCSSRendering::AreAllBackgroundImagesDecodedForFrame(mFrame)) { 1.440 + bool snap; 1.441 + aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap)); 1.442 + } 1.443 + } 1.444 + 1.445 + nsDisplayTableItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); 1.446 +} 1.447 + 1.448 +void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey) 1.449 +{ 1.450 + nsIFrame::InvalidateFrame(aDisplayItemKey); 1.451 + GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey); 1.452 +} 1.453 + 1.454 +void nsTableCellFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) 1.455 +{ 1.456 + nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey); 1.457 + // If we have filters applied that would affects our bounds, then 1.458 + // we get an inactive layer created and this is computed 1.459 + // within FrameLayerBuilder 1.460 + GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey); 1.461 +} 1.462 + 1.463 +static void 1.464 +PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx, 1.465 + const nsRect& aRect, nsPoint aPt) 1.466 +{ 1.467 + static_cast<nsTableCellFrame*>(aFrame)->DecorateForSelection(*aCtx, aPt); 1.468 +} 1.469 + 1.470 +void 1.471 +nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.472 + const nsRect& aDirtyRect, 1.473 + const nsDisplayListSet& aLists) 1.474 +{ 1.475 + DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame"); 1.476 + if (IsVisibleInSelection(aBuilder)) { 1.477 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.478 + int32_t emptyCellStyle = GetContentEmpty() && !tableFrame->IsBorderCollapse() ? 1.479 + StyleTableBorder()->mEmptyCells 1.480 + : NS_STYLE_TABLE_EMPTY_CELLS_SHOW; 1.481 + // take account of 'empty-cells' 1.482 + if (StyleVisibility()->IsVisible() && 1.483 + (NS_STYLE_TABLE_EMPTY_CELLS_HIDE != emptyCellStyle)) { 1.484 + 1.485 + 1.486 + bool isRoot = aBuilder->IsAtRootOfPseudoStackingContext(); 1.487 + if (!isRoot) { 1.488 + nsDisplayTableItem* currentItem = aBuilder->GetCurrentTableItem(); 1.489 + if (currentItem) { 1.490 + currentItem->UpdateForFrameBackground(this); 1.491 + } 1.492 + } 1.493 + 1.494 + // display outset box-shadows if we need to. 1.495 + const nsStyleBorder* borderStyle = StyleBorder(); 1.496 + bool hasBoxShadow = !!borderStyle->mBoxShadow; 1.497 + if (hasBoxShadow) { 1.498 + aLists.BorderBackground()->AppendNewToTop( 1.499 + new (aBuilder) nsDisplayBoxShadowOuter(aBuilder, this)); 1.500 + } 1.501 + 1.502 + // display background if we need to. 1.503 + if (aBuilder->IsForEventDelivery() || 1.504 + (((!tableFrame->IsBorderCollapse() || isRoot) && 1.505 + (!StyleBackground()->IsTransparent() || StyleDisplay()->mAppearance)))) { 1.506 + // The cell background was not painted by the nsTablePainter, 1.507 + // so we need to do it. We have special background processing here 1.508 + // so we need to duplicate some code from nsFrame::DisplayBorderBackgroundOutline 1.509 + nsDisplayTableItem* item = 1.510 + new (aBuilder) nsDisplayTableCellBackground(aBuilder, this); 1.511 + aLists.BorderBackground()->AppendNewToTop(item); 1.512 + item->UpdateForFrameBackground(this); 1.513 + } 1.514 + 1.515 + // display inset box-shadows if we need to. 1.516 + if (hasBoxShadow) { 1.517 + aLists.BorderBackground()->AppendNewToTop( 1.518 + new (aBuilder) nsDisplayBoxShadowInner(aBuilder, this)); 1.519 + } 1.520 + 1.521 + // display borders if we need to 1.522 + ProcessBorders(tableFrame, aBuilder, aLists); 1.523 + 1.524 + // and display the selection border if we need to 1.525 + if (IsSelected()) { 1.526 + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) 1.527 + nsDisplayGeneric(aBuilder, this, ::PaintTableCellSelection, 1.528 + "TableCellSelection", 1.529 + nsDisplayItem::TYPE_TABLE_CELL_SELECTION)); 1.530 + } 1.531 + } 1.532 + 1.533 + // the 'empty-cells' property has no effect on 'outline' 1.534 + DisplayOutline(aBuilder, aLists); 1.535 + } 1.536 + 1.537 + // Push a null 'current table item' so that descendant tables can't 1.538 + // accidentally mess with our table 1.539 + nsAutoPushCurrentTableItem pushTableItem; 1.540 + pushTableItem.Push(aBuilder, nullptr); 1.541 + 1.542 + nsIFrame* kid = mFrames.FirstChild(); 1.543 + NS_ASSERTION(kid && !kid->GetNextSibling(), "Table cells should have just one child"); 1.544 + // The child's background will go in our BorderBackground() list. 1.545 + // This isn't a problem since it won't have a real background except for 1.546 + // event handling. We do not call BuildDisplayListForNonBlockChildren 1.547 + // because that/ would put the child's background in the Content() list 1.548 + // which isn't right (e.g., would end up on top of our child floats for 1.549 + // event handling). 1.550 + BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists); 1.551 +} 1.552 + 1.553 +int 1.554 +nsTableCellFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const 1.555 +{ 1.556 + int skip = 0; 1.557 + if (nullptr != GetPrevInFlow()) { 1.558 + skip |= LOGICAL_SIDE_B_START; 1.559 + } 1.560 + if (nullptr != GetNextInFlow()) { 1.561 + skip |= LOGICAL_SIDE_B_END; 1.562 + } 1.563 + return skip; 1.564 +} 1.565 + 1.566 +/* virtual */ nsMargin 1.567 +nsTableCellFrame::GetBorderOverflow() 1.568 +{ 1.569 + return nsMargin(0, 0, 0, 0); 1.570 +} 1.571 + 1.572 +// Align the cell's child frame within the cell 1.573 + 1.574 +void nsTableCellFrame::VerticallyAlignChild(nscoord aMaxAscent) 1.575 +{ 1.576 + /* It's the 'border-collapse' on the table that matters */ 1.577 + nsMargin borderPadding = GetUsedBorderAndPadding(); 1.578 + 1.579 + nscoord topInset = borderPadding.top; 1.580 + nscoord bottomInset = borderPadding.bottom; 1.581 + 1.582 + uint8_t verticalAlignFlags = GetVerticalAlign(); 1.583 + 1.584 + nscoord height = mRect.height; 1.585 + nsIFrame* firstKid = mFrames.FirstChild(); 1.586 + NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame"); 1.587 + nsRect kidRect = firstKid->GetRect(); 1.588 + nscoord childHeight = kidRect.height; 1.589 + 1.590 + // Vertically align the child 1.591 + nscoord kidYTop = 0; 1.592 + switch (verticalAlignFlags) 1.593 + { 1.594 + case NS_STYLE_VERTICAL_ALIGN_BASELINE: 1.595 + // Align the baselines of the child frame with the baselines of 1.596 + // other children in the same row which have 'vertical-align: baseline' 1.597 + kidYTop = topInset + aMaxAscent - GetCellBaseline(); 1.598 + break; 1.599 + 1.600 + case NS_STYLE_VERTICAL_ALIGN_TOP: 1.601 + // Align the top of the child frame with the top of the content area, 1.602 + kidYTop = topInset; 1.603 + break; 1.604 + 1.605 + case NS_STYLE_VERTICAL_ALIGN_BOTTOM: 1.606 + // Align the bottom of the child frame with the bottom of the content area, 1.607 + kidYTop = height - childHeight - bottomInset; 1.608 + break; 1.609 + 1.610 + default: 1.611 + case NS_STYLE_VERTICAL_ALIGN_MIDDLE: 1.612 + // Align the middle of the child frame with the middle of the content area, 1.613 + kidYTop = (height - childHeight - bottomInset + topInset) / 2; 1.614 + } 1.615 + // if the content is larger than the cell height align from top 1.616 + kidYTop = std::max(0, kidYTop); 1.617 + 1.618 + if (kidYTop != kidRect.y) { 1.619 + // Invalidate at the old position first 1.620 + firstKid->InvalidateFrameSubtree(); 1.621 + } 1.622 + 1.623 + firstKid->SetPosition(nsPoint(kidRect.x, kidYTop)); 1.624 + nsHTMLReflowMetrics desiredSize(GetWritingMode()); // ??? 1.625 + desiredSize.Width() = mRect.width; 1.626 + desiredSize.Height() = mRect.height; 1.627 + 1.628 + nsRect overflow(nsPoint(0,0), GetSize()); 1.629 + overflow.Inflate(GetBorderOverflow()); 1.630 + desiredSize.mOverflowAreas.SetAllTo(overflow); 1.631 + ConsiderChildOverflow(desiredSize.mOverflowAreas, firstKid); 1.632 + FinishAndStoreOverflow(&desiredSize); 1.633 + if (kidYTop != kidRect.y) { 1.634 + // Make sure any child views are correctly positioned. We know the inner table 1.635 + // cell won't have a view 1.636 + nsContainerFrame::PositionChildViews(firstKid); 1.637 + 1.638 + // Invalidate new overflow rect 1.639 + firstKid->InvalidateFrameSubtree(); 1.640 + } 1.641 + if (HasView()) { 1.642 + nsContainerFrame::SyncFrameViewAfterReflow(PresContext(), this, 1.643 + GetView(), 1.644 + desiredSize.VisualOverflow(), 0); 1.645 + } 1.646 +} 1.647 + 1.648 +bool 1.649 +nsTableCellFrame::UpdateOverflow() 1.650 +{ 1.651 + nsRect bounds(nsPoint(0,0), GetSize()); 1.652 + bounds.Inflate(GetBorderOverflow()); 1.653 + nsOverflowAreas overflowAreas(bounds, bounds); 1.654 + 1.655 + nsLayoutUtils::UnionChildOverflow(this, overflowAreas); 1.656 + 1.657 + return FinishAndStoreOverflow(overflowAreas, GetSize()); 1.658 +} 1.659 + 1.660 +// Per CSS 2.1, we map 'sub', 'super', 'text-top', 'text-bottom', 1.661 +// length, percentage, and calc() values to 'baseline'. 1.662 +uint8_t 1.663 +nsTableCellFrame::GetVerticalAlign() const 1.664 +{ 1.665 + const nsStyleCoord& verticalAlign = StyleTextReset()->mVerticalAlign; 1.666 + if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) { 1.667 + uint8_t value = verticalAlign.GetIntValue(); 1.668 + if (value == NS_STYLE_VERTICAL_ALIGN_TOP || 1.669 + value == NS_STYLE_VERTICAL_ALIGN_MIDDLE || 1.670 + value == NS_STYLE_VERTICAL_ALIGN_BOTTOM) { 1.671 + return value; 1.672 + } 1.673 + } 1.674 + return NS_STYLE_VERTICAL_ALIGN_BASELINE; 1.675 +} 1.676 + 1.677 +bool 1.678 +nsTableCellFrame::CellHasVisibleContent(nscoord height, 1.679 + nsTableFrame* tableFrame, 1.680 + nsIFrame* kidFrame) 1.681 +{ 1.682 + // see http://www.w3.org/TR/CSS21/tables.html#empty-cells 1.683 + if (height > 0) 1.684 + return true; 1.685 + if (tableFrame->IsBorderCollapse()) 1.686 + return true; 1.687 + nsIFrame* innerFrame = kidFrame->GetFirstPrincipalChild(); 1.688 + while(innerFrame) { 1.689 + nsIAtom* frameType = innerFrame->GetType(); 1.690 + if (nsGkAtoms::textFrame == frameType) { 1.691 + nsTextFrame* textFrame = static_cast<nsTextFrame*>(innerFrame); 1.692 + if (textFrame->HasNoncollapsedCharacters()) 1.693 + return true; 1.694 + } 1.695 + else if (nsGkAtoms::placeholderFrame != frameType) { 1.696 + return true; 1.697 + } 1.698 + else { 1.699 + nsIFrame *floatFrame = nsLayoutUtils::GetFloatFromPlaceholder(innerFrame); 1.700 + if (floatFrame) 1.701 + return true; 1.702 + } 1.703 + innerFrame = innerFrame->GetNextSibling(); 1.704 + } 1.705 + return false; 1.706 +} 1.707 + 1.708 +nscoord 1.709 +nsTableCellFrame::GetCellBaseline() const 1.710 +{ 1.711 + // Ignore the position of the inner frame relative to the cell frame 1.712 + // since we want the position as though the inner were top-aligned. 1.713 + nsIFrame *inner = mFrames.FirstChild(); 1.714 + nscoord borderPadding = GetUsedBorderAndPadding().top; 1.715 + nscoord result; 1.716 + if (nsLayoutUtils::GetFirstLineBaseline(inner, &result)) 1.717 + return result + borderPadding; 1.718 + return inner->GetContentRect().YMost() - inner->GetPosition().y + 1.719 + borderPadding; 1.720 +} 1.721 + 1.722 +int32_t nsTableCellFrame::GetRowSpan() 1.723 +{ 1.724 + int32_t rowSpan=1; 1.725 + nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent); 1.726 + 1.727 + // Don't look at the content's rowspan if we're a pseudo cell 1.728 + if (hc && !StyleContext()->GetPseudo()) { 1.729 + const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::rowspan); 1.730 + // Note that we don't need to check the tag name, because only table cells 1.731 + // and table headers parse the "rowspan" attribute into an integer. 1.732 + if (attr && attr->Type() == nsAttrValue::eInteger) { 1.733 + rowSpan = attr->GetIntegerValue(); 1.734 + } 1.735 + } 1.736 + return rowSpan; 1.737 +} 1.738 + 1.739 +int32_t nsTableCellFrame::GetColSpan() 1.740 +{ 1.741 + int32_t colSpan=1; 1.742 + nsGenericHTMLElement *hc = nsGenericHTMLElement::FromContent(mContent); 1.743 + 1.744 + // Don't look at the content's colspan if we're a pseudo cell 1.745 + if (hc && !StyleContext()->GetPseudo()) { 1.746 + const nsAttrValue* attr = hc->GetParsedAttr(nsGkAtoms::colspan); 1.747 + // Note that we don't need to check the tag name, because only table cells 1.748 + // and table headers parse the "colspan" attribute into an integer. 1.749 + if (attr && attr->Type() == nsAttrValue::eInteger) { 1.750 + colSpan = attr->GetIntegerValue(); 1.751 + } 1.752 + } 1.753 + return colSpan; 1.754 +} 1.755 + 1.756 +/* virtual */ nscoord 1.757 +nsTableCellFrame::GetMinWidth(nsRenderingContext *aRenderingContext) 1.758 +{ 1.759 + nscoord result = 0; 1.760 + DISPLAY_MIN_WIDTH(this, result); 1.761 + 1.762 + nsIFrame *inner = mFrames.FirstChild(); 1.763 + result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, 1.764 + nsLayoutUtils::MIN_WIDTH); 1.765 + return result; 1.766 +} 1.767 + 1.768 +/* virtual */ nscoord 1.769 +nsTableCellFrame::GetPrefWidth(nsRenderingContext *aRenderingContext) 1.770 +{ 1.771 + nscoord result = 0; 1.772 + DISPLAY_PREF_WIDTH(this, result); 1.773 + 1.774 + nsIFrame *inner = mFrames.FirstChild(); 1.775 + result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, 1.776 + nsLayoutUtils::PREF_WIDTH); 1.777 + return result; 1.778 +} 1.779 + 1.780 +/* virtual */ nsIFrame::IntrinsicWidthOffsetData 1.781 +nsTableCellFrame::IntrinsicWidthOffsets(nsRenderingContext* aRenderingContext) 1.782 +{ 1.783 + IntrinsicWidthOffsetData result = 1.784 + nsContainerFrame::IntrinsicWidthOffsets(aRenderingContext); 1.785 + 1.786 + result.hMargin = 0; 1.787 + result.hPctMargin = 0; 1.788 + 1.789 + nsMargin border; 1.790 + GetBorderWidth(border); 1.791 + result.hBorder = border.LeftRight(); 1.792 + 1.793 + return result; 1.794 +} 1.795 + 1.796 +#ifdef DEBUG 1.797 +#define PROBABLY_TOO_LARGE 1000000 1.798 +static 1.799 +void DebugCheckChildSize(nsIFrame* aChild, 1.800 + nsHTMLReflowMetrics& aMet, 1.801 + nsSize& aAvailSize) 1.802 +{ 1.803 + if ((aMet.Width() < 0) || (aMet.Width() > PROBABLY_TOO_LARGE)) { 1.804 + printf("WARNING: cell content %p has large width %d \n", 1.805 + static_cast<void*>(aChild), int32_t(aMet.Width())); 1.806 + } 1.807 +} 1.808 +#endif 1.809 + 1.810 +// the computed height for the cell, which descendants use for percent height calculations 1.811 +// it is the height (minus border, padding) of the cell's first in flow during its final 1.812 +// reflow without an unconstrained height. 1.813 +static nscoord 1.814 +CalcUnpaginagedHeight(nsPresContext* aPresContext, 1.815 + nsTableCellFrame& aCellFrame, 1.816 + nsTableFrame& aTableFrame, 1.817 + nscoord aVerticalBorderPadding) 1.818 +{ 1.819 + const nsTableCellFrame* firstCellInFlow = 1.820 + static_cast<nsTableCellFrame*>(aCellFrame.FirstInFlow()); 1.821 + nsTableFrame* firstTableInFlow = 1.822 + static_cast<nsTableFrame*>(aTableFrame.FirstInFlow()); 1.823 + nsTableRowFrame* row = 1.824 + static_cast<nsTableRowFrame*>(firstCellInFlow->GetParent()); 1.825 + nsTableRowGroupFrame* firstRGInFlow = 1.826 + static_cast<nsTableRowGroupFrame*>(row->GetParent()); 1.827 + 1.828 + int32_t rowIndex; 1.829 + firstCellInFlow->GetRowIndex(rowIndex); 1.830 + int32_t rowSpan = aTableFrame.GetEffectiveRowSpan(*firstCellInFlow); 1.831 + nscoord cellSpacing = firstTableInFlow->GetCellSpacingX(); 1.832 + 1.833 + nscoord computedHeight = ((rowSpan - 1) * cellSpacing) - aVerticalBorderPadding; 1.834 + int32_t rowX; 1.835 + for (row = firstRGInFlow->GetFirstRow(), rowX = 0; row; row = row->GetNextRow(), rowX++) { 1.836 + if (rowX > rowIndex + rowSpan - 1) { 1.837 + break; 1.838 + } 1.839 + else if (rowX >= rowIndex) { 1.840 + computedHeight += row->GetUnpaginatedHeight(aPresContext); 1.841 + } 1.842 + } 1.843 + return computedHeight; 1.844 +} 1.845 + 1.846 +nsresult nsTableCellFrame::Reflow(nsPresContext* aPresContext, 1.847 + nsHTMLReflowMetrics& aDesiredSize, 1.848 + const nsHTMLReflowState& aReflowState, 1.849 + nsReflowStatus& aStatus) 1.850 +{ 1.851 + DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame"); 1.852 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.853 + 1.854 + if (aReflowState.mFlags.mSpecialHeightReflow) { 1.855 + FirstInFlow()->AddStateBits(NS_TABLE_CELL_HAD_SPECIAL_REFLOW); 1.856 + } 1.857 + 1.858 + // see if a special height reflow needs to occur due to having a pct height 1.859 + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); 1.860 + 1.861 + aStatus = NS_FRAME_COMPLETE; 1.862 + nsSize availSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight()); 1.863 + 1.864 + nsMargin borderPadding = aReflowState.ComputedPhysicalPadding(); 1.865 + nsMargin border; 1.866 + GetBorderWidth(border); 1.867 + borderPadding += border; 1.868 + 1.869 + nscoord topInset = borderPadding.top; 1.870 + nscoord rightInset = borderPadding.right; 1.871 + nscoord bottomInset = borderPadding.bottom; 1.872 + nscoord leftInset = borderPadding.left; 1.873 + 1.874 + // reduce available space by insets, if we're in a constrained situation 1.875 + availSize.width -= leftInset + rightInset; 1.876 + if (NS_UNCONSTRAINEDSIZE != availSize.height) 1.877 + availSize.height -= topInset + bottomInset; 1.878 + 1.879 + // Try to reflow the child into the available space. It might not 1.880 + // fit or might need continuing. 1.881 + if (availSize.height < 0) 1.882 + availSize.height = 1; 1.883 + 1.884 + nsHTMLReflowMetrics kidSize(aReflowState.GetWritingMode(), aDesiredSize.mFlags); 1.885 + kidSize.Width() = kidSize.Height() = 0; 1.886 + SetPriorAvailWidth(aReflowState.AvailableWidth()); 1.887 + nsIFrame* firstKid = mFrames.FirstChild(); 1.888 + NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame"); 1.889 + nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); 1.890 + 1.891 + if (aReflowState.mFlags.mSpecialHeightReflow) { 1.892 + const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(mRect.height - topInset - bottomInset); 1.893 + DISPLAY_REFLOW_CHANGE(); 1.894 + } 1.895 + else if (aPresContext->IsPaginated()) { 1.896 + nscoord computedUnpaginatedHeight = 1.897 + CalcUnpaginagedHeight(aPresContext, (nsTableCellFrame&)*this, 1.898 + *tableFrame, topInset + bottomInset); 1.899 + if (computedUnpaginatedHeight > 0) { 1.900 + const_cast<nsHTMLReflowState&>(aReflowState).SetComputedHeight(computedUnpaginatedHeight); 1.901 + DISPLAY_REFLOW_CHANGE(); 1.902 + } 1.903 + } 1.904 + else { 1.905 + SetHasPctOverHeight(false); 1.906 + } 1.907 + 1.908 + nsHTMLReflowState kidReflowState(aPresContext, aReflowState, firstKid, 1.909 + availSize); 1.910 + 1.911 + // Don't be a percent height observer if we're in the middle of 1.912 + // special-height reflow, in case we get an accidental NotifyPercentHeight() 1.913 + // call (which we shouldn't honor during special-height reflow) 1.914 + if (!aReflowState.mFlags.mSpecialHeightReflow) { 1.915 + // mPercentHeightObserver is for children of cells in quirks mode, 1.916 + // but only those than are tables in standards mode. NeedsToObserve 1.917 + // will determine how far this is propagated to descendants. 1.918 + kidReflowState.mPercentHeightObserver = this; 1.919 + } 1.920 + // Don't propagate special height reflow state to our kids 1.921 + kidReflowState.mFlags.mSpecialHeightReflow = false; 1.922 + 1.923 + if (aReflowState.mFlags.mSpecialHeightReflow || 1.924 + (FirstInFlow()->GetStateBits() & NS_TABLE_CELL_HAD_SPECIAL_REFLOW)) { 1.925 + // We need to force the kid to have mVResize set if we've had a 1.926 + // special reflow in the past, since the non-special reflow needs to 1.927 + // resize back to what it was without the special height reflow. 1.928 + kidReflowState.mFlags.mVResize = true; 1.929 + } 1.930 + 1.931 + nsPoint kidOrigin(leftInset, topInset); 1.932 + nsRect origRect = firstKid->GetRect(); 1.933 + nsRect origVisualOverflow = firstKid->GetVisualOverflowRect(); 1.934 + bool firstReflow = (firstKid->GetStateBits() & NS_FRAME_FIRST_REFLOW) != 0; 1.935 + 1.936 + ReflowChild(firstKid, aPresContext, kidSize, kidReflowState, 1.937 + kidOrigin.x, kidOrigin.y, 0, aStatus); 1.938 + if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) { 1.939 + // Don't pass OVERFLOW_INCOMPLETE through tables until they can actually handle it 1.940 + //XXX should paginate overflow as overflow, but not in this patch (bug 379349) 1.941 + NS_FRAME_SET_INCOMPLETE(aStatus); 1.942 + printf("Set table cell incomplete %p\n", static_cast<void*>(this)); 1.943 + } 1.944 + 1.945 + // XXXbz is this invalidate actually needed, really? 1.946 + if (GetStateBits() & NS_FRAME_IS_DIRTY) { 1.947 + InvalidateFrameSubtree(); 1.948 + } 1.949 + 1.950 +#ifdef DEBUG 1.951 + DebugCheckChildSize(firstKid, kidSize, availSize); 1.952 +#endif 1.953 + 1.954 + // 0 dimensioned cells need to be treated specially in Standard/NavQuirks mode 1.955 + // see testcase "emptyCells.html" 1.956 + nsIFrame* prevInFlow = GetPrevInFlow(); 1.957 + bool isEmpty; 1.958 + if (prevInFlow) { 1.959 + isEmpty = static_cast<nsTableCellFrame*>(prevInFlow)->GetContentEmpty(); 1.960 + } else { 1.961 + isEmpty = !CellHasVisibleContent(kidSize.Height(), tableFrame, firstKid); 1.962 + } 1.963 + SetContentEmpty(isEmpty); 1.964 + 1.965 + // Place the child 1.966 + FinishReflowChild(firstKid, aPresContext, kidSize, &kidReflowState, 1.967 + kidOrigin.x, kidOrigin.y, 0); 1.968 + 1.969 + nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow, 1.970 + firstReflow); 1.971 + 1.972 + // first, compute the height which can be set w/o being restricted by aMaxSize.height 1.973 + nscoord cellHeight = kidSize.Height(); 1.974 + 1.975 + if (NS_UNCONSTRAINEDSIZE != cellHeight) { 1.976 + cellHeight += topInset + bottomInset; 1.977 + } 1.978 + 1.979 + // next determine the cell's width 1.980 + nscoord cellWidth = kidSize.Width(); // at this point, we've factored in the cell's style attributes 1.981 + 1.982 + // factor in border and padding 1.983 + if (NS_UNCONSTRAINEDSIZE != cellWidth) { 1.984 + cellWidth += leftInset + rightInset; 1.985 + } 1.986 + 1.987 + // set the cell's desired size and max element size 1.988 + aDesiredSize.Width() = cellWidth; 1.989 + aDesiredSize.Height() = cellHeight; 1.990 + 1.991 + // the overflow area will be computed when the child will be vertically aligned 1.992 + 1.993 + if (aReflowState.mFlags.mSpecialHeightReflow) { 1.994 + if (aDesiredSize.Height() > mRect.height) { 1.995 + // set a bit indicating that the pct height contents exceeded 1.996 + // the height that they could honor in the pass 2 reflow 1.997 + SetHasPctOverHeight(true); 1.998 + } 1.999 + if (NS_UNCONSTRAINEDSIZE == aReflowState.AvailableHeight()) { 1.1000 + aDesiredSize.Height() = mRect.height; 1.1001 + } 1.1002 + } 1.1003 + 1.1004 + // If our parent is in initial reflow, it'll handle invalidating our 1.1005 + // entire overflow rect. 1.1006 + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && 1.1007 + nsSize(aDesiredSize.Width(), aDesiredSize.Height()) != mRect.Size()) { 1.1008 + InvalidateFrame(); 1.1009 + } 1.1010 + 1.1011 + // remember the desired size for this reflow 1.1012 + SetDesiredSize(aDesiredSize); 1.1013 + 1.1014 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.1015 + return NS_OK; 1.1016 +} 1.1017 + 1.1018 +/* ----- global methods ----- */ 1.1019 + 1.1020 +NS_QUERYFRAME_HEAD(nsTableCellFrame) 1.1021 + NS_QUERYFRAME_ENTRY(nsTableCellFrame) 1.1022 + NS_QUERYFRAME_ENTRY(nsITableCellLayout) 1.1023 + NS_QUERYFRAME_ENTRY(nsIPercentHeightObserver) 1.1024 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) 1.1025 + 1.1026 +#ifdef ACCESSIBILITY 1.1027 +a11y::AccType 1.1028 +nsTableCellFrame::AccessibleType() 1.1029 +{ 1.1030 + return a11y::eHTMLTableCellType; 1.1031 +} 1.1032 +#endif 1.1033 + 1.1034 +/* This is primarily for editor access via nsITableLayout */ 1.1035 +NS_IMETHODIMP 1.1036 +nsTableCellFrame::GetCellIndexes(int32_t &aRowIndex, int32_t &aColIndex) 1.1037 +{ 1.1038 + nsresult res = GetRowIndex(aRowIndex); 1.1039 + if (NS_FAILED(res)) 1.1040 + { 1.1041 + aColIndex = 0; 1.1042 + return res; 1.1043 + } 1.1044 + aColIndex = mColIndex; 1.1045 + return NS_OK; 1.1046 +} 1.1047 + 1.1048 +nsIFrame* 1.1049 +NS_NewTableCellFrame(nsIPresShell* aPresShell, 1.1050 + nsStyleContext* aContext, 1.1051 + bool aIsBorderCollapse) 1.1052 +{ 1.1053 + if (aIsBorderCollapse) 1.1054 + return new (aPresShell) nsBCTableCellFrame(aContext); 1.1055 + else 1.1056 + return new (aPresShell) nsTableCellFrame(aContext); 1.1057 +} 1.1058 + 1.1059 +NS_IMPL_FRAMEARENA_HELPERS(nsBCTableCellFrame) 1.1060 + 1.1061 +nsMargin* 1.1062 +nsTableCellFrame::GetBorderWidth(nsMargin& aBorder) const 1.1063 +{ 1.1064 + aBorder = StyleBorder()->GetComputedBorder(); 1.1065 + return &aBorder; 1.1066 +} 1.1067 + 1.1068 +nsIAtom* 1.1069 +nsTableCellFrame::GetType() const 1.1070 +{ 1.1071 + return nsGkAtoms::tableCellFrame; 1.1072 +} 1.1073 + 1.1074 +#ifdef DEBUG_FRAME_DUMP 1.1075 +nsresult 1.1076 +nsTableCellFrame::GetFrameName(nsAString& aResult) const 1.1077 +{ 1.1078 + return MakeFrameName(NS_LITERAL_STRING("TableCell"), aResult); 1.1079 +} 1.1080 +#endif 1.1081 + 1.1082 +// nsBCTableCellFrame 1.1083 + 1.1084 +nsBCTableCellFrame::nsBCTableCellFrame(nsStyleContext* aContext) 1.1085 +:nsTableCellFrame(aContext) 1.1086 +{ 1.1087 + mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0; 1.1088 +} 1.1089 + 1.1090 +nsBCTableCellFrame::~nsBCTableCellFrame() 1.1091 +{ 1.1092 +} 1.1093 + 1.1094 +nsIAtom* 1.1095 +nsBCTableCellFrame::GetType() const 1.1096 +{ 1.1097 + return nsGkAtoms::bcTableCellFrame; 1.1098 +} 1.1099 + 1.1100 +/* virtual */ nsMargin 1.1101 +nsBCTableCellFrame::GetUsedBorder() const 1.1102 +{ 1.1103 + nsMargin result; 1.1104 + GetBorderWidth(result); 1.1105 + return result; 1.1106 +} 1.1107 + 1.1108 +/* virtual */ bool 1.1109 +nsBCTableCellFrame::GetBorderRadii(nscoord aRadii[8]) const 1.1110 +{ 1.1111 + NS_FOR_CSS_HALF_CORNERS(corner) { 1.1112 + aRadii[corner] = 0; 1.1113 + } 1.1114 + return false; 1.1115 +} 1.1116 + 1.1117 +#ifdef DEBUG_FRAME_DUMP 1.1118 +nsresult 1.1119 +nsBCTableCellFrame::GetFrameName(nsAString& aResult) const 1.1120 +{ 1.1121 + return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult); 1.1122 +} 1.1123 +#endif 1.1124 + 1.1125 +nsMargin* 1.1126 +nsBCTableCellFrame::GetBorderWidth(nsMargin& aBorder) const 1.1127 +{ 1.1128 + int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel(); 1.1129 + aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, mTopBorder); 1.1130 + aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, mRightBorder); 1.1131 + aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mBottomBorder); 1.1132 + aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mLeftBorder); 1.1133 + return &aBorder; 1.1134 +} 1.1135 + 1.1136 +BCPixelSize 1.1137 +nsBCTableCellFrame::GetBorderWidth(mozilla::css::Side aSide) const 1.1138 +{ 1.1139 + switch(aSide) { 1.1140 + case NS_SIDE_TOP: 1.1141 + return BC_BORDER_BOTTOM_HALF(mTopBorder); 1.1142 + case NS_SIDE_RIGHT: 1.1143 + return BC_BORDER_LEFT_HALF(mRightBorder); 1.1144 + case NS_SIDE_BOTTOM: 1.1145 + return BC_BORDER_TOP_HALF(mBottomBorder); 1.1146 + default: 1.1147 + return BC_BORDER_RIGHT_HALF(mLeftBorder); 1.1148 + } 1.1149 +} 1.1150 + 1.1151 +void 1.1152 +nsBCTableCellFrame::SetBorderWidth(mozilla::css::Side aSide, 1.1153 + BCPixelSize aValue) 1.1154 +{ 1.1155 + switch(aSide) { 1.1156 + case NS_SIDE_TOP: 1.1157 + mTopBorder = aValue; 1.1158 + break; 1.1159 + case NS_SIDE_RIGHT: 1.1160 + mRightBorder = aValue; 1.1161 + break; 1.1162 + case NS_SIDE_BOTTOM: 1.1163 + mBottomBorder = aValue; 1.1164 + break; 1.1165 + default: 1.1166 + mLeftBorder = aValue; 1.1167 + } 1.1168 +} 1.1169 + 1.1170 +/* virtual */ nsMargin 1.1171 +nsBCTableCellFrame::GetBorderOverflow() 1.1172 +{ 1.1173 + nsMargin halfBorder; 1.1174 + int32_t p2t = nsPresContext::AppUnitsPerCSSPixel(); 1.1175 + halfBorder.top = BC_BORDER_TOP_HALF_COORD(p2t, mTopBorder); 1.1176 + halfBorder.right = BC_BORDER_RIGHT_HALF_COORD(p2t, mRightBorder); 1.1177 + halfBorder.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, mBottomBorder); 1.1178 + halfBorder.left = BC_BORDER_LEFT_HALF_COORD(p2t, mLeftBorder); 1.1179 + return halfBorder; 1.1180 +} 1.1181 + 1.1182 + 1.1183 +void 1.1184 +nsBCTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext, 1.1185 + const nsRect& aDirtyRect, 1.1186 + nsPoint aPt, 1.1187 + uint32_t aFlags) 1.1188 +{ 1.1189 + // make border-width reflect the half of the border-collapse 1.1190 + // assigned border that's inside the cell 1.1191 + nsMargin borderWidth; 1.1192 + GetBorderWidth(borderWidth); 1.1193 + 1.1194 + nsStyleBorder myBorder(*StyleBorder()); 1.1195 + 1.1196 + NS_FOR_CSS_SIDES(side) { 1.1197 + myBorder.SetBorderWidth(side, borderWidth.Side(side)); 1.1198 + } 1.1199 + 1.1200 + nsRect rect(aPt, GetSize()); 1.1201 + // bypassing nsCSSRendering::PaintBackground is safe because this kind 1.1202 + // of frame cannot be used for the root element 1.1203 + nsCSSRendering::PaintBackgroundWithSC(PresContext(), aRenderingContext, this, 1.1204 + aDirtyRect, rect, 1.1205 + StyleContext(), myBorder, 1.1206 + aFlags, nullptr); 1.1207 +}