Commit 63d372da authored by Masayuki Nakano's avatar Masayuki Nakano
Browse files

Bug 1676702 - part 2: Make `TextControlState` initialize `TextEditor` with...

Bug 1676702 - part 2: Make `TextControlState` initialize `TextEditor` with `PasswordMaskData` r=m_kato

During a `TextControlState` alive, `PasswordMaskData` should be alive too.
Otherwise, we cannot keep unmasked range at reframing.

Depends on D118756

Differential Revision: https://phabricator.services.mozilla.com/D118757
parent 30130a49
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ nsDocShellEditorData::~nsDocShellEditorData() { TearDownEditor(); }
void nsDocShellEditorData::TearDownEditor() {
  if (mHTMLEditor) {
    RefPtr<HTMLEditor> htmlEditor = std::move(mHTMLEditor);
    htmlEditor->PreDestroy(false);
    htmlEditor->PreDestroy();
  }
  mEditingSession = nullptr;
  mIsDetached = false;
@@ -48,7 +48,7 @@ nsresult nsDocShellEditorData::MakeEditable(bool aInWaitForUriLoad) {
    NS_WARNING("Destroying existing editor on frame");

    RefPtr<HTMLEditor> htmlEditor = std::move(mHTMLEditor);
    htmlEditor->PreDestroy(false);
    htmlEditor->PreDestroy();
  }

  if (aInWaitForUriLoad) {
@@ -77,7 +77,7 @@ nsresult nsDocShellEditorData::SetHTMLEditor(HTMLEditor* aHTMLEditor) {

  if (mHTMLEditor) {
    RefPtr<HTMLEditor> htmlEditor = std::move(mHTMLEditor);
    htmlEditor->PreDestroy(false);
    htmlEditor->PreDestroy();
    MOZ_ASSERT(!mHTMLEditor,
               "Nested call of nsDocShellEditorData::SetHTMLEditor() detected");
  }
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include "mozilla/EventStateManager.h"
#include "mozilla/PointerLockManager.h"
#include "mozilla/PresShell.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/SVGUtils.h"
#include "mozilla/dom/AnimatableBinding.h"
#include "mozilla/dom/Document.h"
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <utility>

#include "jsapi.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/Components.h"
+27 −11
Original line number Diff line number Diff line
@@ -1655,7 +1655,7 @@ struct MOZ_STACK_CLASS PreDestroyer {
  void Init(TextEditor* aTextEditor) { mTextEditor = aTextEditor; }
  MOZ_CAN_RUN_SCRIPT ~PreDestroyer() {
    if (mTextEditor) {
      MOZ_KnownLive(mTextEditor)->PreDestroy(true);
      MOZ_KnownLive(mTextEditor)->PreDestroy();
    }
  }
  void Swap(RefPtr<TextEditor>& aTextEditor) {
@@ -1719,7 +1719,6 @@ nsresult TextControlState::PrepareEditor(const nsAString* aValue) {

  bool shouldInitializeEditor = false;
  RefPtr<TextEditor> newTextEditor;  // the editor that we might create
  nsresult rv = NS_OK;
  PreDestroyer preDestroyer;
  if (!mTextEditor) {
    shouldInitializeEditor = true;
@@ -1730,7 +1729,7 @@ nsresult TextControlState::PrepareEditor(const nsAString* aValue) {

    // Make sure we clear out the non-breaking space before we initialize the
    // editor
    rv = mBoundFrame->UpdateValueDisplay(true, true);
    nsresult rv = mBoundFrame->UpdateValueDisplay(true, true);
    if (NS_FAILED(rv)) {
      NS_WARNING("nsTextControlFrame::UpdateValueDisplay() failed");
      return rv;
@@ -1738,7 +1737,8 @@ nsresult TextControlState::PrepareEditor(const nsAString* aValue) {
  } else {
    if (aValue || !mEditorInitialized) {
      // Set the correct value in the root node
      rv = mBoundFrame->UpdateValueDisplay(true, !mEditorInitialized, aValue);
      nsresult rv =
          mBoundFrame->UpdateValueDisplay(true, !mEditorInitialized, aValue);
      if (NS_FAILED(rv)) {
        NS_WARNING("nsTextControlFrame::UpdateValueDisplay() failed");
        return rv;
@@ -1784,10 +1784,22 @@ nsresult TextControlState::PrepareEditor(const nsAString* aValue) {
    // already does the relevant security checks.
    AutoNoJSAPI nojsapi;

    RefPtr<Element> rootElement = GetRootNode();
    RefPtr<TextInputSelectionController> selectionController = mSelCon;
    rv = newTextEditor->Init(*doc, rootElement, selectionController,
                             editorFlags, defaultValue);
    RefPtr<Element> anonymousDivElement = GetRootNode();
    if (NS_WARN_IF(!anonymousDivElement) || NS_WARN_IF(!mSelCon)) {
      return NS_ERROR_FAILURE;
    }
    OwningNonNull<TextInputSelectionController> selectionController(*mSelCon);
    UniquePtr<PasswordMaskData> passwordMaskData;
    if (editorFlags & nsIEditor::eEditorPasswordMask) {
      const bool needToUpdatePasswordMaskData =
          newTextEditor != mTextEditor || !mTextEditor->IsPasswordEditor();
      if (needToUpdatePasswordMaskData) {
        passwordMaskData = MakeUnique<PasswordMaskData>();
      }
    }
    nsresult rv =
        newTextEditor->Init(*doc, *anonymousDivElement, selectionController,
                            editorFlags, std::move(passwordMaskData));
    if (NS_FAILED(rv)) {
      NS_WARNING("TextEditor::Init() failed");
      return rv;
@@ -1796,11 +1808,12 @@ nsresult TextControlState::PrepareEditor(const nsAString* aValue) {

  // Initialize the controller for the editor

  nsresult rv = NS_OK;
  if (!SuppressEventHandlers(presContext)) {
    nsCOMPtr<nsIControllers> controllers;
    if (HTMLInputElement* inputElement =
            HTMLInputElement::FromNodeOrNull(mTextCtrlElement)) {
      rv = inputElement->GetControllers(getter_AddRefs(controllers));
      nsresult rv = inputElement->GetControllers(getter_AddRefs(controllers));
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
      }
@@ -1811,13 +1824,16 @@ nsresult TextControlState::PrepareEditor(const nsAString* aValue) {
        return NS_ERROR_FAILURE;
      }

      rv = textAreaElement->GetControllers(getter_AddRefs(controllers));
      nsresult rv =
          textAreaElement->GetControllers(getter_AddRefs(controllers));
      if (NS_WARN_IF(NS_FAILED(rv))) {
        return rv;
      }
    }

    if (controllers) {
      // XXX Oddly, nsresult value is overwritten in the following loop, and
      //     only the last result or `found` decides the value.
      uint32_t numControllers;
      bool found = false;
      rv = controllers->GetControllerCount(&numControllers);
@@ -2327,7 +2343,7 @@ void TextControlState::DestroyEditor() {
    //      PreDestroy() here even while we're handling actions with
    //      mTextEditor.
    RefPtr<TextEditor> textEditor = mTextEditor;
    textEditor->PreDestroy(true);
    textEditor->PreDestroy();
    mEditorInitialized = false;
  }
}
+33 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@
#include "mozilla/EnumSet.h"
#include "mozilla/Maybe.h"
#include "mozilla/TextControlElement.h"
#include "mozilla/TextEditor.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/dom/HTMLInputElementBinding.h"
#include "mozilla/dom/Nullable.h"
@@ -28,6 +28,7 @@ namespace mozilla {

class AutoTextControlHandlingState;
class ErrorResult;
class TextEditor;
class TextInputListener;
class TextInputSelectionController;

@@ -36,6 +37,37 @@ class Element;
class HTMLInputElement;
}  // namespace dom

/**
 * PasswordMaskData stores making information and necessary timer for
 * `TextEditor` instances.
 */
struct PasswordMaskData final {
  // Timer to mask unmasked characters automatically.  Used only when it's
  // a password field.
  nsCOMPtr<nsITimer> mTimer;

  // Unmasked character range.  Used only when it's a password field.
  // If mUnmaskedLength is 0, it means there is no unmasked characters.
  uint32_t mUnmaskedStart = UINT32_MAX;
  uint32_t mUnmaskedLength = 0;

  // Set to true if all characters are masked or waiting notification from
  // `mTimer`.  Otherwise, i.e., part of or all of password is unmasked
  // without setting `mTimer`, set to false.
  bool mIsMaskingPassword = true;

  // Set to true if a manager of the instance wants to disable echoing
  // password temporarily.
  bool mEchoingPasswordPrevented = false;

  MOZ_ALWAYS_INLINE bool IsAllMasked() const {
    return mUnmaskedStart == UINT32_MAX && mUnmaskedLength == 0;
  }
  MOZ_ALWAYS_INLINE uint32_t UnmaskedEnd() const {
    return mUnmaskedStart + mUnmaskedLength;
  }
};

/**
 * TextControlState is a class which is responsible for managing the state of
 * plaintext controls.  This currently includes the following HTML elements:
Loading