nsDateTimeControlFrame.cpp (6896B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /** 8 * This frame type is used for input type=date, time, month, week, and 9 * datetime-local. 10 */ 11 12 #include "nsDateTimeControlFrame.h" 13 14 #include "mozilla/PresShell.h" 15 #include "nsLayoutUtils.h" 16 #include "nsTextControlFrame.h" 17 18 using namespace mozilla; 19 using namespace mozilla::dom; 20 21 nsIFrame* NS_NewDateTimeControlFrame(PresShell* aPresShell, 22 ComputedStyle* aStyle) { 23 return new (aPresShell) 24 nsDateTimeControlFrame(aStyle, aPresShell->GetPresContext()); 25 } 26 27 NS_IMPL_FRAMEARENA_HELPERS(nsDateTimeControlFrame) 28 29 NS_QUERYFRAME_HEAD(nsDateTimeControlFrame) 30 NS_QUERYFRAME_ENTRY(nsDateTimeControlFrame) 31 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) 32 33 nsDateTimeControlFrame::nsDateTimeControlFrame(ComputedStyle* aStyle, 34 nsPresContext* aPresContext) 35 : nsContainerFrame(aStyle, aPresContext, kClassID) {} 36 37 nscoord nsDateTimeControlFrame::IntrinsicISize(const IntrinsicSizeInput& aInput, 38 IntrinsicISizeType aType) { 39 return mFrames.IsEmpty() ? 0 40 : nsLayoutUtils::IntrinsicForContainer( 41 aInput.mContext, mFrames.FirstChild(), aType); 42 } 43 44 Maybe<nscoord> nsDateTimeControlFrame::GetNaturalBaselineBOffset( 45 WritingMode aWM, BaselineSharingGroup aBaselineGroup, 46 BaselineExportContext) const { 47 return nsTextControlFrame::GetSingleLineTextControlBaseline( 48 this, mFirstBaseline, aWM, aBaselineGroup); 49 } 50 51 void nsDateTimeControlFrame::Reflow(nsPresContext* aPresContext, 52 ReflowOutput& aDesiredSize, 53 const ReflowInput& aReflowInput, 54 nsReflowStatus& aStatus) { 55 MarkInReflow(); 56 57 DO_GLOBAL_REFLOW_COUNT("nsDateTimeControlFrame"); 58 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); 59 NS_FRAME_TRACE( 60 NS_FRAME_TRACE_CALLS, 61 ("enter nsDateTimeControlFrame::Reflow: availSize=%d,%d", 62 aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight())); 63 64 NS_ASSERTION(mFrames.GetLength() <= 1, 65 "There should be no more than 1 frames"); 66 67 const WritingMode myWM = aReflowInput.GetWritingMode(); 68 69 { 70 auto baseline = nsTextControlFrame::ComputeBaseline( 71 this, aReflowInput, /* aForSingleLineControl = */ true); 72 mFirstBaseline = baseline.valueOr(NS_INTRINSIC_ISIZE_UNKNOWN); 73 if (baseline) { 74 aDesiredSize.SetBlockStartAscent(*baseline); 75 } 76 } 77 78 // The ISize of our content box, which is the available ISize 79 // for our anonymous content: 80 const nscoord contentBoxISize = aReflowInput.ComputedISize(); 81 nscoord contentBoxBSize = aReflowInput.ComputedBSize(); 82 83 // Figure out our border-box sizes as well (by adding borderPadding to 84 // content-box sizes): 85 const auto borderPadding = aReflowInput.ComputedLogicalBorderPadding(myWM); 86 const nscoord borderBoxISize = 87 contentBoxISize + borderPadding.IStartEnd(myWM); 88 89 nscoord borderBoxBSize; 90 if (contentBoxBSize != NS_UNCONSTRAINEDSIZE) { 91 borderBoxBSize = contentBoxBSize + borderPadding.BStartEnd(myWM); 92 } // else, we'll figure out borderBoxBSize after we resolve contentBoxBSize. 93 94 nsIFrame* inputAreaFrame = mFrames.FirstChild(); 95 if (!inputAreaFrame) { // display:none? 96 if (contentBoxBSize == NS_UNCONSTRAINEDSIZE) { 97 contentBoxBSize = 0; 98 borderBoxBSize = borderPadding.BStartEnd(myWM); 99 } 100 } else { 101 ReflowOutput childDesiredSize(aReflowInput); 102 103 WritingMode wm = inputAreaFrame->GetWritingMode(); 104 LogicalSize availSize = aReflowInput.ComputedSize(wm); 105 availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE; 106 107 ReflowInput childReflowInput(aPresContext, aReflowInput, inputAreaFrame, 108 availSize); 109 110 // Convert input area margin into my own writing-mode (in case it differs): 111 LogicalMargin childMargin = childReflowInput.ComputedLogicalMargin(myWM); 112 113 // offsets of input area frame within this frame: 114 LogicalPoint childOffset = 115 borderPadding.StartOffset(myWM) + childMargin.StartOffset(myWM); 116 117 nsReflowStatus childStatus; 118 // We initially reflow the child with a dummy containerSize; positioning 119 // will be fixed later. 120 const nsSize dummyContainerSize; 121 ReflowChild(inputAreaFrame, aPresContext, childDesiredSize, 122 childReflowInput, myWM, childOffset, dummyContainerSize, 123 ReflowChildFlags::Default, childStatus); 124 MOZ_ASSERT(childStatus.IsFullyComplete(), 125 "We gave our child unconstrained available block-size, " 126 "so it should be complete"); 127 128 nscoord childMarginBoxBSize = 129 childDesiredSize.BSize(myWM) + childMargin.BStartEnd(myWM); 130 131 if (contentBoxBSize == NS_UNCONSTRAINEDSIZE) { 132 // We are intrinsically sized -- we should shrinkwrap the input area's 133 // block-size, or our line-height: 134 contentBoxBSize = 135 std::max(aReflowInput.GetLineHeight(), childMarginBoxBSize); 136 137 // Make sure we obey min/max-bsize in the case when we're doing intrinsic 138 // sizing (we get it for free when we have a non-intrinsic 139 // aReflowInput.ComputedBSize()). Note that we do this before 140 // adjusting for borderpadding, since ComputedMaxBSize and 141 // ComputedMinBSize are content heights. 142 contentBoxBSize = aReflowInput.ApplyMinMaxBSize(contentBoxBSize); 143 144 borderBoxBSize = contentBoxBSize + borderPadding.BStartEnd(myWM); 145 } 146 147 // Center child in block axis 148 nscoord extraSpace = contentBoxBSize - childMarginBoxBSize; 149 childOffset.B(myWM) += std::max(0, extraSpace / 2); 150 151 // Needed in FinishReflowChild, for logical-to-physical conversion: 152 nsSize borderBoxSize = 153 LogicalSize(myWM, borderBoxISize, borderBoxBSize).GetPhysicalSize(myWM); 154 155 // Place the child 156 FinishReflowChild(inputAreaFrame, aPresContext, childDesiredSize, 157 &childReflowInput, myWM, childOffset, borderBoxSize, 158 ReflowChildFlags::Default); 159 } 160 161 LogicalSize logicalDesiredSize(myWM, borderBoxISize, borderBoxBSize); 162 aDesiredSize.SetSize(myWM, logicalDesiredSize); 163 aDesiredSize.SetOverflowAreasToDesiredBounds(); 164 165 if (inputAreaFrame) { 166 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, inputAreaFrame); 167 } 168 169 FinishAndStoreOverflow(&aDesiredSize); 170 171 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, 172 ("exit nsDateTimeControlFrame::Reflow: size=%d,%d", 173 aDesiredSize.Width(), aDesiredSize.Height())); 174 }