ReflowOutput.h (9605B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* struct containing the output from nsIFrame::Reflow */ 8 9 #ifndef mozilla_ReflowOutput_h 10 #define mozilla_ReflowOutput_h 11 12 #include "mozilla/EnumeratedRange.h" 13 #include "mozilla/WritingModes.h" 14 #include "nsBoundingMetrics.h" 15 #include "nsRect.h" 16 17 //---------------------------------------------------------------------- 18 19 namespace mozilla { 20 struct ReflowInput; 21 22 enum class OverflowType : uint8_t { Ink, Scrollable }; 23 constexpr auto AllOverflowTypes() { 24 return MakeInclusiveEnumeratedRange(OverflowType::Ink, 25 OverflowType::Scrollable); 26 } 27 28 struct OverflowAreas { 29 public: 30 nsRect& InkOverflow() { return mInk; } 31 const nsRect& InkOverflow() const { return mInk; } 32 33 nsRect& ScrollableOverflow() { return mScrollable; } 34 const nsRect& ScrollableOverflow() const { return mScrollable; } 35 36 nsRect& Overflow(OverflowType aType) { 37 return aType == OverflowType::Ink ? InkOverflow() : ScrollableOverflow(); 38 } 39 const nsRect& Overflow(OverflowType aType) const { 40 return aType == OverflowType::Ink ? InkOverflow() : ScrollableOverflow(); 41 } 42 43 OverflowAreas() = default; 44 45 OverflowAreas(const nsRect& aInkOverflow, const nsRect& aScrollableOverflow) 46 : mInk(aInkOverflow), mScrollable(aScrollableOverflow) {} 47 48 bool operator==(const OverflowAreas& aOther) const { 49 // Scrollable overflow is a point-set rectangle and ink overflow 50 // is a pixel-set rectangle. 51 return InkOverflow().IsEqualInterior(aOther.InkOverflow()) && 52 ScrollableOverflow().IsEqualEdges(aOther.ScrollableOverflow()); 53 } 54 55 bool operator!=(const OverflowAreas&) const = default; 56 57 OverflowAreas operator+(const nsPoint& aPoint) const { 58 OverflowAreas result(*this); 59 result += aPoint; 60 return result; 61 } 62 63 OverflowAreas& operator+=(const nsPoint& aPoint) { 64 mInk += aPoint; 65 mScrollable += aPoint; 66 return *this; 67 } 68 69 void Clear() { SetAllTo(nsRect()); } 70 71 // Mutates |this| by unioning both overflow areas with |aOther|. 72 void UnionWith(const OverflowAreas& aOther); 73 74 // Mutates |this| by unioning both overflow areas with |aRect|. 75 void UnionAllWith(const nsRect& aRect); 76 77 // Mutates |this| by setting both overflow areas to |aRect|. 78 void SetAllTo(const nsRect& aRect); 79 80 // Applies overflow clipping (for e.g. overflow: clip) as needed to both our 81 // overflow rects. 82 void ApplyClipping(const nsRect& aBounds, PhysicalAxes aClipAxes, 83 const nsMargin& aOverflowMargin) { 84 ApplyOverflowClippingOnRect(InkOverflow(), aBounds, aClipAxes, 85 aOverflowMargin); 86 ApplyOverflowClippingOnRect(ScrollableOverflow(), aBounds, aClipAxes, 87 aOverflowMargin); 88 } 89 90 // Gets the overflow clipping rect for a given element given a rect to clip, 91 // the frame bounds, a set of axes, and the overflow margin. 92 static nsRect GetOverflowClipRect(const nsRect& aRectToClip, 93 const nsRect& aBounds, 94 PhysicalAxes aClipAxes, 95 const nsMargin& aOverflowMargin); 96 97 // Applies the overflow clipping to a given overflow rect, given the frame 98 // bounds, and the physical axes on which to apply the overflow clip. 99 static void ApplyOverflowClippingOnRect(nsRect& aOverflowRect, 100 const nsRect& aBounds, 101 PhysicalAxes aClipAxes, 102 const nsMargin& aOverflowMargin); 103 104 private: 105 nsRect mInk; 106 nsRect mScrollable; 107 }; 108 109 /** 110 * CollapsingMargin represents a vertical collapsing margin between 111 * blocks as described in section 8.3.1 of CSS2. 112 * <https://www.w3.org/TR/CSS22/box.html#collapsing-margins> 113 * 114 * All adjacent vertical margins collapse, and the resulting margin is 115 * the sum of the largest positive margin included and the smallest (most 116 * negative) negative margin included. 117 */ 118 class CollapsingMargin final { 119 public: 120 bool operator==(const CollapsingMargin&) const = default; 121 bool operator!=(const CollapsingMargin&) const = default; 122 123 void Include(nscoord aCoord) { 124 if (aCoord > mMostPos) { 125 mMostPos = aCoord; 126 } else if (aCoord < mMostNeg) { 127 mMostNeg = aCoord; 128 } 129 } 130 131 void Include(const CollapsingMargin& aOther) { 132 if (aOther.mMostPos > mMostPos) { 133 mMostPos = aOther.mMostPos; 134 } 135 if (aOther.mMostNeg < mMostNeg) { 136 mMostNeg = aOther.mMostNeg; 137 } 138 } 139 140 void Zero() { 141 mMostPos = 0; 142 mMostNeg = 0; 143 } 144 145 bool IsZero() const { return mMostPos == 0 && mMostNeg == 0; } 146 147 nscoord Get() const { return mMostPos + mMostNeg; } 148 149 private: 150 // The largest positive margin included. 151 nscoord mMostPos = 0; 152 153 // The smallest negative margin included. 154 nscoord mMostNeg = 0; 155 }; 156 157 /** 158 * ReflowOutput is initialized by a parent frame as a parameter passing to 159 * Reflow() to allow a child frame to return its desired size and alignment 160 * information. 161 * 162 * ReflowOutput's constructor usually takes a parent frame's WritingMode (or 163 * ReflowInput) because it is more convenient for the parent frame to use the 164 * stored Size() after reflowing the child frame. However, it can actually 165 * accept any WritingMode (or ReflowInput) because SetSize() knows how to 166 * convert a size in any writing mode to the stored writing mode. 167 * 168 * @see nsIFrame::Reflow() for more information. 169 */ 170 class ReflowOutput { 171 public: 172 explicit ReflowOutput(WritingMode aWritingMode) 173 : mSize(aWritingMode), mWritingMode(aWritingMode) {} 174 175 // A convenient constructor to get WritingMode in ReflowInput. 176 explicit ReflowOutput(const ReflowInput& aReflowInput); 177 178 nscoord ISize(WritingMode aWritingMode) const { 179 return mSize.ISize(aWritingMode); 180 } 181 nscoord BSize(WritingMode aWritingMode) const { 182 return mSize.BSize(aWritingMode); 183 } 184 LogicalSize Size(WritingMode aWritingMode) const { 185 return mSize.ConvertTo(aWritingMode, mWritingMode); 186 } 187 188 nscoord& ISize(WritingMode aWritingMode) { return mSize.ISize(aWritingMode); } 189 nscoord& BSize(WritingMode aWritingMode) { return mSize.BSize(aWritingMode); } 190 191 // Set inline and block size from a LogicalSize, converting to our 192 // writing mode as necessary. 193 void SetSize(WritingMode aWM, const LogicalSize& aSize) { 194 mSize = aSize.ConvertTo(mWritingMode, aWM); 195 } 196 197 // Set both inline and block size to zero -- no need for a writing mode! 198 void ClearSize() { mSize.SizeTo(mWritingMode, 0, 0); } 199 200 // Width and Height are physical dimensions, independent of writing mode. 201 // Accessing these is slightly more expensive than accessing the logical 202 // dimensions; as far as possible, client code should work purely with logical 203 // dimensions. 204 nscoord Width() const { return mSize.Width(mWritingMode); } 205 nscoord Height() const { return mSize.Height(mWritingMode); } 206 nscoord& Width() { 207 return mWritingMode.IsVertical() ? mSize.BSize(mWritingMode) 208 : mSize.ISize(mWritingMode); 209 } 210 nscoord& Height() { 211 return mWritingMode.IsVertical() ? mSize.ISize(mWritingMode) 212 : mSize.BSize(mWritingMode); 213 } 214 215 nsSize PhysicalSize() const { return mSize.GetPhysicalSize(mWritingMode); } 216 217 // It's only meaningful to consider "ascent" on the block-start side of the 218 // frame, so no need to pass a writing mode argument 219 enum { ASK_FOR_BASELINE = nscoord_MAX }; 220 nscoord BlockStartAscent() const { return mBlockStartAscent; } 221 void SetBlockStartAscent(nscoord aAscent) { mBlockStartAscent = aAscent; } 222 223 // Metrics that _exactly_ enclose the text to allow precise MathML placements. 224 nsBoundingMetrics mBoundingMetrics; // [OUT] 225 226 // Carried out block-end margin values. This is the collapsed 227 // (generational) block-end margin value. 228 CollapsingMargin mCarriedOutBEndMargin; 229 230 // For frames that have content that overflow their content area 231 // (HasOverflowAreas() is true) these rectangles represent the total 232 // area of the frame including visible overflow, i.e., don't include 233 // overflowing content that is hidden. The rects are in the local 234 // coordinate space of the frame, and should be at least as big as the 235 // desired size. If there is no content that overflows, then the 236 // overflow area is identical to the desired size and should be {0, 0, 237 // width, height}. 238 OverflowAreas mOverflowAreas; 239 240 nsRect& InkOverflow() { return mOverflowAreas.InkOverflow(); } 241 const nsRect& InkOverflow() const { return mOverflowAreas.InkOverflow(); } 242 nsRect& ScrollableOverflow() { return mOverflowAreas.ScrollableOverflow(); } 243 const nsRect& ScrollableOverflow() const { 244 return mOverflowAreas.ScrollableOverflow(); 245 } 246 247 // Set all of mOverflowAreas to (0, 0, width, height). 248 void SetOverflowAreasToDesiredBounds(); 249 250 // Union all of mOverflowAreas with (0, 0, width, height). 251 void UnionOverflowAreasWithDesiredBounds(); 252 253 WritingMode GetWritingMode() const { return mWritingMode; } 254 255 private: 256 // Desired size of a frame's border-box. 257 LogicalSize mSize; 258 259 // Baseline (in block direction), or the default value ASK_FOR_BASELINE. 260 nscoord mBlockStartAscent = ASK_FOR_BASELINE; 261 262 WritingMode mWritingMode; 263 }; 264 265 } // namespace mozilla 266 267 #endif // mozilla_ReflowOutput_h