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