layout/forms/nsMeterFrame.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsMeterFrame.h"
michael@0 7
michael@0 8 #include "nsIContent.h"
michael@0 9 #include "nsPresContext.h"
michael@0 10 #include "nsGkAtoms.h"
michael@0 11 #include "nsNameSpaceManager.h"
michael@0 12 #include "nsIDocument.h"
michael@0 13 #include "nsIPresShell.h"
michael@0 14 #include "nsNodeInfoManager.h"
michael@0 15 #include "nsINodeInfo.h"
michael@0 16 #include "nsContentCreatorFunctions.h"
michael@0 17 #include "nsContentUtils.h"
michael@0 18 #include "nsFormControlFrame.h"
michael@0 19 #include "nsFontMetrics.h"
michael@0 20 #include "mozilla/dom/Element.h"
michael@0 21 #include "mozilla/dom/HTMLMeterElement.h"
michael@0 22 #include "nsContentList.h"
michael@0 23 #include "nsStyleSet.h"
michael@0 24 #include "nsThemeConstants.h"
michael@0 25 #include <algorithm>
michael@0 26
michael@0 27 using mozilla::dom::Element;
michael@0 28 using mozilla::dom::HTMLMeterElement;
michael@0 29
michael@0 30 nsIFrame*
michael@0 31 NS_NewMeterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 32 {
michael@0 33 return new (aPresShell) nsMeterFrame(aContext);
michael@0 34 }
michael@0 35
michael@0 36 NS_IMPL_FRAMEARENA_HELPERS(nsMeterFrame)
michael@0 37
michael@0 38 nsMeterFrame::nsMeterFrame(nsStyleContext* aContext)
michael@0 39 : nsContainerFrame(aContext)
michael@0 40 , mBarDiv(nullptr)
michael@0 41 {
michael@0 42 }
michael@0 43
michael@0 44 nsMeterFrame::~nsMeterFrame()
michael@0 45 {
michael@0 46 }
michael@0 47
michael@0 48 void
michael@0 49 nsMeterFrame::DestroyFrom(nsIFrame* aDestructRoot)
michael@0 50 {
michael@0 51 NS_ASSERTION(!GetPrevContinuation(),
michael@0 52 "nsMeterFrame should not have continuations; if it does we "
michael@0 53 "need to call RegUnregAccessKey only for the first.");
michael@0 54 nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
michael@0 55 nsContentUtils::DestroyAnonymousContent(&mBarDiv);
michael@0 56 nsContainerFrame::DestroyFrom(aDestructRoot);
michael@0 57 }
michael@0 58
michael@0 59 nsresult
michael@0 60 nsMeterFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
michael@0 61 {
michael@0 62 // Get the NodeInfoManager and tag necessary to create the meter bar div.
michael@0 63 nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
michael@0 64
michael@0 65 // Create the div.
michael@0 66 mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div);
michael@0 67
michael@0 68 // Associate ::-moz-meter-bar pseudo-element to the anonymous child.
michael@0 69 nsCSSPseudoElements::Type pseudoType = nsCSSPseudoElements::ePseudo_mozMeterBar;
michael@0 70 nsRefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
michael@0 71 ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
michael@0 72 StyleContext(), mBarDiv->AsElement());
michael@0 73
michael@0 74 if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
michael@0 75 return NS_ERROR_OUT_OF_MEMORY;
michael@0 76 }
michael@0 77
michael@0 78 return NS_OK;
michael@0 79 }
michael@0 80
michael@0 81 void
michael@0 82 nsMeterFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
michael@0 83 uint32_t aFilter)
michael@0 84 {
michael@0 85 aElements.MaybeAppendElement(mBarDiv);
michael@0 86 }
michael@0 87
michael@0 88 NS_QUERYFRAME_HEAD(nsMeterFrame)
michael@0 89 NS_QUERYFRAME_ENTRY(nsMeterFrame)
michael@0 90 NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
michael@0 91 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
michael@0 92
michael@0 93
michael@0 94 nsresult nsMeterFrame::Reflow(nsPresContext* aPresContext,
michael@0 95 nsHTMLReflowMetrics& aDesiredSize,
michael@0 96 const nsHTMLReflowState& aReflowState,
michael@0 97 nsReflowStatus& aStatus)
michael@0 98 {
michael@0 99 DO_GLOBAL_REFLOW_COUNT("nsMeterFrame");
michael@0 100 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
michael@0 101
michael@0 102 NS_ASSERTION(mBarDiv, "Meter bar div must exist!");
michael@0 103 NS_ASSERTION(!GetPrevContinuation(),
michael@0 104 "nsMeterFrame should not have continuations; if it does we "
michael@0 105 "need to call RegUnregAccessKey only for the first.");
michael@0 106
michael@0 107 if (mState & NS_FRAME_FIRST_REFLOW) {
michael@0 108 nsFormControlFrame::RegUnRegAccessKey(this, true);
michael@0 109 }
michael@0 110
michael@0 111 nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
michael@0 112 NS_ASSERTION(barFrame, "The meter frame should have a child with a frame!");
michael@0 113
michael@0 114 ReflowBarFrame(barFrame, aPresContext, aReflowState, aStatus);
michael@0 115
michael@0 116 aDesiredSize.Width() = aReflowState.ComputedWidth() +
michael@0 117 aReflowState.ComputedPhysicalBorderPadding().LeftRight();
michael@0 118 aDesiredSize.Height() = aReflowState.ComputedHeight() +
michael@0 119 aReflowState.ComputedPhysicalBorderPadding().TopBottom();
michael@0 120
michael@0 121 aDesiredSize.SetOverflowAreasToDesiredBounds();
michael@0 122 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, barFrame);
michael@0 123 FinishAndStoreOverflow(&aDesiredSize);
michael@0 124
michael@0 125 aStatus = NS_FRAME_COMPLETE;
michael@0 126
michael@0 127 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
michael@0 128
michael@0 129 return NS_OK;
michael@0 130 }
michael@0 131
michael@0 132 void
michael@0 133 nsMeterFrame::ReflowBarFrame(nsIFrame* aBarFrame,
michael@0 134 nsPresContext* aPresContext,
michael@0 135 const nsHTMLReflowState& aReflowState,
michael@0 136 nsReflowStatus& aStatus)
michael@0 137 {
michael@0 138 bool vertical = StyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL;
michael@0 139 nsHTMLReflowState reflowState(aPresContext, aReflowState, aBarFrame,
michael@0 140 nsSize(aReflowState.ComputedWidth(),
michael@0 141 NS_UNCONSTRAINEDSIZE));
michael@0 142 nscoord size = vertical ? aReflowState.ComputedHeight()
michael@0 143 : aReflowState.ComputedWidth();
michael@0 144 nscoord xoffset = aReflowState.ComputedPhysicalBorderPadding().left;
michael@0 145 nscoord yoffset = aReflowState.ComputedPhysicalBorderPadding().top;
michael@0 146
michael@0 147 // NOTE: Introduce a new function getPosition in the content part ?
michael@0 148 HTMLMeterElement* meterElement = static_cast<HTMLMeterElement*>(mContent);
michael@0 149
michael@0 150 double max = meterElement->Max();
michael@0 151 double min = meterElement->Min();
michael@0 152 double value = meterElement->Value();
michael@0 153
michael@0 154 double position = max - min;
michael@0 155 position = position != 0 ? (value - min) / position : 1;
michael@0 156
michael@0 157 size = NSToCoordRound(size * position);
michael@0 158
michael@0 159 if (!vertical && StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
michael@0 160 xoffset += aReflowState.ComputedWidth() - size;
michael@0 161 }
michael@0 162
michael@0 163 // The bar position is *always* constrained.
michael@0 164 if (vertical) {
michael@0 165 // We want the bar to begin at the bottom.
michael@0 166 yoffset += aReflowState.ComputedHeight() - size;
michael@0 167
michael@0 168 size -= reflowState.ComputedPhysicalMargin().TopBottom() +
michael@0 169 reflowState.ComputedPhysicalBorderPadding().TopBottom();
michael@0 170 size = std::max(size, 0);
michael@0 171 reflowState.SetComputedHeight(size);
michael@0 172 } else {
michael@0 173 size -= reflowState.ComputedPhysicalMargin().LeftRight() +
michael@0 174 reflowState.ComputedPhysicalBorderPadding().LeftRight();
michael@0 175 size = std::max(size, 0);
michael@0 176 reflowState.SetComputedWidth(size);
michael@0 177 }
michael@0 178
michael@0 179 xoffset += reflowState.ComputedPhysicalMargin().left;
michael@0 180 yoffset += reflowState.ComputedPhysicalMargin().top;
michael@0 181
michael@0 182 nsHTMLReflowMetrics barDesiredSize(reflowState);
michael@0 183 ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowState, xoffset,
michael@0 184 yoffset, 0, aStatus);
michael@0 185 FinishReflowChild(aBarFrame, aPresContext, barDesiredSize, &reflowState,
michael@0 186 xoffset, yoffset, 0);
michael@0 187 }
michael@0 188
michael@0 189 nsresult
michael@0 190 nsMeterFrame::AttributeChanged(int32_t aNameSpaceID,
michael@0 191 nsIAtom* aAttribute,
michael@0 192 int32_t aModType)
michael@0 193 {
michael@0 194 NS_ASSERTION(mBarDiv, "Meter bar div must exist!");
michael@0 195
michael@0 196 if (aNameSpaceID == kNameSpaceID_None &&
michael@0 197 (aAttribute == nsGkAtoms::value ||
michael@0 198 aAttribute == nsGkAtoms::max ||
michael@0 199 aAttribute == nsGkAtoms::min )) {
michael@0 200 nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
michael@0 201 NS_ASSERTION(barFrame, "The meter frame should have a child with a frame!");
michael@0 202 PresContext()->PresShell()->FrameNeedsReflow(barFrame,
michael@0 203 nsIPresShell::eResize,
michael@0 204 NS_FRAME_IS_DIRTY);
michael@0 205 InvalidateFrame();
michael@0 206 }
michael@0 207
michael@0 208 return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute,
michael@0 209 aModType);
michael@0 210 }
michael@0 211
michael@0 212 nsSize
michael@0 213 nsMeterFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
michael@0 214 nsSize aCBSize, nscoord aAvailableWidth,
michael@0 215 nsSize aMargin, nsSize aBorder,
michael@0 216 nsSize aPadding, bool aShrinkWrap)
michael@0 217 {
michael@0 218 nsRefPtr<nsFontMetrics> fontMet;
michael@0 219 NS_ENSURE_SUCCESS(nsLayoutUtils::GetFontMetricsForFrame(this,
michael@0 220 getter_AddRefs(fontMet)),
michael@0 221 nsSize(0, 0));
michael@0 222
michael@0 223 nsSize autoSize;
michael@0 224 autoSize.height = autoSize.width = fontMet->Font().size; // 1em
michael@0 225
michael@0 226 if (StyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL) {
michael@0 227 autoSize.height *= 5; // 5em
michael@0 228 } else {
michael@0 229 autoSize.width *= 5; // 5em
michael@0 230 }
michael@0 231
michael@0 232 return autoSize;
michael@0 233 }
michael@0 234
michael@0 235 nscoord
michael@0 236 nsMeterFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
michael@0 237 {
michael@0 238 nsRefPtr<nsFontMetrics> fontMet;
michael@0 239 NS_ENSURE_SUCCESS(
michael@0 240 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet)), 0);
michael@0 241
michael@0 242 nscoord minWidth = fontMet->Font().size; // 1em
michael@0 243
michael@0 244 if (StyleDisplay()->mOrient == NS_STYLE_ORIENT_AUTO ||
michael@0 245 StyleDisplay()->mOrient == NS_STYLE_ORIENT_HORIZONTAL) {
michael@0 246 // The orientation is horizontal
michael@0 247 minWidth *= 5; // 5em
michael@0 248 }
michael@0 249
michael@0 250 return minWidth;
michael@0 251 }
michael@0 252
michael@0 253 nscoord
michael@0 254 nsMeterFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
michael@0 255 {
michael@0 256 return GetMinWidth(aRenderingContext);
michael@0 257 }
michael@0 258
michael@0 259 bool
michael@0 260 nsMeterFrame::ShouldUseNativeStyle() const
michael@0 261 {
michael@0 262 // Use the native style if these conditions are satisfied:
michael@0 263 // - both frames use the native appearance;
michael@0 264 // - neither frame has author specified rules setting the border or the
michael@0 265 // background.
michael@0 266 return StyleDisplay()->mAppearance == NS_THEME_METERBAR &&
michael@0 267 mBarDiv->GetPrimaryFrame()->StyleDisplay()->mAppearance == NS_THEME_METERBAR_CHUNK &&
michael@0 268 !PresContext()->HasAuthorSpecifiedRules(const_cast<nsMeterFrame*>(this),
michael@0 269 NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND) &&
michael@0 270 !PresContext()->HasAuthorSpecifiedRules(mBarDiv->GetPrimaryFrame(),
michael@0 271 NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND);
michael@0 272 }
michael@0 273
michael@0 274 Element*
michael@0 275 nsMeterFrame::GetPseudoElement(nsCSSPseudoElements::Type aType)
michael@0 276 {
michael@0 277 if (aType == nsCSSPseudoElements::ePseudo_mozMeterBar) {
michael@0 278 return mBarDiv;
michael@0 279 }
michael@0 280
michael@0 281 return nsContainerFrame::GetPseudoElement(aType);
michael@0 282 }

mercurial