nsCheckboxRadioFrame.cpp (5531B)
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 #include "nsCheckboxRadioFrame.h" 8 9 #include "mozilla/PresShell.h" 10 #include "nsIContent.h" 11 #include "nsLayoutUtils.h" 12 13 using namespace mozilla; 14 15 nsCheckboxRadioFrame* NS_NewCheckboxRadioFrame(PresShell* aPresShell, 16 ComputedStyle* aStyle) { 17 return new (aPresShell) 18 nsCheckboxRadioFrame(aStyle, aPresShell->GetPresContext()); 19 } 20 21 nsCheckboxRadioFrame::nsCheckboxRadioFrame(ComputedStyle* aStyle, 22 nsPresContext* aPresContext) 23 : nsAtomicContainerFrame(aStyle, aPresContext, kClassID) {} 24 25 nsCheckboxRadioFrame::~nsCheckboxRadioFrame() = default; 26 27 NS_IMPL_FRAMEARENA_HELPERS(nsCheckboxRadioFrame) 28 29 NS_QUERYFRAME_HEAD(nsCheckboxRadioFrame) 30 NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame) 31 32 nscoord nsCheckboxRadioFrame::DefaultSize() { 33 const CSSCoord size = StyleDisplay()->HasAppearance() 34 ? PresContext()->Theme()->GetCheckboxRadioPrefSize() 35 : CSSCoord(13.0f); 36 return CSSPixel::ToAppUnits(Style()->EffectiveZoom().Zoom(size)); 37 } 38 39 /* virtual */ 40 void nsCheckboxRadioFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, 41 const nsDisplayListSet& aLists) { 42 DO_GLOBAL_REFLOW_COUNT_DSP("nsCheckboxRadioFrame"); 43 DisplayBorderBackgroundOutline(aBuilder, aLists); 44 } 45 46 nscoord nsCheckboxRadioFrame::IntrinsicISize(const IntrinsicSizeInput& aInput, 47 IntrinsicISizeType aType) { 48 return StyleDisplay()->HasAppearance() ? DefaultSize() : 0; 49 } 50 51 /* virtual */ 52 LogicalSize nsCheckboxRadioFrame::ComputeAutoSize( 53 const SizeComputationInput& aSizingInput, WritingMode aWM, 54 const LogicalSize& aCBSize, nscoord aAvailableISize, 55 const LogicalSize& aMargin, const LogicalSize& aBorderPadding, 56 const StyleSizeOverrides& aSizeOverrides, ComputeSizeFlags aFlags) { 57 LogicalSize size(aWM, 0, 0); 58 if (!StyleDisplay()->HasAppearance()) { 59 return size; 60 } 61 return nsAtomicContainerFrame::ComputeAutoSize( 62 aSizingInput, aWM, aCBSize, aAvailableISize, aMargin, aBorderPadding, 63 aSizeOverrides, aFlags); 64 } 65 66 Maybe<nscoord> nsCheckboxRadioFrame::GetNaturalBaselineBOffset( 67 WritingMode aWM, BaselineSharingGroup aBaselineGroup, 68 BaselineExportContext) const { 69 NS_ASSERTION(!IsSubtreeDirty(), "frame must not be dirty"); 70 71 if (aBaselineGroup == BaselineSharingGroup::Last) { 72 return Nothing{}; 73 } 74 75 if (StyleDisplay()->IsBlockOutsideStyle()) { 76 return Nothing{}; 77 } 78 79 // For appearance:none we use a standard CSS baseline, i.e. synthesized from 80 // our margin-box. 81 if (!StyleDisplay()->HasAppearance()) { 82 return Nothing{}; 83 } 84 85 if (aWM.IsCentralBaseline()) { 86 return Some(BSize(aWM) / 2); 87 } 88 89 // This is for compatibility with Chrome, Safari and Edge (Dec 2016). 90 // Treat radio buttons and checkboxes as having an intrinsic baseline 91 // at the block-end of the control (use the block-end content edge rather 92 // than the margin edge). 93 // For "inverted" lines (typically in writing-mode:vertical-lr), use the 94 // block-start end instead. 95 // See kCheckboxRadioBorderWidth in Theme.cpp 96 CSSCoord border = PresContext()->Theme()->GetCheckboxRadioBorderWidth(); 97 auto bp = CSSPixel::ToAppUnits(Style()->EffectiveZoom().Zoom(border)); 98 return Some(aWM.IsLineInverted() ? std::min(bp, BSize(aWM)) 99 : std::max(0, BSize(aWM) - bp)); 100 } 101 102 void nsCheckboxRadioFrame::Reflow(nsPresContext* aPresContext, 103 ReflowOutput& aDesiredSize, 104 const ReflowInput& aReflowInput, 105 nsReflowStatus& aStatus) { 106 MarkInReflow(); 107 DO_GLOBAL_REFLOW_COUNT("nsCheckboxRadioFrame"); 108 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); 109 NS_FRAME_TRACE( 110 NS_FRAME_TRACE_CALLS, 111 ("enter nsCheckboxRadioFrame::Reflow: aMaxSize=%d,%d", 112 aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight())); 113 114 const auto wm = aReflowInput.GetWritingMode(); 115 MOZ_ASSERT(aReflowInput.ComputedLogicalBorderPadding(wm).IsAllZero()); 116 117 const auto contentBoxSize = 118 aReflowInput.ComputedSizeWithBSizeFallback([&] { return DefaultSize(); }); 119 aDesiredSize.SetSize(wm, contentBoxSize); 120 if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) { 121 const float inflation = nsLayoutUtils::FontSizeInflationFor(this); 122 aDesiredSize.Width() *= inflation; 123 aDesiredSize.Height() *= inflation; 124 } 125 126 NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, 127 ("exit nsCheckboxRadioFrame::Reflow: size=%d,%d", 128 aDesiredSize.Width(), aDesiredSize.Height())); 129 130 aDesiredSize.SetOverflowAreasToDesiredBounds(); 131 FinishAndStoreOverflow(&aDesiredSize); 132 } 133 134 nsresult nsCheckboxRadioFrame::HandleEvent(nsPresContext* aPresContext, 135 WidgetGUIEvent* aEvent, 136 nsEventStatus* aEventStatus) { 137 // Check for disabled content so that selection works properly (?). 138 if (IsContentDisabled()) { 139 return nsIFrame::HandleEvent(aPresContext, aEvent, aEventStatus); 140 } 141 return NS_OK; 142 }