layout/forms/nsProgressFrame.cpp

Wed, 31 Dec 2014 13:27:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 13:27:57 +0100
branch
TOR_BUG_3246
changeset 6
8bccb770b82d
permissions
-rw-r--r--

Ignore runtime configuration files generated during quality assurance.

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 "nsProgressFrame.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/HTMLProgressElement.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 namespace mozilla::dom;
michael@0 28
michael@0 29 nsIFrame*
michael@0 30 NS_NewProgressFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
michael@0 31 {
michael@0 32 return new (aPresShell) nsProgressFrame(aContext);
michael@0 33 }
michael@0 34
michael@0 35 NS_IMPL_FRAMEARENA_HELPERS(nsProgressFrame)
michael@0 36
michael@0 37 nsProgressFrame::nsProgressFrame(nsStyleContext* aContext)
michael@0 38 : nsContainerFrame(aContext)
michael@0 39 , mBarDiv(nullptr)
michael@0 40 {
michael@0 41 }
michael@0 42
michael@0 43 nsProgressFrame::~nsProgressFrame()
michael@0 44 {
michael@0 45 }
michael@0 46
michael@0 47 void
michael@0 48 nsProgressFrame::DestroyFrom(nsIFrame* aDestructRoot)
michael@0 49 {
michael@0 50 NS_ASSERTION(!GetPrevContinuation(),
michael@0 51 "nsProgressFrame should not have continuations; if it does we "
michael@0 52 "need to call RegUnregAccessKey only for the first.");
michael@0 53 nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
michael@0 54 nsContentUtils::DestroyAnonymousContent(&mBarDiv);
michael@0 55 nsContainerFrame::DestroyFrom(aDestructRoot);
michael@0 56 }
michael@0 57
michael@0 58 nsresult
michael@0 59 nsProgressFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
michael@0 60 {
michael@0 61 // Create the progress bar div.
michael@0 62 nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
michael@0 63 mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div);
michael@0 64
michael@0 65 // Associate ::-moz-progress-bar pseudo-element to the anonymous child.
michael@0 66 nsCSSPseudoElements::Type pseudoType = nsCSSPseudoElements::ePseudo_mozProgressBar;
michael@0 67 nsRefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
michael@0 68 ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
michael@0 69 StyleContext(), mBarDiv->AsElement());
michael@0 70
michael@0 71 if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
michael@0 72 return NS_ERROR_OUT_OF_MEMORY;
michael@0 73 }
michael@0 74
michael@0 75 return NS_OK;
michael@0 76 }
michael@0 77
michael@0 78 void
michael@0 79 nsProgressFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
michael@0 80 uint32_t aFilter)
michael@0 81 {
michael@0 82 aElements.MaybeAppendElement(mBarDiv);
michael@0 83 }
michael@0 84
michael@0 85 NS_QUERYFRAME_HEAD(nsProgressFrame)
michael@0 86 NS_QUERYFRAME_ENTRY(nsProgressFrame)
michael@0 87 NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
michael@0 88 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
michael@0 89
michael@0 90
michael@0 91 void
michael@0 92 nsProgressFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
michael@0 93 const nsRect& aDirtyRect,
michael@0 94 const nsDisplayListSet& aLists)
michael@0 95 {
michael@0 96 BuildDisplayListForInline(aBuilder, aDirtyRect, aLists);
michael@0 97 }
michael@0 98
michael@0 99 nsresult nsProgressFrame::Reflow(nsPresContext* aPresContext,
michael@0 100 nsHTMLReflowMetrics& aDesiredSize,
michael@0 101 const nsHTMLReflowState& aReflowState,
michael@0 102 nsReflowStatus& aStatus)
michael@0 103 {
michael@0 104 DO_GLOBAL_REFLOW_COUNT("nsProgressFrame");
michael@0 105 DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
michael@0 106
michael@0 107 NS_ASSERTION(mBarDiv, "Progress bar div must exist!");
michael@0 108 NS_ASSERTION(!GetPrevContinuation(),
michael@0 109 "nsProgressFrame should not have continuations; if it does we "
michael@0 110 "need to call RegUnregAccessKey only for the first.");
michael@0 111
michael@0 112 if (mState & NS_FRAME_FIRST_REFLOW) {
michael@0 113 nsFormControlFrame::RegUnRegAccessKey(this, true);
michael@0 114 }
michael@0 115
michael@0 116 nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
michael@0 117 NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!");
michael@0 118
michael@0 119 ReflowBarFrame(barFrame, aPresContext, aReflowState, aStatus);
michael@0 120
michael@0 121 aDesiredSize.Width() = aReflowState.ComputedWidth() +
michael@0 122 aReflowState.ComputedPhysicalBorderPadding().LeftRight();
michael@0 123 aDesiredSize.Height() = aReflowState.ComputedHeight() +
michael@0 124 aReflowState.ComputedPhysicalBorderPadding().TopBottom();
michael@0 125
michael@0 126 aDesiredSize.SetOverflowAreasToDesiredBounds();
michael@0 127 ConsiderChildOverflow(aDesiredSize.mOverflowAreas, barFrame);
michael@0 128 FinishAndStoreOverflow(&aDesiredSize);
michael@0 129
michael@0 130 aStatus = NS_FRAME_COMPLETE;
michael@0 131
michael@0 132 NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
michael@0 133
michael@0 134 return NS_OK;
michael@0 135 }
michael@0 136
michael@0 137 void
michael@0 138 nsProgressFrame::ReflowBarFrame(nsIFrame* aBarFrame,
michael@0 139 nsPresContext* aPresContext,
michael@0 140 const nsHTMLReflowState& aReflowState,
michael@0 141 nsReflowStatus& aStatus)
michael@0 142 {
michael@0 143 bool vertical = StyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL;
michael@0 144 nsHTMLReflowState reflowState(aPresContext, aReflowState, aBarFrame,
michael@0 145 nsSize(aReflowState.ComputedWidth(),
michael@0 146 NS_UNCONSTRAINEDSIZE));
michael@0 147 nscoord size = vertical ? aReflowState.ComputedHeight()
michael@0 148 : aReflowState.ComputedWidth();
michael@0 149 nscoord xoffset = aReflowState.ComputedPhysicalBorderPadding().left;
michael@0 150 nscoord yoffset = aReflowState.ComputedPhysicalBorderPadding().top;
michael@0 151
michael@0 152 double position = static_cast<HTMLProgressElement*>(mContent)->Position();
michael@0 153
michael@0 154 // Force the bar's size to match the current progress.
michael@0 155 // When indeterminate, the progress' size will be 100%.
michael@0 156 if (position >= 0.0) {
michael@0 157 size *= position;
michael@0 158 }
michael@0 159
michael@0 160 if (!vertical && StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
michael@0 161 xoffset += aReflowState.ComputedWidth() - size;
michael@0 162 }
michael@0 163
michael@0 164 // The bar size is fixed in these cases:
michael@0 165 // - the progress position is determined: the bar size is fixed according
michael@0 166 // to it's value.
michael@0 167 // - the progress position is indeterminate and the bar appearance should be
michael@0 168 // shown as native: the bar size is forced to 100%.
michael@0 169 // Otherwise (when the progress is indeterminate and the bar appearance isn't
michael@0 170 // native), the bar size isn't fixed and can be set by the author.
michael@0 171 if (position != -1 || ShouldUseNativeStyle()) {
michael@0 172 if (vertical) {
michael@0 173 // We want the bar to begin at the bottom.
michael@0 174 yoffset += aReflowState.ComputedHeight() - size;
michael@0 175
michael@0 176 size -= reflowState.ComputedPhysicalMargin().TopBottom() +
michael@0 177 reflowState.ComputedPhysicalBorderPadding().TopBottom();
michael@0 178 size = std::max(size, 0);
michael@0 179 reflowState.SetComputedHeight(size);
michael@0 180 } else {
michael@0 181 size -= reflowState.ComputedPhysicalMargin().LeftRight() +
michael@0 182 reflowState.ComputedPhysicalBorderPadding().LeftRight();
michael@0 183 size = std::max(size, 0);
michael@0 184 reflowState.SetComputedWidth(size);
michael@0 185 }
michael@0 186 } else if (vertical) {
michael@0 187 // For vertical progress bars, we need to position the bar specificly when
michael@0 188 // the width isn't constrained (position == -1 and !ShouldUseNativeStyle())
michael@0 189 // because aReflowState.ComputedHeight() - size == 0.
michael@0 190 yoffset += aReflowState.ComputedHeight() - reflowState.ComputedHeight();
michael@0 191 }
michael@0 192
michael@0 193 xoffset += reflowState.ComputedPhysicalMargin().left;
michael@0 194 yoffset += reflowState.ComputedPhysicalMargin().top;
michael@0 195
michael@0 196 nsHTMLReflowMetrics barDesiredSize(aReflowState);
michael@0 197 ReflowChild(aBarFrame, aPresContext, barDesiredSize, reflowState, xoffset,
michael@0 198 yoffset, 0, aStatus);
michael@0 199 FinishReflowChild(aBarFrame, aPresContext, barDesiredSize, &reflowState,
michael@0 200 xoffset, yoffset, 0);
michael@0 201 }
michael@0 202
michael@0 203 nsresult
michael@0 204 nsProgressFrame::AttributeChanged(int32_t aNameSpaceID,
michael@0 205 nsIAtom* aAttribute,
michael@0 206 int32_t aModType)
michael@0 207 {
michael@0 208 NS_ASSERTION(mBarDiv, "Progress bar div must exist!");
michael@0 209
michael@0 210 if (aNameSpaceID == kNameSpaceID_None &&
michael@0 211 (aAttribute == nsGkAtoms::value || aAttribute == nsGkAtoms::max)) {
michael@0 212 nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
michael@0 213 NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!");
michael@0 214 PresContext()->PresShell()->FrameNeedsReflow(barFrame, nsIPresShell::eResize,
michael@0 215 NS_FRAME_IS_DIRTY);
michael@0 216 InvalidateFrame();
michael@0 217 }
michael@0 218
michael@0 219 return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
michael@0 220 }
michael@0 221
michael@0 222 nsSize
michael@0 223 nsProgressFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
michael@0 224 nsSize aCBSize, nscoord aAvailableWidth,
michael@0 225 nsSize aMargin, nsSize aBorder,
michael@0 226 nsSize aPadding, bool aShrinkWrap)
michael@0 227 {
michael@0 228 nsSize autoSize;
michael@0 229 autoSize.height = autoSize.width =
michael@0 230 NSToCoordRound(StyleFont()->mFont.size *
michael@0 231 nsLayoutUtils::FontSizeInflationFor(this)); // 1em
michael@0 232
michael@0 233 if (StyleDisplay()->mOrient == NS_STYLE_ORIENT_VERTICAL) {
michael@0 234 autoSize.height *= 10; // 10em
michael@0 235 } else {
michael@0 236 autoSize.width *= 10; // 10em
michael@0 237 }
michael@0 238
michael@0 239 return autoSize;
michael@0 240 }
michael@0 241
michael@0 242 nscoord
michael@0 243 nsProgressFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
michael@0 244 {
michael@0 245 nsRefPtr<nsFontMetrics> fontMet;
michael@0 246 NS_ENSURE_SUCCESS(
michael@0 247 nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet)), 0);
michael@0 248
michael@0 249 nscoord minWidth = fontMet->Font().size; // 1em
michael@0 250
michael@0 251 if (StyleDisplay()->mOrient == NS_STYLE_ORIENT_AUTO ||
michael@0 252 StyleDisplay()->mOrient == NS_STYLE_ORIENT_HORIZONTAL) {
michael@0 253 // The orientation is horizontal
michael@0 254 minWidth *= 10; // 10em
michael@0 255 }
michael@0 256
michael@0 257 return minWidth;
michael@0 258 }
michael@0 259
michael@0 260 nscoord
michael@0 261 nsProgressFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
michael@0 262 {
michael@0 263 return GetMinWidth(aRenderingContext);
michael@0 264 }
michael@0 265
michael@0 266 bool
michael@0 267 nsProgressFrame::ShouldUseNativeStyle() const
michael@0 268 {
michael@0 269 // Use the native style if these conditions are satisfied:
michael@0 270 // - both frames use the native appearance;
michael@0 271 // - neither frame has author specified rules setting the border or the
michael@0 272 // background.
michael@0 273 return StyleDisplay()->mAppearance == NS_THEME_PROGRESSBAR &&
michael@0 274 mBarDiv->GetPrimaryFrame()->StyleDisplay()->mAppearance == NS_THEME_PROGRESSBAR_CHUNK &&
michael@0 275 !PresContext()->HasAuthorSpecifiedRules(const_cast<nsProgressFrame*>(this),
michael@0 276 NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND) &&
michael@0 277 !PresContext()->HasAuthorSpecifiedRules(mBarDiv->GetPrimaryFrame(),
michael@0 278 NS_AUTHOR_SPECIFIED_BORDER | NS_AUTHOR_SPECIFIED_BACKGROUND);
michael@0 279 }
michael@0 280
michael@0 281 Element*
michael@0 282 nsProgressFrame::GetPseudoElement(nsCSSPseudoElements::Type aType)
michael@0 283 {
michael@0 284 if (aType == nsCSSPseudoElements::ePseudo_mozProgressBar) {
michael@0 285 return mBarDiv;
michael@0 286 }
michael@0 287
michael@0 288 return nsContainerFrame::GetPseudoElement(aType);
michael@0 289 }

mercurial