mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1123133 - Vertical writing-mode support in nsFieldSetFrame. r=smontagu
This commit is contained in:
parent
682d07b50e
commit
c45717c168
@ -36,6 +36,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsFieldSetFrame)
|
||||
|
||||
nsFieldSetFrame::nsFieldSetFrame(nsStyleContext* aContext)
|
||||
: nsContainerFrame(aContext)
|
||||
, mLegendRect(GetWritingMode())
|
||||
{
|
||||
mLegendSpace = 0;
|
||||
}
|
||||
@ -49,14 +50,17 @@ nsFieldSetFrame::GetType() const
|
||||
nsRect
|
||||
nsFieldSetFrame::VisualBorderRectRelativeToSelf() const
|
||||
{
|
||||
nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP);
|
||||
nsRect r(nsPoint(0,0), GetSize());
|
||||
if (topBorder < mLegendRect.height) {
|
||||
nscoord yoff = (mLegendRect.height - topBorder) / 2;
|
||||
r.y += yoff;
|
||||
r.height -= yoff;
|
||||
WritingMode wm = GetWritingMode();
|
||||
css::Side legendSide = wm.PhysicalSide(eLogicalSideBStart);
|
||||
nscoord legendBorder = StyleBorder()->GetComputedBorderWidth(legendSide);
|
||||
LogicalRect r(wm, LogicalPoint(wm, 0, 0), GetLogicalSize(wm));
|
||||
nscoord containerWidth = r.Width(wm);
|
||||
if (legendBorder < mLegendRect.BSize(wm)) {
|
||||
nscoord off = (mLegendRect.BSize(wm) - legendBorder) / 2;
|
||||
r.BStart(wm) += off;
|
||||
r.BSize(wm) -= off;
|
||||
}
|
||||
return r;
|
||||
return r.GetPhysicalRect(wm, containerWidth);
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
@ -193,11 +197,12 @@ nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext,
|
||||
nsPoint aPt, const nsRect& aDirtyRect, uint32_t aBGFlags)
|
||||
{
|
||||
// if the border is smaller than the legend. Move the border down
|
||||
// to be centered on the legend.
|
||||
// to be centered on the legend.
|
||||
// FIXME: This means border-radius clamping is incorrect; we should
|
||||
// override nsIFrame::GetBorderRadii.
|
||||
WritingMode wm = GetWritingMode();
|
||||
nsRect rect = VisualBorderRectRelativeToSelf();
|
||||
nscoord yoff = rect.y;
|
||||
nscoord off = wm.IsVertical() ? rect.x : rect.y;
|
||||
rect += aPt;
|
||||
nsPresContext* presContext = PresContext();
|
||||
|
||||
@ -207,57 +212,59 @@ nsFieldSetFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext,
|
||||
nsCSSRendering::PaintBoxShadowInner(presContext, aRenderingContext,
|
||||
this, rect, aDirtyRect);
|
||||
|
||||
if (nsIFrame* legend = GetLegend()) {
|
||||
nscoord topBorder = StyleBorder()->GetComputedBorderWidth(NS_SIDE_TOP);
|
||||
if (nsIFrame* legend = GetLegend()) {
|
||||
css::Side legendSide = wm.PhysicalSide(eLogicalSideBStart);
|
||||
nscoord legendBorderWidth =
|
||||
StyleBorder()->GetComputedBorderWidth(legendSide);
|
||||
|
||||
// Use the rect of the legend frame, not mLegendRect, so we draw our
|
||||
// border under the legend's left and right margins.
|
||||
nsRect legendRect = legend->GetRect() + aPt;
|
||||
|
||||
// we should probably use PaintBorderEdges to do this but for now just use clipping
|
||||
// to achieve the same effect.
|
||||
|
||||
// draw left side
|
||||
nsRect clipRect(rect);
|
||||
clipRect.width = legendRect.x - rect.x;
|
||||
clipRect.height = topBorder;
|
||||
// border under the legend's inline-start and -end margins.
|
||||
LogicalRect legendRect(wm, legend->GetRect() + aPt, rect.width);
|
||||
|
||||
// Compute clipRect using logical coordinates, so that the legend space
|
||||
// will be clipped out of the appropriate physical side depending on mode.
|
||||
LogicalRect clipRect = LogicalRect(wm, rect, rect.width);
|
||||
DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
|
||||
gfxContext* gfx = aRenderingContext.ThebesContext();
|
||||
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
|
||||
// draw inline-start portion of the block-start side of the border
|
||||
clipRect.ISize(wm) = legendRect.IStart(wm) - clipRect.IStart(wm);
|
||||
clipRect.BSize(wm) = legendBorderWidth;
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.width),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext);
|
||||
gfx->Restore();
|
||||
|
||||
|
||||
// draw right side
|
||||
clipRect = rect;
|
||||
clipRect.x = legendRect.XMost();
|
||||
clipRect.width = rect.XMost() - legendRect.XMost();
|
||||
clipRect.height = topBorder;
|
||||
// draw inline-end portion of the block-start side of the border
|
||||
clipRect = LogicalRect(wm, rect, rect.width);
|
||||
clipRect.ISize(wm) = clipRect.IEnd(wm) - legendRect.IEnd(wm);
|
||||
clipRect.IStart(wm) = legendRect.IEnd(wm);
|
||||
clipRect.BSize(wm) = legendBorderWidth;
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.width),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext);
|
||||
gfx->Restore();
|
||||
|
||||
|
||||
// draw bottom
|
||||
clipRect = rect;
|
||||
clipRect.y += topBorder;
|
||||
clipRect.height = mRect.height - (yoff + topBorder);
|
||||
|
||||
// draw remainder of the border (omitting the block-start side)
|
||||
clipRect = LogicalRect(wm, rect, rect.width);
|
||||
clipRect.BStart(wm) += legendBorderWidth;
|
||||
clipRect.BSize(wm) =
|
||||
GetLogicalRect(rect.width).BSize(wm) - (off + legendBorderWidth);
|
||||
|
||||
gfx->Save();
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
|
||||
gfx->Clip(NSRectToSnappedRect(clipRect.GetPhysicalRect(wm, rect.width),
|
||||
appUnitsPerDevPixel, *drawTarget));
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect, rect, mStyleContext);
|
||||
gfx->Restore();
|
||||
} else {
|
||||
|
||||
nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
|
||||
aDirtyRect,
|
||||
nsRect(aPt, mRect.Size()),
|
||||
@ -385,8 +392,9 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
||||
// need logic here to push and pull overflow frames.
|
||||
// Since we're not applying our padding in this frame, we need to add it here
|
||||
// to compute the available width for our children.
|
||||
WritingMode innerWM = inner ? inner->GetWritingMode() : GetWritingMode();
|
||||
WritingMode legendWM = legend ? legend->GetWritingMode() : GetWritingMode();
|
||||
WritingMode wm = GetWritingMode();
|
||||
WritingMode innerWM = inner ? inner->GetWritingMode() : wm;
|
||||
WritingMode legendWM = legend ? legend->GetWritingMode() : wm;
|
||||
LogicalSize innerAvailSize = aReflowState.ComputedSizeWithPadding(innerWM);
|
||||
LogicalSize legendAvailSize = aReflowState.ComputedSizeWithPadding(legendWM);
|
||||
innerAvailSize.BSize(innerWM) = legendAvailSize.BSize(legendWM) =
|
||||
@ -405,11 +413,13 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
||||
"Bogus availSize.ISize; should be bigger");
|
||||
|
||||
// get our border and padding
|
||||
nsMargin border = aReflowState.ComputedPhysicalBorderPadding() - aReflowState.ComputedPhysicalPadding();
|
||||
nsMargin border = aReflowState.ComputedPhysicalBorderPadding() -
|
||||
aReflowState.ComputedPhysicalPadding();
|
||||
LogicalMargin logBorder(wm, border);
|
||||
|
||||
// Figure out how big the legend is if there is one.
|
||||
// Figure out how big the legend is if there is one.
|
||||
// get the legend's margin
|
||||
nsMargin legendMargin(0,0,0,0);
|
||||
LogicalMargin legendMargin(wm);
|
||||
// reflow the legend only if needed
|
||||
Maybe<nsHTMLReflowState> legendReflowState;
|
||||
if (legend) {
|
||||
@ -426,36 +436,37 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
||||
legendDesiredSize.Width(), legendDesiredSize.Height());
|
||||
#endif
|
||||
// figure out the legend's rectangle
|
||||
legendMargin = legend->GetUsedMargin();
|
||||
mLegendRect.width = legendDesiredSize.Width() + legendMargin.left + legendMargin.right;
|
||||
mLegendRect.height = legendDesiredSize.Height() + legendMargin.top + legendMargin.bottom;
|
||||
mLegendRect.x = 0;
|
||||
mLegendRect.y = 0;
|
||||
|
||||
legendMargin = legend->GetLogicalUsedMargin(wm);
|
||||
mLegendRect =
|
||||
LogicalRect(wm, 0, 0,
|
||||
legendDesiredSize.ISize(wm) + legendMargin.IStartEnd(wm),
|
||||
legendDesiredSize.BSize(wm) + legendMargin.BStartEnd(wm));
|
||||
nscoord oldSpace = mLegendSpace;
|
||||
mLegendSpace = 0;
|
||||
if (mLegendRect.height > border.top) {
|
||||
if (mLegendRect.BSize(wm) > logBorder.BStart(wm)) {
|
||||
// center the border on the legend
|
||||
mLegendSpace = mLegendRect.height - border.top;
|
||||
mLegendSpace = mLegendRect.BSize(wm) - logBorder.BStart(wm);
|
||||
} else {
|
||||
mLegendRect.y = (border.top - mLegendRect.height)/2;
|
||||
mLegendRect.BStart(wm) =
|
||||
(logBorder.BStart(wm) - mLegendRect.BSize(wm)) / 2;
|
||||
}
|
||||
|
||||
// if the legend space changes then we need to reflow the
|
||||
// if the legend space changes then we need to reflow the
|
||||
// content area as well.
|
||||
if (mLegendSpace != oldSpace && inner) {
|
||||
reflowInner = true;
|
||||
}
|
||||
|
||||
// We'll move the legend to its proper place later.
|
||||
FinishReflowChild(legend, aPresContext, legendDesiredSize,
|
||||
legendReflowState.ptr(), 0, 0, NS_FRAME_NO_MOVE_FRAME);
|
||||
legendReflowState.ptr(), 0, 0, NS_FRAME_NO_MOVE_FRAME);
|
||||
} else if (!legend) {
|
||||
mLegendRect.SetEmpty();
|
||||
mLegendSpace = 0;
|
||||
} else {
|
||||
// mLegendSpace and mLegendRect haven't changed, but we need
|
||||
// the used margin when placing the legend.
|
||||
legendMargin = legend->GetUsedMargin();
|
||||
legendMargin = legend->GetLogicalUsedMargin(wm);
|
||||
}
|
||||
|
||||
// reflow the content frame only if needed
|
||||
@ -489,7 +500,12 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
||||
// Reflow the frame
|
||||
NS_ASSERTION(kidReflowState.ComputedPhysicalMargin() == nsMargin(0,0,0,0),
|
||||
"Margins on anonymous fieldset child not supported!");
|
||||
nsPoint pt(border.left, border.top + mLegendSpace);
|
||||
nsPoint pt(border.left, border.top);
|
||||
if (wm.IsVerticalLR()) {
|
||||
pt.x += mLegendSpace;
|
||||
} else if (!wm.IsVertical()) {
|
||||
pt.y += mLegendSpace;
|
||||
}
|
||||
ReflowChild(inner, aPresContext, kidDesiredSize, kidReflowState,
|
||||
pt.x, pt.y, 0, aStatus);
|
||||
|
||||
@ -498,72 +514,89 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
|
||||
NS_FRAME_TRACE_REFLOW_OUT("FieldSet::Reflow", aStatus);
|
||||
}
|
||||
|
||||
LogicalRect contentRect(innerWM);
|
||||
nscoord containerWidth =
|
||||
(wm.IsVertical() ? mLegendSpace : 0) +
|
||||
logBorder.LeftRight(wm) + (inner ? inner->GetSize().width : 0);
|
||||
|
||||
LogicalRect contentRect(wm);
|
||||
if (inner) {
|
||||
// We don't support margins on inner, so our content rect is just the
|
||||
// inner's border-box.
|
||||
contentRect = inner->GetLogicalRect(aReflowState.ComputedWidth());
|
||||
// inner's border-box. We don't care about container-width at this point,
|
||||
// as we'll figure out the actual positioning later.
|
||||
contentRect = inner->GetLogicalRect(wm, containerWidth);
|
||||
}
|
||||
|
||||
// Our content rect must fill up the available width
|
||||
if (innerAvailSize.ISize(innerWM) > contentRect.ISize(innerWM)) {
|
||||
contentRect.ISize(innerWM) = innerAvailSize.ISize(innerWM);
|
||||
LogicalSize availSize = aReflowState.ComputedSizeWithPadding(wm);
|
||||
if (availSize.ISize(wm) > contentRect.ISize(wm)) {
|
||||
contentRect.ISize(wm) = innerAvailSize.ISize(wm);
|
||||
}
|
||||
|
||||
//XXX temporary!
|
||||
nsRect physicalContentRect =
|
||||
contentRect.GetPhysicalRect(innerWM, aReflowState.ComputedWidth());
|
||||
if (legend) {
|
||||
// the legend is postioned horizontally within the inner's content rect
|
||||
// The legend is positioned inline-wards within the inner's content rect
|
||||
// (so that padding on the fieldset affects the legend position).
|
||||
nsRect innerContentRect = physicalContentRect;
|
||||
innerContentRect.Deflate(aReflowState.ComputedPhysicalPadding());
|
||||
// if the inner content rect is larger than the legend, we can align the legend
|
||||
if (innerContentRect.width > mLegendRect.width) {
|
||||
LogicalRect innerContentRect = contentRect;
|
||||
innerContentRect.Deflate(wm, aReflowState.ComputedLogicalPadding());
|
||||
// If the inner content rect is larger than the legend, we can align the
|
||||
// legend.
|
||||
if (innerContentRect.ISize(wm) > mLegendRect.ISize(wm)) {
|
||||
int32_t align = static_cast<nsLegendFrame*>
|
||||
(legend->GetContentInsertionFrame())->GetAlign();
|
||||
|
||||
if (!wm.IsBidiLTR()) {
|
||||
if (align == NS_STYLE_TEXT_ALIGN_LEFT ||
|
||||
align == NS_STYLE_TEXT_ALIGN_MOZ_LEFT) {
|
||||
align = NS_STYLE_TEXT_ALIGN_END;
|
||||
} else if (align == NS_STYLE_TEXT_ALIGN_RIGHT ||
|
||||
align == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT) {
|
||||
align = NS_STYLE_TEXT_ALIGN_DEFAULT;
|
||||
}
|
||||
}
|
||||
switch (align) {
|
||||
case NS_STYLE_TEXT_ALIGN_RIGHT:
|
||||
mLegendRect.x = innerContentRect.XMost() - mLegendRect.width;
|
||||
case NS_STYLE_TEXT_ALIGN_END:
|
||||
mLegendRect.IStart(wm) =
|
||||
innerContentRect.IEnd(wm) - mLegendRect.ISize(wm);
|
||||
break;
|
||||
case NS_STYLE_TEXT_ALIGN_CENTER:
|
||||
case NS_STYLE_TEXT_ALIGN_MOZ_CENTER:
|
||||
// Note: rounding removed; there doesn't seem to be any need
|
||||
mLegendRect.x = innerContentRect.width / 2 - mLegendRect.width / 2 + innerContentRect.x;
|
||||
mLegendRect.IStart(wm) = innerContentRect.IStart(wm) +
|
||||
(innerContentRect.ISize(wm) - mLegendRect.ISize(wm)) / 2;
|
||||
break;
|
||||
default:
|
||||
mLegendRect.x = innerContentRect.x;
|
||||
mLegendRect.IStart(wm) = innerContentRect.IStart(wm);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// otherwise make place for the legend
|
||||
mLegendRect.x = innerContentRect.x;
|
||||
innerContentRect.width = mLegendRect.width;
|
||||
physicalContentRect.width = mLegendRect.width +
|
||||
aReflowState.ComputedPhysicalPadding().LeftRight();
|
||||
mLegendRect.IStart(wm) = innerContentRect.IStart(wm);
|
||||
innerContentRect.ISize(wm) = mLegendRect.ISize(wm);
|
||||
contentRect.ISize(wm) = mLegendRect.ISize(wm) +
|
||||
aReflowState.ComputedLogicalPadding().IStartEnd(wm);
|
||||
}
|
||||
|
||||
// place the legend
|
||||
nsRect actualLegendRect(mLegendRect);
|
||||
actualLegendRect.Deflate(legendMargin);
|
||||
nsPoint actualLegendPos(actualLegendRect.TopLeft());
|
||||
legendReflowState->ApplyRelativePositioning(&actualLegendPos);
|
||||
legend->SetPosition(actualLegendPos);
|
||||
LogicalRect actualLegendRect = mLegendRect;
|
||||
actualLegendRect.Deflate(wm, legendMargin);
|
||||
LogicalPoint actualLegendPos(actualLegendRect.Origin(wm));
|
||||
legendReflowState->ApplyRelativePositioning(&actualLegendPos, containerWidth);
|
||||
legend->SetPosition(wm, actualLegendPos, containerWidth);
|
||||
nsContainerFrame::PositionFrameView(legend);
|
||||
nsContainerFrame::PositionChildViews(legend);
|
||||
}
|
||||
|
||||
// Return our size and our result.
|
||||
WritingMode wm = aReflowState.GetWritingMode();
|
||||
nsSize finalSize(physicalContentRect.width + border.LeftRight(),
|
||||
mLegendSpace + border.TopBottom() +
|
||||
(inner ? inner->GetRect().height : 0));
|
||||
aDesiredSize.SetSize(wm, LogicalSize(wm, finalSize));
|
||||
LogicalSize finalSize(wm, contentRect.ISize(wm) + logBorder.IStartEnd(wm),
|
||||
mLegendSpace + logBorder.BStartEnd(wm) +
|
||||
(inner ? inner->GetLogicalSize(wm).BSize(wm) : 0));
|
||||
aDesiredSize.SetSize(wm, finalSize);
|
||||
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
||||
if (legend)
|
||||
|
||||
if (legend) {
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, legend);
|
||||
if (inner)
|
||||
}
|
||||
if (inner) {
|
||||
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inner);
|
||||
}
|
||||
|
||||
// Merge overflow container bounds and status.
|
||||
aDesiredSize.mOverflowAreas.UnionWith(ocBounds);
|
||||
|
@ -99,7 +99,7 @@ public:
|
||||
nsIFrame* GetLegend() const;
|
||||
|
||||
protected:
|
||||
nsRect mLegendRect;
|
||||
mozilla::LogicalRect mLegendRect;
|
||||
nscoord mLegendSpace;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user