forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			330 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			330 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* 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 mozilla_ReflowOutput_h
 | |
| #define mozilla_ReflowOutput_h
 | |
| 
 | |
| #include "mozilla/WritingModes.h"
 | |
| #include "nsBoundingMetrics.h"
 | |
| #include "nsRect.h"
 | |
| 
 | |
| //----------------------------------------------------------------------
 | |
| 
 | |
| namespace mozilla {
 | |
| struct ReflowInput;
 | |
| } // namespace mozilla
 | |
| 
 | |
| /**
 | |
|  * 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,
 | |
|  * <URL: http://www.w3.org/TR/REC-CSS2/box.html#collapsing-margins >.
 | |
|  *
 | |
|  * 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;
 | |
|       }
 | |
| };
 | |
| 
 | |
| namespace mozilla {
 | |
| 
 | |
| /**
 | |
|  * Reflow metrics used to return the frame's desired size and alignment
 | |
|  * information.
 | |
|  *
 | |
|  * @see #Reflow()
 | |
|  */
 | |
| class ReflowOutput {
 | |
| public:
 | |
|   explicit ReflowOutput(mozilla::WritingMode aWritingMode)
 | |
|     : mISize(0)
 | |
|     , mBSize(0)
 | |
|     , mBlockStartAscent(ASK_FOR_BASELINE)
 | |
|     , mWritingMode(aWritingMode)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   explicit ReflowOutput(const ReflowInput& aReflowInput);
 | |
| 
 | |
|   // 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(mozilla::WritingMode aWritingMode) const {
 | |
|     NS_ASSERTION(!aWritingMode.IsOrthogonalTo(mWritingMode),
 | |
|                  "mismatched writing mode");
 | |
|     return mISize;
 | |
|   }
 | |
|   nscoord BSize(mozilla::WritingMode aWritingMode) const {
 | |
|     NS_ASSERTION(!aWritingMode.IsOrthogonalTo(mWritingMode),
 | |
|                  "mismatched writing mode");
 | |
|     return mBSize;
 | |
|   }
 | |
|   mozilla::LogicalSize Size(mozilla::WritingMode aWritingMode) const {
 | |
|     NS_ASSERTION(!aWritingMode.IsOrthogonalTo(mWritingMode),
 | |
|                  "mismatched writing mode");
 | |
|     return mozilla::LogicalSize(aWritingMode, mISize, mBSize);
 | |
|   }
 | |
| 
 | |
|   nscoord& ISize(mozilla::WritingMode aWritingMode) {
 | |
|     NS_ASSERTION(!aWritingMode.IsOrthogonalTo(mWritingMode),
 | |
|                  "mismatched writing mode");
 | |
|     return mISize;
 | |
|   }
 | |
|   nscoord& BSize(mozilla::WritingMode aWritingMode) {
 | |
|     NS_ASSERTION(!aWritingMode.IsOrthogonalTo(mWritingMode),
 | |
|                  "mismatched writing mode");
 | |
|     return mBSize;
 | |
|   }
 | |
| 
 | |
|   // Set inline and block size from a LogicalSize, converting to our
 | |
|   // writing mode as necessary.
 | |
|   void SetSize(mozilla::WritingMode aWM, mozilla::LogicalSize aSize)
 | |
|   {
 | |
|     mozilla::LogicalSize convertedSize = aSize.ConvertTo(mWritingMode, aWM);
 | |
|     mBSize = convertedSize.BSize(mWritingMode);
 | |
|     mISize = convertedSize.ISize(mWritingMode);
 | |
|   }
 | |
| 
 | |
|   // Set both inline and block size to zero -- no need for a writing mode!
 | |
|   void ClearSize()
 | |
|   {
 | |
|     mISize = mBSize = 0;
 | |
|   }
 | |
| 
 | |
|   // 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, so no need to pass a writing mode argument
 | |
|   nscoord BlockStartAscent() const
 | |
|   {
 | |
|     return mBlockStartAscent;
 | |
|   }
 | |
| 
 | |
|   nscoord& Width() { return mWritingMode.IsVertical() ? mBSize : mISize; }
 | |
|   nscoord& Height() { return mWritingMode.IsVertical() ? mISize : mBSize; }
 | |
| 
 | |
|   nsSize PhysicalSize()
 | |
|   {
 | |
|     return Size(mWritingMode).GetPhysicalSize(mWritingMode);
 | |
|   }
 | |
| 
 | |
|   void SetBlockStartAscent(nscoord aAscent)
 | |
|   {
 | |
|     mBlockStartAscent = aAscent;
 | |
|   }
 | |
| 
 | |
|   enum { ASK_FOR_BASELINE = nscoord_MAX };
 | |
| 
 | |
|   // Metrics that _exactly_ enclose the text to allow precise MathML placements.
 | |
|   nsBoundingMetrics mBoundingMetrics;  // [OUT]
 | |
| 
 | |
|   // Carried out block-end margin values. This is the collapsed
 | |
|   // (generational) block-end margin value.
 | |
|   nsCollapsingMargin mCarriedOutBEndMargin;
 | |
| 
 | |
|   // 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
 | |
|   mozilla::WritingMode mWritingMode;
 | |
| };
 | |
| 
 | |
| } // mozilla namespace
 | |
| 
 | |
| #endif // mozilla_ReflowOutput_h
 | 
