Bug 1487659 - Make Selection treat SelectionChangeListener as a concrete class rather than nsISelectionListener r=smaug

SelectionChangeListener is an nsISelectionListener class.  This is added only
to Selection for "normal" and added by nsFrameSelection::Init() after
AccessibleCaretEventHub.  So, we can make Selection directly treat
SelectionChangeListener.

Differential Revision: https://phabricator.services.mozilla.com/D4757

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2018-08-31 21:22:57 +00:00
parent 9c349ade9b
commit 9ab2669f86
6 changed files with 45 additions and 29 deletions

View File

@ -60,7 +60,6 @@
#include "nsINamed.h"
#include "nsISelectionController.h" //for the enums
#include "SelectionChangeListener.h"
#include "nsCopySupport.h"
#include "nsIClipboard.h"
#include "nsIFrameInlines.h"
@ -738,6 +737,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Selection)
// in JS!).
tmp->mNotifyAutoCopy = false;
tmp->StopNotifyingAccessibleCaretEventHub();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectionChangeListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelectionListeners)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedRange)
tmp->RemoveAllRanges(IgnoreErrors());
@ -754,6 +754,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Selection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnchorFocusRange)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedRange)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameSelection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectionChangeListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelectionListeners)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Selection)
@ -3490,7 +3491,7 @@ Selection::NotifySelectionListeners()
// We've notified all selection listeners even when some of them are removed
// (and may be destroyed) during notifying one of them. Therefore, we should
// copy all listeners to the local variable first.
AutoTArray<nsCOMPtr<nsISelectionListener>, 8>
AutoTArray<nsCOMPtr<nsISelectionListener>, 5>
selectionListeners(mSelectionListeners);
int16_t reason = frameSelection->PopReason();
@ -3504,6 +3505,10 @@ Selection::NotifySelectionListeners()
hub->OnSelectionChange(doc, this, reason);
}
if (mSelectionChangeListener) {
RefPtr<SelectionChangeListener> listener(mSelectionChangeListener);
listener->OnSelectionChange(doc, this, reason);
}
for (auto& listener : selectionListeners) {
listener->NotifySelectionChanged(doc, this, reason);
}

View File

@ -12,6 +12,7 @@
#include "mozilla/AccessibleCaretEventHub.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/RangeBoundary.h"
#include "mozilla/SelectionChangeListener.h"
#include "mozilla/TextRange.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
@ -115,6 +116,18 @@ public:
mAccessibleCaretEventHub = nullptr;
}
/**
* EnableSelectionChangeEvent() starts to notify SelectionChangeListener of
* selection change to dispatch a selectionchange event at every selection
* change.
*/
void EnableSelectionChangeEvent()
{
if (!mSelectionChangeListener) {
mSelectionChangeListener = new SelectionChangeListener();
}
}
nsIDocument* GetParentObject() const;
DocGroup* GetDocGroup() const;
@ -718,6 +731,7 @@ private:
RefPtr<nsRange> mCachedRange;
RefPtr<nsFrameSelection> mFrameSelection;
RefPtr<AccessibleCaretEventHub> mAccessibleCaretEventHub;
RefPtr<SelectionChangeListener> mSelectionChangeListener;
RefPtr<nsAutoScrollTimer> mAutoScrollTimer;
nsTArray<nsCOMPtr<nsISelectionListener>> mSelectionListeners;
nsRevocableEventPtr<ScrollSelectionIntoViewEvent> mScrollEvent;

View File

@ -71,22 +71,18 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SelectionChangeListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOldRanges);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SelectionChangeListener)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SelectionChangeListener, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SelectionChangeListener, Release)
NS_IMPL_CYCLE_COLLECTING_ADDREF(SelectionChangeListener)
NS_IMPL_CYCLE_COLLECTING_RELEASE(SelectionChangeListener)
NS_IMETHODIMP
SelectionChangeListener::NotifySelectionChanged(nsIDocument* aDoc,
Selection* aSel, int16_t aReason)
void
SelectionChangeListener::OnSelectionChange(nsIDocument* aDoc,
Selection* aSel,
int16_t aReason)
{
nsIDocument* doc = aSel->GetParentObject();
if (!(doc && nsContentUtils::IsSystemPrincipal(doc->NodePrincipal())) &&
!nsFrameSelection::sSelectionEventsEnabled) {
return NS_OK;
return;
}
// Check if the ranges have actually changed
@ -103,7 +99,7 @@ SelectionChangeListener::NotifySelectionChanged(nsIDocument* aDoc,
}
if (!changed) {
return NS_OK;
return;
}
}
@ -116,7 +112,7 @@ SelectionChangeListener::NotifySelectionChanged(nsIDocument* aDoc,
if (doc) {
nsPIDOMWindowInner* inner = doc->GetInnerWindow();
if (inner && !inner->HasSelectionChangeEventListeners()) {
return NS_OK;
return;
}
}
@ -124,7 +120,7 @@ SelectionChangeListener::NotifySelectionChanged(nsIDocument* aDoc,
// update mOldRanges so that changes after the changes stop being hidden don't
// incorrectly trigger a change, even though they didn't change anything
if (aSel->IsBlockingSelectionChangeEvents()) {
return NS_OK;
return;
}
// The spec currently doesn't say that we should dispatch this event on text
@ -163,7 +159,7 @@ SelectionChangeListener::NotifySelectionChanged(nsIDocument* aDoc,
if (const nsFrameSelection* fs = aSel->GetFrameSelection()) {
if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
if (root->IsInNativeAnonymousSubtree()) {
return NS_OK;
return;
}
}
}
@ -174,6 +170,4 @@ SelectionChangeListener::NotifySelectionChanged(nsIDocument* aDoc,
asyncDispatcher->PostDOMEvent();
}
}
return NS_OK;
}

View File

@ -7,7 +7,6 @@
#ifndef mozilla_SelectionChangeListener_h_
#define mozilla_SelectionChangeListener_h_
#include "nsISelectionListener.h"
#include "mozilla/Attributes.h"
#include "nsCycleCollectionParticipant.h"
#include "nsTArray.h"
@ -19,14 +18,21 @@ class nsINode;
namespace mozilla {
namespace dom {
class SelectionChangeListener final : public nsISelectionListener
// XXX This class name is too generic. Perhaps, SelectionChangeEventDispatcher?
// And also it's odd that this is in |dom| namespace since this is not
// an implementation of any DOM object.
class SelectionChangeListener final
{
public:
// SelectionChangeListener has to participate in cycle collection because
// it holds strong references to nsINodes in its mOldRanges array.
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(SelectionChangeListener)
NS_DECL_NSISELECTIONLISTENER
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SelectionChangeListener)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(SelectionChangeListener)
MOZ_CAN_RUN_SCRIPT
void OnSelectionChange(nsIDocument* aDocument,
Selection* aSelection,
int16_t aReason);
// This field is used to keep track of the ranges which were present in the
// selection when the selectionchange event was previously fired. This allows

View File

@ -132,6 +132,7 @@ EXPORTS.mozilla += [
'FeedWriterEnabled.h',
'FlushType.h',
'RangeBoundary.h',
'SelectionChangeListener.h',
'TextInputProcessor.h',
'UseCounter.h',
]

View File

@ -60,7 +60,6 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
#include "nsIDocument.h"
#include "nsISelectionController.h" //for the enums
#include "SelectionChangeListener.h"
#include "nsCopySupport.h"
#include "nsIClipboard.h"
#include "nsIFrameInlines.h"
@ -667,10 +666,7 @@ nsFrameSelection::Init(nsIPresShell *aShell, nsIContent *aLimiter,
(doc && nsContentUtils::IsSystemPrincipal(doc->NodePrincipal()))) {
int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
if (mDomSelections[index]) {
// The Selection instance will hold a strong reference to its selectionchangelistener
// so we don't have to worry about that!
RefPtr<SelectionChangeListener> listener = new SelectionChangeListener;
mDomSelections[index]->AddSelectionListener(listener);
mDomSelections[index]->EnableSelectionChangeEvent();
}
}
}