gecko-dev/editor/libeditor/EditorUtils.cpp
Masayuki Nakano 365f79c262 Bug 1414713 - EditorUtils::IsDescendantOf() should take EditorDOMPoint and EditorRawDOMPoint as out param r=catalinb,m_kato
EditorUtils::IsDescendantOf() current takes a pointer to offset or a pointer to
child content if the caller needs to know the child of the most ancestor node.

However, some callers should get a child as EditorDOMPoint or EditorRawDOMPoint.
Then, they can be used for some editor methods which need to take child node
for performance optimization.

This patch makes EditorUtils::IsDescendantOf() as only two overloads.  One takes
pointer to EditorRawDOMPoint as optional out argument.  The other takes pointer
to EditorDOMPoint as an out param.

Additionally, this creates new constructor of AutoTrackDOMPoint for making it
can treat EditorDOMPoint directly.

MozReview-Commit-ID: IsAGTUvKI19

--HG--
extra : rebase_source : 97469a21b974c6a1dd515ab472bbc4a88c1899c8
2017-11-06 17:01:33 +09:00

244 lines
6.6 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "mozilla/EditorUtils.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/dom/Selection.h"
#include "nsComponentManagerUtils.h"
#include "nsError.h"
#include "nsIClipboardDragDropHookList.h"
// hooks
#include "nsIClipboardDragDropHooks.h"
#include "nsIContent.h"
#include "nsIContentIterator.h"
#include "nsIDOMDocument.h"
#include "nsIDocShell.h"
#include "nsIDocument.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsINode.h"
#include "nsISimpleEnumerator.h"
class nsISupports;
class nsRange;
namespace mozilla {
using namespace dom;
/******************************************************************************
* AutoSelectionRestorer
*****************************************************************************/
AutoSelectionRestorer::AutoSelectionRestorer(
Selection* aSelection,
EditorBase* aEditorBase
MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
: mEditorBase(nullptr)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
if (NS_WARN_IF(!aSelection) || NS_WARN_IF(!aEditorBase)) {
return;
}
if (aEditorBase->ArePreservingSelection()) {
// We already have initialized mSavedSel, so this must be nested call.
return;
}
mSelection = aSelection;
mEditorBase = aEditorBase;
mEditorBase->PreserveSelectionAcrossActions(mSelection);
}
AutoSelectionRestorer::~AutoSelectionRestorer()
{
NS_ASSERTION(!mSelection || mEditorBase,
"mEditorBase should be non-null when mSelection is");
// mSelection will be null if this was nested call.
if (mSelection && mEditorBase->ArePreservingSelection()) {
mEditorBase->RestorePreservedSelection(mSelection);
}
}
void
AutoSelectionRestorer::Abort()
{
NS_ASSERTION(!mSelection || mEditorBase,
"mEditorBase should be non-null when mSelection is");
if (mSelection) {
mEditorBase->StopPreservingSelection();
}
}
/******************************************************************************
* some helper classes for iterating the dom tree
*****************************************************************************/
DOMIterator::DOMIterator(nsINode& aNode MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
mIter = NS_NewContentIterator();
DebugOnly<nsresult> rv = mIter->Init(&aNode);
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
nsresult
DOMIterator::Init(nsRange& aRange)
{
mIter = NS_NewContentIterator();
return mIter->Init(&aRange);
}
DOMIterator::DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
DOMIterator::~DOMIterator()
{
}
void
DOMIterator::AppendList(const BoolDomIterFunctor& functor,
nsTArray<OwningNonNull<nsINode>>& arrayOfNodes) const
{
// Iterate through dom and build list
for (; !mIter->IsDone(); mIter->Next()) {
nsCOMPtr<nsINode> node = mIter->GetCurrentNode();
if (functor(node)) {
arrayOfNodes.AppendElement(*node);
}
}
}
DOMSubtreeIterator::DOMSubtreeIterator(
MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
: DOMIterator(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT)
{
}
nsresult
DOMSubtreeIterator::Init(nsRange& aRange)
{
mIter = NS_NewContentSubtreeIterator();
return mIter->Init(&aRange);
}
DOMSubtreeIterator::~DOMSubtreeIterator()
{
}
/******************************************************************************
* some general purpose editor utils
*****************************************************************************/
bool
EditorUtils::IsDescendantOf(const nsINode& aNode,
const nsINode& aParent,
EditorRawDOMPoint* aOutPoint /* = nullptr */)
{
if (aOutPoint) {
aOutPoint->Clear();
}
if (&aNode == &aParent) {
return false;
}
for (const nsINode* node = &aNode; node; node = node->GetParentNode()) {
if (node->GetParentNode() == &aParent) {
if (aOutPoint) {
MOZ_ASSERT(node->IsContent());
aOutPoint->Set(node->AsContent());
}
return true;
}
}
return false;
}
bool
EditorUtils::IsDescendantOf(const nsINode& aNode,
const nsINode& aParent,
EditorDOMPoint* aOutPoint)
{
MOZ_ASSERT(aOutPoint);
aOutPoint->Clear();
if (&aNode == &aParent) {
return false;
}
for (const nsINode* node = &aNode; node; node = node->GetParentNode()) {
if (node->GetParentNode() == &aParent) {
MOZ_ASSERT(node->IsContent());
aOutPoint->Set(node->AsContent());
return true;
}
}
return false;
}
bool
EditorUtils::IsLeafNode(nsIDOMNode* aNode)
{
bool hasChildren = false;
if (aNode)
aNode->HasChildNodes(&hasChildren);
return !hasChildren;
}
/******************************************************************************
* utility methods for drag/drop/copy/paste hooks
*****************************************************************************/
nsresult
EditorHookUtils::GetHookEnumeratorFromDocument(nsIDOMDocument* aDoc,
nsISimpleEnumerator** aResult)
{
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocShell> docShell = doc->GetDocShell();
nsCOMPtr<nsIClipboardDragDropHookList> hookObj = do_GetInterface(docShell);
NS_ENSURE_TRUE(hookObj, NS_ERROR_FAILURE);
return hookObj->GetHookEnumerator(aResult);
}
bool
EditorHookUtils::DoInsertionHook(nsIDOMDocument* aDoc,
nsIDOMEvent* aDropEvent,
nsITransferable *aTrans)
{
nsCOMPtr<nsISimpleEnumerator> enumerator;
GetHookEnumeratorFromDocument(aDoc, getter_AddRefs(enumerator));
NS_ENSURE_TRUE(enumerator, true);
bool hasMoreHooks = false;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreHooks)) &&
hasMoreHooks) {
nsCOMPtr<nsISupports> isupp;
if (NS_FAILED(enumerator->GetNext(getter_AddRefs(isupp)))) {
break;
}
nsCOMPtr<nsIClipboardDragDropHooks> override = do_QueryInterface(isupp);
if (override) {
bool doInsert = true;
DebugOnly<nsresult> hookResult =
override->OnPasteOrDrop(aDropEvent, aTrans, &doInsert);
NS_ASSERTION(NS_SUCCEEDED(hookResult), "hook failure in OnPasteOrDrop");
NS_ENSURE_TRUE(doInsert, false);
}
}
return true;
}
} // namespace mozilla