Bug 1609338 - Optimize usage and implementation of UIEvent::GetRangeParent() and UIEvent::RangeOffset() r=smaug

`UIEvent::GetRangeParent()` retrieves `nsIContent` instance but it needs to
return `already_AddRefed<nsINode>` because of a WebIDL method.  However,
`nsIContent` is better type in C++ code.  Therefore, this patch renames it
to `UIEvent::GetRangeParentContent()` and makes new `UIEvent::GetRangeParent()`
and just call it.

Additionally, some callers call `UIEvent::RangeOffset()` too, but that means
that they compute same things twice because both of them use
`nsLayoutUtils::GetContainerAndOffsetAtEvent()` with same input arguments.
Thus, `UIEvent::GetRangeParentContent()` should also return offset with optional
out argument.  (Note that this does not make `RangeOffset()` use
`GetRangeParentContent()` because using out parameter for range parent causes
unnecessary computation cost for `RangeOffset()`.)

Therefore, finally, `UIEvent::GetRangeParentContent()` becomes also an alias of
raw method `UIEvent::GetRangeParentContentAndOffset()` which also returns offset
with out argument.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Masayuki Nakano 2020-01-17 01:23:12 +00:00
parent d55e0a5916
commit 527b3ff65b
7 changed files with 60 additions and 41 deletions

View File

@ -132,7 +132,8 @@ void UIEvent::InitUIEvent(const nsAString& typeArg, bool canBubbleArg,
mView = viewArg ? viewArg->GetOuterWindow() : nullptr;
}
already_AddRefed<nsINode> UIEvent::GetRangeParent() {
already_AddRefed<nsIContent> UIEvent::GetRangeParentContentAndOffset(
int32_t* aOffset) {
if (NS_WARN_IF(!mPresContext)) {
return nullptr;
}
@ -142,7 +143,7 @@ already_AddRefed<nsINode> UIEvent::GetRangeParent() {
}
nsCOMPtr<nsIContent> container;
nsLayoutUtils::GetContainerAndOffsetAtEvent(
presShell, mEvent, getter_AddRefs(container), nullptr);
presShell, mEvent, getter_AddRefs(container), aOffset);
return container.forget();
}

View File

@ -70,11 +70,28 @@ class UIEvent : public Event {
return 0;
}
MOZ_CAN_RUN_SCRIPT
already_AddRefed<nsINode> GetRangeParent();
/**
* GetRangeParent() should be used only by JS. C++ callers should use
* GetRangeParentContent() or GetRangeParentContentAndOffset() instead.
*/
MOZ_CAN_RUN_SCRIPT already_AddRefed<nsINode> GetRangeParent() {
return GetRangeParentContent();
}
MOZ_CAN_RUN_SCRIPT already_AddRefed<nsIContent> GetRangeParentContent() {
return GetRangeParentContentAndOffset(nullptr);
}
/**
* aOffset is optional (i.e., can be nullptr), but when you call this with
* nullptr, you should use GetRangeParentContent() instead.
*/
MOZ_CAN_RUN_SCRIPT already_AddRefed<nsIContent>
GetRangeParentContentAndOffset(int32_t* aOffset);
MOZ_CAN_RUN_SCRIPT
int32_t RangeOffset() const;
/**
* If you also need to compute range parent in C++ code, you should use
* GetRangeParentContentAndOffset() instead.
*/
MOZ_CAN_RUN_SCRIPT int32_t RangeOffset() const;
protected:
~UIEvent() {}

View File

@ -728,11 +728,14 @@ nsresult EditorEventListener::DragOver(DragEvent* aDragEvent) {
return NS_OK;
}
nsCOMPtr<nsINode> parent = aDragEvent->GetRangeParent();
nsCOMPtr<nsIContent> dropParent = do_QueryInterface(parent);
NS_ENSURE_TRUE(dropParent, NS_ERROR_FAILURE);
int32_t dropOffset = -1;
nsCOMPtr<nsIContent> dropParentContent =
aDragEvent->GetRangeParentContentAndOffset(&dropOffset);
if (NS_WARN_IF(!dropParentContent)) {
return NS_ERROR_FAILURE;
}
if (dropParent->IsEditable() && CanDrop(aDragEvent)) {
if (dropParentContent->IsEditable() && CanDrop(aDragEvent)) {
aDragEvent->PreventDefault(); // consumed
// If we handle the dragged item, we need should adjust drop effect here
@ -756,10 +759,8 @@ nsresult EditorEventListener::DragOver(DragEvent* aDragEvent) {
return NS_OK;
}
int32_t offset = aDragEvent->RangeOffset();
mCaret->SetVisible(true);
mCaret->SetCaretPosition(dropParent, offset);
mCaret->SetCaretPosition(dropParentContent, dropOffset);
return NS_OK;
}
@ -818,8 +819,7 @@ nsresult EditorEventListener::Drop(DragEvent* aDragEvent) {
return NS_OK;
}
nsCOMPtr<nsINode> dropParentNode = aDragEvent->GetRangeParent();
nsIContent* dropParentContent = nsIContent::FromNodeOrNull(dropParentNode);
nsCOMPtr<nsIContent> dropParentContent = aDragEvent->GetRangeParentContent();
if (NS_WARN_IF(!dropParentContent)) {
return NS_ERROR_FAILURE;
}
@ -911,13 +911,13 @@ bool EditorEventListener::CanDrop(DragEvent* aEvent) {
return true;
}
nsCOMPtr<nsINode> parent = aEvent->GetRangeParent();
if (!parent) {
int32_t dropOffset = -1;
nsCOMPtr<nsIContent> dropParentContent =
aEvent->GetRangeParentContentAndOffset(&dropOffset);
if (!dropParentContent) {
return false;
}
int32_t offset = aEvent->RangeOffset();
uint32_t rangeCount = selection->RangeCount();
for (uint32_t i = 0; i < rangeCount; i++) {
RefPtr<nsRange> range = selection->GetRangeAt(i);
@ -927,7 +927,7 @@ bool EditorEventListener::CanDrop(DragEvent* aEvent) {
}
IgnoredErrorResult rv;
bool inRange = range->IsPointInRange(*parent, offset, rv);
bool inRange = range->IsPointInRange(*dropParentContent, dropOffset, rv);
if (!rv.Failed() && inRange) {
// Okay, now you can bail, we are over the orginal selection
return false;

View File

@ -286,10 +286,12 @@ nsresult HTMLEditorEventListener::MouseDown(MouseEvent* aMouseEvent) {
NS_ENSURE_TRUE(selection, NS_OK);
// Get location of mouse within target node
nsCOMPtr<nsINode> parent = aMouseEvent->GetRangeParent();
NS_ENSURE_TRUE(parent, NS_ERROR_FAILURE);
int32_t offset = aMouseEvent->RangeOffset();
int32_t offset = -1;
nsCOMPtr<nsIContent> parentContent =
aMouseEvent->GetRangeParentContentAndOffset(&offset);
if (NS_WARN_IF(!parentContent)) {
return NS_ERROR_FAILURE;
}
// Detect if mouse point is within current selection for context click
bool nodeIsInSelection = false;
@ -305,7 +307,7 @@ nsresult HTMLEditorEventListener::MouseDown(MouseEvent* aMouseEvent) {
IgnoredErrorResult err;
nodeIsInSelection =
range->IsPointInRange(*parent, offset, err) && !err.Failed();
range->IsPointInRange(*parentContent, offset, err) && !err.Failed();
// Done when we find a range that we are in
if (nodeIsInSelection) {
@ -318,7 +320,7 @@ nsresult HTMLEditorEventListener::MouseDown(MouseEvent* aMouseEvent) {
if (!element) {
if (isContextClick) {
// Set the selection to the point under the mouse cursor:
selection->Collapse(parent, offset);
selection->Collapse(parentContent, offset);
} else {
// Get enclosing link if in text so we can select the link
Element* linkElement =
@ -332,7 +334,7 @@ nsresult HTMLEditorEventListener::MouseDown(MouseEvent* aMouseEvent) {
// and not the entire body, or table-related elements
if (element) {
if (isContextClick && !HTMLEditUtils::IsImage(node)) {
selection->Collapse(parent, offset);
selection->Collapse(parentContent, offset);
} else {
htmlEditor->SelectElement(element);
}

View File

@ -210,8 +210,10 @@ nsresult TextEditor::OnDrop(DragEvent* aDropEvent) {
// We have to figure out whether to delete and relocate caret only once
// Parent and offset are under the mouse cursor.
EditorDOMPoint droppedAt(aDropEvent->GetRangeParent(),
aDropEvent->RangeOffset());
int32_t dropOffset = -1;
nsCOMPtr<nsIContent> dropParentContent =
aDropEvent->GetRangeParentContentAndOffset(&dropOffset);
EditorDOMPoint droppedAt(dropParentContent, dropOffset);
if (NS_WARN_IF(!droppedAt.IsSet()) ||
NS_WARN_IF(!droppedAt.GetContainerAsContent())) {
return NS_ERROR_FAILURE;

View File

@ -166,7 +166,7 @@ nsXULPopupManager::Observe(nsISupports* aSubject, const char* aTopic,
mKeyListener->RemoveEventListener(NS_LITERAL_STRING("keyup"), this, true);
mKeyListener = nullptr;
}
mRangeParent = nullptr;
mRangeParentContent = nullptr;
// mOpeningPopup is cleared explicitly soon after using it.
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
@ -556,10 +556,6 @@ nsMenuChainItem* nsXULPopupManager::GetTopVisibleMenu() {
return nullptr;
}
nsINode* nsXULPopupManager::GetMouseLocationParent() { return mRangeParent; }
int32_t nsXULPopupManager::MouseLocationOffset() { return mRangeOffset; }
void nsXULPopupManager::InitTriggerEvent(Event* aEvent, nsIContent* aPopup,
nsIContent** aTriggerContent) {
mCachedMousePoint = LayoutDeviceIntPoint(0, 0);
@ -577,8 +573,9 @@ void nsXULPopupManager::InitTriggerEvent(Event* aEvent, nsIContent* aPopup,
RefPtr<UIEvent> uiEvent = aEvent ? aEvent->AsUIEvent() : nullptr;
if (uiEvent) {
mRangeParent = uiEvent->GetRangeParent();
mRangeOffset = uiEvent->RangeOffset();
mRangeOffset = -1;
mRangeParentContent =
uiEvent->GetRangeParentContentAndOffset(&mRangeOffset);
// get the event coordinates relative to the root frame of the document
// containing the popup.
@ -628,7 +625,7 @@ void nsXULPopupManager::InitTriggerEvent(Event* aEvent, nsIContent* aPopup,
}
}
} else {
mRangeParent = nullptr;
mRangeParentContent = nullptr;
mRangeOffset = 0;
}
}
@ -1355,7 +1352,7 @@ void nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup,
}
// clear these as they are no longer valid
mRangeParent = nullptr;
mRangeParentContent = nullptr;
mRangeOffset = 0;
// get the frame again in case it went away

View File

@ -414,8 +414,8 @@ class nsXULPopupManager final : public nsIDOMEventListener,
// the rangeOffset of the event supplied to ShowPopup or ShowPopupAtScreen.
// This is used by the implementation of Document::GetPopupRangeParent
// and Document::GetPopupRangeOffset.
nsINode* GetMouseLocationParent();
int32_t MouseLocationOffset();
nsIContent* GetMouseLocationParent() const { return mRangeParentContent; }
int32_t MouseLocationOffset() const { return mRangeOffset; }
/**
* Open a <menu> given its content node. If aSelectFirstItem is
@ -795,7 +795,7 @@ class nsXULPopupManager final : public nsIDOMEventListener,
nsCOMPtr<nsIWidget> mWidget;
// range parent and offset set in SetTriggerEvent
nsCOMPtr<nsINode> mRangeParent;
nsCOMPtr<nsIContent> mRangeParentContent;
int32_t mRangeOffset;
// Device pixels relative to the showing popup's presshell's
// root prescontext's root frame.