layout/tables/nsTableRowFrame.h
author Dorel Luca <dluca@mozilla.com>
Tue, 12 Mar 2019 07:16:59 +0200
changeset 463594 89988d424c06a3333eb15a880bc1c4c6bbb1c070
parent 457593 525e804dc7e63855e026be9557af15340d71455a
child 469631 4b56de3cd46cab3f1988a2ecc299a63bceae0038
permissions -rw-r--r--
Backed out 4 changesets (bug 1500713) for build bustage Backed out changeset d25ff3b04eeb (bug 1500713) Backed out changeset 98265537ef34 (bug 1500713) Backed out changeset 670b24af24d4 (bug 1500713) Backed out changeset 7e5fa7b1f7bc (bug 1500713)

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsTableRowFrame_h__
#define nsTableRowFrame_h__

#include "mozilla/Attributes.h"
#include "nscore.h"
#include "nsContainerFrame.h"
#include "nsTableRowGroupFrame.h"
#include "mozilla/WritingModes.h"

class nsTableCellFrame;
namespace mozilla {
struct TableCellReflowInput;
}  // namespace mozilla

/**
 * nsTableRowFrame is the frame that maps table rows
 * (HTML tag TR). This class cannot be reused
 * outside of an nsTableRowGroupFrame.  It assumes that its parent is an
 * nsTableRowGroupFrame, and its children are nsTableCellFrames.
 *
 * @see nsTableFrame
 * @see nsTableRowGroupFrame
 * @see nsTableCellFrame
 */
class nsTableRowFrame : public nsContainerFrame {
  using TableCellReflowInput = mozilla::TableCellReflowInput;

 public:
  NS_DECL_QUERYFRAME
  NS_DECL_FRAMEARENA_HELPERS(nsTableRowFrame)

  virtual ~nsTableRowFrame();

  virtual void Init(nsIContent* aContent, nsContainerFrame* aParent,
                    nsIFrame* aPrevInFlow) override;

  virtual void DestroyFrom(nsIFrame* aDestructRoot,
                           PostDestroyData& aPostDestroyData) override;

  /** @see nsIFrame::DidSetComputedStyle */
  virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;

  virtual void AppendFrames(ChildListID aListID,
                            nsFrameList& aFrameList) override;
  virtual void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
                            nsFrameList& aFrameList) override;
  virtual void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) override;

  /** instantiate a new instance of nsTableRowFrame.
   * @param aPresShell the pres shell for this frame
   *
   * @return           the frame that was created
   */
  friend nsTableRowFrame* NS_NewTableRowFrame(nsIPresShell* aPresShell,
                                              ComputedStyle* aStyle);

  nsTableRowGroupFrame* GetTableRowGroupFrame() const {
    nsIFrame* parent = GetParent();
    MOZ_ASSERT(parent && parent->IsTableRowGroupFrame());
    return static_cast<nsTableRowGroupFrame*>(parent);
  }

  nsTableFrame* GetTableFrame() const {
    return GetTableRowGroupFrame()->GetTableFrame();
  }

  virtual nsMargin GetUsedMargin() const override;
  virtual nsMargin GetUsedBorder() const override;
  virtual nsMargin GetUsedPadding() const override;

  virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
                                const nsDisplayListSet& aLists) override;

  // Implemented in nsTableCellFrame.h, because it needs to know about the
  // nsTableCellFrame class, but we can't include nsTableCellFrame.h here.
  inline nsTableCellFrame* GetFirstCell() const;

  /** calls Reflow for all of its child cells.
   *
   * Cells with rowspan=1 are all set to the same height and stacked
   * horizontally.
   *
   * Cells are not split unless absolutely necessary.
   *
   * Cells are resized in nsTableFrame::BalanceColumnWidths and
   * nsTableFrame::ShrinkWrapChildren
   *
   * @param aDesiredSize width set to width of the sum of the cells,
   *                     height set to height of cells with rowspan=1.
   *
   * @see nsIFrame::Reflow
   * @see nsTableFrame::BalanceColumnWidths
   * @see nsTableFrame::ShrinkWrapChildren
   */
  virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
                      const ReflowInput& aReflowInput,
                      nsReflowStatus& aStatus) override;

  void DidResize();

#ifdef DEBUG_FRAME_DUMP
  virtual nsresult GetFrameName(nsAString& aResult) const override;
#endif

  void UpdateBSize(nscoord aBSize, nscoord aAscent, nscoord aDescent,
                   nsTableFrame* aTableFrame = nullptr,
                   nsTableCellFrame* aCellFrame = nullptr);

  void ResetBSize(nscoord aRowStyleBSize);

  // calculate the bsize, considering content bsize of the
  // cells and the style bsize of the row and cells, excluding pct bsizes
  nscoord CalcBSize(const ReflowInput& aReflowInput);

  // Support for cells with 'vertical-align: baseline'.

  /**
   * returns the max-ascent amongst all the cells that have
   * 'vertical-align: baseline', *including* cells with rowspans.
   * returns 0 if we don't have any cell with 'vertical-align: baseline'
   */
  nscoord GetMaxCellAscent() const;

  /* return the row ascent
   */
  nscoord GetRowBaseline(mozilla::WritingMode aWritingMode);

  /** returns the ordinal position of this row in its table */
  virtual int32_t GetRowIndex() const;

  /** set this row's starting row index */
  void SetRowIndex(int aRowIndex);

  // See nsTableFrame.h
  int32_t GetAdjustmentForStoredIndex(int32_t aStoredIndex) const;

  // See nsTableFrame.h
  void AddDeletedRowIndex();

  /** used by row group frame code */
  nscoord ReflowCellFrame(nsPresContext* aPresContext,
                          const ReflowInput& aReflowInput, bool aIsTopOfPage,
                          nsTableCellFrame* aCellFrame, nscoord aAvailableBSize,
                          nsReflowStatus& aStatus);
  /**
   * Collapse the row if required, apply col and colgroup visibility: collapse
   * info to the cells in the row.
   * @return the amount to shift bstart-wards all following rows
   * @param aRowOffset     - shift the row bstart-wards by this amount
   * @param aISize         - new isize of the row
   * @param aCollapseGroup - parent rowgroup is collapsed so this row needs
   *                         to be collapsed
   * @param aDidCollapse   - the row has been collapsed
   */
  nscoord CollapseRowIfNecessary(nscoord aRowOffset, nscoord aISize,
                                 bool aCollapseGroup, bool& aDidCollapse);

  /**
   * Insert a cell frame after the last cell frame that has a col index
   * that is less than aColIndex.  If no such cell frame is found the
   * frame to insert is prepended to the child list.
   * @param aFrame the cell frame to insert
   * @param aColIndex the col index
   */
  void InsertCellFrame(nsTableCellFrame* aFrame, int32_t aColIndex);

  nsresult CalculateCellActualBSize(nsTableCellFrame* aCellFrame,
                                    nscoord& aDesiredBSize,
                                    mozilla::WritingMode aWM);

  bool IsFirstInserted() const;
  void SetFirstInserted(bool aValue);

  nscoord GetContentBSize() const;
  void SetContentBSize(nscoord aTwipValue);

  bool HasStyleBSize() const;

  bool HasFixedBSize() const;
  void SetHasFixedBSize(bool aValue);

  bool HasPctBSize() const;
  void SetHasPctBSize(bool aValue);

  nscoord GetFixedBSize() const;
  void SetFixedBSize(nscoord aValue);

  float GetPctBSize() const;
  void SetPctBSize(float aPctValue, bool aForce = false);

  nscoord GetInitialBSize(nscoord aBasis = 0) const;

  nsTableRowFrame* GetNextRow() const;

  bool HasUnpaginatedBSize();
  void SetHasUnpaginatedBSize(bool aValue);
  nscoord GetUnpaginatedBSize();
  void SetUnpaginatedBSize(nsPresContext* aPresContext, nscoord aValue);

  BCPixelSize GetBStartBCBorderWidth() const { return mBStartBorderWidth; }
  BCPixelSize GetBEndBCBorderWidth() const { return mBEndBorderWidth; }
  void SetBStartBCBorderWidth(BCPixelSize aWidth) {
    mBStartBorderWidth = aWidth;
  }
  void SetBEndBCBorderWidth(BCPixelSize aWidth) { mBEndBorderWidth = aWidth; }
  mozilla::LogicalMargin GetBCBorderWidth(mozilla::WritingMode aWM);

  /**
   * Gets inner border widths before collapsing with cell borders
   * Caller must get block-end border from next row or from table
   * GetContinuousBCBorderWidth will not overwrite that border
   * see nsTablePainter about continuous borders
   */
  void GetContinuousBCBorderWidth(mozilla::WritingMode aWM,
                                  mozilla::LogicalMargin& aBorder);

  /**
   * @returns outer block-start bc border == prev row's block-end inner
   */
  nscoord GetOuterBStartContBCBorderWidth();
  /**
   * Sets full border widths before collapsing with cell borders
   * @param aForSide - side to set; only accepts iend, istart, and bstart
   */
  void SetContinuousBCBorderWidth(mozilla::LogicalSide aForSide,
                                  BCPixelSize aPixelValue);

  virtual bool IsFrameOfType(uint32_t aFlags) const override {
    if (aFlags & eSupportsContainLayoutAndPaint) {
      return false;
    }

    return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eTablePart));
  }

  virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0,
                               bool aRebuildDisplayItems = true) override;
  virtual void InvalidateFrameWithRect(
      const nsRect& aRect, uint32_t aDisplayItemKey = 0,
      bool aRebuildDisplayItems = true) override;
  virtual void InvalidateFrameForRemoval() override {
    InvalidateFrameSubtree();
  }

#ifdef ACCESSIBILITY
  virtual mozilla::a11y::AccType AccessibleType() override;
#endif

 protected:
  /** protected constructor.
   * @see NewFrame
   */
  explicit nsTableRowFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
                           ClassID aID = kClassID);

  void InitChildReflowInput(nsPresContext& aPresContext,
                            const mozilla::LogicalSize& aAvailSize,
                            bool aBorderCollapse,
                            TableCellReflowInput& aReflowInput);

  virtual LogicalSides GetLogicalSkipSides(
      const ReflowInput* aReflowInput = nullptr) const override;

  // row-specific methods

  nscoord ComputeCellXOffset(const ReflowInput& aState, nsIFrame* aKidFrame,
                             const nsMargin& aKidMargin) const;
  /**
   * Called for incremental/dirty and resize reflows. If aDirtyOnly is true then
   * only reflow dirty cells.
   */
  void ReflowChildren(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
                      const ReflowInput& aReflowInput,
                      nsTableFrame& aTableFrame, nsReflowStatus& aStatus);

 private:
  struct RowBits {
    unsigned mRowIndex : 29;
    unsigned mHasFixedBSize : 1;  // set if the dominating style bsize on the
                                  // row or any cell is pixel based
    unsigned mHasPctBSize : 1;  // set if the dominating style bsize on the row
                                // or any cell is pct based
    unsigned mFirstInserted : 1;  // if true, then it was the bstart-most newly
                                  // inserted row
  } mBits;

  // the desired bsize based on the content of the tallest cell in the row
  nscoord mContentBSize;
  // the bsize based on a style percentage bsize on either the row or any cell
  // if mHasPctBSize is set
  nscoord mStylePctBSize;
  // the bsize based on a style pixel bsize on the row or any
  // cell if mHasFixedBSize is set
  nscoord mStyleFixedBSize;

  // max-ascent and max-descent amongst all cells that have
  // 'vertical-align: baseline'
  nscoord mMaxCellAscent;   // does include cells with rowspan > 1
  nscoord mMaxCellDescent;  // does *not* include cells with rowspan > 1

  // border widths in pixels in the collapsing border model of the *inner*
  // half of the border only
  BCPixelSize mBStartBorderWidth;
  BCPixelSize mBEndBorderWidth;
  BCPixelSize mIEndContBorderWidth;
  BCPixelSize mBStartContBorderWidth;
  BCPixelSize mIStartContBorderWidth;

  /**
   * Sets the NS_ROW_HAS_CELL_WITH_STYLE_BSIZE bit to indicate whether
   * this row has any cells that have non-auto-bsize.  (Row-spanning
   * cells are ignored.)
   */
  void InitHasCellWithStyleBSize(nsTableFrame* aTableFrame);
};

inline int32_t nsTableRowFrame::GetAdjustmentForStoredIndex(
    int32_t aStoredIndex) const {
  nsTableRowGroupFrame* parentFrame = GetTableRowGroupFrame();
  return parentFrame->GetAdjustmentForStoredIndex(aStoredIndex);
}

inline void nsTableRowFrame::AddDeletedRowIndex() {
  nsTableRowGroupFrame* parentFrame = GetTableRowGroupFrame();
  parentFrame->AddDeletedRowIndex(int32_t(mBits.mRowIndex));
}

inline int32_t nsTableRowFrame::GetRowIndex() const {
  int32_t storedRowIndex = int32_t(mBits.mRowIndex);
  int32_t rowIndexAdjustment = GetAdjustmentForStoredIndex(storedRowIndex);
  return (storedRowIndex - rowIndexAdjustment);
}

inline void nsTableRowFrame::SetRowIndex(int aRowIndex) {
  // Note: Setting the index of a row (as in the case of adding new rows) should
  // be preceded by a call to nsTableFrame::RecalculateRowIndices()
  // so as to correctly clear mDeletedRowIndexRanges.
  MOZ_ASSERT(
      GetTableRowGroupFrame()->GetTableFrame()->IsDeletedRowIndexRangesEmpty(),
      "mDeletedRowIndexRanges should be empty here!");
  mBits.mRowIndex = aRowIndex;
}

inline bool nsTableRowFrame::IsFirstInserted() const {
  return bool(mBits.mFirstInserted);
}

inline void nsTableRowFrame::SetFirstInserted(bool aValue) {
  mBits.mFirstInserted = aValue;
}

inline bool nsTableRowFrame::HasStyleBSize() const {
  return (bool)mBits.mHasFixedBSize || (bool)mBits.mHasPctBSize;
}

inline bool nsTableRowFrame::HasFixedBSize() const {
  return (bool)mBits.mHasFixedBSize;
}

inline void nsTableRowFrame::SetHasFixedBSize(bool aValue) {
  mBits.mHasFixedBSize = aValue;
}

inline bool nsTableRowFrame::HasPctBSize() const {
  return (bool)mBits.mHasPctBSize;
}

inline void nsTableRowFrame::SetHasPctBSize(bool aValue) {
  mBits.mHasPctBSize = aValue;
}

inline nscoord nsTableRowFrame::GetContentBSize() const {
  return mContentBSize;
}

inline void nsTableRowFrame::SetContentBSize(nscoord aValue) {
  mContentBSize = aValue;
}

inline nscoord nsTableRowFrame::GetFixedBSize() const {
  if (mBits.mHasFixedBSize) {
    return mStyleFixedBSize;
  }
  return 0;
}

inline float nsTableRowFrame::GetPctBSize() const {
  if (mBits.mHasPctBSize) {
    return (float)mStylePctBSize / 100.0f;
  }
  return 0.0f;
}

inline bool nsTableRowFrame::HasUnpaginatedBSize() {
  return HasAnyStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE);
}

inline void nsTableRowFrame::SetHasUnpaginatedBSize(bool aValue) {
  if (aValue) {
    AddStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE);
  } else {
    RemoveStateBits(NS_TABLE_ROW_HAS_UNPAGINATED_BSIZE);
  }
}

inline mozilla::LogicalMargin nsTableRowFrame::GetBCBorderWidth(
    mozilla::WritingMode aWM) {
  nsPresContext* presContext = PresContext();
  return mozilla::LogicalMargin(
      aWM, presContext->DevPixelsToAppUnits(mBStartBorderWidth), 0,
      presContext->DevPixelsToAppUnits(mBEndBorderWidth), 0);
}

inline void nsTableRowFrame::GetContinuousBCBorderWidth(
    mozilla::WritingMode aWM, mozilla::LogicalMargin& aBorder) {
  int32_t d2a = PresContext()->AppUnitsPerDevPixel();
  aBorder.IEnd(aWM) = BC_BORDER_START_HALF_COORD(d2a, mIStartContBorderWidth);
  aBorder.BStart(aWM) = BC_BORDER_END_HALF_COORD(d2a, mBStartContBorderWidth);
  aBorder.IStart(aWM) = BC_BORDER_END_HALF_COORD(d2a, mIEndContBorderWidth);
}

inline nscoord nsTableRowFrame::GetOuterBStartContBCBorderWidth() {
  int32_t aPixelsToTwips = mozilla::AppUnitsPerCSSPixel();
  return BC_BORDER_START_HALF_COORD(aPixelsToTwips, mBStartContBorderWidth);
}

#endif