no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / layout / forms / nsMeterFrame.cpp
bloba72a6816d5c6ff326e9fb9747639f30e63284d0b
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/. */
7 #include "nsMeterFrame.h"
9 #include "mozilla/PresShell.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/Element.h"
12 #include "mozilla/dom/HTMLMeterElement.h"
13 #include "nsIContent.h"
14 #include "nsLayoutUtils.h"
15 #include "nsPresContext.h"
16 #include "nsGkAtoms.h"
17 #include "nsNodeInfoManager.h"
18 #include "nsContentCreatorFunctions.h"
19 #include "nsFontMetrics.h"
20 #include <algorithm>
22 using namespace mozilla;
23 using mozilla::dom::Document;
24 using mozilla::dom::Element;
25 using mozilla::dom::HTMLMeterElement;
27 nsIFrame* NS_NewMeterFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
28 return new (aPresShell) nsMeterFrame(aStyle, aPresShell->GetPresContext());
31 NS_IMPL_FRAMEARENA_HELPERS(nsMeterFrame)
33 nsMeterFrame::nsMeterFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
34 : nsContainerFrame(aStyle, aPresContext, kClassID), mBarDiv(nullptr) {}
36 nsMeterFrame::~nsMeterFrame() = default;
38 void nsMeterFrame::Destroy(DestroyContext& aContext) {
39 NS_ASSERTION(!GetPrevContinuation(),
40 "nsMeterFrame should not have continuations; if it does we "
41 "need to call RegUnregAccessKey only for the first.");
42 aContext.AddAnonymousContent(mBarDiv.forget());
43 nsContainerFrame::Destroy(aContext);
46 nsresult nsMeterFrame::CreateAnonymousContent(
47 nsTArray<ContentInfo>& aElements) {
48 // Get the NodeInfoManager and tag necessary to create the meter bar div.
49 nsCOMPtr<Document> doc = mContent->GetComposedDoc();
51 // Create the div.
52 mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div);
54 // Associate the right pseudo-element to the anonymous child.
55 if (StaticPrefs::layout_css_modern_range_pseudos_enabled()) {
56 // TODO(emilio): Create also a slider-track pseudo-element.
57 mBarDiv->SetPseudoElementType(PseudoStyleType::sliderFill);
58 } else {
59 mBarDiv->SetPseudoElementType(PseudoStyleType::mozMeterBar);
62 aElements.AppendElement(mBarDiv);
64 return NS_OK;
67 void nsMeterFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
68 uint32_t aFilter) {
69 if (mBarDiv) {
70 aElements.AppendElement(mBarDiv);
74 NS_QUERYFRAME_HEAD(nsMeterFrame)
75 NS_QUERYFRAME_ENTRY(nsMeterFrame)
76 NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
77 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
79 void nsMeterFrame::Reflow(nsPresContext* aPresContext,
80 ReflowOutput& aDesiredSize,
81 const ReflowInput& aReflowInput,
82 nsReflowStatus& aStatus) {
83 MarkInReflow();
84 DO_GLOBAL_REFLOW_COUNT("nsMeterFrame");
85 DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
86 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
88 NS_ASSERTION(mBarDiv, "Meter bar div must exist!");
89 NS_ASSERTION(!GetPrevContinuation(),
90 "nsMeterFrame should not have continuations; if it does we "
91 "need to call RegUnregAccessKey only for the first.");
93 nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
94 NS_ASSERTION(barFrame, "The meter frame should have a child with a frame!");
96 ReflowBarFrame(barFrame, aPresContext, aReflowInput, aStatus);
98 const auto wm = aReflowInput.GetWritingMode();
99 aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
101 aDesiredSize.SetOverflowAreasToDesiredBounds();
102 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, barFrame);
103 FinishAndStoreOverflow(&aDesiredSize);
105 aStatus.Reset(); // This type of frame can't be split.
108 void nsMeterFrame::ReflowBarFrame(nsIFrame* aBarFrame,
109 nsPresContext* aPresContext,
110 const ReflowInput& aReflowInput,
111 nsReflowStatus& aStatus) {
112 bool vertical = ResolvedOrientationIsVertical();
113 WritingMode wm = aBarFrame->GetWritingMode();
114 LogicalSize availSize = aReflowInput.ComputedSize(wm);
115 availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
116 ReflowInput reflowInput(aPresContext, aReflowInput, aBarFrame, availSize);
117 nscoord size =
118 vertical ? aReflowInput.ComputedHeight() : aReflowInput.ComputedWidth();
119 nscoord xoffset = aReflowInput.ComputedPhysicalBorderPadding().left;
120 nscoord yoffset = aReflowInput.ComputedPhysicalBorderPadding().top;
122 auto* meterElement = static_cast<HTMLMeterElement*>(GetContent());
123 size = NSToCoordRound(size * meterElement->Position());
125 if (!vertical && wm.IsPhysicalRTL()) {
126 xoffset += aReflowInput.ComputedWidth() - size;
129 // The bar position is *always* constrained.
130 if (vertical) {
131 // We want the bar to begin at the bottom.
132 yoffset += aReflowInput.ComputedHeight() - size;
134 size -= reflowInput.ComputedPhysicalMargin().TopBottom() +
135 reflowInput.ComputedPhysicalBorderPadding().TopBottom();
136 size = std::max(size, 0);
137 reflowInput.SetComputedHeight(size);
138 } else {
139 size -= reflowInput.ComputedPhysicalMargin().LeftRight() +
140 reflowInput.ComputedPhysicalBorderPadding().LeftRight();
141 size = std::max(size, 0);
142 reflowInput.SetComputedWidth(size);
145 xoffset += reflowInput.ComputedPhysicalMargin().left;
146 yoffset += reflowInput.ComputedPhysicalMargin().top;
148 ReflowOutput barDesiredSize(reflowInput);
149 ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowInput, xoffset,
150 yoffset, ReflowChildFlags::Default, aStatus);
151 FinishReflowChild(aBarFrame, aPresContext, barDesiredSize, &reflowInput,
152 xoffset, yoffset, ReflowChildFlags::Default);
155 nsresult nsMeterFrame::AttributeChanged(int32_t aNameSpaceID,
156 nsAtom* aAttribute, int32_t aModType) {
157 NS_ASSERTION(mBarDiv, "Meter bar div must exist!");
159 if (aNameSpaceID == kNameSpaceID_None &&
160 (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max ||
161 aAttribute == nsGkAtoms::min)) {
162 nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
163 NS_ASSERTION(barFrame, "The meter frame should have a child with a frame!");
164 PresShell()->FrameNeedsReflow(barFrame, IntrinsicDirty::None,
165 NS_FRAME_IS_DIRTY);
166 InvalidateFrame();
169 return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
172 LogicalSize nsMeterFrame::ComputeAutoSize(
173 gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
174 nscoord aAvailableISize, const LogicalSize& aMargin,
175 const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
176 ComputeSizeFlags aFlags) {
177 RefPtr<nsFontMetrics> fontMet =
178 nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
180 const WritingMode wm = GetWritingMode();
181 LogicalSize autoSize(wm);
182 autoSize.BSize(wm) = autoSize.ISize(wm) =
183 fontMet->Font().size.ToAppUnits(); // 1em
185 if (ResolvedOrientationIsVertical() == wm.IsVertical()) {
186 autoSize.ISize(wm) *= 5; // 5em
187 } else {
188 autoSize.BSize(wm) *= 5; // 5em
191 return autoSize.ConvertTo(aWM, wm);
194 nscoord nsMeterFrame::GetMinISize(gfxContext* aRenderingContext) {
195 RefPtr<nsFontMetrics> fontMet =
196 nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
198 nscoord minISize = fontMet->Font().size.ToAppUnits(); // 1em
200 if (ResolvedOrientationIsVertical() == GetWritingMode().IsVertical()) {
201 // The orientation is inline
202 minISize *= 5; // 5em
205 return minISize;
208 nscoord nsMeterFrame::GetPrefISize(gfxContext* aRenderingContext) {
209 return GetMinISize(aRenderingContext);
212 bool nsMeterFrame::ShouldUseNativeStyle() const {
213 nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
215 // Use the native style if these conditions are satisfied:
216 // - both frames use the native appearance;
217 // - neither frame has author specified rules setting the border or the
218 // background.
219 return StyleDisplay()->EffectiveAppearance() == StyleAppearance::Meter &&
220 !Style()->HasAuthorSpecifiedBorderOrBackground() && barFrame &&
221 barFrame->StyleDisplay()->EffectiveAppearance() ==
222 StyleAppearance::Meterchunk &&
223 !barFrame->Style()->HasAuthorSpecifiedBorderOrBackground();