layout/tables/nsTableColGroupFrame.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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 "nsStyleContext.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"
    17 #define COL_GROUP_TYPE_BITS          (NS_FRAME_STATE_BIT(30) | \
    18                                       NS_FRAME_STATE_BIT(31))
    19 #define COL_GROUP_TYPE_OFFSET        30
    21 nsTableColGroupType 
    22 nsTableColGroupFrame::GetColType() const 
    23 {
    24   return (nsTableColGroupType)((mState & COL_GROUP_TYPE_BITS) >> COL_GROUP_TYPE_OFFSET);
    25 }
    27 void nsTableColGroupFrame::SetColType(nsTableColGroupType aType) 
    28 {
    29   NS_ASSERTION(GetColType() == eColGroupContent,
    30                "should only call nsTableColGroupFrame::SetColType with aType "
    31                "!= eColGroupContent once");
    32   uint32_t type = aType - eColGroupContent;
    33   RemoveStateBits(COL_GROUP_TYPE_BITS);
    34   AddStateBits(nsFrameState(type << COL_GROUP_TYPE_OFFSET));
    35 }
    37 void nsTableColGroupFrame::ResetColIndices(nsIFrame*       aFirstColGroup,
    38                                            int32_t         aFirstColIndex,
    39                                            nsIFrame*       aStartColFrame)
    40 {
    41   nsTableColGroupFrame* colGroupFrame = (nsTableColGroupFrame*)aFirstColGroup;
    42   int32_t colIndex = aFirstColIndex;
    43   while (colGroupFrame) {
    44     if (nsGkAtoms::tableColGroupFrame == colGroupFrame->GetType()) {
    45       // reset the starting col index for the first cg only if we should reset
    46       // the whole colgroup (aStartColFrame defaults to nullptr) or if
    47       // aFirstColIndex is smaller than the existing starting col index
    48       if ((colIndex != aFirstColIndex) ||
    49           (colIndex < colGroupFrame->GetStartColumnIndex()) ||
    50           !aStartColFrame) {
    51         colGroupFrame->SetStartColumnIndex(colIndex);
    52       }
    53       nsIFrame* colFrame = aStartColFrame; 
    54       if (!colFrame || (colIndex != aFirstColIndex)) {
    55         colFrame = colGroupFrame->GetFirstPrincipalChild();
    56       }
    57       while (colFrame) {
    58         if (nsGkAtoms::tableColFrame == colFrame->GetType()) {
    59           ((nsTableColFrame*)colFrame)->SetColIndex(colIndex);
    60           colIndex++;
    61         }
    62         colFrame = colFrame->GetNextSibling();
    63       }
    64     }
    65     colGroupFrame = static_cast<nsTableColGroupFrame*>
    66                                (colGroupFrame->GetNextSibling());
    67   }
    68 }
    71 nsresult
    72 nsTableColGroupFrame::AddColsToTable(int32_t                   aFirstColIndex,
    73                                      bool                      aResetSubsequentColIndices,
    74                                      const nsFrameList::Slice& aCols)
    75 {
    76   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
    78   tableFrame->InvalidateFrameSubtree();
    80   // set the col indices of the col frames and and add col info to the table
    81   int32_t colIndex = aFirstColIndex;
    82   nsFrameList::Enumerator e(aCols);
    83   for (; !e.AtEnd(); e.Next()) {
    84     ((nsTableColFrame*)e.get())->SetColIndex(colIndex);
    85     mColCount++;
    86     tableFrame->InsertCol((nsTableColFrame &)*e.get(), colIndex);
    87     colIndex++;
    88   }
    90   for (nsFrameList::Enumerator eTail = e.GetUnlimitedEnumerator();
    91        !eTail.AtEnd();
    92        eTail.Next()) {
    93     ((nsTableColFrame*)eTail.get())->SetColIndex(colIndex);
    94     colIndex++;
    95   }
    97   // We have already set the colindex for all the colframes in this
    98   // colgroup that come after the first inserted colframe, but there could
    99   // be other colgroups following this one and their colframes need
   100   // correct colindices too.
   101   if (aResetSubsequentColIndices && GetNextSibling()) {
   102     ResetColIndices(GetNextSibling(), colIndex);
   103   }
   105   return NS_OK;
   106 }
   109 nsTableColGroupFrame*
   110 nsTableColGroupFrame::GetLastRealColGroup(nsTableFrame* aTableFrame)
   111 {
   112   nsFrameList colGroups = aTableFrame->GetColGroups();
   114   nsIFrame* nextToLastColGroup = nullptr;
   115   nsFrameList::FrameLinkEnumerator link(colGroups);
   116   for ( ; !link.AtEnd(); link.Next()) {
   117     nextToLastColGroup = link.PrevFrame();
   118   }
   120   if (!link.PrevFrame()) {
   121     return nullptr; // there are no col group frames
   122   }
   124   nsTableColGroupType lastColGroupType =
   125     static_cast<nsTableColGroupFrame*>(link.PrevFrame())->GetColType();
   126   if (eColGroupAnonymousCell == lastColGroupType) {
   127     return static_cast<nsTableColGroupFrame*>(nextToLastColGroup);
   128   }
   130   return static_cast<nsTableColGroupFrame*>(link.PrevFrame());
   131 }
   133 // don't set mColCount here, it is done in AddColsToTable
   134 nsresult
   135 nsTableColGroupFrame::SetInitialChildList(ChildListID     aListID,
   136                                           nsFrameList&    aChildList)
   137 {
   138   if (!mFrames.IsEmpty()) {
   139     // We already have child frames which means we've already been
   140     // initialized
   141     NS_NOTREACHED("unexpected second call to SetInitialChildList");
   142     return NS_ERROR_UNEXPECTED;
   143   }
   144   if (aListID != kPrincipalList) {
   145     // All we know about is the principal child list.
   146     NS_NOTREACHED("unknown frame list");
   147     return NS_ERROR_INVALID_ARG;
   148   } 
   149   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   150   if (aChildList.IsEmpty()) {
   151     tableFrame->AppendAnonymousColFrames(this, GetSpan(), eColAnonymousColGroup, 
   152                                          false);
   153     return NS_OK; 
   154   }
   156   mFrames.AppendFrames(this, aChildList);
   157   return NS_OK;
   158 }
   160 /* virtual */ void
   161 nsTableColGroupFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
   162 {
   163   nsContainerFrame::DidSetStyleContext(aOldStyleContext);
   165   if (!aOldStyleContext) //avoid this on init
   166     return;
   168   nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   169   if (tableFrame->IsBorderCollapse() &&
   170       tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
   171     int32_t colCount = GetColCount();
   172     if (!colCount)
   173       return; // this is a degenerated colgroup 
   174     nsIntRect damageArea(GetFirstColumn()->GetColIndex(), 0, colCount,
   175                          tableFrame->GetRowCount());
   176     tableFrame->AddBCDamageArea(damageArea);
   177   }
   178 }
   180 nsresult
   181 nsTableColGroupFrame::AppendFrames(ChildListID     aListID,
   182                                    nsFrameList&    aFrameList)
   183 {
   184   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
   186   nsTableColFrame* col = GetFirstColumn();
   187   nsTableColFrame* nextCol;
   188   while (col && col->GetColType() == eColAnonymousColGroup) {
   189     // this colgroup spans one or more columns but now that there is a
   190     // real column below, spanned anonymous columns should be removed,
   191     // since the HTML spec says to ignore the span of a colgroup if it
   192     // has content columns in it.
   193     nextCol = col->GetNextCol();
   194     RemoveFrame(kPrincipalList, col);
   195     col = nextCol;
   196   }
   198   const nsFrameList::Slice& newFrames =
   199     mFrames.AppendFrames(this, aFrameList);
   200   InsertColsReflow(GetStartColumnIndex() + mColCount, newFrames);
   201   return NS_OK;
   202 }
   204 nsresult
   205 nsTableColGroupFrame::InsertFrames(ChildListID     aListID,
   206                                    nsIFrame*       aPrevFrame,
   207                                    nsFrameList&    aFrameList)
   208 {
   209   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
   210   NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
   211                "inserting after sibling frame with different parent");
   213   nsTableColFrame* col = GetFirstColumn();
   214   nsTableColFrame* nextCol;
   215   while (col && col->GetColType() == eColAnonymousColGroup) {
   216     // this colgroup spans one or more columns but now that there is a
   217     // real column below, spanned anonymous columns should be removed,
   218     // since the HTML spec says to ignore the span of a colgroup if it
   219     // has content columns in it.
   220     nextCol = col->GetNextCol();
   221     if (col == aPrevFrame) {
   222       // This can happen when we're being appended to
   223       NS_ASSERTION(!nextCol || nextCol->GetColType() != eColAnonymousColGroup,
   224                    "Inserting in the middle of our anonymous cols?");
   225       // We'll want to insert at the beginning
   226       aPrevFrame = nullptr;
   227     }
   228     RemoveFrame(kPrincipalList, col);
   229     col = nextCol;
   230   }
   232   NS_ASSERTION(!aPrevFrame || aPrevFrame == aPrevFrame->LastContinuation(),
   233                "Prev frame should be last in continuation chain");
   234   NS_ASSERTION(!aPrevFrame || !GetNextColumn(aPrevFrame) ||
   235                GetNextColumn(aPrevFrame)->GetColType() != eColAnonymousCol,
   236                "Shouldn't be inserting before a spanned colframe");
   238   const nsFrameList::Slice& newFrames =
   239     mFrames.InsertFrames(this, aPrevFrame, aFrameList);
   240   nsIFrame* prevFrame = nsTableFrame::GetFrameAtOrBefore(this, aPrevFrame,
   241                                                          nsGkAtoms::tableColFrame);
   243   int32_t colIndex = (prevFrame) ? ((nsTableColFrame*)prevFrame)->GetColIndex() + 1 : GetStartColumnIndex();
   244   InsertColsReflow(colIndex, newFrames);
   246   return NS_OK;
   247 }
   249 void
   250 nsTableColGroupFrame::InsertColsReflow(int32_t                   aColIndex,
   251                                        const nsFrameList::Slice& aCols)
   252 {
   253   AddColsToTable(aColIndex, true, aCols);
   255   PresContext()->PresShell()->FrameNeedsReflow(this,
   256                                                nsIPresShell::eTreeChange,
   257                                                NS_FRAME_HAS_DIRTY_CHILDREN);
   258 }
   260 void
   261 nsTableColGroupFrame::RemoveChild(nsTableColFrame& aChild,
   262                                   bool             aResetSubsequentColIndices)
   263 {
   264   int32_t colIndex = 0;
   265   nsIFrame* nextChild = nullptr;
   266   if (aResetSubsequentColIndices) {
   267     colIndex = aChild.GetColIndex();
   268     nextChild = aChild.GetNextSibling();
   269   }
   270   mFrames.DestroyFrame(&aChild);
   271   mColCount--;
   272   if (aResetSubsequentColIndices) {
   273     if (nextChild) { // reset inside this and all following colgroups
   274       ResetColIndices(this, colIndex, nextChild);
   275     }
   276     else {
   277       nsIFrame* nextGroup = GetNextSibling();
   278       if (nextGroup) // reset next and all following colgroups
   279         ResetColIndices(nextGroup, colIndex);
   280     }
   281   }
   283   PresContext()->PresShell()->FrameNeedsReflow(this,
   284                                                nsIPresShell::eTreeChange,
   285                                                NS_FRAME_HAS_DIRTY_CHILDREN);
   286 }
   288 nsresult
   289 nsTableColGroupFrame::RemoveFrame(ChildListID     aListID,
   290                                   nsIFrame*       aOldFrame)
   291 {
   292   NS_ASSERTION(aListID == kPrincipalList, "unexpected child list");
   294   if (!aOldFrame) return NS_OK;
   295   bool contentRemoval = false;
   297   if (nsGkAtoms::tableColFrame == aOldFrame->GetType()) {
   298     nsTableColFrame* colFrame = (nsTableColFrame*)aOldFrame;
   299     if (colFrame->GetColType() == eColContent) {
   300       contentRemoval = true;
   301       // Remove any anonymous column frames this <col> produced via a colspan
   302       nsTableColFrame* col = colFrame->GetNextCol();
   303       nsTableColFrame* nextCol;
   304       while (col && col->GetColType() == eColAnonymousCol) {
   305 #ifdef DEBUG
   306         nsIFrame* providerFrame = colFrame->GetParentStyleContextFrame();
   307         if (colFrame->StyleContext()->GetParent() ==
   308             providerFrame->StyleContext()) {
   309           NS_ASSERTION(col->StyleContext() == colFrame->StyleContext() &&
   310                        col->GetContent() == colFrame->GetContent(),
   311                        "How did that happen??");
   312         }
   313         // else colFrame is being removed because of a frame
   314         // reconstruct on it, and its style context is still the old
   315         // one, so we can't assert anything about how it compares to
   316         // col's style context.
   317 #endif
   318         nextCol = col->GetNextCol();
   319         RemoveFrame(kPrincipalList, col);
   320         col = nextCol;
   321       }
   322     }
   324     int32_t colIndex = colFrame->GetColIndex();
   325     // The RemoveChild call handles calling FrameNeedsReflow on us.
   326     RemoveChild(*colFrame, true);
   328     nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   329     tableFrame->RemoveCol(this, colIndex, true, true);
   330     if (mFrames.IsEmpty() && contentRemoval && 
   331         GetColType() == eColGroupContent) {
   332       tableFrame->AppendAnonymousColFrames(this, GetSpan(),
   333                                            eColAnonymousColGroup, true);
   334     }
   335   }
   336   else {
   337     mFrames.DestroyFrame(aOldFrame);
   338   }
   340   return NS_OK;
   341 }
   343 int
   344 nsTableColGroupFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
   345 {
   346   int skip = 0;
   347   if (nullptr != GetPrevInFlow()) {
   348     skip |= 1 << LOGICAL_SIDE_B_START;
   349   }
   350   if (nullptr != GetNextInFlow()) {
   351     skip |= 1 << LOGICAL_SIDE_B_END;
   352   }
   353   return skip;
   354 }
   356 nsresult nsTableColGroupFrame::Reflow(nsPresContext*          aPresContext,
   357                                        nsHTMLReflowMetrics&     aDesiredSize,
   358                                        const nsHTMLReflowState& aReflowState,
   359                                        nsReflowStatus&          aStatus)
   360 {
   361   DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame");
   362   DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   363   NS_ASSERTION(nullptr!=mContent, "bad state -- null content for frame");
   364   nsresult rv=NS_OK;
   366   const nsStyleVisibility* groupVis = StyleVisibility();
   367   bool collapseGroup = (NS_STYLE_VISIBILITY_COLLAPSE == groupVis->mVisible);
   368   if (collapseGroup) {
   369     nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this);
   370     tableFrame->SetNeedToCollapse(true);
   371   }
   372   // for every content child that (is a column thingy and does not already have a frame)
   373   // create a frame and adjust it's style
   375   for (nsIFrame *kidFrame = mFrames.FirstChild(); kidFrame;
   376        kidFrame = kidFrame->GetNextSibling()) {
   377     // Give the child frame a chance to reflow, even though we know it'll have 0 size
   378     nsHTMLReflowMetrics kidSize(aReflowState);
   379     nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
   380                                      nsSize(0,0));
   382     nsReflowStatus status;
   383     ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, 0, 0, 0, status);
   384     FinishReflowChild(kidFrame, aPresContext, kidSize, nullptr, 0, 0, 0);
   385   }
   387   aDesiredSize.Width() = 0;
   388   aDesiredSize.Height() = 0;
   389   aStatus = NS_FRAME_COMPLETE;
   390   NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   391   return rv;
   392 }
   394 nsTableColFrame * nsTableColGroupFrame::GetFirstColumn()
   395 {
   396   return GetNextColumn(nullptr);
   397 }
   399 nsTableColFrame * nsTableColGroupFrame::GetNextColumn(nsIFrame *aChildFrame)
   400 {
   401   nsTableColFrame *result = nullptr;
   402   nsIFrame *childFrame = aChildFrame;
   403   if (!childFrame) {
   404     childFrame = mFrames.FirstChild();
   405   }
   406   else {
   407     childFrame = childFrame->GetNextSibling();
   408   }
   409   while (childFrame)
   410   {
   411     if (NS_STYLE_DISPLAY_TABLE_COLUMN ==
   412         childFrame->StyleDisplay()->mDisplay)
   413     {
   414       result = (nsTableColFrame *)childFrame;
   415       break;
   416     }
   417     childFrame = childFrame->GetNextSibling();
   418   }
   419   return result;
   420 }
   422 int32_t nsTableColGroupFrame::GetSpan()
   423 {
   424   return StyleTable()->mSpan;
   425 }
   427 void nsTableColGroupFrame::SetContinuousBCBorderWidth(uint8_t     aForSide,
   428                                                       BCPixelSize aPixelValue)
   429 {
   430   switch (aForSide) {
   431     case NS_SIDE_TOP:
   432       mTopContBorderWidth = aPixelValue;
   433       return;
   434     case NS_SIDE_BOTTOM:
   435       mBottomContBorderWidth = aPixelValue;
   436       return;
   437     default:
   438       NS_ERROR("invalid side arg");
   439   }
   440 }
   442 void nsTableColGroupFrame::GetContinuousBCBorderWidth(nsMargin& aBorder)
   443 {
   444   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
   445   nsTableFrame* table = nsTableFrame::GetTableFrame(this);
   446   nsTableColFrame* col = table->GetColFrame(mStartColIndex + mColCount - 1);
   447   col->GetContinuousBCBorderWidth(aBorder);
   448   aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips,
   449                                             mTopContBorderWidth);
   450   aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips,
   451                                             mBottomContBorderWidth);
   452 }
   454 /* ----- global methods ----- */
   456 nsIFrame*
   457 NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
   458 {
   459   return new (aPresShell) nsTableColGroupFrame(aContext);
   460 }
   462 NS_IMPL_FRAMEARENA_HELPERS(nsTableColGroupFrame)
   464 nsIAtom*
   465 nsTableColGroupFrame::GetType() const
   466 {
   467   return nsGkAtoms::tableColGroupFrame;
   468 }
   470 void 
   471 nsTableColGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey)
   472 {
   473   nsIFrame::InvalidateFrame(aDisplayItemKey);
   474   GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey);
   475 }
   477 void 
   478 nsTableColGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
   479 {
   480   nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey);
   481   // If we have filters applied that would affects our bounds, then
   482   // we get an inactive layer created and this is computed
   483   // within FrameLayerBuilder
   484   GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey);
   485 }
   487 #ifdef DEBUG_FRAME_DUMP
   488 nsresult
   489 nsTableColGroupFrame::GetFrameName(nsAString& aResult) const
   490 {
   491   return MakeFrameName(NS_LITERAL_STRING("TableColGroup"), aResult);
   492 }
   494 void nsTableColGroupFrame::Dump(int32_t aIndent)
   495 {
   496   char* indent = new char[aIndent + 1];
   497   if (!indent) return;
   498   for (int32_t i = 0; i < aIndent + 1; i++) {
   499     indent[i] = ' ';
   500   }
   501   indent[aIndent] = 0;
   503   printf("%s**START COLGROUP DUMP**\n%s startcolIndex=%d  colcount=%d span=%d coltype=",
   504     indent, indent, GetStartColumnIndex(),  GetColCount(), GetSpan());
   505   nsTableColGroupType colType = GetColType();
   506   switch (colType) {
   507   case eColGroupContent:
   508     printf(" content ");
   509     break;
   510   case eColGroupAnonymousCol: 
   511     printf(" anonymous-column  ");
   512     break;
   513   case eColGroupAnonymousCell: 
   514     printf(" anonymous-cell ");
   515     break;
   516   }
   517   // verify the colindices
   518   int32_t j = GetStartColumnIndex();
   519   nsTableColFrame* col = GetFirstColumn();
   520   while (col) {
   521     NS_ASSERTION(j == col->GetColIndex(), "wrong colindex on col frame");
   522     col = col->GetNextCol();
   523     j++;
   524   }
   525   NS_ASSERTION((j - GetStartColumnIndex()) == GetColCount(),
   526                "number of cols out of sync");
   527   printf("\n%s**END COLGROUP DUMP** ", indent);
   528   delete [] indent;
   529 }
   530 #endif

mercurial