diff options
Diffstat (limited to 'layout/tables/nsTableCellFrame.h')
-rw-r--r-- | layout/tables/nsTableCellFrame.h | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h new file mode 100644 index 0000000000..f9b6f3ccac --- /dev/null +++ b/layout/tables/nsTableCellFrame.h @@ -0,0 +1,334 @@ +/* -*- 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 nsTableCellFrame_h__ +#define nsTableCellFrame_h__ + +#include "mozilla/Attributes.h" +#include "celldata.h" +#include "nsITableCellLayout.h" +#include "nscore.h" +#include "nsContainerFrame.h" +#include "mozilla/ComputedStyle.h" +#include "nsIPercentBSizeObserver.h" +#include "nsTArray.h" +#include "nsTableRowFrame.h" +#include "mozilla/WritingModes.h" + +namespace mozilla { +class PresShell; +} // namespace mozilla + +/** + * nsTableCellFrame + * data structure to maintain information about a single table cell's frame + * + * NOTE: frames are not ref counted. We expose addref and release here + * so we can change that decsion in the future. Users of nsITableCellLayout + * should refcount correctly as if this object is being ref counted, though + * no actual support is under the hood. + * + * @author sclark + */ +class nsTableCellFrame : public nsContainerFrame, + public nsITableCellLayout, + public nsIPercentBSizeObserver { + typedef mozilla::gfx::DrawTarget DrawTarget; + typedef mozilla::image::ImgDrawResult ImgDrawResult; + + friend nsTableCellFrame* NS_NewTableCellFrame(mozilla::PresShell* aPresShell, + ComputedStyle* aStyle, + nsTableFrame* aTableFrame); + + nsTableCellFrame(ComputedStyle* aStyle, nsTableFrame* aTableFrame) + : nsTableCellFrame(aStyle, aTableFrame, kClassID) {} + + protected: + typedef mozilla::WritingMode WritingMode; + typedef mozilla::LogicalSide LogicalSide; + typedef mozilla::LogicalMargin LogicalMargin; + + public: + NS_DECL_QUERYFRAME + NS_DECL_FRAMEARENA_HELPERS(nsTableCellFrame) + + nsIScrollableFrame* GetScrollTargetFrame() const final; + + nsTableRowFrame* GetTableRowFrame() const { + nsIFrame* parent = GetParent(); + MOZ_ASSERT(parent && parent->IsTableRowFrame()); + return static_cast<nsTableRowFrame*>(parent); + } + + nsTableFrame* GetTableFrame() const { + return GetTableRowFrame()->GetTableFrame(); + } + + void Init(nsIContent* aContent, nsContainerFrame* aParent, + nsIFrame* aPrevInFlow) override; + + void Destroy(DestroyContext&) override; + +#ifdef ACCESSIBILITY + mozilla::a11y::AccType AccessibleType() override; +#endif + + nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute, + int32_t aModType) override; + + /** @see nsIFrame::DidSetComputedStyle */ + void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override; + +#ifdef DEBUG + // Our anonymous block frame is the content insertion frame so these + // methods should never be called: + void AppendFrames(ChildListID aListID, nsFrameList&& aFrameList) override; + void InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, + const nsLineList::iterator* aPrevFrameLine, + nsFrameList&& aFrameList) override; + void RemoveFrame(DestroyContext&, ChildListID, nsIFrame*) override; +#endif + + nsContainerFrame* GetContentInsertionFrame() override { + return PrincipalChildList().FirstChild()->GetContentInsertionFrame(); + } + + nsIFrame* CellContentFrame() const; + + nsMargin GetUsedMargin() const override; + + void NotifyPercentBSize(const ReflowInput& aReflowInput) override; + + bool NeedsToObserve(const ReflowInput& aReflowInput) override; + + void BuildDisplayList(nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists) override; + + virtual void ProcessBorders(nsTableFrame* aFrame, + nsDisplayListBuilder* aBuilder, + const nsDisplayListSet& aLists); + + nscoord GetMinISize(gfxContext* aRenderingContext) override; + nscoord GetPrefISize(gfxContext* aRenderingContext) override; + IntrinsicSizeOffsetData IntrinsicISizeOffsets( + nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override; + + void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize, + const ReflowInput& aReflowInput, + nsReflowStatus& aStatus) override; + +#ifdef DEBUG_FRAME_DUMP + nsresult GetFrameName(nsAString& aResult) const override; +#endif + + void BlockDirAlignChild(mozilla::WritingMode aWM, nscoord aMaxAscent); + + /* + * Get the value of vertical-align adjusted for CSS 2's rules for a + * table cell, which means the result is always + * StyleVerticalAlignKeyword::{Top,Middle,Bottom,Baseline}. + */ + virtual mozilla::StyleVerticalAlignKeyword GetVerticalAlign() const; + + bool HasVerticalAlignBaseline() const { + return GetVerticalAlign() == mozilla::StyleVerticalAlignKeyword::Baseline && + !GetContentEmpty(); + } + + /** + * Get the first-line baseline of the cell relative to its block-start border + * edge, as if the cell were vertically aligned to the top of the row. + */ + nscoord GetCellBaseline() const; + + /** + * return the cell's specified row span. this is what was specified in the + * content model or in the style info, and is always >= 0. + * to get the effective row span (the actual value that applies), use + * GetEffectiveRowSpan() + * @see nsTableFrame::GetEffectiveRowSpan() + */ + int32_t GetRowSpan(); + + // there is no set row index because row index depends on the cell's parent + // row only + + // Return our cell content frame. + void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override; + + /*---------------- nsITableCellLayout methods ------------------------*/ + + /** + * return the cell's starting row index (starting at 0 for the first row). + * for continued cell frames the row index is that of the cell's first-in-flow + * and the column index (starting at 0 for the first column + */ + NS_IMETHOD GetCellIndexes(int32_t& aRowIndex, int32_t& aColIndex) override; + + /** return the mapped cell's row index (starting at 0 for the first row) */ + uint32_t RowIndex() const { + return static_cast<nsTableRowFrame*>(GetParent())->GetRowIndex(); + } + + /** + * return the cell's specified col span. this is what was specified in the + * content model or in the style info, and is always >= 1. + * to get the effective col span (the actual value that applies), use + * GetEffectiveColSpan() + * @see nsTableFrame::GetEffectiveColSpan() + */ + int32_t GetColSpan(); + + /** return the cell's column index (starting at 0 for the first column) */ + uint32_t ColIndex() const { + // NOTE: We copy this from previous continuations, and we don't ever have + // dynamic updates when tables split, so our mColIndex always matches our + // first continuation's. + MOZ_ASSERT(static_cast<nsTableCellFrame*>(FirstContinuation())->mColIndex == + mColIndex, + "mColIndex out of sync with first continuation"); + return mColIndex; + } + + void SetColIndex(int32_t aColIndex); + + /** return the available isize given to this frame during its last reflow */ + inline nscoord GetPriorAvailISize(); + + /** set the available isize given to this frame during its last reflow */ + inline void SetPriorAvailISize(nscoord aPriorAvailISize); + + /** return the desired size returned by this frame during its last reflow */ + inline mozilla::LogicalSize GetDesiredSize(); + + /** set the desired size returned by this frame during its last reflow */ + inline void SetDesiredSize(const ReflowOutput& aDesiredSize); + + bool GetContentEmpty() const; + void SetContentEmpty(bool aContentEmpty); + + nsTableCellFrame* GetNextCell() const { + nsIFrame* sibling = GetNextSibling(); + MOZ_ASSERT( + !sibling || static_cast<nsTableCellFrame*>(do_QueryFrame(sibling)), + "How do we have a non-cell sibling?"); + return static_cast<nsTableCellFrame*>(sibling); + } + + virtual LogicalMargin GetBorderWidth(WritingMode aWM) const; + + void DecorateForSelection(DrawTarget* aDrawTarget, nsPoint aPt); + + bool ComputeCustomOverflow(mozilla::OverflowAreas& aOverflowAreas) override; + + void InvalidateFrame(uint32_t aDisplayItemKey = 0, + bool aRebuildDisplayItems = true) override; + void InvalidateFrameWithRect(const nsRect& aRect, + uint32_t aDisplayItemKey = 0, + bool aRebuildDisplayItems = true) override; + void InvalidateFrameForRemoval() override { InvalidateFrameSubtree(); } + + bool ShouldPaintBordersAndBackgrounds() const; + + bool ShouldPaintBackground(nsDisplayListBuilder* aBuilder); + + protected: + nsTableCellFrame(ComputedStyle* aStyle, nsTableFrame* aTableFrame, + ClassID aID); + ~nsTableCellFrame(); + + LogicalSides GetLogicalSkipSides() const override; + + /** + * GetBorderOverflow says how far the cell's own borders extend + * outside its own bounds. In the separated borders model this should + * just be zero (as it is for most frames), but in the collapsed + * borders model (for which nsBCTableCellFrame overrides this virtual + * method), it considers the extents of the collapsed border. + */ + virtual nsMargin GetBorderOverflow(); + + friend class nsTableRowFrame; + + uint32_t mColIndex; // the starting column for this cell + + nscoord mPriorAvailISize; // the avail isize during the last reflow + mozilla::LogicalSize mDesiredSize; // the last desired inline and block size +}; + +inline nscoord nsTableCellFrame::GetPriorAvailISize() { + return mPriorAvailISize; +} + +inline void nsTableCellFrame::SetPriorAvailISize(nscoord aPriorAvailISize) { + mPriorAvailISize = aPriorAvailISize; +} + +inline mozilla::LogicalSize nsTableCellFrame::GetDesiredSize() { + return mDesiredSize; +} + +inline void nsTableCellFrame::SetDesiredSize(const ReflowOutput& aDesiredSize) { + mDesiredSize = aDesiredSize.Size(GetWritingMode()); +} + +inline bool nsTableCellFrame::GetContentEmpty() const { + return HasAnyStateBits(NS_TABLE_CELL_CONTENT_EMPTY); +} + +inline void nsTableCellFrame::SetContentEmpty(bool aContentEmpty) { + if (aContentEmpty) { + AddStateBits(NS_TABLE_CELL_CONTENT_EMPTY); + } else { + RemoveStateBits(NS_TABLE_CELL_CONTENT_EMPTY); + } +} + +// nsBCTableCellFrame +class nsBCTableCellFrame final : public nsTableCellFrame { + typedef mozilla::image::ImgDrawResult ImgDrawResult; + + public: + NS_DECL_FRAMEARENA_HELPERS(nsBCTableCellFrame) + + nsBCTableCellFrame(ComputedStyle* aStyle, nsTableFrame* aTableFrame); + + ~nsBCTableCellFrame(); + + nsMargin GetUsedBorder() const override; + + // Get the *inner half of the border only*, in twips. + LogicalMargin GetBorderWidth(WritingMode aWM) const override; + + // Get the *inner half of the border only*, in pixels. + BCPixelSize GetBorderWidth(LogicalSide aSide) const; + + // Set the full (both halves) width of the border + void SetBorderWidth(LogicalSide aSide, BCPixelSize aPixelValue); + + nsMargin GetBorderOverflow() override; + +#ifdef DEBUG_FRAME_DUMP + nsresult GetFrameName(nsAString& aResult) const override; +#endif + + private: + // These are the entire width of the border (the cell edge contains only + // the inner half). + BCPixelSize mBStartBorder; + BCPixelSize mIEndBorder; + BCPixelSize mBEndBorder; + BCPixelSize mIStartBorder; +}; + +// Implemented here because that's a sane-ish way to make the includes work out. +inline nsTableCellFrame* nsTableRowFrame::GetFirstCell() const { + nsIFrame* firstChild = mFrames.FirstChild(); + MOZ_ASSERT( + !firstChild || static_cast<nsTableCellFrame*>(do_QueryFrame(firstChild)), + "How do we have a non-cell child?"); + return static_cast<nsTableCellFrame*>(firstChild); +} + +#endif |