Coverage Report

Created: 2018-09-25 14:53

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