|
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 #include "nsFieldSetFrame.h" |
|
7 |
|
8 #include "nsCSSAnonBoxes.h" |
|
9 #include "nsLegendFrame.h" |
|
10 #include "nsCSSRendering.h" |
|
11 #include <algorithm> |
|
12 #include "nsIFrame.h" |
|
13 #include "nsPresContext.h" |
|
14 #include "RestyleManager.h" |
|
15 #include "nsGkAtoms.h" |
|
16 #include "nsStyleConsts.h" |
|
17 #include "nsDisplayList.h" |
|
18 #include "nsRenderingContext.h" |
|
19 #include "nsIScrollableFrame.h" |
|
20 #include "mozilla/Likely.h" |
|
21 #include "mozilla/Maybe.h" |
|
22 |
|
23 using namespace mozilla; |
|
24 using namespace mozilla::layout; |
|
25 |
|
26 nsIFrame* |
|
27 NS_NewFieldSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) |
|
28 { |
|
29 return new (aPresShell) nsFieldSetFrame(aContext); |
|
30 } |
|
31 |
|
32 NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFrame) |
|
33 |
|
34 nsFieldSetFrame::nsFieldSetFrame(nsStyleContext* aContext) |
|
35 : nsContainerFrame(aContext) |
|
36 { |
|
37 mLegendSpace = 0; |
|
38 } |
|
39 |
|
40 nsIAtom* |
|
41 nsFieldSetFrame::GetType() const |
|
42 { |
|
43 return nsGkAtoms::fieldSetFrame; |
|
44 } |
|
45 |
|
46 #ifdef DEBUG |
|
47 nsresult |
|
48 nsFieldSetFrame::SetInitialChildList(ChildListID aListID, |
|
49 nsFrameList& aChildList) |
|
50 { |
|
51 nsresult rv = nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList); |
|
52 MOZ_ASSERT(GetInner()); |
|
53 return rv; |
|
54 } |
|
55 #endif |
|
56 |
|
57 nsRect |
|
58 nsFieldSetFrame::VisualBorderRectRelativeToSelf() const |
|
59 { |
|
60 nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP); |
|
61 nsRect r(nsPoint(0,0), GetSize()); |
|
62 if (topBorder < mLegendRect.height) { |
|
63 nscoord yoff = (mLegendRect.height - topBorder) / 2; |
|
64 r.y += yoff; |
|
65 r.height -= yoff; |
|
66 } |
|
67 return r; |
|
68 } |
|
69 |
|
70 nsIFrame* |
|
71 nsFieldSetFrame::GetInner() const |
|
72 { |
|
73 nsIFrame* last = mFrames.LastChild(); |
|
74 if (last && |
|
75 last->StyleContext()->GetPseudo() == nsCSSAnonBoxes::fieldsetContent) { |
|
76 return last; |
|
77 } |
|
78 MOZ_ASSERT(mFrames.LastChild() == mFrames.FirstChild()); |
|
79 return nullptr; |
|
80 } |
|
81 |
|
82 nsIFrame* |
|
83 nsFieldSetFrame::GetLegend() const |
|
84 { |
|
85 if (mFrames.FirstChild() == GetInner()) { |
|
86 MOZ_ASSERT(mFrames.LastChild() == mFrames.FirstChild()); |
|
87 return nullptr; |
|
88 } |
|
89 MOZ_ASSERT(mFrames.FirstChild() && |
|
90 mFrames.FirstChild()->GetContentInsertionFrame()->GetType() == |
|
91 nsGkAtoms::legendFrame); |
|
92 return mFrames.FirstChild(); |
|
93 } |
|
94 |
|
95 class nsDisplayFieldSetBorderBackground : public nsDisplayItem { |
|
96 public: |
|
97 nsDisplayFieldSetBorderBackground(nsDisplayListBuilder* aBuilder, |
|
98 nsFieldSetFrame* aFrame) |
|
99 : nsDisplayItem(aBuilder, aFrame) { |
|
100 MOZ_COUNT_CTOR(nsDisplayFieldSetBorderBackground); |
|
101 } |
|
102 #ifdef NS_BUILD_REFCNT_LOGGING |
|
103 virtual ~nsDisplayFieldSetBorderBackground() { |
|
104 MOZ_COUNT_DTOR(nsDisplayFieldSetBorderBackground); |
|
105 } |
|
106 #endif |
|
107 |
|
108 virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, |
|
109 HitTestState* aState, |
|
110 nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE; |
|
111 virtual void Paint(nsDisplayListBuilder* aBuilder, |
|
112 nsRenderingContext* aCtx) MOZ_OVERRIDE; |
|
113 virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, |
|
114 const nsDisplayItemGeometry* aGeometry, |
|
115 nsRegion *aInvalidRegion) MOZ_OVERRIDE; |
|
116 NS_DISPLAY_DECL_NAME("FieldSetBorderBackground", TYPE_FIELDSET_BORDER_BACKGROUND) |
|
117 }; |
|
118 |
|
119 void nsDisplayFieldSetBorderBackground::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, |
|
120 HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) |
|
121 { |
|
122 // aPt is guaranteed to be in this item's bounds. We do the hit test based on the |
|
123 // frame bounds even though our background doesn't cover the whole frame. |
|
124 // It's not clear whether this is correct. |
|
125 aOutFrames->AppendElement(mFrame); |
|
126 } |
|
127 |
|
128 void |
|
129 nsDisplayFieldSetBorderBackground::Paint(nsDisplayListBuilder* aBuilder, |
|
130 nsRenderingContext* aCtx) |
|
131 { |
|
132 static_cast<nsFieldSetFrame*>(mFrame)-> |
|
133 PaintBorderBackground(*aCtx, ToReferenceFrame(), |
|
134 mVisibleRect, aBuilder->GetBackgroundPaintFlags()); |
|
135 } |
|
136 |
|
137 void |
|
138 nsDisplayFieldSetBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, |
|
139 const nsDisplayItemGeometry* aGeometry, |
|
140 nsRegion *aInvalidRegion) |
|
141 { |
|
142 AddInvalidRegionForSyncDecodeBackgroundImages(aBuilder, aGeometry, aInvalidRegion); |
|
143 |
|
144 nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); |
|
145 } |
|
146 |
|
147 void |
|
148 nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
|
149 const nsRect& aDirtyRect, |
|
150 const nsDisplayListSet& aLists) { |
|
151 // Paint our background and border in a special way. |
|
152 // REVIEW: We don't really need to check frame emptiness here; if it's empty, |
|
153 // the background/border display item won't do anything, and if it isn't empty, |
|
154 // we need to paint the outline |
|
155 if (!(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) && |
|
156 IsVisibleForPainting(aBuilder)) { |
|
157 if (StyleBorder()->mBoxShadow) { |
|
158 aLists.BorderBackground()->AppendNewToTop(new (aBuilder) |
|
159 nsDisplayBoxShadowOuter(aBuilder, this)); |
|
160 } |
|
161 |
|
162 // don't bother checking to see if we really have a border or background. |
|
163 // we usually will have a border. |
|
164 aLists.BorderBackground()->AppendNewToTop(new (aBuilder) |
|
165 nsDisplayFieldSetBorderBackground(aBuilder, this)); |
|
166 |
|
167 DisplayOutlineUnconditional(aBuilder, aLists); |
|
168 |
|
169 DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame"); |
|
170 } |
|
171 |
|
172 if (GetPrevInFlow()) { |
|
173 DisplayOverflowContainers(aBuilder, aDirtyRect, aLists); |
|
174 } |
|
175 |
|
176 nsDisplayListCollection contentDisplayItems; |
|
177 if (nsIFrame* inner = GetInner()) { |
|
178 // Collect the inner frame's display items into their own collection. |
|
179 // We need to be calling BuildDisplayList on it before the legend in |
|
180 // case it contains out-of-flow frames whose placeholders are in the |
|
181 // legend. However, we want the inner frame's display items to be |
|
182 // after the legend's display items in z-order, so we need to save them |
|
183 // and append them later. |
|
184 BuildDisplayListForChild(aBuilder, inner, aDirtyRect, contentDisplayItems); |
|
185 } |
|
186 if (nsIFrame* legend = GetLegend()) { |
|
187 // The legend's background goes on our BlockBorderBackgrounds list because |
|
188 // it's a block child. |
|
189 nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds()); |
|
190 BuildDisplayListForChild(aBuilder, legend, aDirtyRect, set); |
|
191 } |
|
192 // Put the inner frame's display items on the master list. Note that this |
|
193 // moves its border/background display items to our BorderBackground() list, |
|
194 // which isn't really correct, but it's OK because the inner frame is |
|
195 // anonymous and can't have its own border and background. |
|
196 contentDisplayItems.MoveTo(aLists); |
|
197 } |
|
198 |
|
199 void |
|
200 nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext, |
|
201 nsPoint aPt, const nsRect& aDirtyRect, uint32_t aBGFlags) |
|
202 { |
|
203 // if the border is smaller than the legend. Move the border down |
|
204 // to be centered on the legend. |
|
205 // FIXME: This means border-radius clamping is incorrect; we should |
|
206 // override nsIFrame::GetBorderRadii. |
|
207 nsRect rect = VisualBorderRectRelativeToSelf(); |
|
208 nscoord yoff = rect.y; |
|
209 rect += aPt; |
|
210 nsPresContext* presContext = PresContext(); |
|
211 |
|
212 nsCSSRendering::PaintBackground(presContext, aRenderingContext, this, |
|
213 aDirtyRect, rect, aBGFlags); |
|
214 |
|
215 nsCSSRendering::PaintBoxShadowInner(presContext, aRenderingContext, |
|
216 this, rect, aDirtyRect); |
|
217 |
|
218 if (nsIFrame* legend = GetLegend()) { |
|
219 nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP); |
|
220 |
|
221 // Use the rect of the legend frame, not mLegendRect, so we draw our |
|
222 // border under the legend's left and right margins. |
|
223 nsRect legendRect = legend->GetRect() + aPt; |
|
224 |
|
225 // we should probably use PaintBorderEdges to do this but for now just use clipping |
|
226 // to achieve the same effect. |
|
227 |
|
228 // draw left side |
|
229 nsRect clipRect(rect); |
|
230 clipRect.width = legendRect.x - rect.x; |
|
231 clipRect.height = topBorder; |
|
232 |
|
233 aRenderingContext.PushState(); |
|
234 aRenderingContext.IntersectClip(clipRect); |
|
235 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, |
|
236 aDirtyRect, rect, mStyleContext); |
|
237 |
|
238 aRenderingContext.PopState(); |
|
239 |
|
240 |
|
241 // draw right side |
|
242 clipRect = rect; |
|
243 clipRect.x = legendRect.XMost(); |
|
244 clipRect.width = rect.XMost() - legendRect.XMost(); |
|
245 clipRect.height = topBorder; |
|
246 |
|
247 aRenderingContext.PushState(); |
|
248 aRenderingContext.IntersectClip(clipRect); |
|
249 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, |
|
250 aDirtyRect, rect, mStyleContext); |
|
251 |
|
252 aRenderingContext.PopState(); |
|
253 |
|
254 |
|
255 // draw bottom |
|
256 clipRect = rect; |
|
257 clipRect.y += topBorder; |
|
258 clipRect.height = mRect.height - (yoff + topBorder); |
|
259 |
|
260 aRenderingContext.PushState(); |
|
261 aRenderingContext.IntersectClip(clipRect); |
|
262 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, |
|
263 aDirtyRect, rect, mStyleContext); |
|
264 |
|
265 aRenderingContext.PopState(); |
|
266 } else { |
|
267 |
|
268 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, |
|
269 aDirtyRect, |
|
270 nsRect(aPt, mRect.Size()), |
|
271 mStyleContext); |
|
272 } |
|
273 } |
|
274 |
|
275 nscoord |
|
276 nsFieldSetFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext, |
|
277 nsLayoutUtils::IntrinsicWidthType aType) |
|
278 { |
|
279 nscoord legendWidth = 0; |
|
280 nscoord contentWidth = 0; |
|
281 if (nsIFrame* legend = GetLegend()) { |
|
282 legendWidth = |
|
283 nsLayoutUtils::IntrinsicForContainer(aRenderingContext, legend, aType); |
|
284 } |
|
285 |
|
286 if (nsIFrame* inner = GetInner()) { |
|
287 // Ignore padding on the inner, since the padding will be applied to the |
|
288 // outer instead, and the padding computed for the inner is wrong |
|
289 // for percentage padding. |
|
290 contentWidth = |
|
291 nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, aType, |
|
292 nsLayoutUtils::IGNORE_PADDING); |
|
293 } |
|
294 |
|
295 return std::max(legendWidth, contentWidth); |
|
296 } |
|
297 |
|
298 |
|
299 nscoord |
|
300 nsFieldSetFrame::GetMinWidth(nsRenderingContext* aRenderingContext) |
|
301 { |
|
302 nscoord result = 0; |
|
303 DISPLAY_MIN_WIDTH(this, result); |
|
304 |
|
305 result = GetIntrinsicWidth(aRenderingContext, nsLayoutUtils::MIN_WIDTH); |
|
306 return result; |
|
307 } |
|
308 |
|
309 nscoord |
|
310 nsFieldSetFrame::GetPrefWidth(nsRenderingContext* aRenderingContext) |
|
311 { |
|
312 nscoord result = 0; |
|
313 DISPLAY_PREF_WIDTH(this, result); |
|
314 |
|
315 result = GetIntrinsicWidth(aRenderingContext, nsLayoutUtils::PREF_WIDTH); |
|
316 return result; |
|
317 } |
|
318 |
|
319 /* virtual */ nsSize |
|
320 nsFieldSetFrame::ComputeSize(nsRenderingContext *aRenderingContext, |
|
321 nsSize aCBSize, nscoord aAvailableWidth, |
|
322 nsSize aMargin, nsSize aBorder, nsSize aPadding, |
|
323 uint32_t aFlags) |
|
324 { |
|
325 nsSize result = |
|
326 nsContainerFrame::ComputeSize(aRenderingContext, aCBSize, aAvailableWidth, |
|
327 aMargin, aBorder, aPadding, aFlags); |
|
328 |
|
329 // Fieldsets never shrink below their min width. |
|
330 |
|
331 // If we're a container for font size inflation, then shrink |
|
332 // wrapping inside of us should not apply font size inflation. |
|
333 AutoMaybeDisableFontInflation an(this); |
|
334 |
|
335 nscoord minWidth = GetMinWidth(aRenderingContext); |
|
336 if (minWidth > result.width) |
|
337 result.width = minWidth; |
|
338 |
|
339 return result; |
|
340 } |
|
341 |
|
342 nsresult |
|
343 nsFieldSetFrame::Reflow(nsPresContext* aPresContext, |
|
344 nsHTMLReflowMetrics& aDesiredSize, |
|
345 const nsHTMLReflowState& aReflowState, |
|
346 nsReflowStatus& aStatus) |
|
347 { |
|
348 DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame"); |
|
349 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); |
|
350 |
|
351 NS_PRECONDITION(aReflowState.ComputedWidth() != NS_INTRINSICSIZE, |
|
352 "Should have a precomputed width!"); |
|
353 |
|
354 // Initialize OUT parameter |
|
355 aStatus = NS_FRAME_COMPLETE; |
|
356 |
|
357 nsOverflowAreas ocBounds; |
|
358 nsReflowStatus ocStatus = NS_FRAME_COMPLETE; |
|
359 if (GetPrevInFlow()) { |
|
360 ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0, |
|
361 ocStatus); |
|
362 } |
|
363 |
|
364 //------------ Handle Incremental Reflow ----------------- |
|
365 bool reflowInner; |
|
366 bool reflowLegend; |
|
367 nsIFrame* legend = GetLegend(); |
|
368 nsIFrame* inner = GetInner(); |
|
369 if (aReflowState.ShouldReflowAllKids()) { |
|
370 reflowInner = inner != nullptr; |
|
371 reflowLegend = legend != nullptr; |
|
372 } else { |
|
373 reflowInner = inner && NS_SUBTREE_DIRTY(inner); |
|
374 reflowLegend = legend && NS_SUBTREE_DIRTY(legend); |
|
375 } |
|
376 |
|
377 // We don't allow fieldsets to break vertically. If we did, we'd |
|
378 // need logic here to push and pull overflow frames. |
|
379 // Since we're not applying our padding in this frame, we need to add it here |
|
380 // to compute the available width for our children. |
|
381 nsSize availSize(aReflowState.ComputedWidth() + aReflowState.ComputedPhysicalPadding().LeftRight(), |
|
382 NS_UNCONSTRAINEDSIZE); |
|
383 NS_ASSERTION(!inner || |
|
384 nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext, |
|
385 inner, |
|
386 nsLayoutUtils::MIN_WIDTH) <= |
|
387 availSize.width, |
|
388 "Bogus availSize.width; should be bigger"); |
|
389 NS_ASSERTION(!legend || |
|
390 nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext, |
|
391 legend, |
|
392 nsLayoutUtils::MIN_WIDTH) <= |
|
393 availSize.width, |
|
394 "Bogus availSize.width; should be bigger"); |
|
395 |
|
396 // get our border and padding |
|
397 nsMargin border = aReflowState.ComputedPhysicalBorderPadding() - aReflowState.ComputedPhysicalPadding(); |
|
398 |
|
399 // Figure out how big the legend is if there is one. |
|
400 // get the legend's margin |
|
401 nsMargin legendMargin(0,0,0,0); |
|
402 // reflow the legend only if needed |
|
403 Maybe<nsHTMLReflowState> legendReflowState; |
|
404 if (legend) { |
|
405 legendReflowState.construct(aPresContext, aReflowState, legend, availSize); |
|
406 } |
|
407 if (reflowLegend) { |
|
408 nsHTMLReflowMetrics legendDesiredSize(aReflowState); |
|
409 |
|
410 ReflowChild(legend, aPresContext, legendDesiredSize, legendReflowState.ref(), |
|
411 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); |
|
412 #ifdef NOISY_REFLOW |
|
413 printf(" returned (%d, %d)\n", legendDesiredSize.Width(), legendDesiredSize.Height()); |
|
414 #endif |
|
415 // figure out the legend's rectangle |
|
416 legendMargin = legend->GetUsedMargin(); |
|
417 mLegendRect.width = legendDesiredSize.Width() + legendMargin.left + legendMargin.right; |
|
418 mLegendRect.height = legendDesiredSize.Height() + legendMargin.top + legendMargin.bottom; |
|
419 mLegendRect.x = 0; |
|
420 mLegendRect.y = 0; |
|
421 |
|
422 nscoord oldSpace = mLegendSpace; |
|
423 mLegendSpace = 0; |
|
424 if (mLegendRect.height > border.top) { |
|
425 // center the border on the legend |
|
426 mLegendSpace = mLegendRect.height - border.top; |
|
427 } else { |
|
428 mLegendRect.y = (border.top - mLegendRect.height)/2; |
|
429 } |
|
430 |
|
431 // if the legend space changes then we need to reflow the |
|
432 // content area as well. |
|
433 if (mLegendSpace != oldSpace && inner) { |
|
434 reflowInner = true; |
|
435 } |
|
436 |
|
437 FinishReflowChild(legend, aPresContext, legendDesiredSize, |
|
438 &legendReflowState.ref(), 0, 0, NS_FRAME_NO_MOVE_FRAME); |
|
439 } else if (!legend) { |
|
440 mLegendRect.SetEmpty(); |
|
441 mLegendSpace = 0; |
|
442 } else { |
|
443 // mLegendSpace and mLegendRect haven't changed, but we need |
|
444 // the used margin when placing the legend. |
|
445 legendMargin = legend->GetUsedMargin(); |
|
446 } |
|
447 |
|
448 // reflow the content frame only if needed |
|
449 if (reflowInner) { |
|
450 nsHTMLReflowState kidReflowState(aPresContext, aReflowState, inner, |
|
451 availSize, -1, -1, nsHTMLReflowState::CALLER_WILL_INIT); |
|
452 // Override computed padding, in case it's percentage padding |
|
453 kidReflowState.Init(aPresContext, -1, -1, nullptr, |
|
454 &aReflowState.ComputedPhysicalPadding()); |
|
455 // Our child is "height:100%" but we actually want its height to be reduced |
|
456 // by the amount of content-height the legend is eating up, unless our |
|
457 // height is unconstrained (in which case the child's will be too). |
|
458 if (aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE) { |
|
459 kidReflowState.SetComputedHeight( |
|
460 std::max(0, aReflowState.ComputedHeight() - mLegendSpace)); |
|
461 } |
|
462 |
|
463 if (aReflowState.ComputedMinHeight() > 0) { |
|
464 kidReflowState.ComputedMinHeight() = |
|
465 std::max(0, aReflowState.ComputedMinHeight() - mLegendSpace); |
|
466 } |
|
467 |
|
468 if (aReflowState.ComputedMaxHeight() != NS_UNCONSTRAINEDSIZE) { |
|
469 kidReflowState.ComputedMaxHeight() = |
|
470 std::max(0, aReflowState.ComputedMaxHeight() - mLegendSpace); |
|
471 } |
|
472 |
|
473 nsHTMLReflowMetrics kidDesiredSize(kidReflowState, |
|
474 aDesiredSize.mFlags); |
|
475 // Reflow the frame |
|
476 NS_ASSERTION(kidReflowState.ComputedPhysicalMargin() == nsMargin(0,0,0,0), |
|
477 "Margins on anonymous fieldset child not supported!"); |
|
478 nsPoint pt(border.left, border.top + mLegendSpace); |
|
479 ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState, |
|
480 pt.x, pt.y, 0, aStatus); |
|
481 |
|
482 FinishReflowChild(inner, aPresContext, kidDesiredSize, |
|
483 &kidReflowState, pt.x, pt.y, 0); |
|
484 NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus); |
|
485 } |
|
486 |
|
487 nsRect contentRect; |
|
488 if (inner) { |
|
489 // We don't support margins on inner, so our content rect is just the |
|
490 // inner's border-box. |
|
491 contentRect = inner->GetRect(); |
|
492 } |
|
493 |
|
494 // Our content rect must fill up the available width |
|
495 if (availSize.width > contentRect.width) { |
|
496 contentRect.width = availSize.width; |
|
497 } |
|
498 |
|
499 if (legend) { |
|
500 // the legend is postioned horizontally within the inner's content rect |
|
501 // (so that padding on the fieldset affects the legend position). |
|
502 nsRect innerContentRect = contentRect; |
|
503 innerContentRect.Deflate(aReflowState.ComputedPhysicalPadding()); |
|
504 // if the inner content rect is larger than the legend, we can align the legend |
|
505 if (innerContentRect.width > mLegendRect.width) { |
|
506 int32_t align = static_cast<nsLegendFrame*> |
|
507 (legend->GetContentInsertionFrame())->GetAlign(); |
|
508 |
|
509 switch (align) { |
|
510 case NS_STYLE_TEXT_ALIGN_RIGHT: |
|
511 mLegendRect.x = innerContentRect.XMost() - mLegendRect.width; |
|
512 break; |
|
513 case NS_STYLE_TEXT_ALIGN_CENTER: |
|
514 // Note: rounding removed; there doesn't seem to be any need |
|
515 mLegendRect.x = innerContentRect.width / 2 - mLegendRect.width / 2 + innerContentRect.x; |
|
516 break; |
|
517 default: |
|
518 mLegendRect.x = innerContentRect.x; |
|
519 break; |
|
520 } |
|
521 } else { |
|
522 // otherwise make place for the legend |
|
523 mLegendRect.x = innerContentRect.x; |
|
524 innerContentRect.width = mLegendRect.width; |
|
525 contentRect.width = mLegendRect.width + aReflowState.ComputedPhysicalPadding().LeftRight(); |
|
526 } |
|
527 |
|
528 // place the legend |
|
529 nsRect actualLegendRect(mLegendRect); |
|
530 actualLegendRect.Deflate(legendMargin); |
|
531 nsPoint actualLegendPos(actualLegendRect.TopLeft()); |
|
532 legendReflowState.ref().ApplyRelativePositioning(&actualLegendPos); |
|
533 legend->SetPosition(actualLegendPos); |
|
534 nsContainerFrame::PositionFrameView(legend); |
|
535 nsContainerFrame::PositionChildViews(legend); |
|
536 } |
|
537 |
|
538 // Return our size and our result. |
|
539 aDesiredSize.Height() = mLegendSpace + border.TopBottom() + |
|
540 (inner ? inner->GetRect().height : 0); |
|
541 aDesiredSize.Width() = contentRect.width + border.LeftRight(); |
|
542 aDesiredSize.SetOverflowAreasToDesiredBounds(); |
|
543 if (legend) |
|
544 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend); |
|
545 if (inner) |
|
546 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner); |
|
547 |
|
548 // Merge overflow container bounds and status. |
|
549 aDesiredSize.mOverflowAreas.UnionWith(ocBounds); |
|
550 NS_MergeReflowStatusInto(&aStatus, ocStatus); |
|
551 |
|
552 FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); |
|
553 |
|
554 InvalidateFrame(); |
|
555 |
|
556 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); |
|
557 return NS_OK; |
|
558 } |
|
559 |
|
560 nsresult |
|
561 nsFieldSetFrame::AppendFrames(ChildListID aListID, |
|
562 nsFrameList& aFrameList) |
|
563 { |
|
564 MOZ_CRASH("nsFieldSetFrame::AppendFrames not supported"); |
|
565 return NS_ERROR_NOT_IMPLEMENTED; |
|
566 } |
|
567 |
|
568 nsresult |
|
569 nsFieldSetFrame::InsertFrames(ChildListID aListID, |
|
570 nsIFrame* aPrevFrame, |
|
571 nsFrameList& aFrameList) |
|
572 { |
|
573 MOZ_CRASH("nsFieldSetFrame::InsertFrames not supported"); |
|
574 return NS_ERROR_NOT_IMPLEMENTED; |
|
575 } |
|
576 |
|
577 nsresult |
|
578 nsFieldSetFrame::RemoveFrame(ChildListID aListID, |
|
579 nsIFrame* aOldFrame) |
|
580 { |
|
581 MOZ_CRASH("nsFieldSetFrame::RemoveFrame not supported"); |
|
582 return NS_ERROR_NOT_IMPLEMENTED; |
|
583 } |
|
584 |
|
585 #ifdef ACCESSIBILITY |
|
586 a11y::AccType |
|
587 nsFieldSetFrame::AccessibleType() |
|
588 { |
|
589 return a11y::eHTMLGroupboxType; |
|
590 } |
|
591 #endif |
|
592 |
|
593 nscoord |
|
594 nsFieldSetFrame::GetBaseline() const |
|
595 { |
|
596 nsIFrame* inner = GetInner(); |
|
597 return inner->GetPosition().y + inner->GetBaseline(); |
|
598 } |