|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* struct containing the output from nsIFrame::Reflow */ |
|
7 |
|
8 #ifndef nsHTMLReflowMetrics_h___ |
|
9 #define nsHTMLReflowMetrics_h___ |
|
10 |
|
11 #include "nsRect.h" |
|
12 #include "nsBoundingMetrics.h" |
|
13 #include "WritingModes.h" |
|
14 |
|
15 //---------------------------------------------------------------------- |
|
16 |
|
17 class nsHTMLReflowState; |
|
18 |
|
19 // Option flags |
|
20 #define NS_REFLOW_CALC_BOUNDING_METRICS 0x0001 |
|
21 |
|
22 /** |
|
23 * When we store overflow areas as an array of scrollable and visual |
|
24 * overflow, we use these indices. |
|
25 * |
|
26 * eOverflowType_LENGTH is needed (for gcc 4.5.*, at least) to ensure |
|
27 * that 2 is a valid value of nsOverflowType for use in |
|
28 * NS_FOR_FRAME_OVERFLOW_TYPES. |
|
29 */ |
|
30 enum nsOverflowType { eVisualOverflow, eScrollableOverflow, |
|
31 eOverflowType_LENGTH }; |
|
32 |
|
33 #define NS_FOR_FRAME_OVERFLOW_TYPES(var_) \ |
|
34 for (nsOverflowType var_ = nsOverflowType(0); var_ < 2; \ |
|
35 var_ = nsOverflowType(var_ + 1)) |
|
36 |
|
37 struct nsOverflowAreas { |
|
38 private: |
|
39 nsRect mRects[2]; |
|
40 public: |
|
41 nsRect& Overflow(size_t aIndex) { |
|
42 NS_ASSERTION(aIndex < 2, "index out of range"); |
|
43 return mRects[aIndex]; |
|
44 } |
|
45 const nsRect& Overflow(size_t aIndex) const { |
|
46 NS_ASSERTION(aIndex < 2, "index out of range"); |
|
47 return mRects[aIndex]; |
|
48 } |
|
49 |
|
50 nsRect& VisualOverflow() { return mRects[eVisualOverflow]; } |
|
51 const nsRect& VisualOverflow() const { return mRects[eVisualOverflow]; } |
|
52 |
|
53 nsRect& ScrollableOverflow() { return mRects[eScrollableOverflow]; } |
|
54 const nsRect& ScrollableOverflow() const { return mRects[eScrollableOverflow]; } |
|
55 |
|
56 nsOverflowAreas() { |
|
57 // default-initializes to zero due to nsRect's default constructor |
|
58 } |
|
59 |
|
60 nsOverflowAreas(const nsRect& aVisualOverflow, |
|
61 const nsRect& aScrollableOverflow) |
|
62 { |
|
63 mRects[eVisualOverflow] = aVisualOverflow; |
|
64 mRects[eScrollableOverflow] = aScrollableOverflow; |
|
65 } |
|
66 |
|
67 nsOverflowAreas(const nsOverflowAreas& aOther) { |
|
68 *this = aOther; |
|
69 } |
|
70 |
|
71 nsOverflowAreas& operator=(const nsOverflowAreas& aOther) { |
|
72 mRects[0] = aOther.mRects[0]; |
|
73 mRects[1] = aOther.mRects[1]; |
|
74 return *this; |
|
75 } |
|
76 |
|
77 bool operator==(const nsOverflowAreas& aOther) const { |
|
78 // Scrollable overflow is a point-set rectangle and visual overflow |
|
79 // is a pixel-set rectangle. |
|
80 return VisualOverflow().IsEqualInterior(aOther.VisualOverflow()) && |
|
81 ScrollableOverflow().IsEqualEdges(aOther.ScrollableOverflow()); |
|
82 } |
|
83 |
|
84 bool operator!=(const nsOverflowAreas& aOther) const { |
|
85 return !(*this == aOther); |
|
86 } |
|
87 |
|
88 nsOverflowAreas operator+(const nsPoint& aPoint) const { |
|
89 nsOverflowAreas result(*this); |
|
90 result += aPoint; |
|
91 return result; |
|
92 } |
|
93 |
|
94 nsOverflowAreas& operator+=(const nsPoint& aPoint) { |
|
95 mRects[0] += aPoint; |
|
96 mRects[1] += aPoint; |
|
97 return *this; |
|
98 } |
|
99 |
|
100 void Clear() { |
|
101 mRects[0].SetRect(0, 0, 0, 0); |
|
102 mRects[1].SetRect(0, 0, 0, 0); |
|
103 } |
|
104 |
|
105 // Mutates |this| by unioning both overflow areas with |aOther|. |
|
106 void UnionWith(const nsOverflowAreas& aOther); |
|
107 |
|
108 // Mutates |this| by unioning both overflow areas with |aRect|. |
|
109 void UnionAllWith(const nsRect& aRect); |
|
110 |
|
111 // Mutates |this| by setting both overflow areas to |aRect|. |
|
112 void SetAllTo(const nsRect& aRect); |
|
113 }; |
|
114 |
|
115 /** |
|
116 * An nsCollapsingMargin represents a vertical collapsing margin between |
|
117 * blocks as described in section 8.3.1 of CSS2, |
|
118 * <URL: http://www.w3.org/TR/REC-CSS2/box.html#collapsing-margins >. |
|
119 * |
|
120 * All adjacent vertical margins collapse, and the resulting margin is |
|
121 * the sum of the largest positive margin included and the smallest (most |
|
122 * negative) negative margin included. |
|
123 */ |
|
124 struct nsCollapsingMargin { |
|
125 private: |
|
126 nscoord mMostPos; // the largest positive margin included |
|
127 nscoord mMostNeg; // the smallest negative margin included |
|
128 |
|
129 public: |
|
130 nsCollapsingMargin() |
|
131 : mMostPos(0), |
|
132 mMostNeg(0) |
|
133 { |
|
134 } |
|
135 |
|
136 nsCollapsingMargin(const nsCollapsingMargin& aOther) |
|
137 : mMostPos(aOther.mMostPos), |
|
138 mMostNeg(aOther.mMostNeg) |
|
139 { |
|
140 } |
|
141 |
|
142 bool operator==(const nsCollapsingMargin& aOther) |
|
143 { |
|
144 return mMostPos == aOther.mMostPos && |
|
145 mMostNeg == aOther.mMostNeg; |
|
146 } |
|
147 |
|
148 bool operator!=(const nsCollapsingMargin& aOther) |
|
149 { |
|
150 return !(*this == aOther); |
|
151 } |
|
152 |
|
153 nsCollapsingMargin& operator=(const nsCollapsingMargin& aOther) |
|
154 { |
|
155 mMostPos = aOther.mMostPos; |
|
156 mMostNeg = aOther.mMostNeg; |
|
157 return *this; |
|
158 } |
|
159 |
|
160 void Include(nscoord aCoord) |
|
161 { |
|
162 if (aCoord > mMostPos) |
|
163 mMostPos = aCoord; |
|
164 else if (aCoord < mMostNeg) |
|
165 mMostNeg = aCoord; |
|
166 } |
|
167 |
|
168 void Include(const nsCollapsingMargin& aOther) |
|
169 { |
|
170 if (aOther.mMostPos > mMostPos) |
|
171 mMostPos = aOther.mMostPos; |
|
172 if (aOther.mMostNeg < mMostNeg) |
|
173 mMostNeg = aOther.mMostNeg; |
|
174 } |
|
175 |
|
176 void Zero() |
|
177 { |
|
178 mMostPos = 0; |
|
179 mMostNeg = 0; |
|
180 } |
|
181 |
|
182 bool IsZero() const |
|
183 { |
|
184 return (mMostPos == 0) && (mMostNeg == 0); |
|
185 } |
|
186 |
|
187 nscoord get() const |
|
188 { |
|
189 return mMostPos + mMostNeg; |
|
190 } |
|
191 }; |
|
192 |
|
193 /** |
|
194 * Reflow metrics used to return the frame's desired size and alignment |
|
195 * information. |
|
196 * |
|
197 * @see #Reflow() |
|
198 */ |
|
199 class nsHTMLReflowMetrics { |
|
200 public: |
|
201 // XXXldb Should |aFlags| generally be passed from parent to child? |
|
202 // Some places do it, and some don't. |aFlags| should perhaps go away |
|
203 // entirely. |
|
204 // XXX width/height/ascent are OUT parameters and so they shouldn't |
|
205 // have to be initialized, but there are some bad frame classes that |
|
206 // aren't properly setting them when returning from Reflow()... |
|
207 nsHTMLReflowMetrics(mozilla::WritingMode aWritingMode, uint32_t aFlags = 0) |
|
208 : mISize(0) |
|
209 , mBSize(0) |
|
210 , mBlockStartAscent(ASK_FOR_BASELINE) |
|
211 , mFlags(aFlags) |
|
212 , mWritingMode(aWritingMode) |
|
213 {} |
|
214 |
|
215 nsHTMLReflowMetrics(const nsHTMLReflowState& aState, uint32_t aFlags = 0); |
|
216 |
|
217 // ISize and BSize are logical-coordinate dimensions: |
|
218 // ISize is the size in the writing mode's inline direction (which equates to |
|
219 // width in horizontal writing modes, height in vertical ones), and BSize is |
|
220 // the size in the block-progression direction. |
|
221 nscoord ISize() const { return mISize; } |
|
222 nscoord BSize() const { return mBSize; } |
|
223 |
|
224 nscoord& ISize() { return mISize; } |
|
225 nscoord& BSize() { return mBSize; } |
|
226 |
|
227 // Width and Height are physical dimensions, independent of writing mode. |
|
228 // Accessing these is slightly more expensive than accessing the logical |
|
229 // dimensions (once vertical writing mode support is enabled); as far as |
|
230 // possible, client code should work purely with logical dimensions. |
|
231 nscoord Width() const { return mWritingMode.IsVertical() ? mBSize : mISize; } |
|
232 nscoord Height() const { return mWritingMode.IsVertical() ? mISize : mBSize; } |
|
233 |
|
234 // It's only meaningful to consider "ascent" on the block-start side of the |
|
235 // frame; asking for the "ascent" on any other side will just return zero. |
|
236 nscoord TopAscent() const |
|
237 { |
|
238 return mWritingMode.IsVertical() ? 0 : mBlockStartAscent; |
|
239 } |
|
240 nscoord LeftAscent() const |
|
241 { |
|
242 return mWritingMode.IsVertical() && mWritingMode.IsVerticalLR() ? |
|
243 mBlockStartAscent : 0; |
|
244 } |
|
245 nscoord RightAscent() const |
|
246 { |
|
247 return mWritingMode.IsVertical() && !mWritingMode.IsVerticalLR() ? |
|
248 mBlockStartAscent : 0; |
|
249 } |
|
250 |
|
251 nscoord& Width() { return mWritingMode.IsVertical() ? mBSize : mISize; } |
|
252 nscoord& Height() { return mWritingMode.IsVertical() ? mISize : mBSize; } |
|
253 |
|
254 // To set the ascent value, we must be sure we're working with the correct |
|
255 // writing mode, so either pass it to the logical setter... |
|
256 void SetBlockStartAscent(mozilla::WritingMode aWritingMode, nscoord aAscent) |
|
257 { |
|
258 NS_ASSERTION(aWritingMode == mWritingMode, "writing mode mismatch"); |
|
259 mBlockStartAscent = aAscent; |
|
260 } |
|
261 // ...or call the appropriate physical setter (these will probably be removed |
|
262 // eventually). |
|
263 void SetTopAscent(nscoord aAscent) |
|
264 { |
|
265 NS_ASSERTION(!mWritingMode.IsVertical(), "writing mode mismatch"); |
|
266 mBlockStartAscent = aAscent; |
|
267 } |
|
268 void SetLeftAscent(nscoord aAscent) |
|
269 { |
|
270 NS_ASSERTION(mWritingMode.IsVertical() && mWritingMode.IsVerticalLR(), |
|
271 "writing mode mismatch"); |
|
272 mBlockStartAscent = aAscent; |
|
273 } |
|
274 void SetRightAscent(nscoord aAscent) |
|
275 { |
|
276 NS_ASSERTION(mWritingMode.IsVertical() && !mWritingMode.IsVerticalLR(), |
|
277 "writing mode mismatch"); |
|
278 mBlockStartAscent = aAscent; |
|
279 } |
|
280 |
|
281 enum { ASK_FOR_BASELINE = nscoord_MAX }; |
|
282 |
|
283 // Metrics that _exactly_ enclose the text to allow precise MathML placements. |
|
284 // If the NS_REFLOW_CALC_BOUNDING_METRICS flag is set, then the caller is |
|
285 // requesting that you also compute additional details about your inner |
|
286 // bounding box and italic correction. For example, the bounding box of |
|
287 // msup is the smallest rectangle that _exactly_ encloses both the text |
|
288 // of the base and the text of the superscript. |
|
289 nsBoundingMetrics mBoundingMetrics; // [OUT] |
|
290 |
|
291 // Carried out bottom margin values. This is the collapsed |
|
292 // (generational) bottom margin value. |
|
293 nsCollapsingMargin mCarriedOutBottomMargin; |
|
294 |
|
295 // For frames that have content that overflow their content area |
|
296 // (HasOverflowAreas() is true) these rectangles represent the total |
|
297 // area of the frame including visible overflow, i.e., don't include |
|
298 // overflowing content that is hidden. The rects are in the local |
|
299 // coordinate space of the frame, and should be at least as big as the |
|
300 // desired size. If there is no content that overflows, then the |
|
301 // overflow area is identical to the desired size and should be {0, 0, |
|
302 // width, height}. |
|
303 nsOverflowAreas mOverflowAreas; |
|
304 |
|
305 nsRect& VisualOverflow() |
|
306 { return mOverflowAreas.VisualOverflow(); } |
|
307 const nsRect& VisualOverflow() const |
|
308 { return mOverflowAreas.VisualOverflow(); } |
|
309 nsRect& ScrollableOverflow() |
|
310 { return mOverflowAreas.ScrollableOverflow(); } |
|
311 const nsRect& ScrollableOverflow() const |
|
312 { return mOverflowAreas.ScrollableOverflow(); } |
|
313 |
|
314 // Set all of mOverflowAreas to (0, 0, width, height). |
|
315 void SetOverflowAreasToDesiredBounds(); |
|
316 |
|
317 // Union all of mOverflowAreas with (0, 0, width, height). |
|
318 void UnionOverflowAreasWithDesiredBounds(); |
|
319 |
|
320 mozilla::WritingMode GetWritingMode() const { return mWritingMode; } |
|
321 |
|
322 private: |
|
323 nscoord mISize, mBSize; // [OUT] desired width and height (border-box) |
|
324 nscoord mBlockStartAscent; // [OUT] baseline (in Block direction), or ASK_FOR_BASELINE |
|
325 |
|
326 public: |
|
327 uint32_t mFlags; |
|
328 |
|
329 private: |
|
330 mozilla::WritingMode mWritingMode; |
|
331 }; |
|
332 |
|
333 #endif /* nsHTMLReflowMetrics_h___ */ |