layout/forms/nsRangeFrame.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/layout/forms/nsRangeFrame.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,886 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsRangeFrame.h"
    1.10 +
    1.11 +#include "mozilla/EventStates.h"
    1.12 +#include "mozilla/TouchEvents.h"
    1.13 +
    1.14 +#include "nsContentCreatorFunctions.h"
    1.15 +#include "nsContentList.h"
    1.16 +#include "nsContentUtils.h"
    1.17 +#include "nsCSSRendering.h"
    1.18 +#include "nsFormControlFrame.h"
    1.19 +#include "nsIContent.h"
    1.20 +#include "nsIDocument.h"
    1.21 +#include "nsNameSpaceManager.h"
    1.22 +#include "nsINodeInfo.h"
    1.23 +#include "nsIPresShell.h"
    1.24 +#include "nsGkAtoms.h"
    1.25 +#include "mozilla/dom/HTMLInputElement.h"
    1.26 +#include "nsPresContext.h"
    1.27 +#include "nsNodeInfoManager.h"
    1.28 +#include "nsRenderingContext.h"
    1.29 +#include "mozilla/dom/Element.h"
    1.30 +#include "nsStyleSet.h"
    1.31 +#include "nsThemeConstants.h"
    1.32 +
    1.33 +#ifdef ACCESSIBILITY
    1.34 +#include "nsAccessibilityService.h"
    1.35 +#endif
    1.36 +
    1.37 +#define LONG_SIDE_TO_SHORT_SIDE_RATIO 10
    1.38 +
    1.39 +using namespace mozilla;
    1.40 +using namespace mozilla::dom;
    1.41 +
    1.42 +nsIFrame*
    1.43 +NS_NewRangeFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
    1.44 +{
    1.45 +  return new (aPresShell) nsRangeFrame(aContext);
    1.46 +}
    1.47 +
    1.48 +nsRangeFrame::nsRangeFrame(nsStyleContext* aContext)
    1.49 +  : nsContainerFrame(aContext)
    1.50 +{
    1.51 +}
    1.52 +
    1.53 +nsRangeFrame::~nsRangeFrame()
    1.54 +{
    1.55 +}
    1.56 +
    1.57 +NS_IMPL_FRAMEARENA_HELPERS(nsRangeFrame)
    1.58 +
    1.59 +NS_QUERYFRAME_HEAD(nsRangeFrame)
    1.60 +  NS_QUERYFRAME_ENTRY(nsRangeFrame)
    1.61 +  NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
    1.62 +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
    1.63 +
    1.64 +void
    1.65 +nsRangeFrame::Init(nsIContent* aContent,
    1.66 +                   nsIFrame*   aParent,
    1.67 +                   nsIFrame*   aPrevInFlow)
    1.68 +{
    1.69 +  // B2G's AsyncPanZoomController::ReceiveInputEvent handles touch events
    1.70 +  // without checking whether the out-of-process document that it controls
    1.71 +  // will handle them, unless it has been told that the document might do so.
    1.72 +  // This is for perf reasons, otherwise it has to wait for the event to be
    1.73 +  // round-tripped to the other process and back, delaying panning, etc.
    1.74 +  // We must call SetHasTouchEventListeners() in order to get APZC to wait
    1.75 +  // until the event has been round-tripped and check whether it has been
    1.76 +  // handled, otherwise B2G will end up panning the document when the user
    1.77 +  // tries to drag our thumb.
    1.78 +  //
    1.79 +  nsIPresShell* presShell = PresContext()->GetPresShell();
    1.80 +  if (presShell) {
    1.81 +    nsIDocument* document = presShell->GetDocument();
    1.82 +    if (document) {
    1.83 +      nsPIDOMWindow* innerWin = document->GetInnerWindow();
    1.84 +      if (innerWin) {
    1.85 +        innerWin->SetHasTouchEventListeners();
    1.86 +      }
    1.87 +    }
    1.88 +  }
    1.89 +
    1.90 +  nsStyleSet *styleSet = PresContext()->StyleSet();
    1.91 +
    1.92 +  mOuterFocusStyle =
    1.93 +    styleSet->ProbePseudoElementStyle(aContent->AsElement(),
    1.94 +                                      nsCSSPseudoElements::ePseudo_mozFocusOuter,
    1.95 +                                      StyleContext());
    1.96 +
    1.97 +  return nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
    1.98 +}
    1.99 +
   1.100 +void
   1.101 +nsRangeFrame::DestroyFrom(nsIFrame* aDestructRoot)
   1.102 +{
   1.103 +  NS_ASSERTION(!GetPrevContinuation() && !GetNextContinuation(),
   1.104 +               "nsRangeFrame should not have continuations; if it does we "
   1.105 +               "need to call RegUnregAccessKey only for the first.");
   1.106 +  nsFormControlFrame::RegUnRegAccessKey(static_cast<nsIFrame*>(this), false);
   1.107 +  nsContentUtils::DestroyAnonymousContent(&mTrackDiv);
   1.108 +  nsContentUtils::DestroyAnonymousContent(&mProgressDiv);
   1.109 +  nsContentUtils::DestroyAnonymousContent(&mThumbDiv);
   1.110 +  nsContainerFrame::DestroyFrom(aDestructRoot);
   1.111 +}
   1.112 +
   1.113 +nsresult
   1.114 +nsRangeFrame::MakeAnonymousDiv(Element** aResult,
   1.115 +                               nsCSSPseudoElements::Type aPseudoType,
   1.116 +                               nsTArray<ContentInfo>& aElements)
   1.117 +{
   1.118 +  nsCOMPtr<nsIDocument> doc = mContent->GetDocument();
   1.119 +  nsRefPtr<Element> resultElement = doc->CreateHTMLElement(nsGkAtoms::div);
   1.120 +
   1.121 +  // Associate the pseudo-element with the anonymous child.
   1.122 +  nsRefPtr<nsStyleContext> newStyleContext =
   1.123 +    PresContext()->StyleSet()->ResolvePseudoElementStyle(mContent->AsElement(),
   1.124 +                                                         aPseudoType,
   1.125 +                                                         StyleContext(),
   1.126 +                                                         resultElement);
   1.127 +
   1.128 +  if (!aElements.AppendElement(ContentInfo(resultElement, newStyleContext))) {
   1.129 +    return NS_ERROR_OUT_OF_MEMORY;
   1.130 +  }
   1.131 +
   1.132 +  resultElement.forget(aResult);
   1.133 +  return NS_OK;
   1.134 +}
   1.135 +
   1.136 +nsresult
   1.137 +nsRangeFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
   1.138 +{
   1.139 +  nsresult rv;
   1.140 +
   1.141 +  // Create the ::-moz-range-track pseuto-element (a div):
   1.142 +  rv = MakeAnonymousDiv(getter_AddRefs(mTrackDiv),
   1.143 +                        nsCSSPseudoElements::ePseudo_mozRangeTrack,
   1.144 +                        aElements);
   1.145 +  NS_ENSURE_SUCCESS(rv, rv);
   1.146 +
   1.147 +  // Create the ::-moz-range-progress pseudo-element (a div):
   1.148 +  rv = MakeAnonymousDiv(getter_AddRefs(mProgressDiv),
   1.149 +                        nsCSSPseudoElements::ePseudo_mozRangeProgress,
   1.150 +                        aElements);
   1.151 +  NS_ENSURE_SUCCESS(rv, rv);
   1.152 +
   1.153 +  // Create the ::-moz-range-thumb pseudo-element (a div):
   1.154 +  rv = MakeAnonymousDiv(getter_AddRefs(mThumbDiv),
   1.155 +                        nsCSSPseudoElements::ePseudo_mozRangeThumb,
   1.156 +                        aElements);
   1.157 +  return rv;
   1.158 +}
   1.159 +
   1.160 +void
   1.161 +nsRangeFrame::AppendAnonymousContentTo(nsBaseContentList& aElements,
   1.162 +                                       uint32_t aFilter)
   1.163 +{
   1.164 +  aElements.MaybeAppendElement(mTrackDiv);
   1.165 +  aElements.MaybeAppendElement(mProgressDiv);
   1.166 +  aElements.MaybeAppendElement(mThumbDiv);
   1.167 +}
   1.168 +
   1.169 +class nsDisplayRangeFocusRing : public nsDisplayItem
   1.170 +{
   1.171 +public:
   1.172 +  nsDisplayRangeFocusRing(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
   1.173 +    : nsDisplayItem(aBuilder, aFrame) {
   1.174 +    MOZ_COUNT_CTOR(nsDisplayRangeFocusRing);
   1.175 +  }
   1.176 +#ifdef NS_BUILD_REFCNT_LOGGING
   1.177 +  virtual ~nsDisplayRangeFocusRing() {
   1.178 +    MOZ_COUNT_DTOR(nsDisplayRangeFocusRing);
   1.179 +  }
   1.180 +#endif
   1.181 +
   1.182 +  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) MOZ_OVERRIDE;
   1.183 +  virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE;
   1.184 +  NS_DISPLAY_DECL_NAME("RangeFocusRing", TYPE_OUTLINE)
   1.185 +};
   1.186 +
   1.187 +nsRect
   1.188 +nsDisplayRangeFocusRing::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap)
   1.189 +{
   1.190 +  *aSnap = false;
   1.191 +  nsRect rect(ToReferenceFrame(), Frame()->GetSize());
   1.192 +
   1.193 +  // We want to paint as if specifying a border for ::-moz-focus-outer
   1.194 +  // specifies an outline for our frame, so inflate by the border widths:
   1.195 +  nsStyleContext* styleContext =
   1.196 +    static_cast<nsRangeFrame*>(mFrame)->mOuterFocusStyle;
   1.197 +  MOZ_ASSERT(styleContext, "We only exist if mOuterFocusStyle is non-null");
   1.198 +  rect.Inflate(styleContext->StyleBorder()->GetComputedBorder());
   1.199 +
   1.200 +  return rect;
   1.201 +}
   1.202 +
   1.203 +void
   1.204 +nsDisplayRangeFocusRing::Paint(nsDisplayListBuilder* aBuilder,
   1.205 +                               nsRenderingContext* aCtx)
   1.206 +{
   1.207 +  bool unused;
   1.208 +  nsStyleContext* styleContext =
   1.209 +    static_cast<nsRangeFrame*>(mFrame)->mOuterFocusStyle;
   1.210 +  MOZ_ASSERT(styleContext, "We only exist if mOuterFocusStyle is non-null");
   1.211 +  nsCSSRendering::PaintBorder(mFrame->PresContext(), *aCtx, mFrame,
   1.212 +                              mVisibleRect, GetBounds(aBuilder, &unused),
   1.213 +                              styleContext);
   1.214 +}
   1.215 +
   1.216 +void
   1.217 +nsRangeFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
   1.218 +                               const nsRect&           aDirtyRect,
   1.219 +                               const nsDisplayListSet& aLists)
   1.220 +{
   1.221 +  if (IsThemed()) {
   1.222 +    DisplayBorderBackgroundOutline(aBuilder, aLists);
   1.223 +    // Only create items for the thumb. Specifically, we do not want
   1.224 +    // the track to paint, since *our* background is used to paint
   1.225 +    // the track, and we don't want the unthemed track painting over
   1.226 +    // the top of the themed track.
   1.227 +    // This logic is copied from
   1.228 +    // nsContainerFrame::BuildDisplayListForNonBlockChildren as
   1.229 +    // called by BuildDisplayListForInline.
   1.230 +    nsIFrame* thumb = mThumbDiv->GetPrimaryFrame();
   1.231 +    if (thumb) {
   1.232 +      nsDisplayListSet set(aLists, aLists.Content());
   1.233 +      BuildDisplayListForChild(aBuilder, thumb, aDirtyRect, set, DISPLAY_CHILD_INLINE);
   1.234 +    }
   1.235 +  } else {
   1.236 +    BuildDisplayListForInline(aBuilder, aDirtyRect, aLists);
   1.237 +  }
   1.238 +
   1.239 +  // Draw a focus outline if appropriate:
   1.240 +
   1.241 +  if (!aBuilder->IsForPainting() ||
   1.242 +      !IsVisibleForPainting(aBuilder)) {
   1.243 +    // we don't want the focus ring item for hit-testing or if the item isn't
   1.244 +    // in the area being [re]painted
   1.245 +    return;
   1.246 +  }
   1.247 +
   1.248 +  EventStates eventStates = mContent->AsElement()->State();
   1.249 +  if (eventStates.HasState(NS_EVENT_STATE_DISABLED) ||
   1.250 +      !eventStates.HasState(NS_EVENT_STATE_FOCUSRING)) {
   1.251 +    return; // can't have focus or doesn't match :-moz-focusring
   1.252 +  }
   1.253 +
   1.254 +  if (!mOuterFocusStyle ||
   1.255 +      !mOuterFocusStyle->StyleBorder()->HasBorder()) {
   1.256 +    // no ::-moz-focus-outer specified border (how style specifies a focus ring
   1.257 +    // for range)
   1.258 +    return;
   1.259 +  }
   1.260 +
   1.261 +  const nsStyleDisplay *disp = StyleDisplay();
   1.262 +  if (IsThemed(disp) &&
   1.263 +      PresContext()->GetTheme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
   1.264 +    return; // the native theme displays its own visual indication of focus
   1.265 +  }
   1.266 +
   1.267 +  aLists.Content()->AppendNewToTop(
   1.268 +    new (aBuilder) nsDisplayRangeFocusRing(aBuilder, this));
   1.269 +}
   1.270 +
   1.271 +nsresult
   1.272 +nsRangeFrame::Reflow(nsPresContext*           aPresContext,
   1.273 +                     nsHTMLReflowMetrics&     aDesiredSize,
   1.274 +                     const nsHTMLReflowState& aReflowState,
   1.275 +                     nsReflowStatus&          aStatus)
   1.276 +{
   1.277 +  DO_GLOBAL_REFLOW_COUNT("nsRangeFrame");
   1.278 +  DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
   1.279 +
   1.280 +  NS_ASSERTION(mTrackDiv, "::-moz-range-track div must exist!");
   1.281 +  NS_ASSERTION(mProgressDiv, "::-moz-range-progress div must exist!");
   1.282 +  NS_ASSERTION(mThumbDiv, "::-moz-range-thumb div must exist!");
   1.283 +  NS_ASSERTION(!GetPrevContinuation() && !GetNextContinuation(),
   1.284 +               "nsRangeFrame should not have continuations; if it does we "
   1.285 +               "need to call RegUnregAccessKey only for the first.");
   1.286 +
   1.287 +  if (mState & NS_FRAME_FIRST_REFLOW) {
   1.288 +    nsFormControlFrame::RegUnRegAccessKey(this, true);
   1.289 +  }
   1.290 +
   1.291 +  nscoord computedHeight = aReflowState.ComputedHeight();
   1.292 +  if (computedHeight == NS_AUTOHEIGHT) {
   1.293 +    computedHeight = 0;
   1.294 +  }
   1.295 +  aDesiredSize.Width() = aReflowState.ComputedWidth() +
   1.296 +                       aReflowState.ComputedPhysicalBorderPadding().LeftRight();
   1.297 +  aDesiredSize.Height() = computedHeight +
   1.298 +                        aReflowState.ComputedPhysicalBorderPadding().TopBottom();
   1.299 +
   1.300 +  nsresult rv =
   1.301 +    ReflowAnonymousContent(aPresContext, aDesiredSize, aReflowState);
   1.302 +  NS_ENSURE_SUCCESS(rv, rv);
   1.303 +
   1.304 +  aDesiredSize.SetOverflowAreasToDesiredBounds();
   1.305 +
   1.306 +  nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame();
   1.307 +  if (trackFrame) {
   1.308 +    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, trackFrame);
   1.309 +  }
   1.310 +
   1.311 +  nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame();
   1.312 +  if (rangeProgressFrame) {
   1.313 +    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, rangeProgressFrame);
   1.314 +  }
   1.315 +
   1.316 +  nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();
   1.317 +  if (thumbFrame) {
   1.318 +    ConsiderChildOverflow(aDesiredSize.mOverflowAreas, thumbFrame);
   1.319 +  }
   1.320 +
   1.321 +  FinishAndStoreOverflow(&aDesiredSize);
   1.322 +
   1.323 +  aStatus = NS_FRAME_COMPLETE;
   1.324 +
   1.325 +  NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
   1.326 +
   1.327 +  return NS_OK;
   1.328 +}
   1.329 +
   1.330 +nsresult
   1.331 +nsRangeFrame::ReflowAnonymousContent(nsPresContext*           aPresContext,
   1.332 +                                     nsHTMLReflowMetrics&     aDesiredSize,
   1.333 +                                     const nsHTMLReflowState& aReflowState)
   1.334 +{
   1.335 +  // The width/height of our content box, which is the available width/height
   1.336 +  // for our anonymous content:
   1.337 +  nscoord rangeFrameContentBoxWidth = aReflowState.ComputedWidth();
   1.338 +  nscoord rangeFrameContentBoxHeight = aReflowState.ComputedHeight();
   1.339 +  if (rangeFrameContentBoxHeight == NS_AUTOHEIGHT) {
   1.340 +    rangeFrameContentBoxHeight = 0;
   1.341 +  }
   1.342 +
   1.343 +  nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame();
   1.344 +
   1.345 +  if (trackFrame) { // display:none?
   1.346 +
   1.347 +    // Position the track:
   1.348 +    // The idea here is that we allow content authors to style the width,
   1.349 +    // height, border and padding of the track, but we ignore margin and
   1.350 +    // positioning properties and do the positioning ourself to keep the center
   1.351 +    // of the track's border box on the center of the nsRangeFrame's content
   1.352 +    // box.
   1.353 +
   1.354 +    nsHTMLReflowState trackReflowState(aPresContext, aReflowState, trackFrame,
   1.355 +                                       nsSize(aReflowState.ComputedWidth(),
   1.356 +                                              NS_UNCONSTRAINEDSIZE));
   1.357 +
   1.358 +    // Find the x/y position of the track frame such that it will be positioned
   1.359 +    // as described above. These coordinates are with respect to the
   1.360 +    // nsRangeFrame's border-box.
   1.361 +    nscoord trackX = rangeFrameContentBoxWidth / 2;
   1.362 +    nscoord trackY = rangeFrameContentBoxHeight / 2;
   1.363 +
   1.364 +    // Account for the track's border and padding (we ignore its margin):
   1.365 +    trackX -= trackReflowState.ComputedPhysicalBorderPadding().left +
   1.366 +                trackReflowState.ComputedWidth() / 2;
   1.367 +    trackY -= trackReflowState.ComputedPhysicalBorderPadding().top +
   1.368 +                trackReflowState.ComputedHeight() / 2;
   1.369 +
   1.370 +    // Make relative to our border box instead of our content box:
   1.371 +    trackX += aReflowState.ComputedPhysicalBorderPadding().left;
   1.372 +    trackY += aReflowState.ComputedPhysicalBorderPadding().top;
   1.373 +
   1.374 +    nsReflowStatus frameStatus;
   1.375 +    nsHTMLReflowMetrics trackDesiredSize(aReflowState);
   1.376 +    nsresult rv = ReflowChild(trackFrame, aPresContext, trackDesiredSize,
   1.377 +                              trackReflowState, trackX, trackY, 0, frameStatus);
   1.378 +    NS_ENSURE_SUCCESS(rv, rv);
   1.379 +    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
   1.380 +               "We gave our child unconstrained height, so it should be complete");
   1.381 +    rv = FinishReflowChild(trackFrame, aPresContext, trackDesiredSize,
   1.382 +                           &trackReflowState, trackX, trackY, 0);
   1.383 +    NS_ENSURE_SUCCESS(rv, rv);
   1.384 +  }
   1.385 +
   1.386 +  nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();
   1.387 +
   1.388 +  if (thumbFrame) { // display:none?
   1.389 +    nsHTMLReflowState thumbReflowState(aPresContext, aReflowState, thumbFrame,
   1.390 +                                       nsSize(aReflowState.ComputedWidth(),
   1.391 +                                              NS_UNCONSTRAINEDSIZE));
   1.392 +
   1.393 +    // Where we position the thumb depends on its size, so we first reflow
   1.394 +    // the thumb at {0,0} to obtain its size, then position it afterwards.
   1.395 +
   1.396 +    nsReflowStatus frameStatus;
   1.397 +    nsHTMLReflowMetrics thumbDesiredSize(aReflowState);
   1.398 +    nsresult rv = ReflowChild(thumbFrame, aPresContext, thumbDesiredSize,
   1.399 +                              thumbReflowState, 0, 0, 0, frameStatus);
   1.400 +    NS_ENSURE_SUCCESS(rv, rv);
   1.401 +    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
   1.402 +               "We gave our child unconstrained height, so it should be complete");
   1.403 +    rv = FinishReflowChild(thumbFrame, aPresContext, thumbDesiredSize,
   1.404 +                           &thumbReflowState, 0, 0, 0);
   1.405 +    NS_ENSURE_SUCCESS(rv, rv);
   1.406 +
   1.407 +    DoUpdateThumbPosition(thumbFrame, nsSize(aDesiredSize.Width(),
   1.408 +                                             aDesiredSize.Height()));
   1.409 +  }
   1.410 +
   1.411 +  nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame();
   1.412 +
   1.413 +  if (rangeProgressFrame) { // display:none?
   1.414 +    nsHTMLReflowState progressReflowState(aPresContext, aReflowState,
   1.415 +                                          rangeProgressFrame,
   1.416 +                                          nsSize(aReflowState.ComputedWidth(),
   1.417 +                                                 NS_UNCONSTRAINEDSIZE));
   1.418 +
   1.419 +    // We first reflow the range-progress frame at {0,0} to obtain its
   1.420 +    // unadjusted dimensions, then we adjust it to so that the appropriate edge
   1.421 +    // ends at the thumb.
   1.422 +
   1.423 +    nsReflowStatus frameStatus;
   1.424 +    nsHTMLReflowMetrics progressDesiredSize(aReflowState);
   1.425 +    nsresult rv = ReflowChild(rangeProgressFrame, aPresContext,
   1.426 +                              progressDesiredSize, progressReflowState, 0, 0,
   1.427 +                              0, frameStatus);
   1.428 +    NS_ENSURE_SUCCESS(rv, rv);
   1.429 +    MOZ_ASSERT(NS_FRAME_IS_FULLY_COMPLETE(frameStatus),
   1.430 +               "We gave our child unconstrained height, so it should be complete");
   1.431 +    rv = FinishReflowChild(rangeProgressFrame, aPresContext,
   1.432 +                           progressDesiredSize, &progressReflowState, 0, 0, 0);
   1.433 +    NS_ENSURE_SUCCESS(rv, rv);
   1.434 +
   1.435 +    DoUpdateRangeProgressFrame(rangeProgressFrame, nsSize(aDesiredSize.Width(),
   1.436 +                                                          aDesiredSize.Height()));
   1.437 +  }
   1.438 +
   1.439 +  return NS_OK;
   1.440 +}
   1.441 +
   1.442 +#ifdef ACCESSIBILITY
   1.443 +a11y::AccType
   1.444 +nsRangeFrame::AccessibleType()
   1.445 +{
   1.446 +  return a11y::eHTMLRangeType;
   1.447 +}
   1.448 +#endif
   1.449 +
   1.450 +double
   1.451 +nsRangeFrame::GetValueAsFractionOfRange()
   1.452 +{
   1.453 +  MOZ_ASSERT(mContent->IsHTML(nsGkAtoms::input), "bad cast");
   1.454 +  dom::HTMLInputElement* input = static_cast<dom::HTMLInputElement*>(mContent);
   1.455 +
   1.456 +  MOZ_ASSERT(input->GetType() == NS_FORM_INPUT_RANGE);
   1.457 +
   1.458 +  Decimal value = input->GetValueAsDecimal();
   1.459 +  Decimal minimum = input->GetMinimum();
   1.460 +  Decimal maximum = input->GetMaximum();
   1.461 +
   1.462 +  MOZ_ASSERT(value.isFinite() && minimum.isFinite() && maximum.isFinite(),
   1.463 +             "type=range should have a default maximum/minimum");
   1.464 +  
   1.465 +  if (maximum <= minimum) {
   1.466 +    MOZ_ASSERT(value == minimum, "Unsanitized value");
   1.467 +    return 0.0;
   1.468 +  }
   1.469 +  
   1.470 +  MOZ_ASSERT(value >= minimum && value <= maximum, "Unsanitized value");
   1.471 +  
   1.472 +  return ((value - minimum) / (maximum - minimum)).toDouble();
   1.473 +}
   1.474 +
   1.475 +Decimal
   1.476 +nsRangeFrame::GetValueAtEventPoint(WidgetGUIEvent* aEvent)
   1.477 +{
   1.478 +  MOZ_ASSERT(aEvent->eventStructType == NS_MOUSE_EVENT ||
   1.479 +             aEvent->eventStructType == NS_TOUCH_EVENT,
   1.480 +             "Unexpected event type - aEvent->refPoint may be meaningless");
   1.481 +
   1.482 +  MOZ_ASSERT(mContent->IsHTML(nsGkAtoms::input), "bad cast");
   1.483 +  dom::HTMLInputElement* input = static_cast<dom::HTMLInputElement*>(mContent);
   1.484 +
   1.485 +  MOZ_ASSERT(input->GetType() == NS_FORM_INPUT_RANGE);
   1.486 +
   1.487 +  Decimal minimum = input->GetMinimum();
   1.488 +  Decimal maximum = input->GetMaximum();
   1.489 +  MOZ_ASSERT(minimum.isFinite() && maximum.isFinite(),
   1.490 +             "type=range should have a default maximum/minimum");
   1.491 +  if (maximum <= minimum) {
   1.492 +    return minimum;
   1.493 +  }
   1.494 +  Decimal range = maximum - minimum;
   1.495 +
   1.496 +  LayoutDeviceIntPoint absPoint;
   1.497 +  if (aEvent->eventStructType == NS_TOUCH_EVENT) {
   1.498 +    MOZ_ASSERT(aEvent->AsTouchEvent()->touches.Length() == 1,
   1.499 +               "Unexpected number of touches");
   1.500 +    absPoint = LayoutDeviceIntPoint::FromUntyped(
   1.501 +      aEvent->AsTouchEvent()->touches[0]->mRefPoint);
   1.502 +  } else {
   1.503 +    absPoint = aEvent->refPoint;
   1.504 +  }
   1.505 +  nsPoint point =
   1.506 +    nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, 
   1.507 +      LayoutDeviceIntPoint::ToUntyped(absPoint), this);
   1.508 +
   1.509 +  if (point == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
   1.510 +    // We don't want to change the current value for this error state.
   1.511 +    return static_cast<dom::HTMLInputElement*>(mContent)->GetValueAsDecimal();
   1.512 +  }
   1.513 +
   1.514 +  nsRect rangeContentRect = GetContentRectRelativeToSelf();
   1.515 +  nsSize thumbSize;
   1.516 +
   1.517 +  if (IsThemed()) {
   1.518 +    // We need to get the size of the thumb from the theme.
   1.519 +    nsPresContext *presContext = PresContext();
   1.520 +    nsRefPtr<nsRenderingContext> tmpCtx =
   1.521 +      presContext->PresShell()->CreateReferenceRenderingContext();
   1.522 +    bool notUsedCanOverride;
   1.523 +    nsIntSize size;
   1.524 +    presContext->GetTheme()->
   1.525 +      GetMinimumWidgetSize(tmpCtx.get(), this, NS_THEME_RANGE_THUMB, &size,
   1.526 +                           &notUsedCanOverride);
   1.527 +    thumbSize.width = presContext->DevPixelsToAppUnits(size.width);
   1.528 +    thumbSize.height = presContext->DevPixelsToAppUnits(size.height);
   1.529 +    MOZ_ASSERT(thumbSize.width > 0 && thumbSize.height > 0);
   1.530 +  } else {
   1.531 +    nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();
   1.532 +    if (thumbFrame) { // diplay:none?
   1.533 +      thumbSize = thumbFrame->GetSize();
   1.534 +    }
   1.535 +  }
   1.536 +
   1.537 +  Decimal fraction;
   1.538 +  if (IsHorizontal()) {
   1.539 +    nscoord traversableDistance = rangeContentRect.width - thumbSize.width;
   1.540 +    if (traversableDistance <= 0) {
   1.541 +      return minimum;
   1.542 +    }
   1.543 +    nscoord posAtStart = rangeContentRect.x + thumbSize.width/2;
   1.544 +    nscoord posAtEnd = posAtStart + traversableDistance;
   1.545 +    nscoord posOfPoint = mozilla::clamped(point.x, posAtStart, posAtEnd);
   1.546 +    fraction = Decimal(posOfPoint - posAtStart) / traversableDistance;
   1.547 +    if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
   1.548 +      fraction = Decimal(1) - fraction;
   1.549 +    }
   1.550 +  } else {
   1.551 +    nscoord traversableDistance = rangeContentRect.height - thumbSize.height;
   1.552 +    if (traversableDistance <= 0) {
   1.553 +      return minimum;
   1.554 +    }
   1.555 +    nscoord posAtStart = rangeContentRect.y + thumbSize.height/2;
   1.556 +    nscoord posAtEnd = posAtStart + traversableDistance;
   1.557 +    nscoord posOfPoint = mozilla::clamped(point.y, posAtStart, posAtEnd);
   1.558 +    // For a vertical range, the top (posAtStart) is the highest value, so we
   1.559 +    // subtract the fraction from 1.0 to get that polarity correct.
   1.560 +    fraction = Decimal(1) - Decimal(posOfPoint - posAtStart) / traversableDistance;
   1.561 +  }
   1.562 +
   1.563 +  MOZ_ASSERT(fraction >= 0 && fraction <= 1);
   1.564 +  return minimum + fraction * range;
   1.565 +}
   1.566 +
   1.567 +void
   1.568 +nsRangeFrame::UpdateForValueChange()
   1.569 +{
   1.570 +  if (NS_SUBTREE_DIRTY(this)) {
   1.571 +    return; // we're going to be updated when we reflow
   1.572 +  }
   1.573 +  nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame();
   1.574 +  nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();
   1.575 +  if (!rangeProgressFrame && !thumbFrame) {
   1.576 +    return; // diplay:none?
   1.577 +  }
   1.578 +  if (rangeProgressFrame) {
   1.579 +    DoUpdateRangeProgressFrame(rangeProgressFrame, GetSize());
   1.580 +  }
   1.581 +  if (thumbFrame) {
   1.582 +    DoUpdateThumbPosition(thumbFrame, GetSize());
   1.583 +  }
   1.584 +  if (IsThemed()) {
   1.585 +    // We don't know the exact dimensions or location of the thumb when native
   1.586 +    // theming is applied, so we just repaint the entire range.
   1.587 +    InvalidateFrame();
   1.588 +  }
   1.589 +
   1.590 +#ifdef ACCESSIBILITY
   1.591 +  nsAccessibilityService* accService = nsIPresShell::AccService();
   1.592 +  if (accService) {
   1.593 +    accService->RangeValueChanged(PresContext()->PresShell(), mContent);
   1.594 +  }
   1.595 +#endif
   1.596 +
   1.597 +  SchedulePaint();
   1.598 +}
   1.599 +
   1.600 +void
   1.601 +nsRangeFrame::DoUpdateThumbPosition(nsIFrame* aThumbFrame,
   1.602 +                                    const nsSize& aRangeSize)
   1.603 +{
   1.604 +  MOZ_ASSERT(aThumbFrame);
   1.605 +
   1.606 +  // The idea here is that we want to position the thumb so that the center
   1.607 +  // of the thumb is on an imaginary line drawn from the middle of one edge
   1.608 +  // of the range frame's content box to the middle of the opposite edge of
   1.609 +  // its content box (the opposite edges being the left/right edge if the
   1.610 +  // range is horizontal, or else the top/bottom edges if the range is
   1.611 +  // vertical). How far along this line the center of the thumb is placed
   1.612 +  // depends on the value of the range.
   1.613 +
   1.614 +  nsMargin borderAndPadding = GetUsedBorderAndPadding();
   1.615 +  nsPoint newPosition(borderAndPadding.left, borderAndPadding.top);
   1.616 +
   1.617 +  nsSize rangeContentBoxSize(aRangeSize);
   1.618 +  rangeContentBoxSize.width -= borderAndPadding.LeftRight();
   1.619 +  rangeContentBoxSize.height -= borderAndPadding.TopBottom();
   1.620 +
   1.621 +  nsSize thumbSize = aThumbFrame->GetSize();
   1.622 +  double fraction = GetValueAsFractionOfRange();
   1.623 +  MOZ_ASSERT(fraction >= 0.0 && fraction <= 1.0);
   1.624 +
   1.625 +  // We are called under Reflow, so we need to pass IsHorizontal a valid rect.
   1.626 +  nsSize frameSizeOverride(aRangeSize.width, aRangeSize.height);
   1.627 +  if (IsHorizontal(&frameSizeOverride)) {
   1.628 +    if (thumbSize.width < rangeContentBoxSize.width) {
   1.629 +      nscoord traversableDistance =
   1.630 +        rangeContentBoxSize.width - thumbSize.width;
   1.631 +      if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
   1.632 +        newPosition.x += NSToCoordRound((1.0 - fraction) * traversableDistance);
   1.633 +      } else {
   1.634 +        newPosition.x += NSToCoordRound(fraction * traversableDistance);
   1.635 +      }
   1.636 +      newPosition.y += (rangeContentBoxSize.height - thumbSize.height)/2;
   1.637 +    }
   1.638 +  } else {
   1.639 +    if (thumbSize.height < rangeContentBoxSize.height) {
   1.640 +      nscoord traversableDistance =
   1.641 +        rangeContentBoxSize.height - thumbSize.height;
   1.642 +      newPosition.x += (rangeContentBoxSize.width - thumbSize.width)/2;
   1.643 +      newPosition.y += NSToCoordRound((1.0 - fraction) * traversableDistance);
   1.644 +    }
   1.645 +  }
   1.646 +  aThumbFrame->SetPosition(newPosition);
   1.647 +}
   1.648 +
   1.649 +void
   1.650 +nsRangeFrame::DoUpdateRangeProgressFrame(nsIFrame* aRangeProgressFrame,
   1.651 +                                         const nsSize& aRangeSize)
   1.652 +{
   1.653 +  MOZ_ASSERT(aRangeProgressFrame);
   1.654 +
   1.655 +  // The idea here is that we want to position the ::-moz-range-progress
   1.656 +  // pseudo-element so that the center line running along its length is on the
   1.657 +  // corresponding center line of the nsRangeFrame's content box. In the other
   1.658 +  // dimension, we align the "start" edge of the ::-moz-range-progress
   1.659 +  // pseudo-element's border-box with the corresponding edge of the
   1.660 +  // nsRangeFrame's content box, and we size the progress element's border-box
   1.661 +  // to have a length of GetValueAsFractionOfRange() times the nsRangeFrame's
   1.662 +  // content-box size.
   1.663 +
   1.664 +  nsMargin borderAndPadding = GetUsedBorderAndPadding();
   1.665 +  nsSize progSize = aRangeProgressFrame->GetSize();
   1.666 +  nsRect progRect(borderAndPadding.left, borderAndPadding.top,
   1.667 +                  progSize.width, progSize.height);
   1.668 +
   1.669 +  nsSize rangeContentBoxSize(aRangeSize);
   1.670 +  rangeContentBoxSize.width -= borderAndPadding.LeftRight();
   1.671 +  rangeContentBoxSize.height -= borderAndPadding.TopBottom();
   1.672 +
   1.673 +  double fraction = GetValueAsFractionOfRange();
   1.674 +  MOZ_ASSERT(fraction >= 0.0 && fraction <= 1.0);
   1.675 +
   1.676 +  // We are called under Reflow, so we need to pass IsHorizontal a valid rect.
   1.677 +  nsSize frameSizeOverride(aRangeSize.width, aRangeSize.height);
   1.678 +  if (IsHorizontal(&frameSizeOverride)) {
   1.679 +    nscoord progLength = NSToCoordRound(fraction * rangeContentBoxSize.width);
   1.680 +    if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
   1.681 +      progRect.x += rangeContentBoxSize.width - progLength;
   1.682 +    }
   1.683 +    progRect.y += (rangeContentBoxSize.height - progSize.height)/2;
   1.684 +    progRect.width = progLength;
   1.685 +  } else {
   1.686 +    nscoord progLength = NSToCoordRound(fraction * rangeContentBoxSize.height);
   1.687 +    progRect.x += (rangeContentBoxSize.width - progSize.width)/2;
   1.688 +    progRect.y += rangeContentBoxSize.height - progLength;
   1.689 +    progRect.height = progLength;
   1.690 +  }
   1.691 +  aRangeProgressFrame->SetRect(progRect);
   1.692 +}
   1.693 +
   1.694 +nsresult
   1.695 +nsRangeFrame::AttributeChanged(int32_t  aNameSpaceID,
   1.696 +                               nsIAtom* aAttribute,
   1.697 +                               int32_t  aModType)
   1.698 +{
   1.699 +  NS_ASSERTION(mTrackDiv, "The track div must exist!");
   1.700 +  NS_ASSERTION(mThumbDiv, "The thumb div must exist!");
   1.701 +
   1.702 +  if (aNameSpaceID == kNameSpaceID_None) {
   1.703 +    if (aAttribute == nsGkAtoms::value ||
   1.704 +        aAttribute == nsGkAtoms::min ||
   1.705 +        aAttribute == nsGkAtoms::max ||
   1.706 +        aAttribute == nsGkAtoms::step) {
   1.707 +      // We want to update the position of the thumb, except in one special
   1.708 +      // case: If the value attribute is being set, it is possible that we are
   1.709 +      // in the middle of a type change away from type=range, under the
   1.710 +      // SetAttr(..., nsGkAtoms::value, ...) call in HTMLInputElement::
   1.711 +      // HandleTypeChange. In that case the HTMLInputElement's type will
   1.712 +      // already have changed, and if we call UpdateForValueChange()
   1.713 +      // we'll fail the asserts under that call that check the type of our
   1.714 +      // HTMLInputElement. Given that we're changing away from being a range
   1.715 +      // and this frame will shortly be destroyed, there's no point in calling
   1.716 +      // UpdateForValueChange() anyway.
   1.717 +      MOZ_ASSERT(mContent->IsHTML(nsGkAtoms::input), "bad cast");
   1.718 +      bool typeIsRange = static_cast<dom::HTMLInputElement*>(mContent)->GetType() ==
   1.719 +                           NS_FORM_INPUT_RANGE;
   1.720 +      // If script changed the <input>'s type before setting these attributes
   1.721 +      // then we don't need to do anything since we are going to be reframed.
   1.722 +      if (typeIsRange) {
   1.723 +        UpdateForValueChange();
   1.724 +      }
   1.725 +    } else if (aAttribute == nsGkAtoms::orient) {
   1.726 +      PresContext()->PresShell()->FrameNeedsReflow(this, nsIPresShell::eResize,
   1.727 +                                                   NS_FRAME_IS_DIRTY);
   1.728 +    }
   1.729 +  }
   1.730 +
   1.731 +  return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
   1.732 +}
   1.733 +
   1.734 +nsSize
   1.735 +nsRangeFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
   1.736 +                              nsSize aCBSize, nscoord aAvailableWidth,
   1.737 +                              nsSize aMargin, nsSize aBorder,
   1.738 +                              nsSize aPadding, bool aShrinkWrap)
   1.739 +{
   1.740 +  nscoord oneEm = NSToCoordRound(StyleFont()->mFont.size *
   1.741 +                                 nsLayoutUtils::FontSizeInflationFor(this)); // 1em
   1.742 +
   1.743 +  // frameSizeOverride values just gets us to fall back to being horizontal
   1.744 +  // (the actual values are irrelevant, as long as width > height):
   1.745 +  nsSize frameSizeOverride(10,1);
   1.746 +  bool isHorizontal = IsHorizontal(&frameSizeOverride);
   1.747 +
   1.748 +  nsSize autoSize;
   1.749 +
   1.750 +  // nsFrame::ComputeSize calls GetMinimumWidgetSize to prevent us from being
   1.751 +  // given too small a size when we're natively themed. If we're themed, we set
   1.752 +  // our "thickness" dimension to zero below and rely on that
   1.753 +  // GetMinimumWidgetSize check to correct that dimension to the natural
   1.754 +  // thickness of a slider in the current theme.
   1.755 +
   1.756 +  if (isHorizontal) {
   1.757 +    autoSize.width = LONG_SIDE_TO_SHORT_SIDE_RATIO * oneEm;
   1.758 +    autoSize.height = IsThemed() ? 0 : oneEm;
   1.759 +  } else {
   1.760 +    autoSize.width = IsThemed() ? 0 : oneEm;
   1.761 +    autoSize.height = LONG_SIDE_TO_SHORT_SIDE_RATIO * oneEm;
   1.762 +  }
   1.763 +
   1.764 +  return autoSize;
   1.765 +}
   1.766 +
   1.767 +nscoord
   1.768 +nsRangeFrame::GetMinWidth(nsRenderingContext *aRenderingContext)
   1.769 +{
   1.770 +  // nsFrame::ComputeSize calls GetMinimumWidgetSize to prevent us from being
   1.771 +  // given too small a size when we're natively themed. If we aren't native
   1.772 +  // themed, we don't mind how small we're sized.
   1.773 +  return nscoord(0);
   1.774 +}
   1.775 +
   1.776 +nscoord
   1.777 +nsRangeFrame::GetPrefWidth(nsRenderingContext *aRenderingContext)
   1.778 +{
   1.779 +  // frameSizeOverride values just gets us to fall back to being horizontal:
   1.780 +  nsSize frameSizeOverride(10,1);
   1.781 +  bool isHorizontal = IsHorizontal(&frameSizeOverride);
   1.782 +
   1.783 +  if (!isHorizontal && IsThemed()) {
   1.784 +    // nsFrame::ComputeSize calls GetMinimumWidgetSize to prevent us from being
   1.785 +    // given too small a size when we're natively themed. We return zero and
   1.786 +    // depend on that correction to get our "natuaral" width when we're a
   1.787 +    // vertical slider.
   1.788 +    return 0;
   1.789 +  }
   1.790 +
   1.791 +  nscoord prefWidth = NSToCoordRound(StyleFont()->mFont.size *
   1.792 +                                     nsLayoutUtils::FontSizeInflationFor(this)); // 1em
   1.793 +
   1.794 +  if (isHorizontal) {
   1.795 +    prefWidth *= LONG_SIDE_TO_SHORT_SIDE_RATIO;
   1.796 +  }
   1.797 +
   1.798 +  return prefWidth;
   1.799 +}
   1.800 +
   1.801 +bool
   1.802 +nsRangeFrame::IsHorizontal(const nsSize *aFrameSizeOverride) const
   1.803 +{
   1.804 +  dom::HTMLInputElement* element = static_cast<dom::HTMLInputElement*>(mContent);
   1.805 +  return !element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::orient,
   1.806 +                               nsGkAtoms::vertical, eCaseMatters);
   1.807 +}
   1.808 +
   1.809 +double
   1.810 +nsRangeFrame::GetMin() const
   1.811 +{
   1.812 +  return static_cast<dom::HTMLInputElement*>(mContent)->GetMinimum().toDouble();
   1.813 +}
   1.814 +
   1.815 +double
   1.816 +nsRangeFrame::GetMax() const
   1.817 +{
   1.818 +  return static_cast<dom::HTMLInputElement*>(mContent)->GetMaximum().toDouble();
   1.819 +}
   1.820 +
   1.821 +double
   1.822 +nsRangeFrame::GetValue() const
   1.823 +{
   1.824 +  return static_cast<dom::HTMLInputElement*>(mContent)->GetValueAsDecimal().toDouble();
   1.825 +}
   1.826 +
   1.827 +nsIAtom*
   1.828 +nsRangeFrame::GetType() const
   1.829 +{
   1.830 +  return nsGkAtoms::rangeFrame;
   1.831 +}
   1.832 +
   1.833 +#define STYLES_DISABLING_NATIVE_THEMING \
   1.834 +  NS_AUTHOR_SPECIFIED_BACKGROUND | \
   1.835 +  NS_AUTHOR_SPECIFIED_PADDING | \
   1.836 +  NS_AUTHOR_SPECIFIED_BORDER
   1.837 +
   1.838 +bool
   1.839 +nsRangeFrame::ShouldUseNativeStyle() const
   1.840 +{
   1.841 +  return (StyleDisplay()->mAppearance == NS_THEME_RANGE) &&
   1.842 +         !PresContext()->HasAuthorSpecifiedRules(const_cast<nsRangeFrame*>(this),
   1.843 +                                                 (NS_AUTHOR_SPECIFIED_BORDER |
   1.844 +                                                  NS_AUTHOR_SPECIFIED_BACKGROUND)) &&
   1.845 +         !PresContext()->HasAuthorSpecifiedRules(mTrackDiv->GetPrimaryFrame(),
   1.846 +                                                 STYLES_DISABLING_NATIVE_THEMING) &&
   1.847 +         !PresContext()->HasAuthorSpecifiedRules(mProgressDiv->GetPrimaryFrame(),
   1.848 +                                                 STYLES_DISABLING_NATIVE_THEMING) &&
   1.849 +         !PresContext()->HasAuthorSpecifiedRules(mThumbDiv->GetPrimaryFrame(),
   1.850 +                                                 STYLES_DISABLING_NATIVE_THEMING);
   1.851 +}
   1.852 +
   1.853 +Element*
   1.854 +nsRangeFrame::GetPseudoElement(nsCSSPseudoElements::Type aType)
   1.855 +{
   1.856 +  if (aType == nsCSSPseudoElements::ePseudo_mozRangeTrack) {
   1.857 +    return mTrackDiv;
   1.858 +  }
   1.859 +
   1.860 +  if (aType == nsCSSPseudoElements::ePseudo_mozRangeThumb) {
   1.861 +    return mThumbDiv;
   1.862 +  }
   1.863 +
   1.864 +  if (aType == nsCSSPseudoElements::ePseudo_mozRangeProgress) {
   1.865 +    return mProgressDiv;
   1.866 +  }
   1.867 +
   1.868 +  return nsContainerFrame::GetPseudoElement(aType);
   1.869 +}
   1.870 +
   1.871 +nsStyleContext*
   1.872 +nsRangeFrame::GetAdditionalStyleContext(int32_t aIndex) const
   1.873 +{
   1.874 +  // We only implement this so that SetAdditionalStyleContext will be
   1.875 +  // called if style changes that would change the -moz-focus-outer
   1.876 +  // pseudo-element have occurred.
   1.877 +  return aIndex == 0 ? mOuterFocusStyle : nullptr;
   1.878 +}
   1.879 +
   1.880 +void
   1.881 +nsRangeFrame::SetAdditionalStyleContext(int32_t aIndex,
   1.882 +                                        nsStyleContext* aStyleContext)
   1.883 +{
   1.884 +  MOZ_ASSERT(aIndex == 0,
   1.885 +             "GetAdditionalStyleContext is handling other indexes?");
   1.886 +
   1.887 +  // The -moz-focus-outer pseudo-element's style has changed.
   1.888 +  mOuterFocusStyle = aStyleContext;
   1.889 +}

mercurial