tor-browser

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

nsTextControlFrame.h (12639B)


      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 #ifndef nsTextControlFrame_h___
      8 #define nsTextControlFrame_h___
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/TextControlElement.h"
     12 #include "nsContainerFrame.h"
     13 #include "nsIAnonymousContentCreator.h"
     14 #include "nsIContent.h"
     15 #include "nsIStatefulFrame.h"
     16 
     17 class nsISelectionController;
     18 class EditorInitializerEntryTracker;
     19 namespace mozilla {
     20 class AutoTextControlHandlingState;
     21 class ScrollContainerFrame;
     22 class TextEditor;
     23 class TextControlState;
     24 enum class PseudoStyleType : uint8_t;
     25 enum class SelectionDirection : uint8_t;
     26 namespace dom {
     27 class Element;
     28 }  // namespace dom
     29 }  // namespace mozilla
     30 
     31 class nsTextControlFrame : public nsContainerFrame,
     32                           public nsIAnonymousContentCreator,
     33                           public nsIStatefulFrame {
     34  using Element = mozilla::dom::Element;
     35 
     36 public:
     37  NS_DECL_FRAMEARENA_HELPERS(nsTextControlFrame)
     38 
     39  NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(ContentScrollPos, nsPoint)
     40 
     41 protected:
     42  nsTextControlFrame(ComputedStyle*, nsPresContext*, nsIFrame::ClassID);
     43 
     44 public:
     45  explicit nsTextControlFrame(ComputedStyle* aStyle,
     46                              nsPresContext* aPresContext)
     47      : nsTextControlFrame(aStyle, aPresContext, kClassID) {}
     48 
     49  virtual ~nsTextControlFrame();
     50 
     51  /**
     52   * Destroy() causes preparing to destroy editor and that may cause running
     53   * selection listeners of spellchecker selection and document state listeners.
     54   * Not sure whether the former does something or not, but nobody should run
     55   * content script.  The latter is currently only FinderHighlighter to clean up
     56   * its fields at destruction.  Thus, the latter won't run content script too.
     57   * Therefore, this won't run unsafe script.
     58   */
     59  MOZ_CAN_RUN_SCRIPT_BOUNDARY void Destroy(DestroyContext&) override;
     60 
     61  mozilla::ScrollContainerFrame* GetScrollTargetFrame() const override;
     62 
     63  nscoord IntrinsicISize(const mozilla::IntrinsicSizeInput& aInput,
     64                         mozilla::IntrinsicISizeType aType) override;
     65 
     66  void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
     67              const ReflowInput& aReflowInput,
     68              nsReflowStatus& aStatus) override;
     69 
     70  Maybe<nscoord> GetNaturalBaselineBOffset(
     71      mozilla::WritingMode aWM, BaselineSharingGroup aBaselineGroup,
     72      BaselineExportContext aExportContext) const override;
     73 
     74  BaselineSharingGroup GetDefaultBaselineSharingGroup() const override {
     75    return BaselineSharingGroup::Last;
     76  }
     77 
     78  static Maybe<nscoord> GetSingleLineTextControlBaseline(
     79      const nsIFrame* aFrame, nscoord aFirstBaseline, mozilla::WritingMode aWM,
     80      BaselineSharingGroup aBaselineGroup) {
     81    if (aFrame->StyleDisplay()->IsContainLayout()) {
     82      return Nothing{};
     83    }
     84    NS_ASSERTION(aFirstBaseline != NS_INTRINSIC_ISIZE_UNKNOWN,
     85                 "please call Reflow before asking for the baseline");
     86    return mozilla::Some(aBaselineGroup == BaselineSharingGroup::First
     87                             ? aFirstBaseline
     88                             : aFrame->BSize(aWM) - aFirstBaseline);
     89  }
     90 
     91 #ifdef ACCESSIBILITY
     92  mozilla::a11y::AccType AccessibleType() override;
     93 #endif
     94 
     95 #ifdef DEBUG_FRAME_DUMP
     96  nsresult GetFrameName(nsAString& aResult) const override {
     97    aResult.AssignLiteral("nsTextControlFrame");
     98    return NS_OK;
     99  }
    100 #endif
    101 
    102  // nsIAnonymousContentCreator
    103  nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
    104  void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
    105                                uint32_t aFilter) override;
    106 
    107  void SetInitialChildList(ChildListID, nsFrameList&&) override;
    108 
    109  void BuildDisplayList(nsDisplayListBuilder* aBuilder,
    110                        const nsDisplayListSet& aLists) override;
    111 
    112  MOZ_CAN_RUN_SCRIPT_BOUNDARY already_AddRefed<mozilla::TextEditor>
    113  GetTextEditor();
    114 
    115  MOZ_CAN_RUN_SCRIPT NS_IMETHOD SetSelectionRange(uint32_t aSelectionStart,
    116                                                  uint32_t aSelectionEnd,
    117                                                  mozilla::SelectionDirection);
    118  NS_IMETHOD GetOwnedSelectionController(nsISelectionController** aSelCon);
    119  nsFrameSelection* GetOwnedFrameSelection() {
    120    return ControlElement()->GetIndependentFrameSelection();
    121  }
    122 
    123  void PlaceholderChanged(const nsAttrValue* aOld, const nsAttrValue* aNew);
    124 
    125  /**
    126   * Ensure mEditor is initialized with the proper flags and the default value.
    127   * @throws NS_ERROR_NOT_INITIALIZED if mEditor has not been created
    128   * @throws various and sundry other things
    129   */
    130  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult EnsureEditorInitialized();
    131 
    132  //==== END NSITEXTCONTROLFRAME
    133 
    134  //==== NSISTATEFULFRAME
    135 
    136  mozilla::UniquePtr<mozilla::PresState> SaveState() override;
    137  NS_IMETHOD RestoreState(mozilla::PresState* aState) override;
    138 
    139  //=== END NSISTATEFULFRAME
    140 
    141  //==== OVERLOAD of nsIFrame
    142 
    143  /** handler for attribute changes to mContent */
    144  MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult AttributeChanged(
    145      int32_t aNameSpaceID, nsAtom* aAttribute, AttrModType aModType) override;
    146  void ElementStateChanged(mozilla::dom::ElementState aStates) override;
    147 
    148  nsresult PeekOffset(mozilla::PeekOffsetStruct* aPos) override;
    149 
    150  NS_DECL_QUERYFRAME
    151 
    152  // Whether we should scroll only the current selection into view in the inner
    153  // scroller, or also ancestors as needed.
    154  enum class ScrollAncestors { No, Yes };
    155  void ScrollSelectionIntoViewAsync(ScrollAncestors = ScrollAncestors::No);
    156 
    157 protected:
    158  MOZ_CAN_RUN_SCRIPT_BOUNDARY void OnFocus();
    159  MOZ_CAN_RUN_SCRIPT_BOUNDARY void HandleReadonlyOrDisabledChange();
    160 
    161  /**
    162   * Launch the reflow on the child frames - see nsTextControlFrame::Reflow()
    163   */
    164  void ReflowTextControlChild(nsIFrame* aKid, nsPresContext* aPresContext,
    165                              const ReflowInput& aReflowInput,
    166                              nsReflowStatus& aStatus,
    167                              ReflowOutput& aParentDesiredSize,
    168                              const mozilla::LogicalSize& aParentContentBoxSize,
    169                              nscoord& aButtonBoxISize);
    170 
    171 public:
    172  static Maybe<nscoord> ComputeBaseline(const nsIFrame*, const ReflowInput&,
    173                                        bool aForSingleLineControl);
    174 
    175  Element* GetRootNode() const { return mRootNode; }
    176 
    177  Element* GetPreviewNode() const { return mPreviewDiv; }
    178 
    179  Element* GetPlaceholderNode() const { return mPlaceholderDiv; }
    180 
    181  Element* GetButton() const { return mButton; }
    182 
    183  bool IsButtonBox(const nsIFrame* aFrame) const {
    184    return aFrame->GetContent() == GetButton();
    185  }
    186 
    187  // called by the focus listener
    188  nsresult MaybeBeginSecureKeyboardInput();
    189  void MaybeEndSecureKeyboardInput();
    190 
    191  mozilla::TextControlElement* ControlElement() const {
    192    MOZ_ASSERT(mozilla::TextControlElement::FromNode(GetContent()));
    193    return static_cast<mozilla::TextControlElement*>(GetContent());
    194  }
    195 
    196 #define DEFINE_TEXTCTRL_CONST_FORWARDER(type, name) \
    197  type name() const { return ControlElement()->name(); }
    198 
    199  DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsSingleLineTextControl)
    200  DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsTextArea)
    201  DEFINE_TEXTCTRL_CONST_FORWARDER(bool, IsPasswordTextControl)
    202  DEFINE_TEXTCTRL_CONST_FORWARDER(Maybe<int32_t>, GetCols)
    203  DEFINE_TEXTCTRL_CONST_FORWARDER(int32_t, GetColsOrDefault)
    204  DEFINE_TEXTCTRL_CONST_FORWARDER(int32_t, GetRows)
    205 
    206 #undef DEFINE_TEXTCTRL_CONST_FORWARDER
    207 
    208  MOZ_CAN_RUN_SCRIPT nsresult SelectAll();
    209 
    210 protected:
    211  class EditorInitializer;
    212  friend class EditorInitializer;
    213  friend class mozilla::AutoTextControlHandlingState;  // needs access to
    214                                                       // CacheValue
    215  friend class mozilla::TextControlState;  // needs access to UpdateValueDisplay
    216 
    217  // Temp reference to scriptrunner
    218  NS_DECLARE_FRAME_PROPERTY_WITH_DTOR(TextControlInitializer, EditorInitializer,
    219                                      nsTextControlFrame::RevokeInitializer)
    220 
    221  static void RevokeInitializer(EditorInitializer* aInitializer) {
    222    aInitializer->Revoke();
    223  };
    224 
    225  class EditorInitializer : public mozilla::Runnable {
    226   public:
    227    explicit EditorInitializer(nsTextControlFrame* aFrame)
    228        : mozilla::Runnable("nsTextControlFrame::EditorInitializer"),
    229          mFrame(aFrame) {}
    230 
    231    NS_IMETHOD Run() override;
    232 
    233    // avoids use of AutoWeakFrame
    234    void Revoke() { mFrame = nullptr; }
    235 
    236   private:
    237    nsTextControlFrame* mFrame;
    238  };
    239 
    240  nsresult OffsetToDOMPoint(uint32_t aOffset, nsINode** aResult,
    241                            uint32_t* aPosition);
    242 
    243  /**
    244   * Update the textnode under our anonymous div to show the new
    245   * value. This should only be called when we have no editor yet.
    246   * @throws NS_ERROR_UNEXPECTED if the div has no text content
    247   */
    248  nsresult UpdateValueDisplay(bool aNotify);
    249 
    250  /**
    251   * Find out whether an attribute exists on the content or not.
    252   * @param aAtt the attribute to determine the existence of
    253   * @returns false if it does not exist
    254   */
    255  bool AttributeExists(nsAtom* aAtt) const {
    256    return mContent && mContent->AsElement()->HasAttr(aAtt);
    257  }
    258 
    259  /**
    260   * We call this when we are being destroyed or removed from the PFM.
    261   * @param aPresContext the current pres context
    262   */
    263  void PreDestroy();
    264 
    265  // Compute our intrinsic size.  This does not include any borders, paddings,
    266  // etc.  Just the size of our actual area for the text (and the scrollbars,
    267  // for <textarea>).
    268  mozilla::LogicalSize CalcIntrinsicSize(gfxContext* aRenderingContext,
    269                                         mozilla::WritingMode aWM) const;
    270 
    271 private:
    272  // helper methods
    273  MOZ_CAN_RUN_SCRIPT nsresult SetSelectionInternal(nsINode* aStartNode,
    274                                                   uint32_t aStartOffset,
    275                                                   nsINode* aEndNode,
    276                                                   uint32_t aEndOffset,
    277                                                   mozilla::SelectionDirection);
    278  MOZ_CAN_RUN_SCRIPT nsresult SetSelectionEndPoints(
    279      uint32_t aSelStart, uint32_t aSelEnd, mozilla::SelectionDirection);
    280 
    281  void FinishedInitializer() { RemoveProperty(TextControlInitializer()); }
    282 
    283  const nsAString& CachedValue() const { return mCachedValue; }
    284 
    285  void ClearCachedValue() { mCachedValue.SetIsVoid(true); }
    286 
    287  void CacheValue(const nsAString& aValue) { mCachedValue.Assign(aValue); }
    288 
    289  [[nodiscard]] bool CacheValue(const nsAString& aValue,
    290                                const mozilla::fallible_t& aFallible) {
    291    if (!mCachedValue.Assign(aValue, aFallible)) {
    292      ClearCachedValue();
    293      return false;
    294    }
    295    return true;
    296  }
    297 
    298 protected:
    299  class nsAnonDivObserver;
    300 
    301  nsresult CreateRootNode();
    302  void CreatePlaceholderIfNeeded();
    303  void UpdatePlaceholderText(nsString&, bool aNotify);
    304  void CreatePreviewIfNeeded();
    305  already_AddRefed<Element> MakeAnonElement(
    306      mozilla::PseudoStyleType, Element* aParent = nullptr,
    307      nsAtom* aTag = nsGkAtoms::div) const;
    308  already_AddRefed<Element> MakeAnonDivWithTextNode(
    309      mozilla::PseudoStyleType) const;
    310 
    311  bool ShouldInitializeEagerly() const;
    312  void InitializeEagerlyIfNeeded();
    313 
    314  RefPtr<Element> mRootNode;
    315  RefPtr<Element> mPlaceholderDiv;
    316  RefPtr<Element> mPreviewDiv;
    317  // If we have type=password, number, or search, then mButton is our
    318  // reveal-password, spinner, or search button box. Otherwise, it's nullptr.
    319  RefPtr<Element> mButton;
    320  RefPtr<nsAnonDivObserver> mMutationObserver;
    321  // Cache of the |.value| of <input> or <textarea> element without hard-wrap.
    322  // If its IsVoid() returns true, it doesn't cache |.value|.
    323  // Otherwise, it's cached when setting specific value or getting value from
    324  // TextEditor.  Additionally, when contents in the anonymous <div> element
    325  // is modified, this is cleared.
    326  //
    327  // FIXME(bug 1402545): Consider using an nsAutoString here.
    328  nsString mCachedValue{VoidString()};
    329 
    330  // Our first baseline, or NS_INTRINSIC_ISIZE_UNKNOWN if we have a pending
    331  // Reflow (or if we're contain:layout, which means we have no baseline).
    332  nscoord mFirstBaseline = NS_INTRINSIC_ISIZE_UNKNOWN;
    333 
    334  // these packed bools could instead use the high order bits on mState, saving
    335  // 4 bytes
    336  bool mEditorHasBeenInitialized = false;
    337  bool mIsProcessing = false;
    338 
    339 #ifdef DEBUG
    340  bool mInEditorInitialization = false;
    341  friend class EditorInitializerEntryTracker;
    342 #endif
    343 };
    344 
    345 #endif