Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/tables/nsTableColGroupFrame.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
#include "nsTableColGroupFrame.h"
6
#include "nsTableColFrame.h"
7
#include "nsTableFrame.h"
8
#include "mozilla/ComputedStyle.h"
9
#include "nsStyleConsts.h"
10
#include "nsPresContext.h"
11
#include "nsHTMLParts.h"
12
#include "nsGkAtoms.h"
13
#include "nsCOMPtr.h"
14
#include "nsCSSRendering.h"
15
#include "nsIPresShell.h"
16
17
using namespace mozilla;
18
19
0
#define COLGROUP_SYNTHETIC_BIT NS_FRAME_STATE_BIT(30)
20
21
bool
22
nsTableColGroupFrame::IsSynthetic() const
23
0
{
24
0
  return HasAnyStateBits(COLGROUP_SYNTHETIC_BIT);
25
0
}
26
27
void nsTableColGroupFrame::SetIsSynthetic()
28
0
{
29
0
  AddStateBits(COLGROUP_SYNTHETIC_BIT);
30
0
}
31
32
void nsTableColGroupFrame::ResetColIndices(nsIFrame*       aFirstColGroup,
33
                                           int32_t         aFirstColIndex,
34
                                           nsIFrame*       aStartColFrame)
35
0
{
36
0
  nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame*)aFirstColGroup;
37
0
  int32_t colIndex = aFirstColIndex;
38
0
  while (colGroupFrame) {
39
0
    if (colGroupFrame->IsTableColGroupFrame()) {
40
0
      // reset the starting col index for the first cg only if we should reset
41
0
      // the whole colgroup (aStartColFrame defaults to nullptr) or if
42
0
      // aFirstColIndex is smaller than the existing starting col index
43
0
      if ((colIndex != aFirstColIndex) ||
44
0
          (colIndex < colGroupFrame->GetStartColumnIndex()) ||
45
0
          !aStartColFrame) {
46
0
        colGroupFrame->SetStartColumnIndex(colIndex);
47
0
      }
48
0
      nsIFrame* colFrame = aStartColFrame;
49
0
      if (!colFrame || (colIndex != aFirstColIndex)) {
50
0
        colFrame = colGroupFrame->PrincipalChildList().FirstChild();
51
0
      }
52
0
      while (colFrame) {
53
0
        if (colFrame->IsTableColFrame()) {
54
0
          ((nsTableColFrame*)colFrame)->SetColIndex(colIndex);
55
0
          colIndex++;
56
0
        }
57
0
        colFrame = colFrame->GetNextSibling();
58
0
      }
59
0
    }
60
0
    colGroupFrame = static_cast<nsTableColGroupFrame*>
61
0
                               (colGroupFrame->GetNextSibling());
62
0
  }
63
0
}
64
65
66
nsresult
67
nsTableColGroupFrame::AddColsToTable(int32_t                   aFirstColIndex,
68
                                     bool                      aResetSubsequentColIndices,
69
                                     const nsFrameList::Slice& aCols)
70
0
{
71
0
  nsTableFrame* tableFrame = GetTableFrame();
72
0
73
0
  tableFrame->InvalidateFrameSubtree();
74
0
75
0
  // set the col indices of the col frames and and add col info to the table
76
0
  int32_t colIndex = aFirstColIndex;
77
0
  nsFrameList::Enumerator e(aCols);
78
0
  for (; !e.AtEnd(); e.Next()) {
79
0
    ((nsTableColFrame*)e.get())->SetColIndex(colIndex);
80
0
    mColCount++;
81
0
    tableFrame->InsertCol((nsTableColFrame &)*e.get(), colIndex);
82
0
    colIndex++;
83
0
  }
84
0
85
0
  for (nsFrameList::Enumerator eTail = e.GetUnlimitedEnumerator();
86
0
       !eTail.AtEnd();
87
0
       eTail.Next()) {
88
0
    ((nsTableColFrame*)eTail.get())->SetColIndex(colIndex);
89
0
    colIndex++;
90
0
  }
91
0
92
0
  // We have already set the colindex for all the colframes in this
93
0
  // colgroup that come after the first inserted colframe, but there could
94
0
  // be other colgroups following this one and their colframes need
95
0
  // correct colindices too.
96
0
  if (aResetSubsequentColIndices && GetNextSibling()) {
97
0
    ResetColIndices(GetNextSibling(), colIndex);
98
0
  }
99
0
100
0
  return NS_OK;
101
0
}
102
103
104
nsTableColGroupFrame*
105
nsTableColGroupFrame::GetLastRealColGroup(nsTableFrame* aTableFrame)
106
0
{
107
0
  nsFrameList colGroups = aTableFrame->GetColGroups();
108
0
109
0
  auto lastColGroup = static_cast<nsTableColGroupFrame*>(colGroups.LastChild());
110
0
  if (!lastColGroup) {
111
0
    return nullptr;
112
0
  }
113
0
114
0
  if (!lastColGroup->IsSynthetic()) {
115
0
    return lastColGroup;
116
0
  }
117
0
118
0
  return static_cast<nsTableColGroupFrame*>(lastColGroup->GetPrevSibling());
119
0
}
120
121
// don't set mColCount here, it is done in AddColsToTable
122
void
123
nsTableColGroupFrame::SetInitialChildList(ChildListID     aListID,
124
                                          nsFrameList&    aChildList)
125
0
{
126
0
  MOZ_ASSERT(mFrames.IsEmpty(),
127
0
             "unexpected second call to SetInitialChildList");
128
0
  MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list");
129
0
  if (aChildList.IsEmpty()) {
130
0
    GetTableFrame()->AppendAnonymousColFrames(this, GetSpan(),
131
0
                                              eColAnonymousColGroup, false);
132
0
    return;
133
0
  }
134
0
135
0
  mFrames.AppendFrames(this, aChildList);
136
0
}
137
138
/* virtual */ void
139
nsTableColGroupFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle)
140
0
{
141
0
  nsContainerFrame::DidSetComputedStyle(aOldComputedStyle);
142
0
143
0
  if (!aOldComputedStyle) //avoid this on init
144
0
    return;
145
0
146
0
  nsTableFrame* tableFrame = GetTableFrame();
147
0
  if (tableFrame->IsBorderCollapse() &&
148
0
      tableFrame->BCRecalcNeeded(aOldComputedStyle, Style())) {
149
0
    int32_t colCount = GetColCount();
150
0
    if (!colCount)
151
0
      return; // this is a degenerated colgroup
152
0
    TableArea damageArea(GetFirstColumn()->GetColIndex(), 0, colCount,
153
0
                         tableFrame->GetRowCount());
154
0
    tableFrame->AddBCDamageArea(damageArea);
155
0
  }
156
0
}
157
158
void
159
nsTableColGroupFrame::AppendFrames(ChildListID     aListID,
160
                                   nsFrameList&    aFrameList)
161
0
{
162
0
  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
163
0
164
0
  nsTableColFrame* col = GetFirstColumn();
165
0
  nsTableColFrame* nextCol;
166
0
  while (col && col->GetColType() == eColAnonymousColGroup) {
167
0
    // this colgroup spans one or more columns but now that there is a
168
0
    // real column below, spanned anonymous columns should be removed,
169
0
    // since the HTML spec says to ignore the span of a colgroup if it
170
0
    // has content columns in it.
171
0
    nextCol = col->GetNextCol();
172
0
    RemoveFrame(kPrincipalList, col);
173
0
    col = nextCol;
174
0
  }
175
0
176
0
  // Our next colframe should be an eColContent.  We've removed all the
177
0
  // eColAnonymousColGroup colframes, eColAnonymousCol colframes always follow
178
0
  // eColContent ones, and eColAnonymousCell colframes only appear in a
179
0
  // synthetic colgroup, which never gets AppendFrames() called on it.
180
0
  MOZ_ASSERT(!col || col->GetColType() == eColContent,
181
0
             "What's going on with our columns?");
182
0
183
0
  const nsFrameList::Slice& newFrames =
184
0
    mFrames.AppendFrames(this, aFrameList);
185
0
  InsertColsReflow(GetStartColumnIndex() + mColCount, newFrames);
186
0
}
187
188
void
189
nsTableColGroupFrame::InsertFrames(ChildListID     aListID,
190
                                   nsIFrame*       aPrevFrame,
191
                                   nsFrameList&    aFrameList)
192
0
{
193
0
  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
194
0
  NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
195
0
               "inserting after sibling frame with different parent");
196
0
197
0
  nsTableColFrame* col = GetFirstColumn();
198
0
  nsTableColFrame* nextCol;
199
0
  while (col && col->GetColType() == eColAnonymousColGroup) {
200
0
    // this colgroup spans one or more columns but now that there is a
201
0
    // real column below, spanned anonymous columns should be removed,
202
0
    // since the HTML spec says to ignore the span of a colgroup if it
203
0
    // has content columns in it.
204
0
    nextCol = col->GetNextCol();
205
0
    if (col == aPrevFrame) {
206
0
      // This can happen when we're being appended to
207
0
      NS_ASSERTION(!nextCol || nextCol->GetColType() != eColAnonymousColGroup,
208
0
                   "Inserting in the middle of our anonymous cols?");
209
0
      // We'll want to insert at the beginning
210
0
      aPrevFrame = nullptr;
211
0
    }
212
0
    RemoveFrame(kPrincipalList, col);
213
0
    col = nextCol;
214
0
  }
215
0
216
0
  // Our next colframe should be an eColContent.  We've removed all the
217
0
  // eColAnonymousColGroup colframes, eColAnonymousCol colframes always follow
218
0
  // eColContent ones, and eColAnonymousCell colframes only appear in a
219
0
  // synthetic colgroup, which never gets InsertFrames() called on it.
220
0
  MOZ_ASSERT(!col || col->GetColType() == eColContent,
221
0
             "What's going on with our columns?");
222
0
223
0
  NS_ASSERTION(!aPrevFrame || aPrevFrame == aPrevFrame->LastContinuation(),
224
0
               "Prev frame should be last in continuation chain");
225
0
  NS_ASSERTION(!aPrevFrame || !GetNextColumn(aPrevFrame) ||
226
0
               GetNextColumn(aPrevFrame)->GetColType() != eColAnonymousCol,
227
0
               "Shouldn't be inserting before a spanned colframe");
228
0
229
0
  const nsFrameList::Slice& newFrames =
230
0
    mFrames.InsertFrames(this, aPrevFrame, aFrameList);
231
0
  nsIFrame* prevFrame = nsTableFrame::GetFrameAtOrBefore(
232
0
    this, aPrevFrame, LayoutFrameType::TableCol);
233
0
234
0
  int32_t colIndex = (prevFrame) ? ((nsTableColFrame*)prevFrame)->GetColIndex() + 1 : GetStartColumnIndex();
235
0
  InsertColsReflow(colIndex, newFrames);
236
0
}
237
238
void
239
nsTableColGroupFrame::InsertColsReflow(int32_t                   aColIndex,
240
                                       const nsFrameList::Slice& aCols)
241
0
{
242
0
  AddColsToTable(aColIndex, true, aCols);
243
0
244
0
  PresShell()->FrameNeedsReflow(this,
245
0
                                               nsIPresShell::eTreeChange,
246
0
                                               NS_FRAME_HAS_DIRTY_CHILDREN);
247
0
}
248
249
void
250
nsTableColGroupFrame::RemoveChild(nsTableColFrame& aChild,
251
                                  bool             aResetSubsequentColIndices)
252
0
{
253
0
  int32_t colIndex = 0;
254
0
  nsIFrame* nextChild = nullptr;
255
0
  if (aResetSubsequentColIndices) {
256
0
    colIndex = aChild.GetColIndex();
257
0
    nextChild = aChild.GetNextSibling();
258
0
  }
259
0
  mFrames.DestroyFrame(&aChild);
260
0
  mColCount--;
261
0
  if (aResetSubsequentColIndices) {
262
0
    if (nextChild) { // reset inside this and all following colgroups
263
0
      ResetColIndices(this, colIndex, nextChild);
264
0
    }
265
0
    else {
266
0
      nsIFrame* nextGroup = GetNextSibling();
267
0
      if (nextGroup) // reset next and all following colgroups
268
0
        ResetColIndices(nextGroup, colIndex);
269
0
    }
270
0
  }
271
0
272
0
  PresShell()->FrameNeedsReflow(this, nsIPresShell::eTreeChange,
273
0
                                NS_FRAME_HAS_DIRTY_CHILDREN);
274
0
}
275
276
void
277
nsTableColGroupFrame::RemoveFrame(ChildListID     aListID,
278
                                  nsIFrame*       aOldFrame)
279
0
{
280
0
  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
281
0
282
0
  if (!aOldFrame) {
283
0
    return;
284
0
  }
285
0
  bool contentRemoval = false;
286
0
287
0
  if (aOldFrame->IsTableColFrame()) {
288
0
    nsTableColFrame* colFrame = (nsTableColFrame*)aOldFrame;
289
0
    if (colFrame->GetColType() == eColContent) {
290
0
      contentRemoval = true;
291
0
      // Remove any anonymous column frames this <col> produced via a colspan
292
0
      nsTableColFrame* col = colFrame->GetNextCol();
293
0
      nsTableColFrame* nextCol;
294
0
      while (col && col->GetColType() == eColAnonymousCol) {
295
#ifdef DEBUG
296
#endif
297
        nextCol = col->GetNextCol();
298
0
        RemoveFrame(kPrincipalList, col);
299
0
        col = nextCol;
300
0
      }
301
0
    }
302
0
303
0
    int32_t colIndex = colFrame->GetColIndex();
304
0
    // The RemoveChild call handles calling FrameNeedsReflow on us.
305
0
    RemoveChild(*colFrame, true);
306
0
307
0
    nsTableFrame* tableFrame = GetTableFrame();
308
0
    tableFrame->RemoveCol(this, colIndex, true, true);
309
0
    if (mFrames.IsEmpty() && contentRemoval && !IsSynthetic()) {
310
0
      tableFrame->AppendAnonymousColFrames(this, GetSpan(),
311
0
                                           eColAnonymousColGroup, true);
312
0
    }
313
0
  }
314
0
  else {
315
0
    mFrames.DestroyFrame(aOldFrame);
316
0
  }
317
0
}
318
319
nsIFrame::LogicalSides
320
nsTableColGroupFrame::GetLogicalSkipSides(const ReflowInput* aReflowInput) const
321
0
{
322
0
  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
323
0
                     StyleBoxDecorationBreak::Clone)) {
324
0
    return LogicalSides();
325
0
  }
326
0
327
0
  LogicalSides skip;
328
0
  if (nullptr != GetPrevInFlow()) {
329
0
    skip |= eLogicalSideBitsBStart;
330
0
  }
331
0
  if (nullptr != GetNextInFlow()) {
332
0
    skip |= eLogicalSideBitsBEnd;
333
0
  }
334
0
  return skip;
335
0
}
336
337
void
338
nsTableColGroupFrame::Reflow(nsPresContext*          aPresContext,
339
                             ReflowOutput&     aDesiredSize,
340
                             const ReflowInput& aReflowInput,
341
                             nsReflowStatus&          aStatus)
342
0
{
343
0
  MarkInReflow();
344
0
  DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame");
345
0
  DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
346
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
347
0
  NS_ASSERTION(nullptr!=mContent, "bad state -- null content for frame");
348
0
349
0
  const nsStyleVisibility* groupVis = StyleVisibility();
350
0
  bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
351
0
  if (collapseGroup) {
352
0
    GetTableFrame()->SetNeedToCollapse(true);
353
0
  }
354
0
  // for every content child that (is a column thingy and does not already have a frame)
355
0
  // create a frame and adjust it's style
356
0
357
0
  for (nsIFrame *kidFrame = mFrames.FirstChild(); kidFrame;
358
0
       kidFrame = kidFrame->GetNextSibling()) {
359
0
    // Give the child frame a chance to reflow, even though we know it'll have 0 size
360
0
    ReflowOutput kidSize(aReflowInput);
361
0
    ReflowInput kidReflowInput(aPresContext, aReflowInput, kidFrame,
362
0
                                     LogicalSize(kidFrame->GetWritingMode()));
363
0
364
0
    nsReflowStatus status;
365
0
    ReflowChild(kidFrame, aPresContext, kidSize, kidReflowInput, 0, 0, 0, status);
366
0
    FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, 0, 0, 0);
367
0
  }
368
0
369
0
  aDesiredSize.ClearSize();
370
0
  NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
371
0
}
372
373
void
374
nsTableColGroupFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
375
                                       const nsDisplayListSet& aLists)
376
0
{
377
0
  nsTableFrame::DisplayGenericTablePart(aBuilder, this, aLists);
378
0
}
379
380
nsTableColFrame * nsTableColGroupFrame::GetFirstColumn()
381
0
{
382
0
  return GetNextColumn(nullptr);
383
0
}
384
385
nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame)
386
0
{
387
0
  nsTableColFrame *result = nullptr;
388
0
  nsIFrame *childFrame = aChildFrame;
389
0
  if (!childFrame) {
390
0
    childFrame = mFrames.FirstChild();
391
0
  }
392
0
  else {
393
0
    childFrame = childFrame->GetNextSibling();
394
0
  }
395
0
  while (childFrame)
396
0
  {
397
0
    if (mozilla::StyleDisplay::TableColumn ==
398
0
        childFrame->StyleDisplay()->mDisplay)
399
0
    {
400
0
      result = (nsTableColFrame *)childFrame;
401
0
      break;
402
0
    }
403
0
    childFrame = childFrame->GetNextSibling();
404
0
  }
405
0
  return result;
406
0
}
407
408
int32_t nsTableColGroupFrame::GetSpan()
409
0
{
410
0
  return StyleTable()->mSpan;
411
0
}
412
413
void nsTableColGroupFrame::SetContinuousBCBorderWidth(LogicalSide aForSide,
414
                                                      BCPixelSize aPixelValue)
415
0
{
416
0
  switch (aForSide) {
417
0
    case eLogicalSideBStart:
418
0
      mBStartContBorderWidth = aPixelValue;
419
0
      return;
420
0
    case eLogicalSideBEnd:
421
0
      mBEndContBorderWidth = aPixelValue;
422
0
      return;
423
0
    default:
424
0
      NS_ERROR("invalid side arg");
425
0
  }
426
0
}
427
428
void nsTableColGroupFrame::GetContinuousBCBorderWidth(WritingMode aWM,
429
                                                      LogicalMargin& aBorder)
430
0
{
431
0
  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
432
0
  nsTableColFrame* col = GetTableFrame()->
433
0
    GetColFrame(mStartColIndex + mColCount - 1);
434
0
  col->GetContinuousBCBorderWidth(aWM, aBorder);
435
0
  aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(d2a,
436
0
                                                 mBStartContBorderWidth);
437
0
  aBorder.BEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a,
438
0
                                                 mBEndContBorderWidth);
439
0
}
440
441
/* ----- global methods ----- */
442
443
nsTableColGroupFrame*
444
NS_NewTableColGroupFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
445
0
{
446
0
  return new (aPresShell) nsTableColGroupFrame(aStyle);
447
0
}
448
449
NS_IMPL_FRAMEARENA_HELPERS(nsTableColGroupFrame)
450
451
void
452
nsTableColGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey, bool aRebuildDisplayItems)
453
0
{
454
0
  nsIFrame::InvalidateFrame(aDisplayItemKey, aRebuildDisplayItems);
455
0
  if (GetTableFrame()->IsBorderCollapse()) {
456
0
    GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey, false);
457
0
  }
458
0
}
459
460
void
461
nsTableColGroupFrame::InvalidateFrameWithRect(const nsRect& aRect,
462
                                              uint32_t aDisplayItemKey,
463
                                              bool aRebuildDisplayItems)
464
0
{
465
0
  nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey, aRebuildDisplayItems);
466
0
  // If we have filters applied that would affects our bounds, then
467
0
  // we get an inactive layer created and this is computed
468
0
  // within FrameLayerBuilder
469
0
  GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey, false);
470
0
}
471
472
#ifdef DEBUG_FRAME_DUMP
473
nsresult
474
nsTableColGroupFrame::GetFrameName(nsAString& aResult) const
475
{
476
  return MakeFrameName(NS_LITERAL_STRING("TableColGroup"), aResult);
477
}
478
479
void nsTableColGroupFrame::Dump(int32_t aIndent)
480
{
481
  char* indent = new char[aIndent + 1];
482
  if (!indent) return;
483
  for (int32_t i = 0; i < aIndent + 1; i++) {
484
    indent[i] = ' ';
485
  }
486
  indent[aIndent] = 0;
487
488
  printf("%s**START COLGROUP DUMP**\n%s startcolIndex=%d  colcount=%d span=%d isSynthetic=%s",
489
         indent, indent, GetStartColumnIndex(),  GetColCount(), GetSpan(),
490
         IsSynthetic() ? "true" : "false");
491
492
  // verify the colindices
493
  int32_t j = GetStartColumnIndex();
494
  nsTableColFrame* col = GetFirstColumn();
495
  while (col) {
496
    NS_ASSERTION(j == col->GetColIndex(), "wrong colindex on col frame");
497
    col = col->GetNextCol();
498
    j++;
499
  }
500
  NS_ASSERTION((j - GetStartColumnIndex()) == GetColCount(),
501
               "number of cols out of sync");
502
  printf("\n%s**END COLGROUP DUMP** ", indent);
503
  delete [] indent;
504
}
505
#endif
506