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.

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

mercurial