Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/. */
6 #include "nsFieldSetFrame.h"
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"
23 using namespace mozilla;
24 using namespace mozilla::layout;
26 nsIFrame*
27 NS_NewFieldSetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
28 {
29 return new (aPresShell) nsFieldSetFrame(aContext);
30 }
32 NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFrame)
34 nsFieldSetFrame::nsFieldSetFrame(nsStyleContext* aContext)
35 : nsContainerFrame(aContext)
36 {
37 mLegendSpace = 0;
38 }
40 nsIAtom*
41 nsFieldSetFrame::GetType() const
42 {
43 return nsGkAtoms::fieldSetFrame;
44 }
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
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 }
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 }
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 }
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
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 };
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 }
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 }
137 void
138 nsDisplayFieldSetBorderBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
139 const nsDisplayItemGeometry* aGeometry,
140 nsRegion *aInvalidRegion)
141 {
142 AddInvalidRegionForSyncDecodeBackgroundImages(aBuilder, aGeometry, aInvalidRegion);
144 nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
145 }
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 }
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));
167 DisplayOutlineUnconditional(aBuilder, aLists);
169 DO_GLOBAL_REFLOW_COUNT_DSP("nsFieldSetFrame");
170 }
172 if (GetPrevInFlow()) {
173 DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
174 }
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 }
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();
212 nsCSSRendering::PaintBackground(presContext, aRenderingContext, this,
213 aDirtyRect, rect, aBGFlags);
215 nsCSSRendering::PaintBoxShadowInner(presContext, aRenderingContext,
216 this, rect, aDirtyRect);
218 if (nsIFrame* legend = GetLegend()) {
219 nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP);
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;
225 // we should probably use PaintBorderEdges to do this but for now just use clipping
226 // to achieve the same effect.
228 // draw left side
229 nsRect clipRect(rect);
230 clipRect.width = legendRect.x - rect.x;
231 clipRect.height = topBorder;
233 aRenderingContext.PushState();
234 aRenderingContext.IntersectClip(clipRect);
235 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
236 aDirtyRect, rect, mStyleContext);
238 aRenderingContext.PopState();
241 // draw right side
242 clipRect = rect;
243 clipRect.x = legendRect.XMost();
244 clipRect.width = rect.XMost() - legendRect.XMost();
245 clipRect.height = topBorder;
247 aRenderingContext.PushState();
248 aRenderingContext.IntersectClip(clipRect);
249 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
250 aDirtyRect, rect, mStyleContext);
252 aRenderingContext.PopState();
255 // draw bottom
256 clipRect = rect;
257 clipRect.y += topBorder;
258 clipRect.height = mRect.height - (yoff + topBorder);
260 aRenderingContext.PushState();
261 aRenderingContext.IntersectClip(clipRect);
262 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
263 aDirtyRect, rect, mStyleContext);
265 aRenderingContext.PopState();
266 } else {
268 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
269 aDirtyRect,
270 nsRect(aPt, mRect.Size()),
271 mStyleContext);
272 }
273 }
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 }
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 }
295 return std::max(legendWidth, contentWidth);
296 }
299 nscoord
300 nsFieldSetFrame::GetMinWidth(nsRenderingContext* aRenderingContext)
301 {
302 nscoord result = 0;
303 DISPLAY_MIN_WIDTH(this, result);
305 result = GetIntrinsicWidth(aRenderingContext, nsLayoutUtils::MIN_WIDTH);
306 return result;
307 }
309 nscoord
310 nsFieldSetFrame::GetPrefWidth(nsRenderingContext* aRenderingContext)
311 {
312 nscoord result = 0;
313 DISPLAY_PREF_WIDTH(this, result);
315 result = GetIntrinsicWidth(aRenderingContext, nsLayoutUtils::PREF_WIDTH);
316 return result;
317 }
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);
329 // Fieldsets never shrink below their min width.
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);
335 nscoord minWidth = GetMinWidth(aRenderingContext);
336 if (minWidth > result.width)
337 result.width = minWidth;
339 return result;
340 }
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);
351 NS_PRECONDITION(aReflowState.ComputedWidth() != NS_INTRINSICSIZE,
352 "Should have a precomputed width!");
354 // Initialize OUT parameter
355 aStatus = NS_FRAME_COMPLETE;
357 nsOverflowAreas ocBounds;
358 nsReflowStatus ocStatus = NS_FRAME_COMPLETE;
359 if (GetPrevInFlow()) {
360 ReflowOverflowContainerChildren(aPresContext, aReflowState, ocBounds, 0,
361 ocStatus);
362 }
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 }
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");
396 // get our border and padding
397 nsMargin border = aReflowState.ComputedPhysicalBorderPadding() - aReflowState.ComputedPhysicalPadding();
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);
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;
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 }
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 }
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 }
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 }
463 if (aReflowState.ComputedMinHeight() > 0) {
464 kidReflowState.ComputedMinHeight() =
465 std::max(0, aReflowState.ComputedMinHeight() - mLegendSpace);
466 }
468 if (aReflowState.ComputedMaxHeight() != NS_UNCONSTRAINEDSIZE) {
469 kidReflowState.ComputedMaxHeight() =
470 std::max(0, aReflowState.ComputedMaxHeight() - mLegendSpace);
471 }
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);
482 FinishReflowChild(inner, aPresContext, kidDesiredSize,
483 &kidReflowState, pt.x, pt.y, 0);
484 NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);
485 }
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 }
494 // Our content rect must fill up the available width
495 if (availSize.width > contentRect.width) {
496 contentRect.width = availSize.width;
497 }
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();
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 }
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 }
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);
548 // Merge overflow container bounds and status.
549 aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
550 NS_MergeReflowStatusInto(&aStatus, ocStatus);
552 FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus);
554 InvalidateFrame();
556 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
557 return NS_OK;
558 }
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 }
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 }
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 }
585 #ifdef ACCESSIBILITY
586 a11y::AccType
587 nsFieldSetFrame::AccessibleType()
588 {
589 return a11y::eHTMLGroupboxType;
590 }
591 #endif
593 nscoord
594 nsFieldSetFrame::GetBaseline() const
595 {
596 nsIFrame* inner = GetInner();
597 return inner->GetPosition().y + inner->GetBaseline();
598 }