1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/forms/nsFieldSetFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,598 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsFieldSetFrame.h" 1.10 + 1.11 +#include "nsCSSAnonBoxes.h" 1.12 +#include "nsLegendFrame.h" 1.13 +#include "nsCSSRendering.h" 1.14 +#include <algorithm> 1.15 +#include "nsIFrame.h" 1.16 +#include "nsPresContext.h" 1.17 +#include "RestyleManager.h" 1.18 +#include "nsGkAtoms.h" 1.19 +#include "nsStyleConsts.h" 1.20 +#include "nsDisplayList.h" 1.21 +#include "nsRenderingContext.h" 1.22 +#include "nsIScrollableFrame.h" 1.23 +#include "mozilla/Likely.h" 1.24 +#include "mozilla/Maybe.h" 1.25 + 1.26 +using namespace mozilla; 1.27 +using namespace mozilla::layout; 1.28 + 1.29 +nsIFrame* 1.30 +NS_NewFieldSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) 1.31 +{ 1.32 + return new (aPresShell) nsFieldSetFrame(aContext); 1.33 +} 1.34 + 1.35 +NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFrame) 1.36 + 1.37 +nsFieldSetFrame::nsFieldSetFrame(nsStyleContext* aContext) 1.38 + : nsContainerFrame(aContext) 1.39 +{ 1.40 + mLegendSpace = 0; 1.41 +} 1.42 + 1.43 +nsIAtom* 1.44 +nsFieldSetFrame::GetType() const 1.45 +{ 1.46 + return nsGkAtoms::fieldSetFrame; 1.47 +} 1.48 + 1.49 +#ifdef DEBUG 1.50 +nsresult 1.51 +nsFieldSetFrame::SetInitialChildList(ChildListID aListID, 1.52 + nsFrameList& aChildList) 1.53 +{ 1.54 + nsresult rv = nsContainerFrame::SetInitialChildList(kPrincipalList, aChildList); 1.55 + MOZ_ASSERT(GetInner()); 1.56 + return rv; 1.57 +} 1.58 +#endif 1.59 + 1.60 +nsRect 1.61 +nsFieldSetFrame::VisualBorderRectRelativeToSelf() const 1.62 +{ 1.63 + nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP); 1.64 + nsRect r(nsPoint(0,0), GetSize()); 1.65 + if (topBorder < mLegendRect.height) { 1.66 + nscoord yoff = (mLegendRect.height - topBorder) / 2; 1.67 + r.y += yoff; 1.68 + r.height -= yoff; 1.69 + } 1.70 + return r; 1.71 +} 1.72 + 1.73 +nsIFrame* 1.74 +nsFieldSetFrame::GetInner() const 1.75 +{ 1.76 + nsIFrame* last = mFrames.LastChild(); 1.77 + if (last && 1.78 + last->StyleContext()->GetPseudo() == nsCSSAnonBoxes::fieldsetContent) { 1.79 + return last; 1.80 + } 1.81 + MOZ_ASSERT(mFrames.LastChild() == mFrames.FirstChild()); 1.82 + return nullptr; 1.83 +} 1.84 + 1.85 +nsIFrame* 1.86 +nsFieldSetFrame::GetLegend() const 1.87 +{ 1.88 + if (mFrames.FirstChild() == GetInner()) { 1.89 + MOZ_ASSERT(mFrames.LastChild() == mFrames.FirstChild()); 1.90 + return nullptr; 1.91 + } 1.92 + MOZ_ASSERT(mFrames.FirstChild() && 1.93 + mFrames.FirstChild()->GetContentInsertionFrame()->GetType() == 1.94 + nsGkAtoms::legendFrame); 1.95 + return mFrames.FirstChild(); 1.96 +} 1.97 + 1.98 +class nsDisplayFieldSetBorderBackground : public nsDisplayItem { 1.99 +public: 1.100 + nsDisplayFieldSetBorderBackground(nsDisplayListBuilder* aBuilder, 1.101 + nsFieldSetFrame* aFrame) 1.102 + : nsDisplayItem(aBuilder, aFrame) { 1.103 + MOZ_COUNT_CTOR(nsDisplayFieldSetBorderBackground); 1.104 + } 1.105 +#ifdef NS_BUILD_REFCNT_LOGGING 1.106 + virtual ~nsDisplayFieldSetBorderBackground() { 1.107 + MOZ_COUNT_DTOR(nsDisplayFieldSetBorderBackground); 1.108 + } 1.109 +#endif 1.110 + 1.111 + virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 1.112 + HitTestState* aState, 1.113 + nsTArray<nsIFrame*> *aOutFrames) MOZ_OVERRIDE; 1.114 + virtual void Paint(nsDisplayListBuilder* aBuilder, 1.115 + nsRenderingContext* aCtx) MOZ_OVERRIDE; 1.116 + virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.117 + const nsDisplayItemGeometry* aGeometry, 1.118 + nsRegion *aInvalidRegion) MOZ_OVERRIDE; 1.119 + NS_DISPLAY_DECL_NAME("FieldSetBorderBackground", TYPE_FIELDSET_BORDER_BACKGROUND) 1.120 +}; 1.121 + 1.122 +void nsDisplayFieldSetBorderBackground::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 1.123 + HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) 1.124 +{ 1.125 + // aPt is guaranteed to be in this item's bounds. We do the hit test based on the 1.126 + // frame bounds even though our background doesn't cover the whole frame. 1.127 + // It's not clear whether this is correct. 1.128 + aOutFrames->AppendElement(mFrame); 1.129 +} 1.130 + 1.131 +void 1.132 +nsDisplayFieldSetBorderBackground::Paint(nsDisplayListBuilder* aBuilder, 1.133 + nsRenderingContext* aCtx) 1.134 +{ 1.135 + static_cast<nsFieldSetFrame*>(mFrame)-> 1.136 + PaintBorderBackground(*aCtx, ToReferenceFrame(), 1.137 + mVisibleRect, aBuilder->GetBackgroundPaintFlags()); 1.138 +} 1.139 + 1.140 +void 1.141 +nsDisplayFieldSetBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, 1.142 + const nsDisplayItemGeometry* aGeometry, 1.143 + nsRegion *aInvalidRegion) 1.144 +{ 1.145 + AddInvalidRegionForSyncDecodeBackgroundImages(aBuilder, aGeometry, aInvalidRegion); 1.146 + 1.147 + nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); 1.148 +} 1.149 + 1.150 +void 1.151 +nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 1.152 + const nsRect& aDirtyRect, 1.153 + const nsDisplayListSet& aLists) { 1.154 + // Paint our background and border in a special way. 1.155 + // REVIEW: We don't really need to check frame emptiness here; if it's empty, 1.156 + // the background/border display item won't do anything, and if it isn't empty, 1.157 + // we need to paint the outline 1.158 + if (!(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) && 1.159 + IsVisibleForPainting(aBuilder)) { 1.160 + if (StyleBorder()->mBoxShadow) { 1.161 + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) 1.162 + nsDisplayBoxShadowOuter(aBuilder, this)); 1.163 + } 1.164 + 1.165 + // don't bother checking to see if we really have a border or background. 1.166 + // we usually will have a border. 1.167 + aLists.BorderBackground()->AppendNewToTop(new (aBuilder) 1.168 + nsDisplayFieldSetBorderBackground(aBuilder, this)); 1.169 + 1.170 + DisplayOutlineUnconditional(aBuilder, aLists); 1.171 + 1.172 + DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame"); 1.173 + } 1.174 + 1.175 + if (GetPrevInFlow()) { 1.176 + DisplayOverflowContainers(aBuilder, aDirtyRect, aLists); 1.177 + } 1.178 + 1.179 + nsDisplayListCollection contentDisplayItems; 1.180 + if (nsIFrame* inner = GetInner()) { 1.181 + // Collect the inner frame's display items into their own collection. 1.182 + // We need to be calling BuildDisplayList on it before the legend in 1.183 + // case it contains out-of-flow frames whose placeholders are in the 1.184 + // legend. However, we want the inner frame's display items to be 1.185 + // after the legend's display items in z-order, so we need to save them 1.186 + // and append them later. 1.187 + BuildDisplayListForChild(aBuilder, inner, aDirtyRect, contentDisplayItems); 1.188 + } 1.189 + if (nsIFrame* legend = GetLegend()) { 1.190 + // The legend's background goes on our BlockBorderBackgrounds list because 1.191 + // it's a block child. 1.192 + nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds()); 1.193 + BuildDisplayListForChild(aBuilder, legend, aDirtyRect, set); 1.194 + } 1.195 + // Put the inner frame's display items on the master list. Note that this 1.196 + // moves its border/background display items to our BorderBackground() list, 1.197 + // which isn't really correct, but it's OK because the inner frame is 1.198 + // anonymous and can't have its own border and background. 1.199 + contentDisplayItems.MoveTo(aLists); 1.200 +} 1.201 + 1.202 +void 1.203 +nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext, 1.204 + nsPoint aPt, const nsRect& aDirtyRect, uint32_t aBGFlags) 1.205 +{ 1.206 + // if the border is smaller than the legend. Move the border down 1.207 + // to be centered on the legend. 1.208 + // FIXME: This means border-radius clamping is incorrect; we should 1.209 + // override nsIFrame::GetBorderRadii. 1.210 + nsRect rect = VisualBorderRectRelativeToSelf(); 1.211 + nscoord yoff = rect.y; 1.212 + rect += aPt; 1.213 + nsPresContext* presContext = PresContext(); 1.214 + 1.215 + nsCSSRendering::PaintBackground(presContext, aRenderingContext, this, 1.216 + aDirtyRect, rect, aBGFlags); 1.217 + 1.218 + nsCSSRendering::PaintBoxShadowInner(presContext, aRenderingContext, 1.219 + this, rect, aDirtyRect); 1.220 + 1.221 + if (nsIFrame* legend = GetLegend()) { 1.222 + nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP); 1.223 + 1.224 + // Use the rect of the legend frame, not mLegendRect, so we draw our 1.225 + // border under the legend's left and right margins. 1.226 + nsRect legendRect = legend->GetRect() + aPt; 1.227 + 1.228 + // we should probably use PaintBorderEdges to do this but for now just use clipping 1.229 + // to achieve the same effect. 1.230 + 1.231 + // draw left side 1.232 + nsRect clipRect(rect); 1.233 + clipRect.width = legendRect.x - rect.x; 1.234 + clipRect.height = topBorder; 1.235 + 1.236 + aRenderingContext.PushState(); 1.237 + aRenderingContext.IntersectClip(clipRect); 1.238 + nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, 1.239 + aDirtyRect, rect, mStyleContext); 1.240 + 1.241 + aRenderingContext.PopState(); 1.242 + 1.243 + 1.244 + // draw right side 1.245 + clipRect = rect; 1.246 + clipRect.x = legendRect.XMost(); 1.247 + clipRect.width = rect.XMost() - legendRect.XMost(); 1.248 + clipRect.height = topBorder; 1.249 + 1.250 + aRenderingContext.PushState(); 1.251 + aRenderingContext.IntersectClip(clipRect); 1.252 + nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, 1.253 + aDirtyRect, rect, mStyleContext); 1.254 + 1.255 + aRenderingContext.PopState(); 1.256 + 1.257 + 1.258 + // draw bottom 1.259 + clipRect = rect; 1.260 + clipRect.y += topBorder; 1.261 + clipRect.height = mRect.height - (yoff + topBorder); 1.262 + 1.263 + aRenderingContext.PushState(); 1.264 + aRenderingContext.IntersectClip(clipRect); 1.265 + nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, 1.266 + aDirtyRect, rect, mStyleContext); 1.267 + 1.268 + aRenderingContext.PopState(); 1.269 + } else { 1.270 + 1.271 + nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, 1.272 + aDirtyRect, 1.273 + nsRect(aPt, mRect.Size()), 1.274 + mStyleContext); 1.275 + } 1.276 +} 1.277 + 1.278 +nscoord 1.279 +nsFieldSetFrame::GetIntrinsicWidth(nsRenderingContext* aRenderingContext, 1.280 + nsLayoutUtils::IntrinsicWidthType aType) 1.281 +{ 1.282 + nscoord legendWidth = 0; 1.283 + nscoord contentWidth = 0; 1.284 + if (nsIFrame* legend = GetLegend()) { 1.285 + legendWidth = 1.286 + nsLayoutUtils::IntrinsicForContainer(aRenderingContext, legend, aType); 1.287 + } 1.288 + 1.289 + if (nsIFrame* inner = GetInner()) { 1.290 + // Ignore padding on the inner, since the padding will be applied to the 1.291 + // outer instead, and the padding computed for the inner is wrong 1.292 + // for percentage padding. 1.293 + contentWidth = 1.294 + nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner, aType, 1.295 + nsLayoutUtils::IGNORE_PADDING); 1.296 + } 1.297 + 1.298 + return std::max(legendWidth, contentWidth); 1.299 +} 1.300 + 1.301 + 1.302 +nscoord 1.303 +nsFieldSetFrame::GetMinWidth(nsRenderingContext* aRenderingContext) 1.304 +{ 1.305 + nscoord result = 0; 1.306 + DISPLAY_MIN_WIDTH(this, result); 1.307 + 1.308 + result = GetIntrinsicWidth(aRenderingContext, nsLayoutUtils::MIN_WIDTH); 1.309 + return result; 1.310 +} 1.311 + 1.312 +nscoord 1.313 +nsFieldSetFrame::GetPrefWidth(nsRenderingContext* aRenderingContext) 1.314 +{ 1.315 + nscoord result = 0; 1.316 + DISPLAY_PREF_WIDTH(this, result); 1.317 + 1.318 + result = GetIntrinsicWidth(aRenderingContext, nsLayoutUtils::PREF_WIDTH); 1.319 + return result; 1.320 +} 1.321 + 1.322 +/* virtual */ nsSize 1.323 +nsFieldSetFrame::ComputeSize(nsRenderingContext *aRenderingContext, 1.324 + nsSize aCBSize, nscoord aAvailableWidth, 1.325 + nsSize aMargin, nsSize aBorder, nsSize aPadding, 1.326 + uint32_t aFlags) 1.327 +{ 1.328 + nsSize result = 1.329 + nsContainerFrame::ComputeSize(aRenderingContext, aCBSize, aAvailableWidth, 1.330 + aMargin, aBorder, aPadding, aFlags); 1.331 + 1.332 + // Fieldsets never shrink below their min width. 1.333 + 1.334 + // If we're a container for font size inflation, then shrink 1.335 + // wrapping inside of us should not apply font size inflation. 1.336 + AutoMaybeDisableFontInflation an(this); 1.337 + 1.338 + nscoord minWidth = GetMinWidth(aRenderingContext); 1.339 + if (minWidth > result.width) 1.340 + result.width = minWidth; 1.341 + 1.342 + return result; 1.343 +} 1.344 + 1.345 +nsresult 1.346 +nsFieldSetFrame::Reflow(nsPresContext* aPresContext, 1.347 + nsHTMLReflowMetrics& aDesiredSize, 1.348 + const nsHTMLReflowState& aReflowState, 1.349 + nsReflowStatus& aStatus) 1.350 +{ 1.351 + DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame"); 1.352 + DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus); 1.353 + 1.354 + NS_PRECONDITION(aReflowState.ComputedWidth() != NS_INTRINSICSIZE, 1.355 + "Should have a precomputed width!"); 1.356 + 1.357 + // Initialize OUT parameter 1.358 + aStatus = NS_FRAME_COMPLETE; 1.359 + 1.360 + nsOverflowAreas ocBounds; 1.361 + nsReflowStatus ocStatus = NS_FRAME_COMPLETE; 1.362 + if (GetPrevInFlow()) { 1.363 + ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0, 1.364 + ocStatus); 1.365 + } 1.366 + 1.367 + //------------ Handle Incremental Reflow ----------------- 1.368 + bool reflowInner; 1.369 + bool reflowLegend; 1.370 + nsIFrame* legend = GetLegend(); 1.371 + nsIFrame* inner = GetInner(); 1.372 + if (aReflowState.ShouldReflowAllKids()) { 1.373 + reflowInner = inner != nullptr; 1.374 + reflowLegend = legend != nullptr; 1.375 + } else { 1.376 + reflowInner = inner && NS_SUBTREE_DIRTY(inner); 1.377 + reflowLegend = legend && NS_SUBTREE_DIRTY(legend); 1.378 + } 1.379 + 1.380 + // We don't allow fieldsets to break vertically. If we did, we'd 1.381 + // need logic here to push and pull overflow frames. 1.382 + // Since we're not applying our padding in this frame, we need to add it here 1.383 + // to compute the available width for our children. 1.384 + nsSize availSize(aReflowState.ComputedWidth() + aReflowState.ComputedPhysicalPadding().LeftRight(), 1.385 + NS_UNCONSTRAINEDSIZE); 1.386 + NS_ASSERTION(!inner || 1.387 + nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext, 1.388 + inner, 1.389 + nsLayoutUtils::MIN_WIDTH) <= 1.390 + availSize.width, 1.391 + "Bogus availSize.width; should be bigger"); 1.392 + NS_ASSERTION(!legend || 1.393 + nsLayoutUtils::IntrinsicForContainer(aReflowState.rendContext, 1.394 + legend, 1.395 + nsLayoutUtils::MIN_WIDTH) <= 1.396 + availSize.width, 1.397 + "Bogus availSize.width; should be bigger"); 1.398 + 1.399 + // get our border and padding 1.400 + nsMargin border = aReflowState.ComputedPhysicalBorderPadding() - aReflowState.ComputedPhysicalPadding(); 1.401 + 1.402 + // Figure out how big the legend is if there is one. 1.403 + // get the legend's margin 1.404 + nsMargin legendMargin(0,0,0,0); 1.405 + // reflow the legend only if needed 1.406 + Maybe<nsHTMLReflowState> legendReflowState; 1.407 + if (legend) { 1.408 + legendReflowState.construct(aPresContext, aReflowState, legend, availSize); 1.409 + } 1.410 + if (reflowLegend) { 1.411 + nsHTMLReflowMetrics legendDesiredSize(aReflowState); 1.412 + 1.413 + ReflowChild(legend, aPresContext, legendDesiredSize, legendReflowState.ref(), 1.414 + 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); 1.415 +#ifdef NOISY_REFLOW 1.416 + printf(" returned (%d, %d)\n", legendDesiredSize.Width(), legendDesiredSize.Height()); 1.417 +#endif 1.418 + // figure out the legend's rectangle 1.419 + legendMargin = legend->GetUsedMargin(); 1.420 + mLegendRect.width = legendDesiredSize.Width() + legendMargin.left + legendMargin.right; 1.421 + mLegendRect.height = legendDesiredSize.Height() + legendMargin.top + legendMargin.bottom; 1.422 + mLegendRect.x = 0; 1.423 + mLegendRect.y = 0; 1.424 + 1.425 + nscoord oldSpace = mLegendSpace; 1.426 + mLegendSpace = 0; 1.427 + if (mLegendRect.height > border.top) { 1.428 + // center the border on the legend 1.429 + mLegendSpace = mLegendRect.height - border.top; 1.430 + } else { 1.431 + mLegendRect.y = (border.top - mLegendRect.height)/2; 1.432 + } 1.433 + 1.434 + // if the legend space changes then we need to reflow the 1.435 + // content area as well. 1.436 + if (mLegendSpace != oldSpace && inner) { 1.437 + reflowInner = true; 1.438 + } 1.439 + 1.440 + FinishReflowChild(legend, aPresContext, legendDesiredSize, 1.441 + &legendReflowState.ref(), 0, 0, NS_FRAME_NO_MOVE_FRAME); 1.442 + } else if (!legend) { 1.443 + mLegendRect.SetEmpty(); 1.444 + mLegendSpace = 0; 1.445 + } else { 1.446 + // mLegendSpace and mLegendRect haven't changed, but we need 1.447 + // the used margin when placing the legend. 1.448 + legendMargin = legend->GetUsedMargin(); 1.449 + } 1.450 + 1.451 + // reflow the content frame only if needed 1.452 + if (reflowInner) { 1.453 + nsHTMLReflowState kidReflowState(aPresContext, aReflowState, inner, 1.454 + availSize, -1, -1, nsHTMLReflowState::CALLER_WILL_INIT); 1.455 + // Override computed padding, in case it's percentage padding 1.456 + kidReflowState.Init(aPresContext, -1, -1, nullptr, 1.457 + &aReflowState.ComputedPhysicalPadding()); 1.458 + // Our child is "height:100%" but we actually want its height to be reduced 1.459 + // by the amount of content-height the legend is eating up, unless our 1.460 + // height is unconstrained (in which case the child's will be too). 1.461 + if (aReflowState.ComputedHeight() != NS_UNCONSTRAINEDSIZE) { 1.462 + kidReflowState.SetComputedHeight( 1.463 + std::max(0, aReflowState.ComputedHeight() - mLegendSpace)); 1.464 + } 1.465 + 1.466 + if (aReflowState.ComputedMinHeight() > 0) { 1.467 + kidReflowState.ComputedMinHeight() = 1.468 + std::max(0, aReflowState.ComputedMinHeight() - mLegendSpace); 1.469 + } 1.470 + 1.471 + if (aReflowState.ComputedMaxHeight() != NS_UNCONSTRAINEDSIZE) { 1.472 + kidReflowState.ComputedMaxHeight() = 1.473 + std::max(0, aReflowState.ComputedMaxHeight() - mLegendSpace); 1.474 + } 1.475 + 1.476 + nsHTMLReflowMetrics kidDesiredSize(kidReflowState, 1.477 + aDesiredSize.mFlags); 1.478 + // Reflow the frame 1.479 + NS_ASSERTION(kidReflowState.ComputedPhysicalMargin() == nsMargin(0,0,0,0), 1.480 + "Margins on anonymous fieldset child not supported!"); 1.481 + nsPoint pt(border.left, border.top + mLegendSpace); 1.482 + ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState, 1.483 + pt.x, pt.y, 0, aStatus); 1.484 + 1.485 + FinishReflowChild(inner, aPresContext, kidDesiredSize, 1.486 + &kidReflowState, pt.x, pt.y, 0); 1.487 + NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus); 1.488 + } 1.489 + 1.490 + nsRect contentRect; 1.491 + if (inner) { 1.492 + // We don't support margins on inner, so our content rect is just the 1.493 + // inner's border-box. 1.494 + contentRect = inner->GetRect(); 1.495 + } 1.496 + 1.497 + // Our content rect must fill up the available width 1.498 + if (availSize.width > contentRect.width) { 1.499 + contentRect.width = availSize.width; 1.500 + } 1.501 + 1.502 + if (legend) { 1.503 + // the legend is postioned horizontally within the inner's content rect 1.504 + // (so that padding on the fieldset affects the legend position). 1.505 + nsRect innerContentRect = contentRect; 1.506 + innerContentRect.Deflate(aReflowState.ComputedPhysicalPadding()); 1.507 + // if the inner content rect is larger than the legend, we can align the legend 1.508 + if (innerContentRect.width > mLegendRect.width) { 1.509 + int32_t align = static_cast<nsLegendFrame*> 1.510 + (legend->GetContentInsertionFrame())->GetAlign(); 1.511 + 1.512 + switch (align) { 1.513 + case NS_STYLE_TEXT_ALIGN_RIGHT: 1.514 + mLegendRect.x = innerContentRect.XMost() - mLegendRect.width; 1.515 + break; 1.516 + case NS_STYLE_TEXT_ALIGN_CENTER: 1.517 + // Note: rounding removed; there doesn't seem to be any need 1.518 + mLegendRect.x = innerContentRect.width / 2 - mLegendRect.width / 2 + innerContentRect.x; 1.519 + break; 1.520 + default: 1.521 + mLegendRect.x = innerContentRect.x; 1.522 + break; 1.523 + } 1.524 + } else { 1.525 + // otherwise make place for the legend 1.526 + mLegendRect.x = innerContentRect.x; 1.527 + innerContentRect.width = mLegendRect.width; 1.528 + contentRect.width = mLegendRect.width + aReflowState.ComputedPhysicalPadding().LeftRight(); 1.529 + } 1.530 + 1.531 + // place the legend 1.532 + nsRect actualLegendRect(mLegendRect); 1.533 + actualLegendRect.Deflate(legendMargin); 1.534 + nsPoint actualLegendPos(actualLegendRect.TopLeft()); 1.535 + legendReflowState.ref().ApplyRelativePositioning(&actualLegendPos); 1.536 + legend->SetPosition(actualLegendPos); 1.537 + nsContainerFrame::PositionFrameView(legend); 1.538 + nsContainerFrame::PositionChildViews(legend); 1.539 + } 1.540 + 1.541 + // Return our size and our result. 1.542 + aDesiredSize.Height() = mLegendSpace + border.TopBottom() + 1.543 + (inner ? inner->GetRect().height : 0); 1.544 + aDesiredSize.Width() = contentRect.width + border.LeftRight(); 1.545 + aDesiredSize.SetOverflowAreasToDesiredBounds(); 1.546 + if (legend) 1.547 + ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend); 1.548 + if (inner) 1.549 + ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner); 1.550 + 1.551 + // Merge overflow container bounds and status. 1.552 + aDesiredSize.mOverflowAreas.UnionWith(ocBounds); 1.553 + NS_MergeReflowStatusInto(&aStatus, ocStatus); 1.554 + 1.555 + FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); 1.556 + 1.557 + InvalidateFrame(); 1.558 + 1.559 + NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); 1.560 + return NS_OK; 1.561 +} 1.562 + 1.563 +nsresult 1.564 +nsFieldSetFrame::AppendFrames(ChildListID aListID, 1.565 + nsFrameList& aFrameList) 1.566 +{ 1.567 + MOZ_CRASH("nsFieldSetFrame::AppendFrames not supported"); 1.568 + return NS_ERROR_NOT_IMPLEMENTED; 1.569 +} 1.570 + 1.571 +nsresult 1.572 +nsFieldSetFrame::InsertFrames(ChildListID aListID, 1.573 + nsIFrame* aPrevFrame, 1.574 + nsFrameList& aFrameList) 1.575 +{ 1.576 + MOZ_CRASH("nsFieldSetFrame::InsertFrames not supported"); 1.577 + return NS_ERROR_NOT_IMPLEMENTED; 1.578 +} 1.579 + 1.580 +nsresult 1.581 +nsFieldSetFrame::RemoveFrame(ChildListID aListID, 1.582 + nsIFrame* aOldFrame) 1.583 +{ 1.584 + MOZ_CRASH("nsFieldSetFrame::RemoveFrame not supported"); 1.585 + return NS_ERROR_NOT_IMPLEMENTED; 1.586 +} 1.587 + 1.588 +#ifdef ACCESSIBILITY 1.589 +a11y::AccType 1.590 +nsFieldSetFrame::AccessibleType() 1.591 +{ 1.592 + return a11y::eHTMLGroupboxType; 1.593 +} 1.594 +#endif 1.595 + 1.596 +nscoord 1.597 +nsFieldSetFrame::GetBaseline() const 1.598 +{ 1.599 + nsIFrame* inner = GetInner(); 1.600 + return inner->GetPosition().y + inner->GetBaseline(); 1.601 +}