diff -r 000000000000 -r 6474c204b198 layout/generic/nsHTMLReflowMetrics.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layout/generic/nsHTMLReflowMetrics.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,333 @@ +/* -*- 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/. */ + +/* struct containing the output from nsIFrame::Reflow */ + +#ifndef nsHTMLReflowMetrics_h___ +#define nsHTMLReflowMetrics_h___ + +#include "nsRect.h" +#include "nsBoundingMetrics.h" +#include "WritingModes.h" + +//---------------------------------------------------------------------- + +class nsHTMLReflowState; + +// Option flags +#define NS_REFLOW_CALC_BOUNDING_METRICS 0x0001 + +/** + * When we store overflow areas as an array of scrollable and visual + * overflow, we use these indices. + * + * eOverflowType_LENGTH is needed (for gcc 4.5.*, at least) to ensure + * that 2 is a valid value of nsOverflowType for use in + * NS_FOR_FRAME_OVERFLOW_TYPES. + */ +enum nsOverflowType { eVisualOverflow, eScrollableOverflow, + eOverflowType_LENGTH }; + +#define NS_FOR_FRAME_OVERFLOW_TYPES(var_) \ + for (nsOverflowType var_ = nsOverflowType(0); var_ < 2; \ + var_ = nsOverflowType(var_ + 1)) + +struct nsOverflowAreas { +private: + nsRect mRects[2]; +public: + nsRect& Overflow(size_t aIndex) { + NS_ASSERTION(aIndex < 2, "index out of range"); + return mRects[aIndex]; + } + const nsRect& Overflow(size_t aIndex) const { + NS_ASSERTION(aIndex < 2, "index out of range"); + return mRects[aIndex]; + } + + nsRect& VisualOverflow() { return mRects[eVisualOverflow]; } + const nsRect& VisualOverflow() const { return mRects[eVisualOverflow]; } + + nsRect& ScrollableOverflow() { return mRects[eScrollableOverflow]; } + const nsRect& ScrollableOverflow() const { return mRects[eScrollableOverflow]; } + + nsOverflowAreas() { + // default-initializes to zero due to nsRect's default constructor + } + + nsOverflowAreas(const nsRect& aVisualOverflow, + const nsRect& aScrollableOverflow) + { + mRects[eVisualOverflow] = aVisualOverflow; + mRects[eScrollableOverflow] = aScrollableOverflow; + } + + nsOverflowAreas(const nsOverflowAreas& aOther) { + *this = aOther; + } + + nsOverflowAreas& operator=(const nsOverflowAreas& aOther) { + mRects[0] = aOther.mRects[0]; + mRects[1] = aOther.mRects[1]; + return *this; + } + + bool operator==(const nsOverflowAreas& aOther) const { + // Scrollable overflow is a point-set rectangle and visual overflow + // is a pixel-set rectangle. + return VisualOverflow().IsEqualInterior(aOther.VisualOverflow()) && + ScrollableOverflow().IsEqualEdges(aOther.ScrollableOverflow()); + } + + bool operator!=(const nsOverflowAreas& aOther) const { + return !(*this == aOther); + } + + nsOverflowAreas operator+(const nsPoint& aPoint) const { + nsOverflowAreas result(*this); + result += aPoint; + return result; + } + + nsOverflowAreas& operator+=(const nsPoint& aPoint) { + mRects[0] += aPoint; + mRects[1] += aPoint; + return *this; + } + + void Clear() { + mRects[0].SetRect(0, 0, 0, 0); + mRects[1].SetRect(0, 0, 0, 0); + } + + // Mutates |this| by unioning both overflow areas with |aOther|. + void UnionWith(const nsOverflowAreas& aOther); + + // Mutates |this| by unioning both overflow areas with |aRect|. + void UnionAllWith(const nsRect& aRect); + + // Mutates |this| by setting both overflow areas to |aRect|. + void SetAllTo(const nsRect& aRect); +}; + +/** + * An nsCollapsingMargin represents a vertical collapsing margin between + * blocks as described in section 8.3.1 of CSS2, + * . + * + * All adjacent vertical margins collapse, and the resulting margin is + * the sum of the largest positive margin included and the smallest (most + * negative) negative margin included. + */ +struct nsCollapsingMargin { + private: + nscoord mMostPos; // the largest positive margin included + nscoord mMostNeg; // the smallest negative margin included + + public: + nsCollapsingMargin() + : mMostPos(0), + mMostNeg(0) + { + } + + nsCollapsingMargin(const nsCollapsingMargin& aOther) + : mMostPos(aOther.mMostPos), + mMostNeg(aOther.mMostNeg) + { + } + + bool operator==(const nsCollapsingMargin& aOther) + { + return mMostPos == aOther.mMostPos && + mMostNeg == aOther.mMostNeg; + } + + bool operator!=(const nsCollapsingMargin& aOther) + { + return !(*this == aOther); + } + + nsCollapsingMargin& operator=(const nsCollapsingMargin& aOther) + { + mMostPos = aOther.mMostPos; + mMostNeg = aOther.mMostNeg; + return *this; + } + + void Include(nscoord aCoord) + { + if (aCoord > mMostPos) + mMostPos = aCoord; + else if (aCoord < mMostNeg) + mMostNeg = aCoord; + } + + void Include(const nsCollapsingMargin& aOther) + { + if (aOther.mMostPos > mMostPos) + mMostPos = aOther.mMostPos; + if (aOther.mMostNeg < mMostNeg) + mMostNeg = aOther.mMostNeg; + } + + void Zero() + { + mMostPos = 0; + mMostNeg = 0; + } + + bool IsZero() const + { + return (mMostPos == 0) && (mMostNeg == 0); + } + + nscoord get() const + { + return mMostPos + mMostNeg; + } +}; + +/** + * Reflow metrics used to return the frame's desired size and alignment + * information. + * + * @see #Reflow() + */ +class nsHTMLReflowMetrics { +public: + // XXXldb Should |aFlags| generally be passed from parent to child? + // Some places do it, and some don't. |aFlags| should perhaps go away + // entirely. + // XXX width/height/ascent are OUT parameters and so they shouldn't + // have to be initialized, but there are some bad frame classes that + // aren't properly setting them when returning from Reflow()... + nsHTMLReflowMetrics(mozilla::WritingMode aWritingMode, uint32_t aFlags = 0) + : mISize(0) + , mBSize(0) + , mBlockStartAscent(ASK_FOR_BASELINE) + , mFlags(aFlags) + , mWritingMode(aWritingMode) + {} + + nsHTMLReflowMetrics(const nsHTMLReflowState& aState, uint32_t aFlags = 0); + + // ISize and BSize are logical-coordinate dimensions: + // ISize is the size in the writing mode's inline direction (which equates to + // width in horizontal writing modes, height in vertical ones), and BSize is + // the size in the block-progression direction. + nscoord ISize() const { return mISize; } + nscoord BSize() const { return mBSize; } + + nscoord& ISize() { return mISize; } + nscoord& BSize() { return mBSize; } + + // Width and Height are physical dimensions, independent of writing mode. + // Accessing these is slightly more expensive than accessing the logical + // dimensions (once vertical writing mode support is enabled); as far as + // possible, client code should work purely with logical dimensions. + nscoord Width() const { return mWritingMode.IsVertical() ? mBSize : mISize; } + nscoord Height() const { return mWritingMode.IsVertical() ? mISize : mBSize; } + + // It's only meaningful to consider "ascent" on the block-start side of the + // frame; asking for the "ascent" on any other side will just return zero. + nscoord TopAscent() const + { + return mWritingMode.IsVertical() ? 0 : mBlockStartAscent; + } + nscoord LeftAscent() const + { + return mWritingMode.IsVertical() && mWritingMode.IsVerticalLR() ? + mBlockStartAscent : 0; + } + nscoord RightAscent() const + { + return mWritingMode.IsVertical() && !mWritingMode.IsVerticalLR() ? + mBlockStartAscent : 0; + } + + nscoord& Width() { return mWritingMode.IsVertical() ? mBSize : mISize; } + nscoord& Height() { return mWritingMode.IsVertical() ? mISize : mBSize; } + + // To set the ascent value, we must be sure we're working with the correct + // writing mode, so either pass it to the logical setter... + void SetBlockStartAscent(mozilla::WritingMode aWritingMode, nscoord aAscent) + { + NS_ASSERTION(aWritingMode == mWritingMode, "writing mode mismatch"); + mBlockStartAscent = aAscent; + } + // ...or call the appropriate physical setter (these will probably be removed + // eventually). + void SetTopAscent(nscoord aAscent) + { + NS_ASSERTION(!mWritingMode.IsVertical(), "writing mode mismatch"); + mBlockStartAscent = aAscent; + } + void SetLeftAscent(nscoord aAscent) + { + NS_ASSERTION(mWritingMode.IsVertical() && mWritingMode.IsVerticalLR(), + "writing mode mismatch"); + mBlockStartAscent = aAscent; + } + void SetRightAscent(nscoord aAscent) + { + NS_ASSERTION(mWritingMode.IsVertical() && !mWritingMode.IsVerticalLR(), + "writing mode mismatch"); + mBlockStartAscent = aAscent; + } + + enum { ASK_FOR_BASELINE = nscoord_MAX }; + + // Metrics that _exactly_ enclose the text to allow precise MathML placements. + // If the NS_REFLOW_CALC_BOUNDING_METRICS flag is set, then the caller is + // requesting that you also compute additional details about your inner + // bounding box and italic correction. For example, the bounding box of + // msup is the smallest rectangle that _exactly_ encloses both the text + // of the base and the text of the superscript. + nsBoundingMetrics mBoundingMetrics; // [OUT] + + // Carried out bottom margin values. This is the collapsed + // (generational) bottom margin value. + nsCollapsingMargin mCarriedOutBottomMargin; + + // For frames that have content that overflow their content area + // (HasOverflowAreas() is true) these rectangles represent the total + // area of the frame including visible overflow, i.e., don't include + // overflowing content that is hidden. The rects are in the local + // coordinate space of the frame, and should be at least as big as the + // desired size. If there is no content that overflows, then the + // overflow area is identical to the desired size and should be {0, 0, + // width, height}. + nsOverflowAreas mOverflowAreas; + + nsRect& VisualOverflow() + { return mOverflowAreas.VisualOverflow(); } + const nsRect& VisualOverflow() const + { return mOverflowAreas.VisualOverflow(); } + nsRect& ScrollableOverflow() + { return mOverflowAreas.ScrollableOverflow(); } + const nsRect& ScrollableOverflow() const + { return mOverflowAreas.ScrollableOverflow(); } + + // Set all of mOverflowAreas to (0, 0, width, height). + void SetOverflowAreasToDesiredBounds(); + + // Union all of mOverflowAreas with (0, 0, width, height). + void UnionOverflowAreasWithDesiredBounds(); + + mozilla::WritingMode GetWritingMode() const { return mWritingMode; } + +private: + nscoord mISize, mBSize; // [OUT] desired width and height (border-box) + nscoord mBlockStartAscent; // [OUT] baseline (in Block direction), or ASK_FOR_BASELINE + +public: + uint32_t mFlags; + +private: + mozilla::WritingMode mWritingMode; +}; + +#endif /* nsHTMLReflowMetrics_h___ */