layout/forms/nsFieldSetFrame.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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

mercurial