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