gecko-dev/layout/forms/nsDateTimeControlFrame.cpp

204 строки
7.5 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This frame type is used for input type=date, time, month, week, and
* datetime-local.
*/
#include "nsDateTimeControlFrame.h"
#include "mozilla/PresShell.h"
#include "nsLayoutUtils.h"
#include "nsTextControlFrame.h"
using namespace mozilla;
using namespace mozilla::dom;
nsIFrame* NS_NewDateTimeControlFrame(PresShell* aPresShell,
ComputedStyle* aStyle) {
return new (aPresShell)
nsDateTimeControlFrame(aStyle, aPresShell->GetPresContext());
}
NS_IMPL_FRAMEARENA_HELPERS(nsDateTimeControlFrame)
NS_QUERYFRAME_HEAD(nsDateTimeControlFrame)
NS_QUERYFRAME_ENTRY(nsDateTimeControlFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
nsDateTimeControlFrame::nsDateTimeControlFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext)
: nsContainerFrame(aStyle, aPresContext, kClassID) {}
nscoord nsDateTimeControlFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord result;
DISPLAY_MIN_INLINE_SIZE(this, result);
nsIFrame* kid = mFrames.FirstChild();
if (kid) { // display:none?
result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, kid,
IntrinsicISizeType::MinISize);
} else {
result = 0;
}
return result;
}
nscoord nsDateTimeControlFrame::GetPrefISize(gfxContext* aRenderingContext) {
nscoord result;
DISPLAY_PREF_INLINE_SIZE(this, result);
nsIFrame* kid = mFrames.FirstChild();
if (kid) { // display:none?
result = nsLayoutUtils::IntrinsicForContainer(
aRenderingContext, kid, IntrinsicISizeType::PrefISize);
} else {
result = 0;
}
return result;
}
bool nsDateTimeControlFrame::GetNaturalBaselineBOffset(
mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup,
nscoord* aBaseline) const {
return nsTextControlFrame::GetSingleLineTextControlBaseline(
this, mFirstBaseline, aWM, aBaselineGroup, aBaseline);
}
void nsDateTimeControlFrame::Reflow(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsDateTimeControlFrame");
DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE(
NS_FRAME_TRACE_CALLS,
("enter nsDateTimeControlFrame::Reflow: availSize=%d,%d",
aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
NS_ASSERTION(mFrames.GetLength() <= 1,
"There should be no more than 1 frames");
const WritingMode myWM = aReflowInput.GetWritingMode();
{
auto baseline = nsTextControlFrame::ComputeBaseline(
this, aReflowInput, /* aForSingleLineControl = */ true);
mFirstBaseline = baseline.valueOr(NS_INTRINSIC_ISIZE_UNKNOWN);
if (baseline) {
aDesiredSize.SetBlockStartAscent(*baseline);
}
}
// The ISize of our content box, which is the available ISize
// for our anonymous content:
const nscoord contentBoxISize = aReflowInput.ComputedISize();
nscoord contentBoxBSize = aReflowInput.ComputedBSize();
// Figure out our border-box sizes as well (by adding borderPadding to
// content-box sizes):
const auto borderPadding = aReflowInput.ComputedLogicalBorderPadding(myWM);
const nscoord borderBoxISize =
contentBoxISize + borderPadding.IStartEnd(myWM);
nscoord borderBoxBSize;
if (contentBoxBSize != NS_UNCONSTRAINEDSIZE) {
borderBoxBSize = contentBoxBSize + borderPadding.BStartEnd(myWM);
} // else, we'll figure out borderBoxBSize after we resolve contentBoxBSize.
nsIFrame* inputAreaFrame = mFrames.FirstChild();
if (!inputAreaFrame) { // display:none?
if (contentBoxBSize == NS_UNCONSTRAINEDSIZE) {
contentBoxBSize = 0;
borderBoxBSize = borderPadding.BStartEnd(myWM);
}
} else {
ReflowOutput childDesiredSize(aReflowInput);
WritingMode wm = inputAreaFrame->GetWritingMode();
LogicalSize availSize = aReflowInput.ComputedSize(wm);
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
ReflowInput childReflowInput(aPresContext, aReflowInput, inputAreaFrame,
availSize);
// Convert input area margin into my own writing-mode (in case it differs):
LogicalMargin childMargin = childReflowInput.ComputedLogicalMargin(myWM);
// offsets of input area frame within this frame:
LogicalPoint childOffset(
myWM, borderPadding.IStart(myWM) + childMargin.IStart(myWM),
borderPadding.BStart(myWM) + childMargin.BStart(myWM));
nsReflowStatus childStatus;
// We initially reflow the child with a dummy containerSize; positioning
// will be fixed later.
const nsSize dummyContainerSize;
ReflowChild(inputAreaFrame, aPresContext, childDesiredSize,
childReflowInput, myWM, childOffset, dummyContainerSize,
ReflowChildFlags::Default, childStatus);
MOZ_ASSERT(childStatus.IsFullyComplete(),
"We gave our child unconstrained available block-size, "
"so it should be complete");
nscoord childMarginBoxBSize =
childDesiredSize.BSize(myWM) + childMargin.BStartEnd(myWM);
if (contentBoxBSize == NS_UNCONSTRAINEDSIZE) {
// We are intrinsically sized -- we should shrinkwrap the input area's
// block-size, or our line-height:
contentBoxBSize =
std::max(aReflowInput.GetLineHeight(), childMarginBoxBSize);
// Make sure we obey min/max-bsize in the case when we're doing intrinsic
// sizing (we get it for free when we have a non-intrinsic
// aReflowInput.ComputedBSize()). Note that we do this before
// adjusting for borderpadding, since ComputedMaxBSize and
// ComputedMinBSize are content heights.
contentBoxBSize =
NS_CSS_MINMAX(contentBoxBSize, aReflowInput.ComputedMinBSize(),
aReflowInput.ComputedMaxBSize());
borderBoxBSize = contentBoxBSize + borderPadding.BStartEnd(myWM);
}
// Center child in block axis
nscoord extraSpace = contentBoxBSize - childMarginBoxBSize;
childOffset.B(myWM) += std::max(0, extraSpace / 2);
// Needed in FinishReflowChild, for logical-to-physical conversion:
nsSize borderBoxSize =
LogicalSize(myWM, borderBoxISize, borderBoxBSize).GetPhysicalSize(myWM);
// Place the child
FinishReflowChild(inputAreaFrame, aPresContext, childDesiredSize,
&childReflowInput, myWM, childOffset, borderBoxSize,
ReflowChildFlags::Default);
}
LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize);
aDesiredSize.SetSize(myWM, logicalDesiredSize);
aDesiredSize.SetOverflowAreasToDesiredBounds();
if (inputAreaFrame) {
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inputAreaFrame);
}
FinishAndStoreOverflow(&aDesiredSize);
NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS,
("exit nsDateTimeControlFrame::Reflow: size=%d,%d",
aDesiredSize.Width(), aDesiredSize.Height()));
NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
}