зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1486370 - Change nsAutoCopyListener to a static class r=smaug
nsAutoCopyListener is a singleton class but refcountable and a selection listener. nsFrameSelection adds it to only normal Selection when it's on macOS or it's enabled by the pref. Additionally, it's always first selection listener since it's added immediately after Selection instance is created. So, we can make it a static class, and normal Selection instance should have a bool to decide whether it should notify nsAutoCopyListener of its changes. Then, we can save the cost of grabbing it with local RefPtr and the virtual call. Additionally, this patch renames nsAutoCopyListener to mozilla::AutoCopyListener and optimizes constructor of nsFrameSelection (using bool var cache to retrieve the pref, avoid retrieving the pref on macOS). Differential Revision: https://phabricator.services.mozilla.com/D4504 --HG-- rename : layout/generic/nsAutoCopyListener.h => layout/generic/AutoCopyListener.h extra : moz-landing-system : lando
This commit is contained in:
Родитель
aa3c35e3d7
Коммит
be86e183fd
|
@ -10,11 +10,18 @@
|
|||
|
||||
#include "mozilla/dom/Selection.h"
|
||||
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/AutoCopyListener.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/SelectionBinding.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/HTMLEditor.h"
|
||||
#include "mozilla/RangeBoundary.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
@ -53,7 +60,6 @@
|
|||
#include "nsINamed.h"
|
||||
|
||||
#include "nsISelectionController.h" //for the enums
|
||||
#include "nsAutoCopyListener.h"
|
||||
#include "SelectionChangeListener.h"
|
||||
#include "nsCopySupport.h"
|
||||
#include "nsIClipboard.h"
|
||||
|
@ -62,12 +68,6 @@
|
|||
#include "nsIBidiKeyboard.h"
|
||||
|
||||
#include "nsError.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/SelectionBinding.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsViewManager.h"
|
||||
|
||||
#include "nsFocusManager.h"
|
||||
|
@ -666,9 +666,10 @@ Selection::Selection()
|
|||
, mDirection(eDirNext)
|
||||
, mSelectionType(SelectionType::eNormal)
|
||||
, mCustomColors(nullptr)
|
||||
, mSelectionChangeBlockerCount(0)
|
||||
, mUserInitiated(false)
|
||||
, mCalledByJS(false)
|
||||
, mSelectionChangeBlockerCount(0)
|
||||
, mNotifyAutoCopy(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -678,9 +679,10 @@ Selection::Selection(nsFrameSelection* aList)
|
|||
, mDirection(eDirNext)
|
||||
, mSelectionType(SelectionType::eNormal)
|
||||
, mCustomColors(nullptr)
|
||||
, mSelectionChangeBlockerCount(0)
|
||||
, mUserInitiated(false)
|
||||
, mCalledByJS(false)
|
||||
, mSelectionChangeBlockerCount(0)
|
||||
, mNotifyAutoCopy(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -3475,8 +3477,6 @@ Selection::NotifySelectionListeners()
|
|||
// If there are no selection listeners, we're done!
|
||||
return NS_OK;
|
||||
}
|
||||
AutoTArray<nsCOMPtr<nsISelectionListener>, 8>
|
||||
selectionListeners(mSelectionListeners);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
nsIPresShell* ps = GetPresShell();
|
||||
|
@ -3484,7 +3484,18 @@ Selection::NotifySelectionListeners()
|
|||
doc = ps->GetDocument();
|
||||
}
|
||||
|
||||
short reason = frameSelection->PopReason();
|
||||
// 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>
|
||||
selectionListeners(mSelectionListeners);
|
||||
|
||||
int16_t reason = frameSelection->PopReason();
|
||||
|
||||
if (mNotifyAutoCopy) {
|
||||
AutoCopyListener::OnSelectionChange(doc, *this, reason);
|
||||
}
|
||||
|
||||
for (auto& listener : selectionListeners) {
|
||||
listener->NotifySelectionChanged(doc, this, reason);
|
||||
}
|
||||
|
|
|
@ -86,6 +86,14 @@ public:
|
|||
// match this up with StartBatchChanges
|
||||
void EndBatchChanges(int16_t aReason = nsISelectionListener::NO_REASON);
|
||||
|
||||
/**
|
||||
* NotifyAutoCopy() starts to notify AutoCopyListener of selection changes.
|
||||
*/
|
||||
void NotifyAutoCopy()
|
||||
{
|
||||
mNotifyAutoCopy = true;
|
||||
}
|
||||
|
||||
nsIDocument* GetParentObject() const;
|
||||
DocGroup* GetDocGroup() const;
|
||||
|
||||
|
@ -678,6 +686,10 @@ private:
|
|||
SelectionType mSelectionType;
|
||||
UniquePtr<SelectionCustomColors> mCustomColors;
|
||||
|
||||
// Non-zero if we don't want any changes we make to the selection to be
|
||||
// visible to content. If non-zero, content won't be notified about changes.
|
||||
uint32_t mSelectionChangeBlockerCount;
|
||||
|
||||
/**
|
||||
* True if the current selection operation was initiated by user action.
|
||||
* It determines whether we exclude -moz-user-select:none nodes or not,
|
||||
|
@ -691,9 +703,10 @@ private:
|
|||
*/
|
||||
bool mCalledByJS;
|
||||
|
||||
// Non-zero if we don't want any changes we make to the selection to be
|
||||
// visible to content. If non-zero, content won't be notified about changes.
|
||||
uint32_t mSelectionChangeBlockerCount;
|
||||
/**
|
||||
* true if AutoCopyListner::OnSelectionChange() should be called.
|
||||
*/
|
||||
bool mNotifyAutoCopy;
|
||||
};
|
||||
|
||||
// Stack-class to turn on/off selection batching.
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "DateTimeFormat.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsAutoCopyListener.h"
|
||||
#include "nsColorNames.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsContentDLF.h"
|
||||
|
@ -355,7 +354,6 @@ nsLayoutStatics::Shutdown()
|
|||
WebIDLGlobalNameHash::Shutdown();
|
||||
nsListControlFrame::Shutdown();
|
||||
nsXBLService::Shutdown();
|
||||
nsAutoCopyListener::Shutdown();
|
||||
FrameLayerBuilder::Shutdown();
|
||||
|
||||
CubebUtils::ShutdownLibrary();
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_AutoCopyListener_h
|
||||
#define mozilla_AutoCopyListener_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
#include "nsIClipboard.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AutoCopyListener final
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* OnSelectionChange() is called when a Selection whose NotifyAutoCopy() was
|
||||
* called is changed.
|
||||
*
|
||||
* @param aDocument The document of the Selection. May be nullptr.
|
||||
* @param aSelection The selection.
|
||||
* @param aReason The reasons of the change.
|
||||
* See nsISelectionListener::*_REASON.
|
||||
*/
|
||||
static void OnSelectionChange(nsIDocument* aDocument,
|
||||
dom::Selection& aSelection,
|
||||
int16_t aReason);
|
||||
|
||||
/**
|
||||
* Init() initializes all static members of this class. Should be called
|
||||
* only once.
|
||||
*/
|
||||
static void Init(int16_t aClipboardID)
|
||||
{
|
||||
MOZ_ASSERT(IsValidClipboardID(aClipboardID));
|
||||
static bool sInitialized = false;
|
||||
if (!sInitialized && IsValidClipboardID(aClipboardID)) {
|
||||
sClipboardID = aClipboardID;
|
||||
sInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* IsPrefEnabled() returns true if the pref enables auto-copy feature.
|
||||
*/
|
||||
static bool IsPrefEnabled()
|
||||
{
|
||||
return StaticPrefs::clipboard_autocopy();
|
||||
}
|
||||
|
||||
private:
|
||||
static bool IsValidClipboardID(int16_t aClipboardID)
|
||||
{
|
||||
return aClipboardID >= nsIClipboard::kSelectionClipboard &&
|
||||
aClipboardID <= nsIClipboard::kSelectionCache;
|
||||
}
|
||||
|
||||
static int16_t sClipboardID;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // #ifndef mozilla_AutoCopyListener_h
|
|
@ -109,6 +109,7 @@ EXPORTS += [
|
|||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'AutoCopyListener.h',
|
||||
'CSSAlignUtils.h',
|
||||
'CSSOrderAwareFrameIterator.h',
|
||||
'FrameTypeList.h',
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAutoCopyListener_h_
|
||||
#define nsAutoCopyListener_h_
|
||||
|
||||
#include "nsISelectionListener.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
|
||||
class nsAutoCopyListener final : public nsISelectionListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISELECTIONLISTENER
|
||||
|
||||
explicit nsAutoCopyListener(int16_t aClipboardID)
|
||||
: mCachedClipboard(aClipboardID)
|
||||
{}
|
||||
|
||||
void Listen(mozilla::dom::Selection *aSelection)
|
||||
{
|
||||
NS_ASSERTION(aSelection, "Null selection passed to Listen()");
|
||||
aSelection->AddSelectionListener(this);
|
||||
}
|
||||
|
||||
static nsAutoCopyListener* GetInstance(int16_t aClipboardID)
|
||||
{
|
||||
if (!sInstance) {
|
||||
sInstance = new nsAutoCopyListener(aClipboardID);
|
||||
|
||||
NS_ADDREF(sInstance);
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
static void Shutdown()
|
||||
{
|
||||
NS_IF_RELEASE(sInstance);
|
||||
}
|
||||
|
||||
private:
|
||||
~nsAutoCopyListener() {}
|
||||
|
||||
static nsAutoCopyListener* sInstance;
|
||||
int16_t mCachedClipboard;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -61,7 +61,6 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
|
|||
#include "nsIDocument.h"
|
||||
|
||||
#include "nsISelectionController.h" //for the enums
|
||||
#include "nsAutoCopyListener.h"
|
||||
#include "SelectionChangeListener.h"
|
||||
#include "nsCopySupport.h"
|
||||
#include "nsIClipboard.h"
|
||||
|
@ -70,6 +69,7 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
|
|||
#include "nsIBidiKeyboard.h"
|
||||
|
||||
#include "nsError.h"
|
||||
#include "mozilla/AutoCopyListener.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
|
@ -301,22 +301,23 @@ nsFrameSelection::nsFrameSelection()
|
|||
mDomSelections[i]->SetType(kPresentSelectionTypes[i]);
|
||||
}
|
||||
|
||||
nsAutoCopyListener *autoCopy = nullptr;
|
||||
// On macOS, cache the current selection to send to osx service menu.
|
||||
#ifdef XP_MACOSX
|
||||
autoCopy = nsAutoCopyListener::GetInstance(nsIClipboard::kSelectionCache);
|
||||
#endif
|
||||
|
||||
// Check to see if the autocopy pref is enabled
|
||||
// and add the autocopy listener if it is
|
||||
if (Preferences::GetBool("clipboard.autocopy")) {
|
||||
autoCopy = nsAutoCopyListener::GetInstance(nsIClipboard::kSelectionClipboard);
|
||||
// On macOS, cache the current selection to send to service menu of macOS.
|
||||
bool enableAutoCopy = true;
|
||||
AutoCopyListener::Init(nsIClipboard::kSelectionCache);
|
||||
#else // #ifdef XP_MACOSX
|
||||
// Check to see if the auto-copy pref is enabled and make the normal
|
||||
// Selection notifies auto-copy listener of its changes.
|
||||
bool enableAutoCopy = AutoCopyListener::IsPrefEnabled();
|
||||
if (enableAutoCopy) {
|
||||
AutoCopyListener::Init(nsIClipboard::kSelectionClipboard);
|
||||
}
|
||||
#endif // #ifdef XP_MACOSX #else
|
||||
|
||||
if (autoCopy) {
|
||||
if (enableAutoCopy) {
|
||||
int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
|
||||
if (mDomSelections[index]) {
|
||||
autoCopy->Listen(mDomSelections[index]);
|
||||
mDomSelections[index]->NotifyAutoCopy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2898,7 +2899,7 @@ nsFrameSelection::DisconnectFromPresShell()
|
|||
* if the current selection being repainted is not an empty selection.
|
||||
*
|
||||
* If the current selection is empty. The current selection cache
|
||||
* would be cleared by nsAutoCopyListener::NotifySelectionChanged.
|
||||
* would be cleared by AutoCopyListener::OnSelectionChange().
|
||||
*/
|
||||
nsresult
|
||||
nsFrameSelection::UpdateSelectionCacheOnRepaintSelection(Selection* aSel)
|
||||
|
@ -2917,11 +2918,9 @@ nsFrameSelection::UpdateSelectionCacheOnRepaintSelection(Selection* aSel)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsAutoCopyListener
|
||||
// mozilla::AutoCopyListener
|
||||
|
||||
nsAutoCopyListener* nsAutoCopyListener::sInstance = nullptr;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAutoCopyListener, nsISelectionListener)
|
||||
int16_t AutoCopyListener::sClipboardID = -1;
|
||||
|
||||
/*
|
||||
* What we do now:
|
||||
|
@ -2955,40 +2954,51 @@ NS_IMPL_ISUPPORTS(nsAutoCopyListener, nsISelectionListener)
|
|||
* widget cocoa nsClipboard whenever selection changes.
|
||||
*/
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAutoCopyListener::NotifySelectionChanged(nsIDocument *aDoc,
|
||||
Selection *aSel, int16_t aReason)
|
||||
// static
|
||||
void
|
||||
AutoCopyListener::OnSelectionChange(nsIDocument* aDocument,
|
||||
Selection& aSelection,
|
||||
int16_t aReason)
|
||||
{
|
||||
if (mCachedClipboard == nsIClipboard::kSelectionCache) {
|
||||
MOZ_ASSERT(IsValidClipboardID(sClipboardID));
|
||||
|
||||
if (sClipboardID == nsIClipboard::kSelectionCache) {
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
// If no active window, do nothing because a current selection changed
|
||||
// cannot occur unless it is in the active window.
|
||||
if (!fm->GetActiveWindow()) {
|
||||
return NS_OK;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(aReason & nsISelectionListener::MOUSEUP_REASON ||
|
||||
aReason & nsISelectionListener::SELECTALL_REASON ||
|
||||
aReason & nsISelectionListener::KEYPRESS_REASON))
|
||||
return NS_OK; //dont care if we are still dragging
|
||||
static const int16_t kResasonsToHandle =
|
||||
nsISelectionListener::MOUSEUP_REASON |
|
||||
nsISelectionListener::SELECTALL_REASON |
|
||||
nsISelectionListener::KEYPRESS_REASON;
|
||||
if (!(aReason & kResasonsToHandle)) {
|
||||
return; // Don't care if we are still dragging.
|
||||
}
|
||||
|
||||
if (!aDoc || !aSel || aSel->IsCollapsed()) {
|
||||
if (!aDocument || aSelection.IsCollapsed()) {
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
fprintf(stderr, "CLIPBOARD: no selection/collapsed selection\n");
|
||||
#endif
|
||||
if (sClipboardID != nsIClipboard::kSelectionCache) {
|
||||
// XXX Should we clear X clipboard?
|
||||
return;
|
||||
}
|
||||
|
||||
// If on macOS, clear the current selection transferable cached
|
||||
// on the parent process (nsClipboard) when the selection is empty.
|
||||
if (mCachedClipboard == nsIClipboard::kSelectionCache) {
|
||||
return nsCopySupport::ClearSelectionCache();
|
||||
}
|
||||
/* clear X clipboard? */
|
||||
return NS_OK;
|
||||
DebugOnly<nsresult> rv = nsCopySupport::ClearSelectionCache();
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsCopySupport::ClearSelectionCache() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(aDoc, NS_ERROR_FAILURE);
|
||||
|
||||
// call the copy code
|
||||
return nsCopySupport::HTMLCopy(aSel, aDoc,
|
||||
mCachedClipboard, false);
|
||||
// Call the copy code.
|
||||
DebugOnly<nsresult> rv =
|
||||
nsCopySupport::HTMLCopy(&aSelection, aDocument, sClipboardID, false);
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"nsCopySupport::HTMLCopy() failed");
|
||||
}
|
||||
|
|
|
@ -87,6 +87,22 @@ VARCACHE_PREF(
|
|||
RelaxedAtomicBool, false
|
||||
)
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Clipboard prefs
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
#if !defined(ANDROID) && !defined(XP_MACOSX) && defined(XP_UNIX)
|
||||
# define PREF_VALUE true
|
||||
#else
|
||||
# define PREF_VALUE false
|
||||
#endif
|
||||
VARCACHE_PREF(
|
||||
"clipboard.autocopy",
|
||||
clipboard_autocopy,
|
||||
bool, PREF_VALUE
|
||||
)
|
||||
#undef PREF_VALUE
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// DOM prefs
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
Загрузка…
Ссылка в новой задаче