Ejemplo n.º 1
0
nsresult
nsTextControlFrame::EnsureEditorInitialized()
{
  // This method initializes our editor, if needed.

  // This code used to be called from CreateAnonymousContent(), but
  // when the editor set the initial string, it would trigger a
  // PresShell listener which called FlushPendingNotifications()
  // during frame construction. This was causing other form controls
  // to display wrong values.  Additionally, calling this every time
  // a text frame control is instantiated means that we're effectively
  // instantiating the editor for all text fields, even if they
  // never get used.  So, now this method is being called lazily only
  // when we actually need an editor.

  // Check if this method has been called already.
  // If so, just return early.
  if (mUseEditor)
    return NS_OK;

  NS_TIME_FUNCTION;

  nsIDocument* doc = mContent->GetCurrentDoc();
  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);

  nsWeakFrame weakFrame(this);

  // Flush out content on our document.  Have to do this, because script
  // blockers don't prevent the sink flushing out content and notifying in the
  // process, which can destroy frames.
  doc->FlushPendingNotifications(Flush_ContentAndNotify);
  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_ERROR_FAILURE);

  // Make sure that editor init doesn't do things that would kill us off
  // (especially off the script blockers it'll create for its DOM mutations).
  nsAutoScriptBlocker scriptBlocker;

  // Time to mess with our security context... See comments in GetValue()
  // for why this is needed.
  nsCxPusher pusher;
  pusher.PushNull();

  // Make sure that we try to focus the content even if the method fails
  class EnsureSetFocus {
  public:
    explicit EnsureSetFocus(nsTextControlFrame* aFrame)
      : mFrame(aFrame) {}
    ~EnsureSetFocus() {
      if (nsContentUtils::IsFocusedContent(mFrame->GetContent()))
        mFrame->SetFocus(PR_TRUE, PR_FALSE);
    }
  private:
    nsTextControlFrame *mFrame;
  };
  EnsureSetFocus makeSureSetFocusHappens(this);

#ifdef DEBUG
  // Make sure we are not being called again until we're finished.
  // If reentrancy happens, just pretend that we don't have an editor.
  const EditorInitializerEntryTracker tracker(*this);
  NS_ASSERTION(!tracker.EnteredMoreThanOnce(),
               "EnsureEditorInitialized has been called while a previous call was in progress");
#endif

  // Create an editor for the frame, if one doesn't already exist
  nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
  NS_ASSERTION(txtCtrl, "Content not a text control element");
  nsresult rv = txtCtrl->CreateEditor();
  NS_ENSURE_SUCCESS(rv, rv);

  // Turn on mUseEditor so that subsequent calls will use the
  // editor.
  mUseEditor = PR_TRUE;

  // Set the selection to the beginning of the text field.
  SetSelectionEndPoints(0, 0);

  return NS_OK;
}
Ejemplo n.º 2
0
nsresult
nsTextControlFrame::EnsureEditorInitialized()
{
  // This method initializes our editor, if needed.

  // This code used to be called from CreateAnonymousContent(), but
  // when the editor set the initial string, it would trigger a
  // PresShell listener which called FlushPendingNotifications()
  // during frame construction. This was causing other form controls
  // to display wrong values.  Additionally, calling this every time
  // a text frame control is instantiated means that we're effectively
  // instantiating the editor for all text fields, even if they
  // never get used.  So, now this method is being called lazily only
  // when we actually need an editor.

  if (mEditorHasBeenInitialized)
    return NS_OK;

  nsIDocument* doc = mContent->GetComposedDoc();
  NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);

  nsWeakFrame weakFrame(this);

  // Flush out content on our document.  Have to do this, because script
  // blockers don't prevent the sink flushing out content and notifying in the
  // process, which can destroy frames.
  doc->FlushPendingNotifications(FlushType::ContentAndNotify);
  NS_ENSURE_TRUE(weakFrame.IsAlive(), NS_ERROR_FAILURE);

  // Make sure that editor init doesn't do things that would kill us off
  // (especially off the script blockers it'll create for its DOM mutations).
  {
    nsCOMPtr<nsITextControlElement> txtCtrl = do_QueryInterface(GetContent());
    MOZ_ASSERT(txtCtrl, "Content not a text control element");

    // Hide selection changes during the initialization, as webpages should not
    // be aware of these initializations
    AutoHideSelectionChanges hideSelectionChanges(txtCtrl->GetConstFrameSelection());

    nsAutoScriptBlocker scriptBlocker;

    // Time to mess with our security context... See comments in GetValue()
    // for why this is needed.
    mozilla::dom::AutoNoJSAPI nojsapi;

    // Make sure that we try to focus the content even if the method fails
    class EnsureSetFocus {
    public:
      explicit EnsureSetFocus(nsTextControlFrame* aFrame)
        : mFrame(aFrame) {}
      ~EnsureSetFocus() {
        if (nsContentUtils::IsFocusedContent(mFrame->GetContent()))
          mFrame->SetFocus(true, false);
      }
    private:
      nsTextControlFrame *mFrame;
    };
    EnsureSetFocus makeSureSetFocusHappens(this);

#ifdef DEBUG
    // Make sure we are not being called again until we're finished.
    // If reentrancy happens, just pretend that we don't have an editor.
    const EditorInitializerEntryTracker tracker(*this);
    NS_ASSERTION(!tracker.EnteredMoreThanOnce(),
                 "EnsureEditorInitialized has been called while a previous call was in progress");
#endif

    // Create an editor for the frame, if one doesn't already exist
    nsresult rv = txtCtrl->CreateEditor();
    NS_ENSURE_SUCCESS(rv, rv);
    NS_ENSURE_STATE(weakFrame.IsAlive());

    // Set mEditorHasBeenInitialized so that subsequent calls will use the
    // editor.
    mEditorHasBeenInitialized = true;

    nsAutoString val;
    txtCtrl->GetTextEditorValue(val, true);
    int32_t length = val.Length();

    // Set the selection to the end of the text field. (bug 1287655)
    if (weakFrame.IsAlive()) {
      SetSelectionEndPoints(length, length);
    }
  }
  NS_ENSURE_STATE(weakFrame.IsAlive());
  return NS_OK;
}