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

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

mercurial