tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsNumberControlFrame.cpp (5714B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "nsNumberControlFrame.h"
      8 
      9 #include "HTMLInputElement.h"
     10 #include "mozilla/BasicEvents.h"
     11 #include "mozilla/PresShell.h"
     12 #include "nsCSSPseudoElements.h"
     13 #include "nsContentCreatorFunctions.h"
     14 #include "nsContentUtils.h"
     15 #include "nsGkAtoms.h"
     16 #include "nsLayoutUtils.h"
     17 #include "nsNameSpaceManager.h"
     18 #include "nsStyleConsts.h"
     19 
     20 #ifdef ACCESSIBILITY
     21 #  include "mozilla/a11y/AccTypes.h"
     22 #endif
     23 
     24 using namespace mozilla;
     25 using namespace mozilla::dom;
     26 
     27 nsIFrame* NS_NewNumberControlFrame(PresShell* aPresShell,
     28                                   ComputedStyle* aStyle) {
     29  return new (aPresShell)
     30      nsNumberControlFrame(aStyle, aPresShell->GetPresContext());
     31 }
     32 
     33 NS_IMPL_FRAMEARENA_HELPERS(nsNumberControlFrame)
     34 
     35 NS_QUERYFRAME_HEAD(nsNumberControlFrame)
     36  NS_QUERYFRAME_ENTRY(nsNumberControlFrame)
     37 NS_QUERYFRAME_TAIL_INHERITING(nsTextControlFrame)
     38 
     39 nsNumberControlFrame::nsNumberControlFrame(ComputedStyle* aStyle,
     40                                           nsPresContext* aPresContext)
     41    : nsTextControlFrame(aStyle, aPresContext, kClassID) {}
     42 
     43 nsresult nsNumberControlFrame::CreateAnonymousContent(
     44    nsTArray<ContentInfo>& aElements) {
     45  // We create an anonymous tree for our input element that is structured as
     46  // follows:
     47  //
     48  // input
     49  //   div    - placeholder
     50  //   div    - preview div
     51  //   div    - editor root
     52  //   div    - spin box wrapping up/down arrow buttons
     53  //     div  - spin up (up arrow button)
     54  //     div  - spin down (down arrow button)
     55  //
     56  // If you change this, be careful to change the order of stuff returned in
     57  // AppendAnonymousContentTo.
     58 
     59  nsTextControlFrame::CreateAnonymousContent(aElements);
     60 
     61 #if defined(MOZ_WIDGET_ANDROID)
     62  // We don't want spin buttons on Android
     63  return NS_OK;
     64 #else
     65  // The author has elected to hide the spinner by setting this
     66  // -moz-appearance. We will reframe if it changes.
     67  if (StyleDisplay()->EffectiveAppearance() == StyleAppearance::Textfield) {
     68    return NS_OK;
     69  }
     70 
     71  // Create the ::-moz-number-spin-box pseudo-element:
     72  mButton = MakeAnonElement(PseudoStyleType::mozNumberSpinBox);
     73 
     74  // Create the ::-moz-number-spin-up pseudo-element:
     75  mSpinUp = MakeAnonElement(PseudoStyleType::mozNumberSpinUp, mButton);
     76 
     77  // Create the ::-moz-number-spin-down pseudo-element:
     78  mSpinDown = MakeAnonElement(PseudoStyleType::mozNumberSpinDown, mButton);
     79 
     80  aElements.AppendElement(mButton);
     81 
     82  return NS_OK;
     83 #endif
     84 }
     85 
     86 /* static */
     87 nsNumberControlFrame* nsNumberControlFrame::GetNumberControlFrameForSpinButton(
     88    nsIFrame* aFrame) {
     89  // If aFrame is a spin button for an <input type=number> then we expect the
     90  // frame of the NAC root parent to be that input's frame. We have to check for
     91  // this via the content tree because we don't know whether extra frames will
     92  // be wrapped around any of the elements between aFrame and the
     93  // nsNumberControlFrame that we're looking for (e.g. flex wrappers).
     94  nsIContent* content = aFrame->GetContent();
     95  auto* nacHost = content->GetClosestNativeAnonymousSubtreeRootParentOrHost();
     96  if (!nacHost) {
     97    return nullptr;
     98  }
     99  auto* input = HTMLInputElement::FromNode(nacHost);
    100  if (!input || input->ControlType() != FormControlType::InputNumber) {
    101    return nullptr;
    102  }
    103  return do_QueryFrame(input->GetPrimaryFrame());
    104 }
    105 
    106 int32_t nsNumberControlFrame::GetSpinButtonForPointerEvent(
    107    WidgetGUIEvent* aEvent) const {
    108  MOZ_ASSERT(aEvent->mClass == eMouseEventClass, "Unexpected event type");
    109 
    110  if (!mButton) {
    111    // we don't have a spinner
    112    return eSpinButtonNone;
    113  }
    114  if (aEvent->mOriginalTarget == mSpinUp) {
    115    return eSpinButtonUp;
    116  }
    117  if (aEvent->mOriginalTarget == mSpinDown) {
    118    return eSpinButtonDown;
    119  }
    120  if (aEvent->mOriginalTarget == mButton) {
    121    // In the case that the up/down buttons are hidden (display:none) we use
    122    // just the spin box element, spinning up if the pointer is over the top
    123    // half of the element, or down if it's over the bottom half. This is
    124    // important to handle since this is the state things are in for the
    125    // default UA style sheet. See the comment in forms.css for why.
    126    LayoutDeviceIntPoint absPoint = aEvent->mRefPoint;
    127    nsPoint point = nsLayoutUtils::GetEventCoordinatesRelativeTo(
    128        aEvent, absPoint, RelativeTo{mButton->GetPrimaryFrame()});
    129    if (point != nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
    130      if (point.y < mButton->GetPrimaryFrame()->GetSize().height / 2) {
    131        return eSpinButtonUp;
    132      }
    133      return eSpinButtonDown;
    134    }
    135  }
    136  return eSpinButtonNone;
    137 }
    138 
    139 void nsNumberControlFrame::SpinnerStateChanged() const {
    140  if (mSpinUp) {
    141    nsIFrame* spinUpFrame = mSpinUp->GetPrimaryFrame();
    142    if (spinUpFrame && spinUpFrame->IsThemed()) {
    143      spinUpFrame->InvalidateFrame();
    144    }
    145  }
    146  if (mSpinDown) {
    147    nsIFrame* spinDownFrame = mSpinDown->GetPrimaryFrame();
    148    if (spinDownFrame && spinDownFrame->IsThemed()) {
    149      spinDownFrame->InvalidateFrame();
    150    }
    151  }
    152 }
    153 
    154 bool nsNumberControlFrame::SpinnerUpButtonIsDepressed() const {
    155  return HTMLInputElement::FromNode(mContent)
    156      ->NumberSpinnerUpButtonIsDepressed();
    157 }
    158 
    159 bool nsNumberControlFrame::SpinnerDownButtonIsDepressed() const {
    160  return HTMLInputElement::FromNode(mContent)
    161      ->NumberSpinnerDownButtonIsDepressed();
    162 }
    163 
    164 #ifdef ACCESSIBILITY
    165 a11y::AccType nsNumberControlFrame::AccessibleType() {
    166  return a11y::eHTMLSpinnerType;
    167 }
    168 #endif