mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1678553
- part 13: Make WidgetQueryContentEvent
use Maybe
to store some data r=m_kato,geckoview-reviewers
Sorry for this big patch. This makes `WidgetQueryContentEvent::Reply` is stored with `Maybe` to get rid of `WidgetQueryContentEvent`. And `Reply` stores offset and string with `Maybe` and ``OffsetAndData<uint32_t>`, and also tentative caret offset with `Maybe`. Then, we can get rid of `WidgetQueryContentEvent::NOT_FOUND`. Note that I tried to make `OffsetAndData` have a method to create `NSRange` for cocoa widget. However, it causes the column limit`to 100 or longer and that causes unrelated changes in `TextEvents.h` and `IMEData.h`. Therefore, I create an inline function in `TextInputHandler.mm` instead. Differential Revision: https://phabricator.services.mozilla.com/D98264
This commit is contained in:
parent
d9c63734d9
commit
912a5bc76d
@ -2055,7 +2055,7 @@ nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, int64_t aOffset,
|
||||
nsresult rv = targetWidget->DispatchEvent(&queryEvent, status);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
auto* result = new nsQueryContentEventResult(queryEvent);
|
||||
auto* result = new nsQueryContentEventResult(std::move(queryEvent));
|
||||
result->SetEventResult(widget);
|
||||
NS_ADDREF(*aResult = result);
|
||||
return NS_OK;
|
||||
|
@ -947,34 +947,37 @@ nsLookUpDictionaryCommand::DoCommandParams(const char* aCommandName,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent charAt(true, eQueryCharacterAtPoint, widget);
|
||||
charAt.mRefPoint.x = x;
|
||||
charAt.mRefPoint.y = y;
|
||||
WidgetQueryContentEvent queryCharAtPointEvent(true, eQueryCharacterAtPoint,
|
||||
widget);
|
||||
queryCharAtPointEvent.mRefPoint.x = x;
|
||||
queryCharAtPointEvent.mRefPoint.y = y;
|
||||
ContentEventHandler handler(presContext);
|
||||
handler.OnQueryCharacterAtPoint(&charAt);
|
||||
handler.OnQueryCharacterAtPoint(&queryCharAtPointEvent);
|
||||
|
||||
if (NS_WARN_IF(!charAt.mSucceeded) ||
|
||||
charAt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
|
||||
if (NS_WARN_IF(queryCharAtPointEvent.Failed()) ||
|
||||
queryCharAtPointEvent.DidNotFindChar()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent selection(true, eQuerySelectedText, widget);
|
||||
handler.OnQuerySelectedText(&selection);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
widget);
|
||||
handler.OnQuerySelectedText(&querySelectedTextEvent);
|
||||
if (NS_WARN_IF(querySelectedTextEvent.DidNotFindSelection())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool useSelection = false;
|
||||
uint32_t offset = charAt.mReply.mOffset;
|
||||
uint32_t offset = queryCharAtPointEvent.mReply->StartOffset();
|
||||
uint32_t begin, length;
|
||||
|
||||
// macOS prioritizes user selected text if the current point falls within the
|
||||
// selection range. So we check the selection first.
|
||||
if (selection.mSucceeded) {
|
||||
begin = selection.mReply.mOffset;
|
||||
length = selection.mReply.mString.Length();
|
||||
useSelection = (offset >= begin && offset < (begin + length));
|
||||
}
|
||||
|
||||
if (!useSelection) {
|
||||
WidgetQueryContentEvent textContent(true, eQueryTextContent, widget);
|
||||
if (querySelectedTextEvent.FoundSelection() &&
|
||||
querySelectedTextEvent.mReply->IsOffsetInRange(offset)) {
|
||||
begin = querySelectedTextEvent.mReply->StartOffset();
|
||||
length = querySelectedTextEvent.mReply->DataLength();
|
||||
} else {
|
||||
WidgetQueryContentEvent queryTextContentEvent(true, eQueryTextContent,
|
||||
widget);
|
||||
// OSX 10.7 queries 50 characters before/after current point. So we fetch
|
||||
// same length.
|
||||
if (offset > 50) {
|
||||
@ -982,10 +985,10 @@ nsLookUpDictionaryCommand::DoCommandParams(const char* aCommandName,
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
textContent.InitForQueryTextContent(offset, 100);
|
||||
handler.OnQueryTextContent(&textContent);
|
||||
if (NS_WARN_IF(!textContent.mSucceeded ||
|
||||
textContent.mReply.mString.IsEmpty())) {
|
||||
queryTextContentEvent.InitForQueryTextContent(offset, 100);
|
||||
handler.OnQueryTextContent(&queryTextContentEvent);
|
||||
if (NS_WARN_IF(queryTextContentEvent.Failed()) ||
|
||||
NS_WARN_IF(queryTextContentEvent.mReply->IsDataEmpty())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -998,8 +1001,9 @@ nsLookUpDictionaryCommand::DoCommandParams(const char* aCommandName,
|
||||
}
|
||||
|
||||
mozilla::intl::WordRange range = wordBreaker->FindWord(
|
||||
textContent.mReply.mString.get(), textContent.mReply.mString.Length(),
|
||||
charAt.mReply.mOffset - offset);
|
||||
queryTextContentEvent.mReply->DataRef().get(),
|
||||
queryTextContentEvent.mReply->DataLength(),
|
||||
queryCharAtPointEvent.mReply->StartOffset() - offset);
|
||||
if (range.mEnd == range.mBegin) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -1007,26 +1011,27 @@ nsLookUpDictionaryCommand::DoCommandParams(const char* aCommandName,
|
||||
length = range.mEnd - range.mBegin;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent lookUpContent(true, eQueryTextContent, widget);
|
||||
lookUpContent.InitForQueryTextContent(begin, length);
|
||||
lookUpContent.RequestFontRanges();
|
||||
handler.OnQueryTextContent(&lookUpContent);
|
||||
if (NS_WARN_IF(!lookUpContent.mSucceeded ||
|
||||
lookUpContent.mReply.mString.IsEmpty())) {
|
||||
WidgetQueryContentEvent queryLookUpContentEvent(true, eQueryTextContent,
|
||||
widget);
|
||||
queryLookUpContentEvent.InitForQueryTextContent(begin, length);
|
||||
queryLookUpContentEvent.RequestFontRanges();
|
||||
handler.OnQueryTextContent(&queryLookUpContentEvent);
|
||||
if (NS_WARN_IF(queryLookUpContentEvent.Failed()) ||
|
||||
NS_WARN_IF(queryLookUpContentEvent.mReply->IsDataEmpty())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent charRect(true, eQueryTextRect, widget);
|
||||
charRect.InitForQueryTextRect(begin, length);
|
||||
handler.OnQueryTextRect(&charRect);
|
||||
if (NS_WARN_IF(!charRect.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryTextRectEvent(true, eQueryTextRect, widget);
|
||||
queryTextRectEvent.InitForQueryTextRect(begin, length);
|
||||
handler.OnQueryTextRect(&queryTextRectEvent);
|
||||
if (NS_WARN_IF(queryTextRectEvent.Failed())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
widget->LookUpDictionary(lookUpContent.mReply.mString,
|
||||
lookUpContent.mReply.mFontRanges,
|
||||
charRect.mReply.mWritingMode.IsVertical(),
|
||||
charRect.mReply.mRect.TopLeft());
|
||||
widget->LookUpDictionary(queryLookUpContentEvent.mReply->DataRef(),
|
||||
queryLookUpContentEvent.mReply->mFontRanges,
|
||||
queryTextRectEvent.mReply->mWritingMode.IsVertical(),
|
||||
queryTextRectEvent.mReply->mRect.TopLeft());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -48,18 +48,29 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_ADDREF(nsQueryContentEventResult)
|
||||
NS_IMPL_RELEASE(nsQueryContentEventResult)
|
||||
|
||||
#define NOT_FOUND UINT32_MAX
|
||||
|
||||
nsQueryContentEventResult::nsQueryContentEventResult(
|
||||
mozilla::WidgetQueryContentEvent& aEvent)
|
||||
mozilla::WidgetQueryContentEvent&& aEvent)
|
||||
: mEventMessage(aEvent.mMessage),
|
||||
mOffset(aEvent.mReply.mOffset),
|
||||
mTentativeCaretOffset(aEvent.mReply.mTentativeCaretOffset),
|
||||
mString(aEvent.mReply.mString),
|
||||
mRect(aEvent.mReply.mRect),
|
||||
mRectArray(std::move(aEvent.mReply.mRectArray)),
|
||||
mSucceeded(aEvent.mSucceeded),
|
||||
mReversed(aEvent.mReply.mReversed) {
|
||||
mOffset(NOT_FOUND),
|
||||
mTentativeCaretOffset(NOT_FOUND),
|
||||
mSucceeded(aEvent.Succeeded()),
|
||||
mReversed(false) {
|
||||
if (mSucceeded) {
|
||||
if (aEvent.mReply->mOffsetAndData.isSome()) {
|
||||
mOffset = aEvent.mReply->StartOffset();
|
||||
mString = aEvent.mReply->DataRef();
|
||||
}
|
||||
if (aEvent.mReply->mTentativeCaretOffset.isSome()) {
|
||||
mTentativeCaretOffset = aEvent.mReply->mTentativeCaretOffset.value();
|
||||
}
|
||||
mRect = std::move(aEvent.mReply->mRect);
|
||||
mRectArray = std::move(aEvent.mReply->mRectArray);
|
||||
mReversed = aEvent.mReply->mReversed;
|
||||
}
|
||||
// Mark as result that is longer used.
|
||||
aEvent.mSucceeded = false;
|
||||
aEvent.mReply.reset();
|
||||
}
|
||||
|
||||
nsQueryContentEventResult::~nsQueryContentEventResult() = default;
|
||||
@ -177,7 +188,7 @@ nsQueryContentEventResult::GetNotFound(bool* aNotFound) {
|
||||
NS_WARN_IF(!IsNotFoundPropertyAvailable(mEventMessage))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
*aNotFound = (mOffset == WidgetQueryContentEvent::NOT_FOUND);
|
||||
*aNotFound = mOffset == NOT_FOUND;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -189,7 +200,7 @@ nsQueryContentEventResult::GetTentativeCaretOffsetNotFound(bool* aNotFound) {
|
||||
if (NS_WARN_IF(mEventMessage != eQueryCharacterAtPoint)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
*aNotFound = (mTentativeCaretOffset == WidgetQueryContentEvent::NOT_FOUND);
|
||||
*aNotFound = mTentativeCaretOffset == NOT_FOUND;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -231,3 +242,5 @@ void nsQueryContentEventResult::SetEventResult(nsIWidget* aWidget) {
|
||||
mRectArray[i].MoveBy(-offset);
|
||||
}
|
||||
}
|
||||
|
||||
#undef NOT_FOUND
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nsIQueryContentEventResult.h"
|
||||
#include "nsString.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsTArray.h"
|
||||
#include "Units.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
@ -18,7 +19,7 @@ class nsIWidget;
|
||||
|
||||
class nsQueryContentEventResult final : public nsIQueryContentEventResult {
|
||||
public:
|
||||
explicit nsQueryContentEventResult(mozilla::WidgetQueryContentEvent& aEvent);
|
||||
explicit nsQueryContentEventResult(mozilla::WidgetQueryContentEvent&& aEvent);
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIQUERYCONTENTEVENTRESULT
|
||||
|
||||
@ -33,7 +34,7 @@ class nsQueryContentEventResult final : public nsIQueryContentEventResult {
|
||||
uint32_t mTentativeCaretOffset;
|
||||
nsString mString;
|
||||
mozilla::LayoutDeviceIntRect mRect;
|
||||
nsTArray<mozilla::LayoutDeviceIntRect> mRectArray;
|
||||
CopyableTArray<mozilla::LayoutDeviceIntRect> mRectArray;
|
||||
|
||||
bool mSucceeded;
|
||||
bool mReversed;
|
||||
|
@ -127,25 +127,21 @@ function runTests()
|
||||
var top = {};
|
||||
var width = {};
|
||||
var height = {};
|
||||
textRectArray.getCharacterRect(0, left, top, width, height);
|
||||
is(top.value, textRect.top,
|
||||
"sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same top that returns QUERY_TEXT_RECT");
|
||||
is(left.value, textRect.left,
|
||||
"sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same left that returns QUERY_TEXT_RECT");
|
||||
|
||||
var left2 = {};
|
||||
var top2 = {};
|
||||
var width2 = {};
|
||||
var height2 = {};
|
||||
textRectArray.getCharacterRect(0, left, top, width, height);
|
||||
is(textRect.top, top.value,
|
||||
"sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same top that returns QUERY_TEXT_RECT");
|
||||
is(textRect.left, left.value,
|
||||
"sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same left that returns QUERY_TEXT_RECT");
|
||||
textRectArray.getCharacterRect(1, left2, top2, width2, height2);
|
||||
isfuzzy(width.value + width2.value, textRect.width, 2,
|
||||
"sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same width that QUERY_TEXT_RECT is returned for offset 1 and 2");
|
||||
|
||||
// XXX: Switched to from ok() to todo_is() in Bug 1467712. Follow up in 1500961
|
||||
// jdescottes: Bug 1467712 - wrong usage of ok(). This does not pass when switching to is():
|
||||
// "got 16, expected 17". However on some other platforms it works as expected so we cannot
|
||||
// use todo_is().
|
||||
// is(textRect.width, width.value + width2.value,
|
||||
// "sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same width that QUERY_TEXT_RECT is returned for offset 1 and 2");
|
||||
|
||||
is(textRect.height, height.value,
|
||||
is(height.value, textRect.height,
|
||||
"sendQueryContentEvent(QUERY_TEXT_RECT_ARRAY) should return same height that returns QUERY_TEXT_RECT");
|
||||
|
||||
// QueryCharacterAtOffset
|
||||
|
@ -417,11 +417,15 @@ nsresult ContentEventHandler::Init(WidgetQueryContentEvent* aEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = false;
|
||||
// Ideally, we should emplace only when we return succeeded event.
|
||||
// However, we need to emplace here since it's hard to store the various
|
||||
// result. Intead, `HandleQueryContentEvent()` will reset `mReply` if
|
||||
// corresponding handler returns error.
|
||||
aEvent->EmplaceReply();
|
||||
|
||||
aEvent->mReply.mContentsRoot = mRootContent.get();
|
||||
aEvent->mReply->mContentsRoot = mRootContent.get();
|
||||
|
||||
aEvent->mReply.mHasSelection = !mSelection->IsCollapsed();
|
||||
aEvent->mReply->mHasSelection = !mSelection->IsCollapsed();
|
||||
|
||||
nsRect r;
|
||||
nsIFrame* frame = nsCaret::GetGeometry(mSelection, &r);
|
||||
@ -431,7 +435,7 @@ nsresult ContentEventHandler::Init(WidgetQueryContentEvent* aEvent) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
aEvent->mReply.mFocusedWidget = frame->GetNearestWidget();
|
||||
aEvent->mReply->mFocusedWidget = frame->GetNearestWidget();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -482,12 +486,11 @@ nsresult ContentEventHandler::QueryContentRect(
|
||||
resultRect.UnionRect(resultRect, frameRect);
|
||||
}
|
||||
|
||||
aEvent->mReply.mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
aEvent->mReply->mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
resultRect, presContext->AppUnitsPerDevPixel());
|
||||
// Returning empty rect may cause native IME confused, let's make sure to
|
||||
// return non-empty rect.
|
||||
EnsureNonEmptyRect(aEvent->mReply.mRect);
|
||||
aEvent->mSucceeded = true;
|
||||
EnsureNonEmptyRect(aEvent->mReply->mRect);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1264,30 +1267,47 @@ LineBreakType ContentEventHandler::GetLineBreakType(bool aUseNativeLineBreak) {
|
||||
|
||||
nsresult ContentEventHandler::HandleQueryContentEvent(
|
||||
WidgetQueryContentEvent* aEvent) {
|
||||
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
|
||||
switch (aEvent->mMessage) {
|
||||
case eQuerySelectedText:
|
||||
return OnQuerySelectedText(aEvent);
|
||||
rv = OnQuerySelectedText(aEvent);
|
||||
break;
|
||||
case eQueryTextContent:
|
||||
return OnQueryTextContent(aEvent);
|
||||
rv = OnQueryTextContent(aEvent);
|
||||
break;
|
||||
case eQueryCaretRect:
|
||||
return OnQueryCaretRect(aEvent);
|
||||
rv = OnQueryCaretRect(aEvent);
|
||||
break;
|
||||
case eQueryTextRect:
|
||||
return OnQueryTextRect(aEvent);
|
||||
rv = OnQueryTextRect(aEvent);
|
||||
break;
|
||||
case eQueryTextRectArray:
|
||||
return OnQueryTextRectArray(aEvent);
|
||||
rv = OnQueryTextRectArray(aEvent);
|
||||
break;
|
||||
case eQueryEditorRect:
|
||||
return OnQueryEditorRect(aEvent);
|
||||
rv = OnQueryEditorRect(aEvent);
|
||||
break;
|
||||
case eQueryContentState:
|
||||
return OnQueryContentState(aEvent);
|
||||
rv = OnQueryContentState(aEvent);
|
||||
break;
|
||||
case eQuerySelectionAsTransferable:
|
||||
return OnQuerySelectionAsTransferable(aEvent);
|
||||
rv = OnQuerySelectionAsTransferable(aEvent);
|
||||
break;
|
||||
case eQueryCharacterAtPoint:
|
||||
return OnQueryCharacterAtPoint(aEvent);
|
||||
rv = OnQueryCharacterAtPoint(aEvent);
|
||||
break;
|
||||
case eQueryDOMWidgetHittest:
|
||||
return OnQueryDOMWidgetHittest(aEvent);
|
||||
rv = OnQueryDOMWidgetHittest(aEvent);
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
aEvent->mReply.reset(); // Mark the query failed.
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1310,12 +1330,15 @@ nsresult ContentEventHandler::OnQuerySelectedText(
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
|
||||
|
||||
if (!mFirstSelectedRawRange.IsPositioned()) {
|
||||
MOZ_ASSERT(aEvent->mInput.mSelectionType != SelectionType::eNormal);
|
||||
MOZ_ASSERT(aEvent->mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND);
|
||||
MOZ_ASSERT(aEvent->mReply.mString.IsEmpty());
|
||||
MOZ_ASSERT(!aEvent->mReply.mHasSelection);
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
|
||||
MOZ_ASSERT(!aEvent->mReply->mHasSelection);
|
||||
// This is special case that `mReply` is emplaced, but mOffsetAndData is
|
||||
// not emplaced but treated as succeeded because of no selection ranges
|
||||
// is a usual case.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1328,82 +1351,74 @@ nsresult ContentEventHandler::OnQuerySelectedText(
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
|
||||
"The reply string must be empty");
|
||||
|
||||
LineBreakType lineBreakType = GetLineBreakType(aEvent);
|
||||
rv = GetStartOffset(mFirstSelectedRawRange, &aEvent->mReply.mOffset,
|
||||
lineBreakType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t startOffset = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(GetStartOffset(mFirstSelectedRawRange, &startOffset,
|
||||
lineBreakType)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const RangeBoundary& anchorRef = mSelection->RangeCount() > 0
|
||||
? mSelection->AnchorRef()
|
||||
: mFirstSelectedRawRange.Start();
|
||||
const RangeBoundary& focusRef = mSelection->RangeCount() > 0
|
||||
? mSelection->FocusRef()
|
||||
: mFirstSelectedRawRange.End();
|
||||
if (NS_WARN_IF(!anchorRef.IsSet()) || NS_WARN_IF(!focusRef.IsSet())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINode> anchorNode, focusNode;
|
||||
int32_t anchorOffset = 0, focusOffset = 0;
|
||||
if (mSelection->RangeCount()) {
|
||||
// If there is only one selection range, the anchor/focus node and offset
|
||||
// are the information of the range. Therefore, we have the direction
|
||||
// information.
|
||||
if (mSelection->RangeCount() == 1) {
|
||||
anchorNode = mSelection->GetAnchorNode();
|
||||
focusNode = mSelection->GetFocusNode();
|
||||
if (NS_WARN_IF(!anchorNode) || NS_WARN_IF(!focusNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
anchorOffset = static_cast<int32_t>(mSelection->AnchorOffset());
|
||||
focusOffset = static_cast<int32_t>(mSelection->FocusOffset());
|
||||
if (NS_WARN_IF(anchorOffset < 0) || NS_WARN_IF(focusOffset < 0)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// The selection's points should always be comparable, independent of the
|
||||
// selection (see nsISelectionController.idl).
|
||||
int16_t compare = *nsContentUtils::ComparePoints(anchorNode, anchorOffset,
|
||||
focusNode, focusOffset);
|
||||
Maybe<int32_t> compare =
|
||||
nsContentUtils::ComparePoints(anchorRef, focusRef);
|
||||
if (compare.isNothing()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aEvent->mReply.mReversed = compare > 0;
|
||||
aEvent->mReply->mReversed = compare.value() > 0;
|
||||
}
|
||||
// However, if there are 2 or more selection ranges, we have no information
|
||||
// of that.
|
||||
else {
|
||||
aEvent->mReply.mReversed = false;
|
||||
aEvent->mReply->mReversed = false;
|
||||
}
|
||||
|
||||
if (!mFirstSelectedRawRange.Collapsed()) {
|
||||
rv = GenerateFlatTextContent(mFirstSelectedRawRange,
|
||||
aEvent->mReply.mString, lineBreakType);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
aEvent->mReply.mString.Truncate();
|
||||
nsString selectedString;
|
||||
if (!mFirstSelectedRawRange.Collapsed() &&
|
||||
NS_WARN_IF(NS_FAILED(GenerateFlatTextContent(
|
||||
mFirstSelectedRawRange, selectedString, lineBreakType)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aEvent->mReply->mOffsetAndData.emplace(startOffset, selectedString,
|
||||
OffsetAndDataFor::SelectedString);
|
||||
} else {
|
||||
NS_ASSERTION(mFirstSelectedRawRange.Collapsed(),
|
||||
NS_ASSERTION(anchorRef == focusRef,
|
||||
"When mSelection doesn't have selection, "
|
||||
"mFirstSelectedRawRange must be "
|
||||
"collapsed");
|
||||
anchorNode = focusNode = mFirstSelectedRawRange.GetStartContainer();
|
||||
if (NS_WARN_IF(!anchorNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
anchorOffset = focusOffset =
|
||||
static_cast<int32_t>(mFirstSelectedRawRange.StartOffset());
|
||||
if (NS_WARN_IF(anchorOffset < 0)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
"mFirstSelectedRawRange must be collapsed");
|
||||
|
||||
aEvent->mReply.mReversed = false;
|
||||
aEvent->mReply.mString.Truncate();
|
||||
aEvent->mReply->mReversed = false;
|
||||
aEvent->mReply->mOffsetAndData.emplace(startOffset, EmptyString(),
|
||||
OffsetAndDataFor::SelectedString);
|
||||
}
|
||||
|
||||
nsIFrame* frame = nullptr;
|
||||
rv = GetFrameForTextRect(focusNode, focusOffset, true, &frame);
|
||||
rv = GetFrameForTextRect(
|
||||
focusRef.Container(),
|
||||
focusRef.Offset(RangeBoundary::OffsetFilter::kValidOffsets).valueOr(0),
|
||||
true, &frame);
|
||||
if (NS_SUCCEEDED(rv) && frame) {
|
||||
aEvent->mReply.mWritingMode = frame->GetWritingMode();
|
||||
aEvent->mReply->mWritingMode = frame->GetWritingMode();
|
||||
} else {
|
||||
aEvent->mReply.mWritingMode = WritingMode();
|
||||
aEvent->mReply->mWritingMode = WritingMode();
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1414,34 +1429,40 @@ nsresult ContentEventHandler::OnQueryTextContent(
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_ASSERTION(aEvent->mReply.mString.IsEmpty(),
|
||||
"The reply string must be empty");
|
||||
MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
|
||||
|
||||
LineBreakType lineBreakType = GetLineBreakType(aEvent);
|
||||
|
||||
RawRange rawRange;
|
||||
rv = SetRawRangeFromFlatTextOffset(&rawRange, aEvent->mInput.mOffset,
|
||||
aEvent->mInput.mLength, lineBreakType,
|
||||
false, &aEvent->mReply.mOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t startOffset = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(SetRawRangeFromFlatTextOffset(
|
||||
&rawRange, aEvent->mInput.mOffset, aEvent->mInput.mLength,
|
||||
lineBreakType, false, &startOffset)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = GenerateFlatTextContent(rawRange, aEvent->mReply.mString, lineBreakType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsString textInRange;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
GenerateFlatTextContent(rawRange, textInRange, lineBreakType)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aEvent->mReply->mOffsetAndData.emplace(startOffset, textInRange,
|
||||
OffsetAndDataFor::EditorString);
|
||||
|
||||
if (aEvent->mWithFontRanges) {
|
||||
uint32_t fontRangeLength;
|
||||
rv = GenerateFlatFontRanges(rawRange, aEvent->mReply.mFontRanges,
|
||||
fontRangeLength, lineBreakType);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
GenerateFlatFontRanges(rawRange, aEvent->mReply->mFontRanges,
|
||||
fontRangeLength, lineBreakType)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(fontRangeLength == aEvent->mReply.mString.Length(),
|
||||
MOZ_ASSERT(fontRangeLength == aEvent->mReply->DataLength(),
|
||||
"Font ranges doesn't match the string");
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = true;
|
||||
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -1803,6 +1824,8 @@ nsresult ContentEventHandler::OnQueryTextRectArray(
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
|
||||
|
||||
LineBreakType lineBreakType = GetLineBreakType(aEvent);
|
||||
const uint32_t kBRLength = GetBRLength(lineBreakType);
|
||||
|
||||
@ -2037,7 +2060,7 @@ nsresult ContentEventHandler::OnQueryTextRectArray(
|
||||
// return non-empty rect.
|
||||
EnsureNonEmptyRect(rect);
|
||||
|
||||
aEvent->mReply.mRectArray.AppendElement(rect);
|
||||
aEvent->mReply->mRectArray.AppendElement(rect);
|
||||
offset++;
|
||||
|
||||
// If it's not a line breaker or the line breaker length is same as
|
||||
@ -2066,7 +2089,7 @@ nsresult ContentEventHandler::OnQueryTextRectArray(
|
||||
// append same rect for "\n" too because querying rect of "\r" and "\n"
|
||||
// should return same rect. E.g., IME may query previous character's
|
||||
// rect of first character of a line.
|
||||
aEvent->mReply.mRectArray.AppendElement(rect);
|
||||
aEvent->mReply->mRectArray.AppendElement(rect);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
@ -2077,12 +2100,12 @@ nsresult ContentEventHandler::OnQueryTextRectArray(
|
||||
// deciding the position of a popup window (e.g., suggest window for next
|
||||
// word). Note that when this method hasn't appended character rects, it
|
||||
// means that the offset is too large or the query range is collapsed.
|
||||
if (offset < kEndOffset || aEvent->mReply.mRectArray.IsEmpty()) {
|
||||
if (offset < kEndOffset || aEvent->mReply->mRectArray.IsEmpty()) {
|
||||
// If we've already retrieved some character rects before current offset,
|
||||
// we can guess the last rect from the last character's rect unless it's a
|
||||
// line breaker. (If it's a line breaker, the caret rect is in next line.)
|
||||
if (!aEvent->mReply.mRectArray.IsEmpty() && !wasLineBreaker) {
|
||||
rect = aEvent->mReply.mRectArray.LastElement();
|
||||
if (!aEvent->mReply->mRectArray.IsEmpty() && !wasLineBreaker) {
|
||||
rect = aEvent->mReply->mRectArray.LastElement();
|
||||
if (isVertical) {
|
||||
rect.y = rect.YMost() + 1;
|
||||
rect.height = 1;
|
||||
@ -2092,57 +2115,64 @@ nsresult ContentEventHandler::OnQueryTextRectArray(
|
||||
rect.width = 1;
|
||||
MOZ_ASSERT(rect.height);
|
||||
}
|
||||
aEvent->mReply.mRectArray.AppendElement(rect);
|
||||
aEvent->mReply->mRectArray.AppendElement(rect);
|
||||
} else {
|
||||
// Note that don't use eQueryCaretRect here because if caret is at the
|
||||
// end of the content, it returns actual caret rect instead of computing
|
||||
// the rect itself. It means that the result depends on caret position.
|
||||
// So, we shouldn't use it for consistency result in automated tests.
|
||||
WidgetQueryContentEvent queryTextRect(eQueryTextRect, *aEvent);
|
||||
WidgetQueryContentEvent queryTextRectEvent(eQueryTextRect, *aEvent);
|
||||
WidgetQueryContentEvent::Options options(*aEvent);
|
||||
queryTextRect.InitForQueryTextRect(offset, 1, options);
|
||||
rv = OnQueryTextRect(&queryTextRect);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
if (NS_WARN_IF(!queryTextRect.mSucceeded)) {
|
||||
queryTextRectEvent.InitForQueryTextRect(offset, 1, options);
|
||||
if (NS_WARN_IF(NS_FAILED(OnQueryTextRect(&queryTextRectEvent))) ||
|
||||
NS_WARN_IF(queryTextRectEvent.Failed())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
MOZ_ASSERT(!queryTextRect.mReply.mRect.IsEmpty());
|
||||
if (queryTextRect.mReply.mWritingMode.IsVertical()) {
|
||||
queryTextRect.mReply.mRect.height = 1;
|
||||
if (queryTextRectEvent.mReply->mWritingMode.IsVertical()) {
|
||||
queryTextRectEvent.mReply->mRect.height = 1;
|
||||
} else {
|
||||
queryTextRect.mReply.mRect.width = 1;
|
||||
queryTextRectEvent.mReply->mRect.width = 1;
|
||||
}
|
||||
aEvent->mReply.mRectArray.AppendElement(queryTextRect.mReply.mRect);
|
||||
aEvent->mReply->mRectArray.AppendElement(
|
||||
queryTextRectEvent.mReply->mRect);
|
||||
}
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent) {
|
||||
nsresult rv = Init(aEvent);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// If mLength is 0 (this may be caused by bug of native IME), we should
|
||||
// redirect this event to OnQueryCaretRect().
|
||||
if (!aEvent->mInput.mLength) {
|
||||
return OnQueryCaretRect(aEvent);
|
||||
}
|
||||
|
||||
nsresult rv = Init(aEvent);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
|
||||
|
||||
LineBreakType lineBreakType = GetLineBreakType(aEvent);
|
||||
RawRange rawRange;
|
||||
nsCOMPtr<nsIContent> lastTextContent;
|
||||
rv = SetRawRangeFromFlatTextOffset(
|
||||
&rawRange, aEvent->mInput.mOffset, aEvent->mInput.mLength, lineBreakType,
|
||||
true, &aEvent->mReply.mOffset, getter_AddRefs(lastTextContent));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = GenerateFlatTextContent(rawRange, aEvent->mReply.mString, lineBreakType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
uint32_t startOffset = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(SetRawRangeFromFlatTextOffset(
|
||||
&rawRange, aEvent->mInput.mOffset, aEvent->mInput.mLength,
|
||||
lineBreakType, true, &startOffset,
|
||||
getter_AddRefs(lastTextContent))))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsString string;
|
||||
if (NS_WARN_IF(NS_FAILED(
|
||||
GenerateFlatTextContent(rawRange, string, lineBreakType)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aEvent->mReply->mOffsetAndData.emplace(startOffset, string,
|
||||
OffsetAndDataFor::EditorString);
|
||||
|
||||
// used to iterate over all contents and their frames
|
||||
PostContentIterator postOrderIter;
|
||||
@ -2209,7 +2239,7 @@ nsresult ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent) {
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
aEvent->mReply.mWritingMode = lastFrame->GetWritingMode();
|
||||
aEvent->mReply->mWritingMode = lastFrame->GetWritingMode();
|
||||
}
|
||||
// Otherwise, if there are no contents in mRootContent, guess caret rect in
|
||||
// its frame (with its font height and content box).
|
||||
@ -2228,19 +2258,19 @@ nsresult ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent) {
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
aEvent->mReply.mWritingMode = rootContentFrame->GetWritingMode();
|
||||
aEvent->mReply->mWritingMode = rootContentFrame->GetWritingMode();
|
||||
}
|
||||
aEvent->mReply.mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
aEvent->mReply->mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
rect, presContext->AppUnitsPerDevPixel());
|
||||
if (nsPresContext* rootContext =
|
||||
presContext->GetInProcessRootContentDocumentPresContext()) {
|
||||
aEvent->mReply.mRect =
|
||||
aEvent->mReply->mRect =
|
||||
RoundedOut(ViewportUtils::DocumentRelativeLayoutToVisual(
|
||||
aEvent->mReply.mRect, rootContext->PresShell()));
|
||||
aEvent->mReply->mRect, rootContext->PresShell()));
|
||||
}
|
||||
EnsureNonEmptyRect(aEvent->mReply->mRect);
|
||||
|
||||
EnsureNonEmptyRect(aEvent->mReply.mRect);
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2420,19 +2450,20 @@ nsresult ContentEventHandler::OnQueryTextRect(WidgetQueryContentEvent* aEvent) {
|
||||
}
|
||||
|
||||
nsPresContext* presContext = lastFrame->PresContext();
|
||||
aEvent->mReply.mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
aEvent->mReply->mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
rect, presContext->AppUnitsPerDevPixel());
|
||||
if (nsPresContext* rootContext =
|
||||
presContext->GetInProcessRootContentDocumentPresContext()) {
|
||||
aEvent->mReply.mRect =
|
||||
aEvent->mReply->mRect =
|
||||
RoundedOut(ViewportUtils::DocumentRelativeLayoutToVisual(
|
||||
aEvent->mReply.mRect, rootContext->PresShell()));
|
||||
aEvent->mReply->mRect, rootContext->PresShell()));
|
||||
}
|
||||
// Returning empty rect may cause native IME confused, let's make sure to
|
||||
// return non-empty rect.
|
||||
EnsureNonEmptyRect(aEvent->mReply.mRect);
|
||||
aEvent->mReply.mWritingMode = lastFrame->GetWritingMode();
|
||||
aEvent->mSucceeded = true;
|
||||
EnsureNonEmptyRect(aEvent->mReply->mRect);
|
||||
aEvent->mReply->mWritingMode = lastFrame->GetWritingMode();
|
||||
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2444,9 +2475,13 @@ nsresult ContentEventHandler::OnQueryEditorRect(
|
||||
}
|
||||
|
||||
nsIContent* focusedContent = GetFocusedContent();
|
||||
rv = QueryContentRect(
|
||||
IsPlugin(focusedContent) ? focusedContent : mRootContent.get(), aEvent);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(QueryContentRect(
|
||||
IsPlugin(focusedContent) ? focusedContent : mRootContent.get(),
|
||||
aEvent)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2471,20 +2506,23 @@ nsresult ContentEventHandler::OnQueryCaretRect(
|
||||
rv = ConvertToRootRelativeOffset(caretFrame, caretRect);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsPresContext* presContext = caretFrame->PresContext();
|
||||
aEvent->mReply.mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
aEvent->mReply->mRect = LayoutDeviceIntRect::FromAppUnitsToOutside(
|
||||
caretRect, presContext->AppUnitsPerDevPixel());
|
||||
if (nsPresContext* rootContext =
|
||||
presContext->GetInProcessRootContentDocumentPresContext()) {
|
||||
aEvent->mReply.mRect =
|
||||
aEvent->mReply->mRect =
|
||||
RoundedOut(ViewportUtils::DocumentRelativeLayoutToVisual(
|
||||
aEvent->mReply.mRect, rootContext->PresShell()));
|
||||
aEvent->mReply->mRect, rootContext->PresShell()));
|
||||
}
|
||||
// Returning empty rect may cause native IME confused, let's make sure
|
||||
// to return non-empty rect.
|
||||
EnsureNonEmptyRect(aEvent->mReply.mRect);
|
||||
aEvent->mReply.mWritingMode = caretFrame->GetWritingMode();
|
||||
aEvent->mReply.mOffset = aEvent->mInput.mOffset;
|
||||
aEvent->mSucceeded = true;
|
||||
EnsureNonEmptyRect(aEvent->mReply->mRect);
|
||||
aEvent->mReply->mWritingMode = caretFrame->GetWritingMode();
|
||||
aEvent->mReply->mOffsetAndData.emplace(
|
||||
aEvent->mInput.mOffset, EmptyString(),
|
||||
OffsetAndDataFor::SelectedString);
|
||||
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
@ -2494,30 +2532,33 @@ nsresult ContentEventHandler::OnQueryCaretRect(
|
||||
WidgetQueryContentEvent queryTextRectEvent(eQueryTextRect, *aEvent);
|
||||
WidgetQueryContentEvent::Options options(*aEvent);
|
||||
queryTextRectEvent.InitForQueryTextRect(aEvent->mInput.mOffset, 1, options);
|
||||
rv = OnQueryTextRect(&queryTextRectEvent);
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!queryTextRectEvent.mSucceeded)) {
|
||||
if (NS_WARN_IF(NS_FAILED(OnQueryTextRect(&queryTextRectEvent))) ||
|
||||
NS_WARN_IF(queryTextRectEvent.Failed())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
queryTextRectEvent.mReply.mString.Truncate();
|
||||
aEvent->mReply = queryTextRectEvent.mReply;
|
||||
if (aEvent->GetWritingMode().IsVertical()) {
|
||||
aEvent->mReply.mRect.height = 1;
|
||||
queryTextRectEvent.mReply->TruncateData();
|
||||
aEvent->mReply->mOffsetAndData =
|
||||
std::move(queryTextRectEvent.mReply->mOffsetAndData);
|
||||
aEvent->mReply->mRect = std::move(queryTextRectEvent.mReply->mRect);
|
||||
aEvent->mReply->mWritingMode =
|
||||
std::move(queryTextRectEvent.mReply->mWritingMode);
|
||||
if (aEvent->mReply->WritingModeRef().IsVertical()) {
|
||||
aEvent->mReply->mRect.height = 1;
|
||||
} else {
|
||||
aEvent->mReply.mRect.width = 1;
|
||||
aEvent->mReply->mRect.width = 1;
|
||||
}
|
||||
// Returning empty rect may cause native IME confused, let's make sure to
|
||||
// return non-empty rect.
|
||||
aEvent->mSucceeded = true;
|
||||
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult ContentEventHandler::OnQueryContentState(
|
||||
WidgetQueryContentEvent* aEvent) {
|
||||
nsresult rv = Init(aEvent);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
if (NS_FAILED(Init(aEvent))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->mReply.isSome());
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2528,17 +2569,20 @@ nsresult ContentEventHandler::OnQuerySelectionAsTransferable(
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!aEvent->mReply.mHasSelection) {
|
||||
aEvent->mSucceeded = true;
|
||||
aEvent->mReply.mTransferable = nullptr;
|
||||
MOZ_ASSERT(aEvent->mReply.isSome());
|
||||
|
||||
if (!aEvent->mReply->mHasSelection) {
|
||||
MOZ_ASSERT(!aEvent->mReply->mTransferable);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = nsCopySupport::GetTransferableForSelection(
|
||||
mSelection, mDocument, getter_AddRefs(aEvent->mReply.mTransferable));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(nsCopySupport::GetTransferableForSelection(
|
||||
mSelection, mDocument,
|
||||
getter_AddRefs(aEvent->mReply->mTransferable))))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2549,8 +2593,8 @@ nsresult ContentEventHandler::OnQueryCharacterAtPoint(
|
||||
return rv;
|
||||
}
|
||||
|
||||
aEvent->mReply.mOffset = aEvent->mReply.mTentativeCaretOffset =
|
||||
WidgetQueryContentEvent::NOT_FOUND;
|
||||
MOZ_ASSERT(aEvent->mReply->mOffsetAndData.isNothing());
|
||||
MOZ_ASSERT(aEvent->mReply->mTentativeCaretOffset.isNothing());
|
||||
|
||||
PresShell* presShell = mDocument->GetPresShell();
|
||||
NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
|
||||
@ -2571,22 +2615,25 @@ nsresult ContentEventHandler::OnQueryCharacterAtPoint(
|
||||
NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent eventOnRoot(true, eQueryCharacterAtPoint, rootWidget);
|
||||
eventOnRoot.mUseNativeLineBreak = aEvent->mUseNativeLineBreak;
|
||||
eventOnRoot.mRefPoint = aEvent->mRefPoint;
|
||||
WidgetQueryContentEvent queryCharAtPointOnRootWidgetEvent(
|
||||
true, eQueryCharacterAtPoint, rootWidget);
|
||||
queryCharAtPointOnRootWidgetEvent.mUseNativeLineBreak =
|
||||
aEvent->mUseNativeLineBreak;
|
||||
queryCharAtPointOnRootWidgetEvent.mRefPoint = aEvent->mRefPoint;
|
||||
if (rootWidget != aEvent->mWidget) {
|
||||
eventOnRoot.mRefPoint += aEvent->mWidget->WidgetToScreenOffset() -
|
||||
rootWidget->WidgetToScreenOffset();
|
||||
queryCharAtPointOnRootWidgetEvent.mRefPoint +=
|
||||
aEvent->mWidget->WidgetToScreenOffset() -
|
||||
rootWidget->WidgetToScreenOffset();
|
||||
}
|
||||
nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo(
|
||||
&eventOnRoot, RelativeTo{rootFrame});
|
||||
&queryCharAtPointOnRootWidgetEvent, RelativeTo{rootFrame});
|
||||
|
||||
nsIFrame* targetFrame =
|
||||
nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot);
|
||||
if (!targetFrame || !targetFrame->GetContent() ||
|
||||
!targetFrame->GetContent()->IsInclusiveDescendantOf(mRootContent)) {
|
||||
// There is no character at the point.
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
nsPoint ptInTarget = ptInRoot + rootFrame->GetOffsetToCrossDoc(targetFrame);
|
||||
@ -2599,53 +2646,49 @@ nsresult ContentEventHandler::OnQueryCharacterAtPoint(
|
||||
if (!tentativeCaretOffsets.content ||
|
||||
!tentativeCaretOffsets.content->IsInclusiveDescendantOf(mRootContent)) {
|
||||
// There is no character nor tentative caret point at the point.
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = GetFlatTextLengthInRange(
|
||||
NodePosition(mRootContent, 0), NodePosition(tentativeCaretOffsets),
|
||||
mRootContent, &aEvent->mReply.mTentativeCaretOffset,
|
||||
GetLineBreakType(aEvent));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
uint32_t tentativeCaretOffset = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(GetFlatTextLengthInRange(
|
||||
NodePosition(mRootContent, 0), NodePosition(tentativeCaretOffsets),
|
||||
mRootContent, &tentativeCaretOffset, GetLineBreakType(aEvent))))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aEvent->mReply->mTentativeCaretOffset.emplace(tentativeCaretOffset);
|
||||
if (!targetFrame->IsTextFrame()) {
|
||||
// There is no character at the point but there is tentative caret point.
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aEvent->mReply.mTentativeCaretOffset !=
|
||||
WidgetQueryContentEvent::NOT_FOUND,
|
||||
"The point is inside a character bounding box. Why tentative "
|
||||
"caret point "
|
||||
"hasn't been found?");
|
||||
|
||||
nsTextFrame* textframe = static_cast<nsTextFrame*>(targetFrame);
|
||||
nsIFrame::ContentOffsets contentOffsets =
|
||||
textframe->GetCharacterOffsetAtFramePoint(ptInTarget);
|
||||
NS_ENSURE_TRUE(contentOffsets.content, NS_ERROR_FAILURE);
|
||||
uint32_t offset;
|
||||
rv = GetFlatTextLengthInRange(NodePosition(mRootContent, 0),
|
||||
NodePosition(contentOffsets), mRootContent,
|
||||
&offset, GetLineBreakType(aEvent));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
uint32_t offset = 0;
|
||||
if (NS_WARN_IF(NS_FAILED(GetFlatTextLengthInRange(
|
||||
NodePosition(mRootContent, 0), NodePosition(contentOffsets),
|
||||
mRootContent, &offset, GetLineBreakType(aEvent))))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent textRect(true, eQueryTextRect, aEvent->mWidget);
|
||||
WidgetQueryContentEvent queryTextRectEvent(true, eQueryTextRect,
|
||||
aEvent->mWidget);
|
||||
WidgetQueryContentEvent::Options options(*aEvent);
|
||||
textRect.InitForQueryTextRect(offset, 1, options);
|
||||
rv = OnQueryTextRect(&textRect);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE);
|
||||
queryTextRectEvent.InitForQueryTextRect(offset, 1, options);
|
||||
if (NS_WARN_IF(NS_FAILED(OnQueryTextRect(&queryTextRectEvent))) ||
|
||||
NS_WARN_IF(queryTextRectEvent.Failed())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// currently, we don't need to get the actual text.
|
||||
aEvent->mReply.mOffset = offset;
|
||||
aEvent->mReply.mRect = textRect.mReply.mRect;
|
||||
aEvent->mSucceeded = true;
|
||||
aEvent->mReply->mOffsetAndData =
|
||||
std::move(queryTextRectEvent.mReply->mOffsetAndData);
|
||||
aEvent->mReply->mRect = queryTextRectEvent.mReply->mRect;
|
||||
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2658,8 +2701,7 @@ nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
|
||||
return rv;
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = false;
|
||||
aEvent->mReply.mWidgetIsHit = false;
|
||||
aEvent->mReply->mWidgetIsHit = false;
|
||||
|
||||
NS_ENSURE_TRUE(aEvent->mWidget, NS_ERROR_FAILURE);
|
||||
|
||||
@ -2689,11 +2731,11 @@ nsresult ContentEventHandler::OnQueryDOMWidgetHittest(
|
||||
targetWidget = targetFrame->GetNearestWidget();
|
||||
}
|
||||
if (aEvent->mWidget == targetWidget) {
|
||||
aEvent->mReply.mWidgetIsHit = true;
|
||||
aEvent->mReply->mWidgetIsHit = true;
|
||||
}
|
||||
}
|
||||
|
||||
aEvent->mSucceeded = true;
|
||||
MOZ_ASSERT(aEvent->Succeeded());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -856,11 +856,14 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
|
||||
// If the event is trusted event, set the selected text to data of
|
||||
// composition event.
|
||||
WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
|
||||
WidgetQueryContentEvent selectedText(true, eQuerySelectedText,
|
||||
compositionEvent->mWidget);
|
||||
HandleQueryContentEvent(&selectedText);
|
||||
NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
|
||||
compositionEvent->mData = selectedText.mReply.mString;
|
||||
WidgetQueryContentEvent querySelectedTextEvent(
|
||||
true, eQuerySelectedText, compositionEvent->mWidget);
|
||||
HandleQueryContentEvent(&querySelectedTextEvent);
|
||||
if (querySelectedTextEvent.FoundSelection()) {
|
||||
compositionEvent->mData = querySelectedTextEvent.mReply->DataRef();
|
||||
}
|
||||
NS_ASSERTION(querySelectedTextEvent.Succeeded(),
|
||||
"Failed to get selected text");
|
||||
}
|
||||
break;
|
||||
case eTouchStart:
|
||||
|
@ -647,17 +647,18 @@ nsresult IMEContentObserver::HandleQueryContentEvent(
|
||||
!mNeedsToNotifyIMEOfSelectionChange;
|
||||
if (isSelectionCacheAvailable && aEvent->mMessage == eQuerySelectedText &&
|
||||
aEvent->mInput.mSelectionType == SelectionType::eNormal) {
|
||||
aEvent->mReply.mContentsRoot = mRootContent;
|
||||
aEvent->mReply.mHasSelection = !mSelectionData.IsCollapsed();
|
||||
aEvent->mReply.mOffset = mSelectionData.mOffset;
|
||||
aEvent->mReply.mString = mSelectionData.String();
|
||||
aEvent->mReply.mWritingMode = mSelectionData.GetWritingMode();
|
||||
aEvent->mReply.mReversed = mSelectionData.mReversed;
|
||||
aEvent->mSucceeded = true;
|
||||
aEvent->EmplaceReply();
|
||||
aEvent->mReply->mOffsetAndData.emplace(mSelectionData.mOffset,
|
||||
mSelectionData.String(),
|
||||
OffsetAndDataFor::SelectedString);
|
||||
aEvent->mReply->mContentsRoot = mRootContent;
|
||||
aEvent->mReply->mHasSelection = !mSelectionData.IsCollapsed();
|
||||
aEvent->mReply->mWritingMode = mSelectionData.GetWritingMode();
|
||||
aEvent->mReply->mReversed = mSelectionData.mReversed;
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
||||
("0x%p IMEContentObserver::HandleQueryContentEvent(aEvent={ "
|
||||
"mMessage=%s })",
|
||||
this, ToChar(aEvent->mMessage)));
|
||||
"mMessage=%s, mReply=%s })",
|
||||
this, ToChar(aEvent->mMessage), ToString(aEvent->mReply).c_str()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -699,7 +700,7 @@ nsresult IMEContentObserver::HandleQueryContentEvent(
|
||||
if (NS_WARN_IF(Destroyed())) {
|
||||
// If this has already destroyed during querying the content, the query
|
||||
// is outdated even if it's succeeded. So, make the query fail.
|
||||
aEvent->mSucceeded = false;
|
||||
aEvent->mReply.reset();
|
||||
MOZ_LOG(sIMECOLog, LogLevel::Warning,
|
||||
("0x%p IMEContentObserver::HandleQueryContentEvent(), WARNING, "
|
||||
"IMEContentObserver has been destroyed during the query, "
|
||||
@ -708,10 +709,10 @@ nsresult IMEContentObserver::HandleQueryContentEvent(
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!IsInitializedWithPlugin() &&
|
||||
NS_WARN_IF(aEvent->mReply.mContentsRoot != mRootContent)) {
|
||||
if (aEvent->Succeeded() && !IsInitializedWithPlugin() &&
|
||||
NS_WARN_IF(aEvent->mReply->mContentsRoot != mRootContent)) {
|
||||
// Focus has changed unexpectedly, so make the query fail.
|
||||
aEvent->mSucceeded = false;
|
||||
aEvent->mReply.reset();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@ -740,13 +741,13 @@ bool IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
|
||||
|
||||
RefPtr<IMEContentObserver> kungFuDeathGrip(this);
|
||||
|
||||
WidgetQueryContentEvent charAtPt(true, eQueryCharacterAtPoint,
|
||||
aMouseEvent->mWidget);
|
||||
charAtPt.mRefPoint = aMouseEvent->mRefPoint;
|
||||
WidgetQueryContentEvent queryCharAtPointEvent(true, eQueryCharacterAtPoint,
|
||||
aMouseEvent->mWidget);
|
||||
queryCharAtPointEvent.mRefPoint = aMouseEvent->mRefPoint;
|
||||
ContentEventHandler handler(aPresContext);
|
||||
handler.OnQueryCharacterAtPoint(&charAtPt);
|
||||
if (NS_WARN_IF(!charAtPt.mSucceeded) ||
|
||||
charAtPt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
|
||||
handler.OnQueryCharacterAtPoint(&queryCharAtPointEvent);
|
||||
if (NS_WARN_IF(queryCharAtPointEvent.Failed()) ||
|
||||
queryCharAtPointEvent.DidNotFindChar()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -760,23 +761,26 @@ bool IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
|
||||
// We should notify it with offset in the widget.
|
||||
nsIWidget* topLevelWidget = mWidget->GetTopLevelWidget();
|
||||
if (topLevelWidget && topLevelWidget != mWidget) {
|
||||
charAtPt.mReply.mRect.MoveBy(topLevelWidget->WidgetToScreenOffset() -
|
||||
mWidget->WidgetToScreenOffset());
|
||||
queryCharAtPointEvent.mReply->mRect.MoveBy(
|
||||
topLevelWidget->WidgetToScreenOffset() -
|
||||
mWidget->WidgetToScreenOffset());
|
||||
}
|
||||
// The refPt is relative to its widget.
|
||||
// We should notify it with offset in the widget.
|
||||
if (aMouseEvent->mWidget != mWidget) {
|
||||
charAtPt.mRefPoint += aMouseEvent->mWidget->WidgetToScreenOffset() -
|
||||
mWidget->WidgetToScreenOffset();
|
||||
queryCharAtPointEvent.mRefPoint +=
|
||||
aMouseEvent->mWidget->WidgetToScreenOffset() -
|
||||
mWidget->WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
IMENotification notification(NOTIFY_IME_OF_MOUSE_BUTTON_EVENT);
|
||||
notification.mMouseButtonEventData.mEventMessage = aMouseEvent->mMessage;
|
||||
notification.mMouseButtonEventData.mOffset = charAtPt.mReply.mOffset;
|
||||
notification.mMouseButtonEventData.mOffset =
|
||||
queryCharAtPointEvent.mReply->StartOffset();
|
||||
notification.mMouseButtonEventData.mCursorPos.Set(
|
||||
charAtPt.mRefPoint.ToUnknownPoint());
|
||||
queryCharAtPointEvent.mRefPoint.ToUnknownPoint());
|
||||
notification.mMouseButtonEventData.mCharRect.Set(
|
||||
charAtPt.mReply.mRect.ToUnknownRect());
|
||||
queryCharAtPointEvent.mReply->mRect.ToUnknownRect());
|
||||
notification.mMouseButtonEventData.mButton = aMouseEvent->mButton;
|
||||
notification.mMouseButtonEventData.mButtons = aMouseEvent->mButtons;
|
||||
notification.mMouseButtonEventData.mModifiers = aMouseEvent->mModifiers;
|
||||
@ -1311,20 +1315,24 @@ bool IMEContentObserver::UpdateSelectionCache(bool aRequireFlush /* = true */) {
|
||||
|
||||
// XXX Cannot we cache some information for reducing the cost to compute
|
||||
// selection offset and writing mode?
|
||||
WidgetQueryContentEvent selection(true, eQuerySelectedText, mWidget);
|
||||
selection.mNeedsToFlushLayout = aRequireFlush;
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
mWidget);
|
||||
querySelectedTextEvent.mNeedsToFlushLayout = aRequireFlush;
|
||||
ContentEventHandler handler(GetPresContext());
|
||||
handler.OnQuerySelectedText(&selection);
|
||||
if (NS_WARN_IF(!selection.mSucceeded) ||
|
||||
NS_WARN_IF(selection.mReply.mContentsRoot != mRootContent)) {
|
||||
handler.OnQuerySelectedText(&querySelectedTextEvent);
|
||||
if (NS_WARN_IF(querySelectedTextEvent.DidNotFindSelection()) ||
|
||||
NS_WARN_IF(querySelectedTextEvent.mReply->mContentsRoot !=
|
||||
mRootContent)) {
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(querySelectedTextEvent.mReply->mOffsetAndData.isSome());
|
||||
|
||||
mFocusedWidget = selection.mReply.mFocusedWidget;
|
||||
mSelectionData.mOffset = selection.mReply.mOffset;
|
||||
*mSelectionData.mString = selection.mReply.mString;
|
||||
mSelectionData.SetWritingMode(selection.GetWritingMode());
|
||||
mSelectionData.mReversed = selection.mReply.mReversed;
|
||||
mFocusedWidget = querySelectedTextEvent.mReply->mFocusedWidget;
|
||||
mSelectionData.mOffset = querySelectedTextEvent.mReply->StartOffset();
|
||||
*mSelectionData.mString = querySelectedTextEvent.mReply->DataRef();
|
||||
mSelectionData.SetWritingMode(
|
||||
querySelectedTextEvent.mReply->WritingModeRef());
|
||||
mSelectionData.mReversed = querySelectedTextEvent.mReply->mReversed;
|
||||
|
||||
// WARNING: Don't modify the reason of selection change here.
|
||||
|
||||
|
@ -448,18 +448,19 @@ void TextComposition::HandleSelectionEvent(
|
||||
|
||||
uint32_t TextComposition::GetSelectionStartOffset() {
|
||||
nsCOMPtr<nsIWidget> widget = mPresContext->GetRootWidget();
|
||||
WidgetQueryContentEvent selectedTextEvent(true, eQuerySelectedText, widget);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
widget);
|
||||
// Due to a bug of widget, mRanges may not be nullptr even though composition
|
||||
// string is empty. So, we need to check it here for avoiding to return
|
||||
// odd start offset.
|
||||
if (!mLastData.IsEmpty() && mRanges && mRanges->HasClauses()) {
|
||||
selectedTextEvent.InitForQuerySelectedText(
|
||||
querySelectedTextEvent.InitForQuerySelectedText(
|
||||
ToSelectionType(mRanges->GetFirstClause()->mRangeType));
|
||||
} else {
|
||||
NS_WARNING_ASSERTION(
|
||||
!mLastData.IsEmpty() || !mRanges || !mRanges->HasClauses(),
|
||||
"Shouldn't have empty clause info when composition string is empty");
|
||||
selectedTextEvent.InitForQuerySelectedText(SelectionType::eNormal);
|
||||
querySelectedTextEvent.InitForQuerySelectedText(SelectionType::eNormal);
|
||||
}
|
||||
|
||||
// The editor which has this composition is observed by active
|
||||
@ -470,7 +471,7 @@ uint32_t TextComposition::GetSelectionStartOffset() {
|
||||
if (contentObserver) {
|
||||
if (contentObserver->IsManaging(this)) {
|
||||
doQuerySelection = false;
|
||||
contentObserver->HandleQueryContentEvent(&selectedTextEvent);
|
||||
contentObserver->HandleQueryContentEvent(&querySelectedTextEvent);
|
||||
}
|
||||
// If another editor already has focus, we cannot retrieve selection
|
||||
// in the editor which has this composition...
|
||||
@ -483,13 +484,13 @@ uint32_t TextComposition::GetSelectionStartOffset() {
|
||||
// ContentEventHandler)
|
||||
if (doQuerySelection) {
|
||||
ContentEventHandler handler(mPresContext);
|
||||
handler.HandleQueryContentEvent(&selectedTextEvent);
|
||||
handler.HandleQueryContentEvent(&querySelectedTextEvent);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!selectedTextEvent.mSucceeded)) {
|
||||
if (NS_WARN_IF(querySelectedTextEvent.DidNotFindSelection())) {
|
||||
return 0; // XXX Is this okay?
|
||||
}
|
||||
return selectedTextEvent.mReply.mOffset;
|
||||
return querySelectedTextEvent.mReply->SelectionStartOffset();
|
||||
}
|
||||
|
||||
void TextComposition::OnCompositionEventDispatched(
|
||||
@ -825,11 +826,15 @@ TextComposition::CompositionEventDispatcher::Run() {
|
||||
case eCompositionStart: {
|
||||
WidgetCompositionEvent compStart(true, eCompositionStart, widget);
|
||||
compStart.mNativeIMEContext = mTextComposition->mNativeContext;
|
||||
WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
widget);
|
||||
ContentEventHandler handler(presContext);
|
||||
handler.OnQuerySelectedText(&selectedText);
|
||||
NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
|
||||
compStart.mData = selectedText.mReply.mString;
|
||||
handler.OnQuerySelectedText(&querySelectedTextEvent);
|
||||
NS_ASSERTION(querySelectedTextEvent.Succeeded(),
|
||||
"Failed to get selected text");
|
||||
if (querySelectedTextEvent.FoundSelection()) {
|
||||
compStart.mData = querySelectedTextEvent.mReply->DataRef();
|
||||
}
|
||||
compStart.mFlags.mIsSynthesizedForTests =
|
||||
mTextComposition->IsSynthesizedForTests();
|
||||
IMEStateManager::DispatchCompositionEvent(
|
||||
|
@ -2903,7 +2903,7 @@ bool BrowserParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) {
|
||||
}
|
||||
if (NS_WARN_IF(!mContentCache.HandleQueryContentEvent(
|
||||
aEvent, textInputHandlingWidget)) ||
|
||||
NS_WARN_IF(!aEvent.mSucceeded)) {
|
||||
NS_WARN_IF(aEvent.Failed())) {
|
||||
return true;
|
||||
}
|
||||
switch (aEvent.mMessage) {
|
||||
@ -2912,10 +2912,10 @@ bool BrowserParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent) {
|
||||
case eQueryEditorRect: {
|
||||
nsCOMPtr<nsIWidget> browserWidget = GetWidget();
|
||||
if (browserWidget != textInputHandlingWidget) {
|
||||
aEvent.mReply.mRect += nsLayoutUtils::WidgetToWidgetOffset(
|
||||
aEvent.mReply->mRect += nsLayoutUtils::WidgetToWidgetOffset(
|
||||
browserWidget, textInputHandlingWidget);
|
||||
}
|
||||
aEvent.mReply.mRect = TransformChildToParent(aEvent.mReply.mRect);
|
||||
aEvent.mReply->mRect = TransformChildToParent(aEvent.mReply->mRect);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -126,24 +126,25 @@ bool ContentCacheInChild::CacheSelection(nsIWidget* aWidget,
|
||||
mSelection.reset();
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetQueryContentEvent selection(true, eQuerySelectedText, aWidget);
|
||||
aWidget->DispatchEvent(&selection, status);
|
||||
if (NS_WARN_IF(!selection.mSucceeded)) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p CacheSelection(), FAILED, "
|
||||
"couldn't retrieve the selected text",
|
||||
this));
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
aWidget);
|
||||
aWidget->DispatchEvent(&querySelectedTextEvent, status);
|
||||
if (NS_WARN_IF(querySelectedTextEvent.DidNotFindSelection())) {
|
||||
MOZ_LOG(
|
||||
sContentCacheLog, LogLevel::Error,
|
||||
("0x%p CacheSelection(), FAILED, couldn't retrieve the selected text",
|
||||
this));
|
||||
return false;
|
||||
}
|
||||
if (selection.mReply.mReversed) {
|
||||
mSelection.emplace(
|
||||
selection.mReply.mOffset + selection.mReply.mString.Length(),
|
||||
selection.mReply.mOffset, selection.GetWritingMode());
|
||||
MOZ_ASSERT(querySelectedTextEvent.mReply->mOffsetAndData.isSome());
|
||||
if (querySelectedTextEvent.mReply->mReversed) {
|
||||
mSelection.emplace(querySelectedTextEvent.mReply->EndOffset(),
|
||||
querySelectedTextEvent.mReply->StartOffset(),
|
||||
querySelectedTextEvent.mReply->WritingModeRef());
|
||||
} else {
|
||||
mSelection.emplace(
|
||||
selection.mReply.mOffset,
|
||||
selection.mReply.mOffset + selection.mReply.mString.Length(),
|
||||
selection.GetWritingMode());
|
||||
mSelection.emplace(querySelectedTextEvent.mReply->StartOffset(),
|
||||
querySelectedTextEvent.mReply->EndOffset(),
|
||||
querySelectedTextEvent.mReply->WritingModeRef());
|
||||
}
|
||||
|
||||
return CacheCaret(aWidget, aNotification) &&
|
||||
@ -166,17 +167,17 @@ bool ContentCacheInChild::CacheCaret(nsIWidget* aWidget,
|
||||
uint32_t offset = mSelection->StartOffset();
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetQueryContentEvent caretRect(true, eQueryCaretRect, aWidget);
|
||||
caretRect.InitForQueryCaretRect(offset);
|
||||
aWidget->DispatchEvent(&caretRect, status);
|
||||
if (NS_WARN_IF(!caretRect.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryCaretRectEvet(true, eQueryCaretRect, aWidget);
|
||||
queryCaretRectEvet.InitForQueryCaretRect(offset);
|
||||
aWidget->DispatchEvent(&queryCaretRectEvet, status);
|
||||
if (NS_WARN_IF(queryCaretRectEvet.Failed())) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p CacheCaret(), FAILED, "
|
||||
"couldn't retrieve the caret rect at offset=%u",
|
||||
("0x%p CacheCaret(), FAILED, couldn't retrieve the caret rect at "
|
||||
"offset=%u",
|
||||
this, offset));
|
||||
return false;
|
||||
}
|
||||
mCaret.emplace(offset, caretRect.mReply.mRect);
|
||||
mCaret.emplace(offset, queryCaretRectEvet.mReply->mRect);
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p CacheCaret(), Succeeded, "
|
||||
"mSelection=%s, mCaret=%s",
|
||||
@ -191,16 +192,16 @@ bool ContentCacheInChild::CacheEditorRect(
|
||||
aWidget, GetNotificationName(aNotification)));
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetQueryContentEvent editorRectEvent(true, eQueryEditorRect, aWidget);
|
||||
aWidget->DispatchEvent(&editorRectEvent, status);
|
||||
if (NS_WARN_IF(!editorRectEvent.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryEditorRectEvent(true, eQueryEditorRect, aWidget);
|
||||
aWidget->DispatchEvent(&queryEditorRectEvent, status);
|
||||
if (NS_WARN_IF(queryEditorRectEvent.Failed())) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p CacheEditorRect(), FAILED, "
|
||||
"couldn't retrieve the editor rect",
|
||||
this));
|
||||
return false;
|
||||
}
|
||||
mEditorRect = editorRectEvent.mReply.mRect;
|
||||
mEditorRect = queryEditorRectEvent.mReply->mRect;
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p CacheEditorRect(), Succeeded, "
|
||||
"mEditorRect=%s",
|
||||
@ -215,16 +216,17 @@ bool ContentCacheInChild::CacheText(nsIWidget* aWidget,
|
||||
GetNotificationName(aNotification)));
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetQueryContentEvent queryText(true, eQueryTextContent, aWidget);
|
||||
queryText.InitForQueryTextContent(0, UINT32_MAX);
|
||||
aWidget->DispatchEvent(&queryText, status);
|
||||
if (NS_WARN_IF(!queryText.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryTextContentEvent(true, eQueryTextContent,
|
||||
aWidget);
|
||||
queryTextContentEvent.InitForQueryTextContent(0, UINT32_MAX);
|
||||
aWidget->DispatchEvent(&queryTextContentEvent, status);
|
||||
if (NS_WARN_IF(queryTextContentEvent.Failed())) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p CacheText(), FAILED, couldn't retrieve whole text", this));
|
||||
mText.Truncate();
|
||||
return false;
|
||||
}
|
||||
mText = queryText.mReply.mString;
|
||||
mText = queryTextContentEvent.mReply->DataRef();
|
||||
MOZ_LOG(
|
||||
sContentCacheLog, LogLevel::Info,
|
||||
("0x%p CacheText(), Succeeded, mText.Length()=%u", this, mText.Length()));
|
||||
@ -254,13 +256,13 @@ bool ContentCacheInChild::QueryCharRect(nsIWidget* aWidget, uint32_t aOffset,
|
||||
aCharRect.SetEmpty();
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetQueryContentEvent textRect(true, eQueryTextRect, aWidget);
|
||||
textRect.InitForQueryTextRect(aOffset, 1);
|
||||
aWidget->DispatchEvent(&textRect, status);
|
||||
if (NS_WARN_IF(!textRect.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryTextRectEvent(true, eQueryTextRect, aWidget);
|
||||
queryTextRectEvent.InitForQueryTextRect(aOffset, 1);
|
||||
aWidget->DispatchEvent(&queryTextRectEvent, status);
|
||||
if (NS_WARN_IF(queryTextRectEvent.Failed())) {
|
||||
return false;
|
||||
}
|
||||
aCharRect = textRect.mReply.mRect;
|
||||
aCharRect = queryTextRectEvent.mReply->mRect;
|
||||
|
||||
// Guarantee the rect is not empty.
|
||||
if (NS_WARN_IF(!aCharRect.Height())) {
|
||||
@ -276,14 +278,15 @@ bool ContentCacheInChild::QueryCharRectArray(nsIWidget* aWidget,
|
||||
uint32_t aOffset, uint32_t aLength,
|
||||
RectArray& aCharRectArray) const {
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetQueryContentEvent textRects(true, eQueryTextRectArray, aWidget);
|
||||
textRects.InitForQueryTextRectArray(aOffset, aLength);
|
||||
aWidget->DispatchEvent(&textRects, status);
|
||||
if (NS_WARN_IF(!textRects.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryTextRectsEvent(true, eQueryTextRectArray,
|
||||
aWidget);
|
||||
queryTextRectsEvent.InitForQueryTextRectArray(aOffset, aLength);
|
||||
aWidget->DispatchEvent(&queryTextRectsEvent, status);
|
||||
if (NS_WARN_IF(queryTextRectsEvent.Failed())) {
|
||||
aCharRectArray.Clear();
|
||||
return false;
|
||||
}
|
||||
aCharRectArray = std::move(textRects.mReply.mRectArray);
|
||||
aCharRectArray = std::move(queryTextRectsEvent.mReply->mRectArray);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -401,17 +404,17 @@ bool ContentCacheInChild::CacheTextRects(nsIWidget* aWidget,
|
||||
|
||||
if (!mSelection->Collapsed()) {
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetQueryContentEvent textRect(true, eQueryTextRect, aWidget);
|
||||
textRect.InitForQueryTextRect(mSelection->StartOffset(),
|
||||
mSelection->Length());
|
||||
aWidget->DispatchEvent(&textRect, status);
|
||||
if (NS_WARN_IF(!textRect.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryTextRectEvent(true, eQueryTextRect, aWidget);
|
||||
queryTextRectEvent.InitForQueryTextRect(mSelection->StartOffset(),
|
||||
mSelection->Length());
|
||||
aWidget->DispatchEvent(&queryTextRectEvent, status);
|
||||
if (NS_WARN_IF(queryTextRectEvent.Failed())) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p CacheTextRects(), FAILED, "
|
||||
"couldn't retrieve text rect of whole selected text",
|
||||
this));
|
||||
} else {
|
||||
mSelection->mRect = textRect.mReply.mRect;
|
||||
mSelection->mRect = queryTextRectEvent.mReply->mRect;
|
||||
}
|
||||
}
|
||||
|
||||
@ -578,9 +581,6 @@ bool ContentCacheInParent::HandleQueryContentEvent(
|
||||
WidgetQueryContentEvent& aEvent, nsIWidget* aWidget) const {
|
||||
MOZ_ASSERT(aWidget);
|
||||
|
||||
aEvent.mSucceeded = false;
|
||||
aEvent.mReply.mFocusedWidget = aWidget;
|
||||
|
||||
// ContentCache doesn't store offset of its start with XP linebreaks.
|
||||
// So, we don't support to query contents relative to composition start
|
||||
// offset with XP linebreaks.
|
||||
@ -673,59 +673,53 @@ bool ContentCacheInParent::HandleQueryContentEvent(
|
||||
switch (aEvent.mMessage) {
|
||||
case eQuerySelectedText:
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent("
|
||||
"aEvent={ mMessage=eQuerySelectedText }, aWidget=0x%p)",
|
||||
("0x%p HandleQueryContentEvent(aEvent={ "
|
||||
"mMessage=eQuerySelectedText }, aWidget=0x%p)",
|
||||
this, aWidget));
|
||||
if (aWidget->PluginHasFocus()) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"return emtpy selection becasue plugin has focus",
|
||||
("0x%p HandleQueryContentEvent(), return emtpy selection "
|
||||
"because plugin has focus",
|
||||
this));
|
||||
aEvent.mSucceeded = true;
|
||||
aEvent.mReply.mOffset = 0;
|
||||
aEvent.mReply.mReversed = false;
|
||||
aEvent.mReply.mHasSelection = false;
|
||||
aEvent.EmplaceReply();
|
||||
aEvent.mReply->mFocusedWidget = aWidget;
|
||||
aEvent.mReply->mOffsetAndData.emplace(0, EmptyString(),
|
||||
OffsetAndDataFor::SelectedString);
|
||||
aEvent.mReply->mReversed = false;
|
||||
aEvent.mReply->mHasSelection = false;
|
||||
return true;
|
||||
}
|
||||
if (NS_WARN_IF(!IsSelectionValid())) {
|
||||
// If content cache hasn't been initialized properly, make the query
|
||||
// failed.
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"FAILED because mSelection is not valid",
|
||||
("0x%p HandleQueryContentEvent(), FAILED because mSelection is "
|
||||
"not valid",
|
||||
this));
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
aEvent.mReply.mOffset = mSelection->StartOffset();
|
||||
if (mSelection->Collapsed()) {
|
||||
aEvent.mReply.mString.Truncate(0);
|
||||
} else {
|
||||
if (NS_WARN_IF(mSelection->EndOffset() > mText.Length())) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"FAILED because mSelection->EndOffset()=%u is larger than "
|
||||
"mText.Length()=%u",
|
||||
this, mSelection->EndOffset(), mText.Length()));
|
||||
return false;
|
||||
}
|
||||
aEvent.mReply.mString =
|
||||
Substring(mText, aEvent.mReply.mOffset, mSelection->Length());
|
||||
if (!mSelection->Collapsed() &&
|
||||
NS_WARN_IF(mSelection->EndOffset() > mText.Length())) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), FAILED because "
|
||||
"mSelection->EndOffset()=%u is larger than mText.Length()=%u",
|
||||
this, mSelection->EndOffset(), mText.Length()));
|
||||
return false;
|
||||
}
|
||||
aEvent.mReply.mReversed = mSelection->Reversed();
|
||||
aEvent.mReply.mHasSelection = true;
|
||||
aEvent.mReply.mWritingMode = mSelection->mWritingMode;
|
||||
aEvent.EmplaceReply();
|
||||
aEvent.mReply->mFocusedWidget = aWidget;
|
||||
aEvent.mReply->mOffsetAndData.emplace(
|
||||
mSelection->StartOffset(),
|
||||
Substring(mText, mSelection->StartOffset(), mSelection->Length()),
|
||||
OffsetAndDataFor::SelectedString);
|
||||
aEvent.mReply->mReversed = mSelection->Reversed();
|
||||
aEvent.mReply->mHasSelection = true;
|
||||
aEvent.mReply->mWritingMode = mSelection->mWritingMode;
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"Succeeded, aEvent={ mReply={ mOffset=%u, mString=\"%s\", "
|
||||
"mReversed=%s, mHasSelection=%s, mWritingMode=%s } }",
|
||||
this, aEvent.mReply.mOffset,
|
||||
PrintStringDetail(aEvent.mReply.mString,
|
||||
PrintStringDetail::kMaxLengthForSelectedString)
|
||||
.get(),
|
||||
GetBoolName(aEvent.mReply.mReversed),
|
||||
GetBoolName(aEvent.mReply.mHasSelection),
|
||||
ToString(aEvent.mReply.mWritingMode).c_str()));
|
||||
break;
|
||||
"Succeeded, aEvent={ mMessage=eQuerySelectedText, mReply=%s }",
|
||||
this, ToString(aEvent.mReply).c_str()));
|
||||
return true;
|
||||
case eQueryTextContent: {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent("
|
||||
@ -737,24 +731,26 @@ bool ContentCacheInParent::HandleQueryContentEvent(
|
||||
uint32_t inputEndOffset =
|
||||
std::min(aEvent.mInput.EndOffset(), mText.Length());
|
||||
if (NS_WARN_IF(inputEndOffset < inputOffset)) {
|
||||
MOZ_LOG(
|
||||
sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"FAILED because inputOffset=%u is larger than inputEndOffset=%u",
|
||||
this, inputOffset, inputEndOffset));
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), FAILED because "
|
||||
"inputOffset=%u is larger than inputEndOffset=%u",
|
||||
this, inputOffset, inputEndOffset));
|
||||
return false;
|
||||
}
|
||||
aEvent.mReply.mOffset = inputOffset;
|
||||
aEvent.mReply.mString =
|
||||
Substring(mText, inputOffset, inputEndOffset - inputOffset);
|
||||
MOZ_LOG(
|
||||
sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"Succeeded, aEvent={ mReply={ mOffset=%u, mString.Length()=%u } }",
|
||||
this, aEvent.mReply.mOffset, aEvent.mReply.mString.Length()));
|
||||
break;
|
||||
aEvent.EmplaceReply();
|
||||
aEvent.mReply->mFocusedWidget = aWidget;
|
||||
aEvent.mReply->mOffsetAndData.emplace(
|
||||
inputOffset,
|
||||
Substring(mText, inputOffset, inputEndOffset - inputOffset),
|
||||
OffsetAndDataFor::EditorString);
|
||||
// TODO: Support font ranges
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), Succeeded, aEvent={ "
|
||||
"mMessage=eQueryTextContent, mReply=%s }",
|
||||
this, ToString(aEvent.mReply).c_str()));
|
||||
return true;
|
||||
}
|
||||
case eQueryTextRect:
|
||||
case eQueryTextRect: {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent("
|
||||
"aEvent={ mMessage=eQueryTextRect, mInput={ mOffset=%" PRId64
|
||||
@ -765,112 +761,127 @@ bool ContentCacheInParent::HandleQueryContentEvent(
|
||||
// If content cache hasn't been initialized properly, make the query
|
||||
// failed.
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"FAILED because mSelection is not valid",
|
||||
("0x%p HandleQueryContentEvent(), FAILED because mSelection is "
|
||||
"not valid",
|
||||
this));
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
// Note that if the query is relative to insertion point, the query was
|
||||
// probably requested by native IME. In such case, we should return
|
||||
// non-empty rect since returning failure causes IME showing its window
|
||||
// at odd position.
|
||||
LayoutDeviceIntRect textRect;
|
||||
if (aEvent.mInput.mLength) {
|
||||
if (NS_WARN_IF(!GetUnionTextRects(
|
||||
aEvent.mInput.mOffset, aEvent.mInput.mLength,
|
||||
isRelativeToInsertionPoint, aEvent.mReply.mRect))) {
|
||||
if (NS_WARN_IF(
|
||||
!GetUnionTextRects(aEvent.mInput.mOffset, aEvent.mInput.mLength,
|
||||
isRelativeToInsertionPoint, textRect))) {
|
||||
// XXX We don't have cache for this request.
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"FAILED to get union rect",
|
||||
("0x%p HandleQueryContentEvent(), FAILED to get union rect",
|
||||
this));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// If the length is 0, we should return caret rect instead.
|
||||
if (NS_WARN_IF(!GetCaretRect(aEvent.mInput.mOffset,
|
||||
isRelativeToInsertionPoint,
|
||||
aEvent.mReply.mRect))) {
|
||||
isRelativeToInsertionPoint, textRect))) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"FAILED to get caret rect",
|
||||
("0x%p HandleQueryContentEvent(), FAILED to get caret rect",
|
||||
this));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (aEvent.mInput.mOffset < mText.Length()) {
|
||||
aEvent.mReply.mString = Substring(
|
||||
mText, aEvent.mInput.mOffset,
|
||||
mText.Length() >= aEvent.mInput.EndOffset() ? aEvent.mInput.mLength
|
||||
: UINT32_MAX);
|
||||
} else {
|
||||
aEvent.mReply.mString.Truncate(0);
|
||||
}
|
||||
aEvent.mReply.mOffset = aEvent.mInput.mOffset;
|
||||
aEvent.EmplaceReply();
|
||||
aEvent.mReply->mFocusedWidget = aWidget;
|
||||
aEvent.mReply->mRect = textRect;
|
||||
aEvent.mReply->mOffsetAndData.emplace(
|
||||
aEvent.mInput.mOffset,
|
||||
aEvent.mInput.mOffset < mText.Length()
|
||||
? static_cast<const nsAString&>(
|
||||
Substring(mText, aEvent.mInput.mOffset,
|
||||
mText.Length() >= aEvent.mInput.EndOffset()
|
||||
? aEvent.mInput.mLength
|
||||
: UINT32_MAX))
|
||||
: static_cast<const nsAString&>(EmptyString()),
|
||||
OffsetAndDataFor::EditorString);
|
||||
// XXX This may be wrong if storing range isn't in the selection range.
|
||||
aEvent.mReply.mWritingMode = mSelection->mWritingMode;
|
||||
aEvent.mReply->mWritingMode = mSelection->mWritingMode;
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"Succeeded, aEvent={ mReply={ mOffset=%u, mString=\"%s\", "
|
||||
"mWritingMode=%s, mRect=%s } }",
|
||||
this, aEvent.mReply.mOffset,
|
||||
PrintStringDetail(aEvent.mReply.mString,
|
||||
PrintStringDetail::kMaxLengthForSelectedString)
|
||||
.get(),
|
||||
ToString(aEvent.mReply.mWritingMode).c_str(),
|
||||
ToString(aEvent.mReply.mRect).c_str()));
|
||||
break;
|
||||
case eQueryCaretRect:
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent("
|
||||
"aEvent={ mMessage=eQueryCaretRect, mInput={ mOffset=%" PRId64
|
||||
" } }, "
|
||||
"aWidget=0x%p), mText.Length()=%u",
|
||||
this, aEvent.mInput.mOffset, aWidget, mText.Length()));
|
||||
("0x%p HandleQueryContentEvent(), Succeeded, aEvent={ "
|
||||
"mMessage=eQueryTextRect mReply=%s }",
|
||||
this, ToString(aEvent.mReply).c_str()));
|
||||
return true;
|
||||
}
|
||||
case eQueryCaretRect: {
|
||||
MOZ_LOG(
|
||||
sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(aEvent={ mMessage=eQueryCaretRect, "
|
||||
"mInput={ mOffset=%" PRId64 " } }, aWidget=0x%p), mText.Length()=%u",
|
||||
this, aEvent.mInput.mOffset, aWidget, mText.Length()));
|
||||
if (NS_WARN_IF(!IsSelectionValid())) {
|
||||
// If content cache hasn't been initialized properly, make the query
|
||||
// failed.
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"FAILED because mSelection is not valid",
|
||||
("0x%p HandleQueryContentEvent(), FAILED because mSelection is "
|
||||
"not valid",
|
||||
this));
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
// Note that if the query is relative to insertion point, the query was
|
||||
// probably requested by native IME. In such case, we should return
|
||||
// non-empty rect since returning failure causes IME showing its window
|
||||
// at odd position.
|
||||
LayoutDeviceIntRect caretRect;
|
||||
if (NS_WARN_IF(!GetCaretRect(aEvent.mInput.mOffset,
|
||||
isRelativeToInsertionPoint,
|
||||
aEvent.mReply.mRect))) {
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"FAILED to get caret rect",
|
||||
this));
|
||||
isRelativeToInsertionPoint, caretRect))) {
|
||||
MOZ_LOG(
|
||||
sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(),FAILED to get caret rect", this));
|
||||
return false;
|
||||
}
|
||||
aEvent.mReply.mOffset = aEvent.mInput.mOffset;
|
||||
MOZ_LOG(
|
||||
sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"Succeeded, aEvent={ mReply={ mOffset=%u, mRect=%s } }",
|
||||
this, aEvent.mReply.mOffset, ToString(aEvent.mReply.mRect).c_str()));
|
||||
break;
|
||||
aEvent.EmplaceReply();
|
||||
aEvent.mReply->mFocusedWidget = aWidget;
|
||||
aEvent.mReply->mRect = caretRect;
|
||||
aEvent.mReply->mOffsetAndData.emplace(aEvent.mInput.mOffset,
|
||||
EmptyString(),
|
||||
OffsetAndDataFor::SelectedString);
|
||||
// TODO: Set mWritingMode here
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), Succeeded, aEvent={ "
|
||||
"mMessage=eQueryCaretRect, mReply=%s }",
|
||||
this, ToString(aEvent.mReply).c_str()));
|
||||
return true;
|
||||
}
|
||||
case eQueryEditorRect:
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent("
|
||||
"aEvent={ mMessage=eQueryEditorRect }, aWidget=0x%p)",
|
||||
("0x%p HandleQueryContentEvent(aEvent={ "
|
||||
"mMessage=eQueryEditorRect }, aWidget=0x%p)",
|
||||
this, aWidget));
|
||||
aEvent.mReply.mRect = mEditorRect;
|
||||
aEvent.EmplaceReply();
|
||||
aEvent.mReply->mFocusedWidget = aWidget;
|
||||
aEvent.mReply->mRect = mEditorRect;
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), "
|
||||
"Succeeded, aEvent={ mReply={ mRect=%s } }",
|
||||
this, ToString(aEvent.mReply.mRect).c_str()));
|
||||
break;
|
||||
("0x%p HandleQueryContentEvent(), Succeeded, aEvent={ "
|
||||
"mMessage=eQueryEditorRect, mReply=%s }",
|
||||
this, ToString(aEvent.mReply).c_str()));
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
aEvent.EmplaceReply();
|
||||
aEvent.mReply->mFocusedWidget = aWidget;
|
||||
if (NS_WARN_IF(aEvent.Failed())) {
|
||||
MOZ_LOG(
|
||||
sContentCacheLog, LogLevel::Error,
|
||||
("0x%p HandleQueryContentEvent(), FAILED due to not set enough "
|
||||
"data, aEvent={ mMessage=%s, mReply=%s }",
|
||||
this, ToChar(aEvent.mMessage), ToString(aEvent.mReply).c_str()));
|
||||
return false;
|
||||
}
|
||||
MOZ_LOG(sContentCacheLog, LogLevel::Info,
|
||||
("0x%p HandleQueryContentEvent(), Succeeded, aEvent={ "
|
||||
"mMessage=%s, mReply=%s }",
|
||||
this, ToChar(aEvent.mMessage), ToString(aEvent.mReply).c_str()));
|
||||
return true;
|
||||
}
|
||||
aEvent.mSucceeded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ContentCacheInParent::GetTextRect(uint32_t aOffset,
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/ToString.h"
|
||||
|
||||
#include "nsPoint.h"
|
||||
#include "nsRect.h"
|
||||
@ -106,6 +107,11 @@ class StartAndEndOffsets {
|
||||
// the length is shrunken. However, the string itself is not shrunken.
|
||||
// Therefore, moving it to where all of the string can be contained,
|
||||
// they will return longer/bigger value.
|
||||
enum class OffsetAndDataFor {
|
||||
CompositionString,
|
||||
SelectedString,
|
||||
EditorString,
|
||||
};
|
||||
template <typename IntType>
|
||||
class OffsetAndData {
|
||||
protected:
|
||||
@ -113,8 +119,10 @@ class OffsetAndData {
|
||||
|
||||
public:
|
||||
OffsetAndData() = delete;
|
||||
explicit OffsetAndData(IntType aStartOffset, const nsAString& aData)
|
||||
: mData(aData), mOffset(aStartOffset) {}
|
||||
explicit OffsetAndData(
|
||||
IntType aStartOffset, const nsAString& aData,
|
||||
OffsetAndDataFor aFor = OffsetAndDataFor::CompositionString)
|
||||
: mData(aData), mOffset(aStartOffset), mFor(aFor) {}
|
||||
|
||||
IntType StartOffset() const { return mOffset; }
|
||||
IntType Length() const {
|
||||
@ -132,6 +140,7 @@ class OffsetAndData {
|
||||
// this just returns the data as-is.
|
||||
return mData;
|
||||
}
|
||||
bool IsDataEmpty() const { return mData.IsEmpty(); }
|
||||
|
||||
bool IsOffsetInRange(IntType aOffset) const {
|
||||
return aOffset >= mOffset && aOffset < EndOffset();
|
||||
@ -146,6 +155,7 @@ class OffsetAndData {
|
||||
mData = aData;
|
||||
}
|
||||
void SetData(const nsAString& aData) { mData = aData; }
|
||||
void TruncateData(uint32_t aLength = 0) { mData.Truncate(aLength); }
|
||||
void ReplaceData(nsAString::size_type aCutStart,
|
||||
nsAString::size_type aCutLength,
|
||||
const nsAString& aNewString) {
|
||||
@ -154,11 +164,14 @@ class OffsetAndData {
|
||||
|
||||
friend std::ostream& operator<<(
|
||||
std::ostream& aStream, const OffsetAndData<IntType>& aOffsetAndData) {
|
||||
const auto maxDataLength =
|
||||
aOffsetAndData.mFor == OffsetAndDataFor::CompositionString
|
||||
? PrintStringDetail::kMaxLengthForCompositionString
|
||||
: (aOffsetAndData.mFor == OffsetAndDataFor::SelectedString
|
||||
? PrintStringDetail::kMaxLengthForSelectedString
|
||||
: PrintStringDetail::kMaxLengthForEditor);
|
||||
aStream << "{ mOffset=" << aOffsetAndData.mOffset << ", mData="
|
||||
<< PrintStringDetail(
|
||||
aOffsetAndData.mData,
|
||||
PrintStringDetail::kMaxLengthForCompositionString)
|
||||
.get()
|
||||
<< PrintStringDetail(aOffsetAndData.mData, maxDataLength).get()
|
||||
<< ", Length()=" << aOffsetAndData.Length()
|
||||
<< ", EndOffset()=" << aOffsetAndData.EndOffset() << " }";
|
||||
return aStream;
|
||||
@ -167,6 +180,7 @@ class OffsetAndData {
|
||||
private:
|
||||
nsString mData;
|
||||
IntType mOffset;
|
||||
OffsetAndDataFor mFor;
|
||||
};
|
||||
|
||||
namespace widget {
|
||||
|
@ -11,15 +11,16 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "mozilla/dom/StaticRange.h"
|
||||
#include "mozilla/EventForwards.h" // for KeyNameIndex, temporarily
|
||||
#include "mozilla/FontRange.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/OwningNonNull.h"
|
||||
#include "mozilla/TextRange.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
#include "mozilla/dom/DataTransfer.h"
|
||||
#include "mozilla/dom/KeyboardEventBinding.h"
|
||||
#include "mozilla/dom/StaticRange.h"
|
||||
#include "mozilla/widget/IMEData.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISelectionListener.h"
|
||||
#include "nsITransferable.h"
|
||||
@ -911,8 +912,7 @@ class WidgetQueryContentEvent : public WidgetGUIEvent {
|
||||
friend class dom::PBrowserChild;
|
||||
|
||||
WidgetQueryContentEvent()
|
||||
: mSucceeded(false),
|
||||
mUseNativeLineBreak(true),
|
||||
: mUseNativeLineBreak(true),
|
||||
mWithFontRanges(false),
|
||||
mNeedsToFlushLayout(true) {
|
||||
MOZ_CRASH("WidgetQueryContentEvent is created without proper arguments");
|
||||
@ -926,7 +926,6 @@ class WidgetQueryContentEvent : public WidgetGUIEvent {
|
||||
WidgetQueryContentEvent(bool aIsTrusted, EventMessage aMessage,
|
||||
nsIWidget* aWidget)
|
||||
: WidgetGUIEvent(aIsTrusted, aMessage, aWidget, eQueryContentEventClass),
|
||||
mSucceeded(false),
|
||||
mUseNativeLineBreak(true),
|
||||
mWithFontRanges(false),
|
||||
mNeedsToFlushLayout(true) {}
|
||||
@ -936,7 +935,6 @@ class WidgetQueryContentEvent : public WidgetGUIEvent {
|
||||
: WidgetGUIEvent(aOtherEvent.IsTrusted(), aMessage,
|
||||
const_cast<nsIWidget*>(aOtherEvent.mWidget.get()),
|
||||
eQueryContentEventClass),
|
||||
mSucceeded(false),
|
||||
mUseNativeLineBreak(aOtherEvent.mUseNativeLineBreak),
|
||||
mWithFontRanges(false),
|
||||
mNeedsToFlushLayout(aOtherEvent.mNeedsToFlushLayout) {}
|
||||
@ -1019,28 +1017,59 @@ class WidgetQueryContentEvent : public WidgetGUIEvent {
|
||||
bool NeedsToFlushLayout() const { return mNeedsToFlushLayout; }
|
||||
|
||||
void RequestFontRanges() {
|
||||
NS_ASSERTION(mMessage == eQueryTextContent, "not querying text content");
|
||||
MOZ_ASSERT(mMessage == eQueryTextContent);
|
||||
mWithFontRanges = true;
|
||||
}
|
||||
|
||||
uint32_t GetSelectionStart(void) const {
|
||||
NS_ASSERTION(mMessage == eQuerySelectedText, "not querying selection");
|
||||
return mReply.mOffset + (mReply.mReversed ? mReply.mString.Length() : 0);
|
||||
bool Succeeded() const {
|
||||
if (mReply.isNothing()) {
|
||||
return false;
|
||||
}
|
||||
switch (mMessage) {
|
||||
case eQuerySelectedText:
|
||||
return mReply->mOffsetAndData.isSome() ||
|
||||
mInput.mSelectionType != SelectionType::eNormal;
|
||||
case eQueryTextContent:
|
||||
case eQueryTextRect:
|
||||
case eQueryCaretRect:
|
||||
return mReply->mOffsetAndData.isSome();
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GetSelectionEnd(void) const {
|
||||
NS_ASSERTION(mMessage == eQuerySelectedText, "not querying selection");
|
||||
return mReply.mOffset + (mReply.mReversed ? 0 : mReply.mString.Length());
|
||||
bool Failed() const { return !Succeeded(); }
|
||||
|
||||
bool FoundSelection() const {
|
||||
MOZ_ASSERT(mMessage == eQuerySelectedText);
|
||||
return Succeeded() && mReply->mOffsetAndData.isSome();
|
||||
}
|
||||
|
||||
mozilla::WritingMode GetWritingMode(void) const {
|
||||
NS_ASSERTION(mMessage == eQuerySelectedText ||
|
||||
mMessage == eQueryCaretRect || mMessage == eQueryTextRect,
|
||||
"not querying selection or text rect");
|
||||
return mReply.mWritingMode;
|
||||
bool FoundChar() const {
|
||||
MOZ_ASSERT(mMessage == eQueryCharacterAtPoint);
|
||||
return Succeeded() && mReply->mOffsetAndData.isSome();
|
||||
}
|
||||
|
||||
bool FoundTentativeCaretOffset() const {
|
||||
MOZ_ASSERT(mMessage == eQueryCharacterAtPoint);
|
||||
return Succeeded() && mReply->mTentativeCaretOffset.isSome();
|
||||
}
|
||||
|
||||
bool DidNotFindSelection() const {
|
||||
MOZ_ASSERT(mMessage == eQuerySelectedText);
|
||||
return Failed() || mReply->mOffsetAndData.isNothing();
|
||||
}
|
||||
|
||||
bool DidNotFindChar() const {
|
||||
MOZ_ASSERT(mMessage == eQueryCharacterAtPoint);
|
||||
return Failed() || mReply->mOffsetAndData.isNothing();
|
||||
}
|
||||
|
||||
bool DidNotFindTentativeCaretOffset() const {
|
||||
MOZ_ASSERT(mMessage == eQueryCharacterAtPoint);
|
||||
return Failed() || mReply->mTentativeCaretOffset.isNothing();
|
||||
}
|
||||
|
||||
bool mSucceeded;
|
||||
bool mUseNativeLineBreak;
|
||||
bool mWithFontRanges;
|
||||
bool mNeedsToFlushLayout;
|
||||
@ -1103,12 +1132,12 @@ class WidgetQueryContentEvent : public WidgetGUIEvent {
|
||||
} mInput;
|
||||
|
||||
struct Reply final {
|
||||
EventMessage const mEventMessage;
|
||||
void* mContentsRoot;
|
||||
uint32_t mOffset;
|
||||
Maybe<OffsetAndData<uint32_t>> mOffsetAndData;
|
||||
// mTentativeCaretOffset is used by only eQueryCharacterAtPoint.
|
||||
// This is the offset where caret would be if user clicked at the mRefPoint.
|
||||
uint32_t mTentativeCaretOffset;
|
||||
nsString mString;
|
||||
Maybe<uint32_t> mTentativeCaretOffset;
|
||||
// mRect is used by eQueryTextRect, eQueryCaretRect, eQueryCharacterAtPoint
|
||||
// and eQueryEditorRect. The coordinates is system coordinates relative to
|
||||
// the top level widget of mFocusedWidget. E.g., if a <xul:panel> which
|
||||
@ -1132,17 +1161,136 @@ class WidgetQueryContentEvent : public WidgetGUIEvent {
|
||||
// true if DOM element under mouse belongs to widget
|
||||
bool mWidgetIsHit;
|
||||
|
||||
Reply()
|
||||
: mContentsRoot(nullptr),
|
||||
mOffset(NOT_FOUND),
|
||||
mTentativeCaretOffset(NOT_FOUND),
|
||||
Reply() = delete;
|
||||
explicit Reply(EventMessage aEventMessage)
|
||||
: mEventMessage(aEventMessage),
|
||||
mContentsRoot(nullptr),
|
||||
mFocusedWidget(nullptr),
|
||||
mReversed(false),
|
||||
mHasSelection(false),
|
||||
mWidgetIsHit(false) {}
|
||||
} mReply;
|
||||
|
||||
enum { NOT_FOUND = UINT32_MAX };
|
||||
// Don't allow to copy/move because of `mEventMessage`.
|
||||
Reply(const Reply& aOther) = delete;
|
||||
Reply(Reply&& aOther) = delete;
|
||||
Reply& operator=(const Reply& aOther) = delete;
|
||||
Reply& operator=(Reply&& aOther) = delete;
|
||||
|
||||
MOZ_NEVER_INLINE_DEBUG uint32_t StartOffset() const {
|
||||
MOZ_ASSERT(mOffsetAndData.isSome());
|
||||
return mOffsetAndData->StartOffset();
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG uint32_t EndOffset() const {
|
||||
MOZ_ASSERT(mOffsetAndData.isSome());
|
||||
return mOffsetAndData->EndOffset();
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG uint32_t DataLength() const {
|
||||
MOZ_ASSERT(mOffsetAndData.isSome() ||
|
||||
mEventMessage == eQuerySelectedText);
|
||||
return mOffsetAndData.isSome() ? mOffsetAndData->Length() : 0;
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG uint32_t SelectionStartOffset() const {
|
||||
MOZ_ASSERT(mEventMessage == eQuerySelectedText);
|
||||
MOZ_ASSERT(mOffsetAndData.isSome());
|
||||
return StartOffset() + (mReversed ? DataLength() : 0);
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE_DEBUG uint32_t SelectionEndOffset() const {
|
||||
MOZ_ASSERT(mEventMessage == eQuerySelectedText);
|
||||
MOZ_ASSERT(mOffsetAndData.isSome());
|
||||
return StartOffset() + (mReversed ? 0 : DataLength());
|
||||
}
|
||||
|
||||
const WritingMode& WritingModeRef() const {
|
||||
MOZ_ASSERT(mEventMessage == eQuerySelectedText ||
|
||||
mEventMessage == eQueryCaretRect ||
|
||||
mEventMessage == eQueryTextRect);
|
||||
MOZ_ASSERT(mOffsetAndData.isSome() ||
|
||||
mEventMessage == eQuerySelectedText);
|
||||
return mWritingMode;
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE_DEBUG const nsString& DataRef() const {
|
||||
MOZ_ASSERT(mOffsetAndData.isSome() ||
|
||||
mEventMessage == eQuerySelectedText);
|
||||
return mOffsetAndData.isSome() ? mOffsetAndData->DataRef()
|
||||
: EmptyString();
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG bool IsDataEmpty() const {
|
||||
MOZ_ASSERT(mOffsetAndData.isSome() ||
|
||||
mEventMessage == eQuerySelectedText);
|
||||
return mOffsetAndData.isSome() ? mOffsetAndData->IsDataEmpty() : true;
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG bool IsOffsetInRange(uint32_t aOffset) const {
|
||||
MOZ_ASSERT(mOffsetAndData.isSome() ||
|
||||
mEventMessage == eQuerySelectedText);
|
||||
return mOffsetAndData.isSome() ? mOffsetAndData->IsOffsetInRange(aOffset)
|
||||
: false;
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG bool IsOffsetInRangeOrEndOffset(
|
||||
uint32_t aOffset) const {
|
||||
MOZ_ASSERT(mOffsetAndData.isSome() ||
|
||||
mEventMessage == eQuerySelectedText);
|
||||
return mOffsetAndData.isSome()
|
||||
? mOffsetAndData->IsOffsetInRangeOrEndOffset(aOffset)
|
||||
: false;
|
||||
}
|
||||
MOZ_NEVER_INLINE_DEBUG void TruncateData(uint32_t aLength = 0) {
|
||||
MOZ_ASSERT(mOffsetAndData.isSome());
|
||||
mOffsetAndData->TruncateData(aLength);
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& aStream,
|
||||
const Reply& aReply) {
|
||||
aStream << "{ ";
|
||||
if (aReply.mEventMessage == eQuerySelectedText ||
|
||||
aReply.mEventMessage == eQueryTextContent ||
|
||||
aReply.mEventMessage == eQueryTextRect ||
|
||||
aReply.mEventMessage == eQueryCaretRect ||
|
||||
aReply.mEventMessage == eQueryCharacterAtPoint) {
|
||||
aStream << "mOffsetAndData=" << ToString(aReply.mOffsetAndData).c_str()
|
||||
<< ", ";
|
||||
if (aReply.mEventMessage == eQueryCharacterAtPoint) {
|
||||
aStream << "mTentativeCaretOffset="
|
||||
<< ToString(aReply.mTentativeCaretOffset).c_str() << ", ";
|
||||
}
|
||||
}
|
||||
aStream << "mHasSelection=" << (aReply.mHasSelection ? "true" : "false");
|
||||
if (aReply.mHasSelection) {
|
||||
if (aReply.mEventMessage == eQuerySelectedText) {
|
||||
aStream << ", mReversed=" << (aReply.mReversed ? "true" : "false");
|
||||
}
|
||||
if (aReply.mEventMessage == eQuerySelectionAsTransferable) {
|
||||
aStream << ", mTransferable=0x" << aReply.mTransferable;
|
||||
}
|
||||
}
|
||||
if (aReply.mEventMessage == eQuerySelectedText ||
|
||||
aReply.mEventMessage == eQueryTextRect ||
|
||||
aReply.mEventMessage == eQueryCaretRect) {
|
||||
aStream << ", mWritingMode=" << ToString(aReply.mWritingMode).c_str();
|
||||
}
|
||||
aStream << ", mContentsRoot=0x" << aReply.mContentsRoot
|
||||
<< ", mFocusedWidget=0x" << aReply.mFocusedWidget;
|
||||
if (aReply.mEventMessage == eQueryTextContent) {
|
||||
aStream << ", mFontRanges={ Length()=" << aReply.mFontRanges.Length()
|
||||
<< " }";
|
||||
} else if (aReply.mEventMessage == eQueryTextRect ||
|
||||
aReply.mEventMessage == eQueryCaretRect ||
|
||||
aReply.mEventMessage == eQueryCharacterAtPoint) {
|
||||
aStream << ", mRect=" << ToString(aReply.mRect).c_str();
|
||||
} else if (aReply.mEventMessage == eQueryTextRectArray) {
|
||||
aStream << ", mRectArray={ Length()=" << aReply.mRectArray.Length()
|
||||
<< " }";
|
||||
} else if (aReply.mEventMessage == eQueryDOMWidgetHittest) {
|
||||
aStream << ", mWidgetIsHit="
|
||||
<< (aReply.mWidgetIsHit ? "true" : "false");
|
||||
}
|
||||
return aStream << " }";
|
||||
}
|
||||
};
|
||||
|
||||
void EmplaceReply() { mReply.emplace(mMessage); }
|
||||
Maybe<Reply> mReply;
|
||||
|
||||
// values of mComputedScrollAction
|
||||
enum { SCROLL_ACTION_NONE, SCROLL_ACTION_LINE, SCROLL_ACTION_PAGE };
|
||||
|
@ -695,35 +695,42 @@ void GeckoEditableSupport::FlushIMEChanges(FlushChangesFlag aFlags) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent event(true, eQueryTextContent, widget);
|
||||
nsString insertedString;
|
||||
WidgetQueryContentEvent queryTextContentEvent(true, eQueryTextContent,
|
||||
widget);
|
||||
|
||||
if (change.mNewEnd != change.mStart) {
|
||||
event.InitForQueryTextContent(change.mStart,
|
||||
change.mNewEnd - change.mStart);
|
||||
widget->DispatchEvent(&event, status);
|
||||
queryTextContentEvent.InitForQueryTextContent(
|
||||
change.mStart, change.mNewEnd - change.mStart);
|
||||
widget->DispatchEvent(&queryTextContentEvent, status);
|
||||
|
||||
if (shouldAbort(NS_WARN_IF(!event.mSucceeded))) {
|
||||
if (shouldAbort(NS_WARN_IF(queryTextContentEvent.Failed()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
insertedString = queryTextContentEvent.mReply->DataRef();
|
||||
}
|
||||
|
||||
textTransaction.AppendElement(TextRecord{
|
||||
event.mReply.mString, change.mStart, change.mOldEnd, change.mNewEnd});
|
||||
textTransaction.AppendElement(TextRecord{insertedString, change.mStart,
|
||||
change.mOldEnd, change.mNewEnd});
|
||||
}
|
||||
|
||||
int32_t selStart = -1;
|
||||
int32_t selEnd = -1;
|
||||
|
||||
if (mIMESelectionChanged) {
|
||||
WidgetQueryContentEvent event(true, eQuerySelectedText, widget);
|
||||
widget->DispatchEvent(&event, status);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
widget);
|
||||
widget->DispatchEvent(&querySelectedTextEvent, status);
|
||||
|
||||
if (shouldAbort(NS_WARN_IF(!event.mSucceeded))) {
|
||||
if (shouldAbort(NS_WARN_IF(querySelectedTextEvent.DidNotFindSelection()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
selStart = int32_t(event.GetSelectionStart());
|
||||
selEnd = int32_t(event.GetSelectionEnd());
|
||||
selStart = static_cast<int32_t>(
|
||||
querySelectedTextEvent.mReply->SelectionStartOffset());
|
||||
selEnd = static_cast<int32_t>(
|
||||
querySelectedTextEvent.mReply->SelectionEndOffset());
|
||||
|
||||
if (aFlags == FLUSH_FLAG_RECOVER) {
|
||||
// Sometimes we get out-of-bounds selection during recovery.
|
||||
@ -816,12 +823,17 @@ void GeckoEditableSupport::UpdateCompositionRects() {
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
uint32_t offset = composition->NativeOffsetOfStartComposition();
|
||||
WidgetQueryContentEvent textRects(true, eQueryTextRectArray, widget);
|
||||
textRects.InitForQueryTextRectArray(offset, composition->String().Length());
|
||||
widget->DispatchEvent(&textRects, status);
|
||||
WidgetQueryContentEvent queryTextRectsEvent(true, eQueryTextRectArray,
|
||||
widget);
|
||||
queryTextRectsEvent.InitForQueryTextRectArray(offset,
|
||||
composition->String().Length());
|
||||
widget->DispatchEvent(&queryTextRectsEvent, status);
|
||||
|
||||
auto rects = ConvertRectArrayToJavaRectFArray(textRects.mReply.mRectArray,
|
||||
widget->GetDefaultScale());
|
||||
auto rects = ConvertRectArrayToJavaRectFArray(
|
||||
queryTextRectsEvent.Succeeded()
|
||||
? queryTextRectsEvent.mReply->mRectArray
|
||||
: CopyableTArray<mozilla::LayoutDeviceIntRect>(),
|
||||
widget->GetDefaultScale());
|
||||
|
||||
mEditable->UpdateCompositionRects(rects);
|
||||
}
|
||||
@ -894,11 +906,13 @@ bool GeckoEditableSupport::DoReplaceText(int32_t aStart, int32_t aEnd,
|
||||
#ifdef NIGHTLY_BUILD
|
||||
{
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
WidgetQueryContentEvent selection(true, eQuerySelectedText, widget);
|
||||
widget->DispatchEvent(&selection, status);
|
||||
if (selection.mSucceeded) {
|
||||
ALOGIME("IME: Current selection: { Offset=%u, Length=%u }",
|
||||
selection.mReply.mOffset, selection.mReply.mString.Length());
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
widget);
|
||||
widget->DispatchEvent(&querySelectedTextEvent, status);
|
||||
if (querySelectedTextEvent.Succeeded()) {
|
||||
ALOGIME(
|
||||
"IME: Current selection: %s",
|
||||
ToString(querySelectedTextEvent.mReply->mOffsetAndData).c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1112,10 +1126,13 @@ bool GeckoEditableSupport::DoUpdateComposition(int32_t aStart, int32_t aEnd,
|
||||
}
|
||||
|
||||
{
|
||||
WidgetQueryContentEvent event(true, eQuerySelectedText, widget);
|
||||
widget->DispatchEvent(&event, status);
|
||||
MOZ_ASSERT(event.mSucceeded);
|
||||
string = event.mReply.mString;
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
widget);
|
||||
widget->DispatchEvent(&querySelectedTextEvent, status);
|
||||
MOZ_ASSERT(querySelectedTextEvent.Succeeded());
|
||||
if (querySelectedTextEvent.FoundSelection()) {
|
||||
string = querySelectedTextEvent.mReply->DataRef();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the new composition matches the existing composition,
|
||||
@ -1158,17 +1175,18 @@ class MOZ_STACK_CLASS AutoSelectionRestore final {
|
||||
mLength = UINT32_MAX;
|
||||
return;
|
||||
}
|
||||
WidgetQueryContentEvent selection(true, eQuerySelectedText, widget);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
widget);
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
widget->DispatchEvent(&selection, status);
|
||||
if (!selection.mSucceeded) {
|
||||
widget->DispatchEvent(&querySelectedTextEvent, status);
|
||||
if (querySelectedTextEvent.DidNotFindSelection()) {
|
||||
mOffset = UINT32_MAX;
|
||||
mLength = UINT32_MAX;
|
||||
return;
|
||||
}
|
||||
|
||||
mOffset = selection.mReply.mOffset;
|
||||
mLength = selection.mReply.mString.Length();
|
||||
mOffset = querySelectedTextEvent.mReply->StartOffset();
|
||||
mLength = querySelectedTextEvent.mReply->DataLength();
|
||||
}
|
||||
|
||||
~AutoSelectionRestore() {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/ToString.h"
|
||||
|
||||
#include "nsChildView.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
@ -405,6 +406,13 @@ static void EnsureToLogAllKeyboardLayoutsAndIMEs() {
|
||||
}
|
||||
}
|
||||
|
||||
inline NSRange MakeNSRangeFrom(const Maybe<OffsetAndData<uint32_t>>& aOffsetAndData) {
|
||||
if (aOffsetAndData.isNothing()) {
|
||||
return NSMakeRange(NSNotFound, 0);
|
||||
}
|
||||
return NSMakeRange(aOffsetAndData->StartOffset(), aOffsetAndData->Length());
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
/******************************************************************************
|
||||
@ -4036,7 +4044,7 @@ NSAttributedString* IMEInputHandler::GetAttributedSubstringFromRange(NSRange& aR
|
||||
}
|
||||
|
||||
nsAutoString str;
|
||||
WidgetQueryContentEvent textContent(true, eQueryTextContent, mWidget);
|
||||
WidgetQueryContentEvent queryTextContentEvent(true, eQueryTextContent, mWidget);
|
||||
WidgetQueryContentEvent::Options options;
|
||||
int64_t startOffset = aRange.location;
|
||||
if (IsIMEComposing()) {
|
||||
@ -4048,28 +4056,26 @@ NSAttributedString* IMEInputHandler::GetAttributedSubstringFromRange(NSRange& aR
|
||||
options.mRelativeToInsertionPoint = true;
|
||||
startOffset -= mIMECompositionStart;
|
||||
}
|
||||
textContent.InitForQueryTextContent(startOffset, aRange.length, options);
|
||||
textContent.RequestFontRanges();
|
||||
DispatchEvent(textContent);
|
||||
queryTextContentEvent.InitForQueryTextContent(startOffset, aRange.length, options);
|
||||
queryTextContentEvent.RequestFontRanges();
|
||||
DispatchEvent(queryTextContentEvent);
|
||||
|
||||
MOZ_LOG(gLog, LogLevel::Info,
|
||||
("%p IMEInputHandler::GetAttributedSubstringFromRange, "
|
||||
"textContent={ mSucceeded=%s, mReply={ mString=\"%s\", mOffset=%u } }",
|
||||
this, TrueOrFalse(textContent.mSucceeded),
|
||||
NS_ConvertUTF16toUTF8(textContent.mReply.mString).get(), textContent.mReply.mOffset));
|
||||
"queryTextContentEvent={ mReply=%s }",
|
||||
this, ToString(queryTextContentEvent.mReply).c_str()));
|
||||
|
||||
if (!textContent.mSucceeded) {
|
||||
if (queryTextContentEvent.Failed()) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// We don't set vertical information at this point. If required,
|
||||
// OS will calls drawsVerticallyForCharacterAtIndex.
|
||||
NSMutableAttributedString* result = nsCocoaUtils::GetNSMutableAttributedString(
|
||||
textContent.mReply.mString, textContent.mReply.mFontRanges, false,
|
||||
queryTextContentEvent.mReply->DataRef(), queryTextContentEvent.mReply->mFontRanges, false,
|
||||
mWidget->BackingScaleFactor());
|
||||
if (aActualRange) {
|
||||
aActualRange->location = textContent.mReply.mOffset;
|
||||
aActualRange->length = textContent.mReply.mString.Length();
|
||||
*aActualRange = MakeNSRangeFrom(queryTextContentEvent.mReply->mOffsetAndData);
|
||||
}
|
||||
return result;
|
||||
|
||||
@ -4119,21 +4125,19 @@ NSRange IMEInputHandler::SelectedRange() {
|
||||
|
||||
RefPtr<IMEInputHandler> kungFuDeathGrip(this);
|
||||
|
||||
WidgetQueryContentEvent selection(true, eQuerySelectedText, mWidget);
|
||||
DispatchEvent(selection);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText, mWidget);
|
||||
DispatchEvent(querySelectedTextEvent);
|
||||
|
||||
MOZ_LOG(gLog, LogLevel::Info,
|
||||
("%p IMEInputHandler::SelectedRange, selection={ mSucceeded=%s, "
|
||||
"mReply={ mOffset=%u, mString.Length()=%u } }",
|
||||
this, TrueOrFalse(selection.mSucceeded), selection.mReply.mOffset,
|
||||
selection.mReply.mString.Length()));
|
||||
("%p IMEInputHandler::SelectedRange, querySelectedTextEvent={ mReply=%s }", this,
|
||||
ToString(querySelectedTextEvent.mReply).c_str()));
|
||||
|
||||
if (!selection.mSucceeded) {
|
||||
if (querySelectedTextEvent.Failed()) {
|
||||
return mSelectedRange;
|
||||
}
|
||||
|
||||
mWritingMode = selection.GetWritingMode();
|
||||
mRangeForWritingMode = NSMakeRange(selection.mReply.mOffset, selection.mReply.mString.Length());
|
||||
mWritingMode = querySelectedTextEvent.mReply->WritingModeRef();
|
||||
mRangeForWritingMode = MakeNSRangeFrom(querySelectedTextEvent.mReply->mOffsetAndData);
|
||||
|
||||
if (mIMEHasFocus) {
|
||||
mSelectedRange = mRangeForWritingMode;
|
||||
@ -4202,7 +4206,7 @@ NSRect IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange, NSRange* aAc
|
||||
LayoutDeviceIntRect r;
|
||||
bool useCaretRect = (aRange.length == 0);
|
||||
if (!useCaretRect) {
|
||||
WidgetQueryContentEvent charRect(true, eQueryTextRect, mWidget);
|
||||
WidgetQueryContentEvent queryTextRectEvent(true, eQueryTextRect, mWidget);
|
||||
WidgetQueryContentEvent::Options options;
|
||||
int64_t startOffset = aRange.location;
|
||||
if (IsIMEComposing()) {
|
||||
@ -4214,13 +4218,12 @@ NSRect IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange, NSRange* aAc
|
||||
options.mRelativeToInsertionPoint = true;
|
||||
startOffset -= mIMECompositionStart;
|
||||
}
|
||||
charRect.InitForQueryTextRect(startOffset, 1, options);
|
||||
DispatchEvent(charRect);
|
||||
if (charRect.mSucceeded) {
|
||||
r = charRect.mReply.mRect;
|
||||
actualRange.location = charRect.mReply.mOffset;
|
||||
actualRange.length = charRect.mReply.mString.Length();
|
||||
mWritingMode = charRect.GetWritingMode();
|
||||
queryTextRectEvent.InitForQueryTextRect(startOffset, 1, options);
|
||||
DispatchEvent(queryTextRectEvent);
|
||||
if (queryTextRectEvent.Succeeded()) {
|
||||
r = queryTextRectEvent.mReply->mRect;
|
||||
actualRange = MakeNSRangeFrom(queryTextRectEvent.mReply->mOffsetAndData);
|
||||
mWritingMode = queryTextRectEvent.mReply->WritingModeRef();
|
||||
mRangeForWritingMode = actualRange;
|
||||
} else {
|
||||
useCaretRect = true;
|
||||
@ -4228,7 +4231,7 @@ NSRect IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange, NSRange* aAc
|
||||
}
|
||||
|
||||
if (useCaretRect) {
|
||||
WidgetQueryContentEvent caretRect(true, eQueryCaretRect, mWidget);
|
||||
WidgetQueryContentEvent queryCaretRectEvent(true, eQueryCaretRect, mWidget);
|
||||
WidgetQueryContentEvent::Options options;
|
||||
int64_t startOffset = aRange.location;
|
||||
if (IsIMEComposing()) {
|
||||
@ -4240,14 +4243,14 @@ NSRect IMEInputHandler::FirstRectForCharacterRange(NSRange& aRange, NSRange* aAc
|
||||
options.mRelativeToInsertionPoint = true;
|
||||
startOffset -= mIMECompositionStart;
|
||||
}
|
||||
caretRect.InitForQueryCaretRect(startOffset, options);
|
||||
DispatchEvent(caretRect);
|
||||
if (!caretRect.mSucceeded) {
|
||||
queryCaretRectEvent.InitForQueryCaretRect(startOffset, options);
|
||||
DispatchEvent(queryCaretRectEvent);
|
||||
if (queryCaretRectEvent.Failed()) {
|
||||
return rect;
|
||||
}
|
||||
r = caretRect.mReply.mRect;
|
||||
r = queryCaretRectEvent.mReply->mRect;
|
||||
r.width = 0;
|
||||
actualRange.location = caretRect.mReply.mOffset;
|
||||
actualRange.location = queryCaretRectEvent.mReply->StartOffset();
|
||||
actualRange.length = 0;
|
||||
}
|
||||
|
||||
@ -4290,18 +4293,20 @@ NSUInteger IMEInputHandler::CharacterIndexForPoint(NSPoint& aPoint) {
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent charAt(true, eQueryCharacterAtPoint, mWidget);
|
||||
WidgetQueryContentEvent queryCharAtPointEvent(true, eQueryCharacterAtPoint, mWidget);
|
||||
NSPoint ptInWindow = nsCocoaUtils::ConvertPointFromScreen(mainWindow, aPoint);
|
||||
NSPoint ptInView = [mView convertPoint:ptInWindow fromView:nil];
|
||||
charAt.mRefPoint.x = static_cast<int32_t>(ptInView.x) * mWidget->BackingScaleFactor();
|
||||
charAt.mRefPoint.y = static_cast<int32_t>(ptInView.y) * mWidget->BackingScaleFactor();
|
||||
mWidget->DispatchWindowEvent(charAt);
|
||||
if (!charAt.mSucceeded || charAt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND ||
|
||||
charAt.mReply.mOffset >= static_cast<uint32_t>(NSNotFound)) {
|
||||
queryCharAtPointEvent.mRefPoint.x =
|
||||
static_cast<int32_t>(ptInView.x) * mWidget->BackingScaleFactor();
|
||||
queryCharAtPointEvent.mRefPoint.y =
|
||||
static_cast<int32_t>(ptInView.y) * mWidget->BackingScaleFactor();
|
||||
mWidget->DispatchWindowEvent(queryCharAtPointEvent);
|
||||
if (queryCharAtPointEvent.Failed() || queryCharAtPointEvent.DidNotFindChar() ||
|
||||
queryCharAtPointEvent.mReply->StartOffset() >= static_cast<uint32_t>(NSNotFound)) {
|
||||
return NSNotFound;
|
||||
}
|
||||
|
||||
return charAt.mReply.mOffset;
|
||||
return queryCharAtPointEvent.mReply->StartOffset();
|
||||
|
||||
NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSNotFound);
|
||||
}
|
||||
|
@ -1616,16 +1616,17 @@ bool nsChildView::GetEditCommands(NativeKeyBindingsType aType, const WidgetKeybo
|
||||
// the physical direction of the arrow.
|
||||
if (aEvent.mKeyCode >= NS_VK_LEFT && aEvent.mKeyCode <= NS_VK_DOWN) {
|
||||
// XXX This may be expensive. Should use the cache in TextInputHandler.
|
||||
WidgetQueryContentEvent query(true, eQuerySelectedText, this);
|
||||
DispatchWindowEvent(query);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText, this);
|
||||
DispatchWindowEvent(querySelectedTextEvent);
|
||||
|
||||
if (query.mSucceeded && query.mReply.mWritingMode.IsVertical()) {
|
||||
if (querySelectedTextEvent.FoundSelection() &&
|
||||
querySelectedTextEvent.mReply->mWritingMode.IsVertical()) {
|
||||
uint32_t geckoKey = 0;
|
||||
uint32_t cocoaKey = 0;
|
||||
|
||||
switch (aEvent.mKeyCode) {
|
||||
case NS_VK_LEFT:
|
||||
if (query.mReply.mWritingMode.IsVerticalLR()) {
|
||||
if (querySelectedTextEvent.mReply->mWritingMode.IsVerticalLR()) {
|
||||
geckoKey = NS_VK_UP;
|
||||
cocoaKey = kVK_UpArrow;
|
||||
} else {
|
||||
@ -1635,7 +1636,7 @@ bool nsChildView::GetEditCommands(NativeKeyBindingsType aType, const WidgetKeybo
|
||||
break;
|
||||
|
||||
case NS_VK_RIGHT:
|
||||
if (query.mReply.mWritingMode.IsVerticalLR()) {
|
||||
if (querySelectedTextEvent.mReply->mWritingMode.IsVerticalLR()) {
|
||||
geckoKey = NS_VK_DOWN;
|
||||
cocoaKey = kVK_DownArrow;
|
||||
} else {
|
||||
@ -1677,9 +1678,9 @@ NSView<mozView>* nsChildView::GetEditorView() {
|
||||
// need any layout information right now.
|
||||
queryContentState.mNeedsToFlushLayout = false;
|
||||
DispatchWindowEvent(queryContentState);
|
||||
if (queryContentState.mSucceeded && queryContentState.mReply.mFocusedWidget) {
|
||||
if (queryContentState.Succeeded() && queryContentState.mReply->mFocusedWidget) {
|
||||
NSView<mozView>* view = static_cast<NSView<mozView>*>(
|
||||
queryContentState.mReply.mFocusedWidget->GetNativeData(NS_NATIVE_WIDGET));
|
||||
queryContentState.mReply->mFocusedWidget->GetNativeData(NS_NATIVE_WIDGET));
|
||||
if (view) editorView = view;
|
||||
}
|
||||
return editorView;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/ToString.h"
|
||||
#include "WritingModes.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -2784,25 +2785,27 @@ void IMContextWrapper::SetCursorPosition(GtkIMContext* aContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent charRect(
|
||||
WidgetQueryContentEvent queryCaretOrTextRectEvent(
|
||||
true, useCaret ? eQueryCaretRect : eQueryTextRect, mLastFocusedWindow);
|
||||
if (useCaret) {
|
||||
charRect.InitForQueryCaretRect(mSelection.mOffset);
|
||||
queryCaretOrTextRectEvent.InitForQueryCaretRect(mSelection.mOffset);
|
||||
} else {
|
||||
if (mSelection.mWritingMode.IsVertical()) {
|
||||
// For preventing the candidate window to overlap the target
|
||||
// clause, we should set fake (typically, very tall) caret rect.
|
||||
uint32_t length =
|
||||
mCompositionTargetRange.mLength ? mCompositionTargetRange.mLength : 1;
|
||||
charRect.InitForQueryTextRect(mCompositionTargetRange.mOffset, length);
|
||||
queryCaretOrTextRectEvent.InitForQueryTextRect(
|
||||
mCompositionTargetRange.mOffset, length);
|
||||
} else {
|
||||
charRect.InitForQueryTextRect(mCompositionTargetRange.mOffset, 1);
|
||||
queryCaretOrTextRectEvent.InitForQueryTextRect(
|
||||
mCompositionTargetRange.mOffset, 1);
|
||||
}
|
||||
}
|
||||
InitEvent(charRect);
|
||||
InitEvent(queryCaretOrTextRectEvent);
|
||||
nsEventStatus status;
|
||||
mLastFocusedWindow->DispatchEvent(&charRect, status);
|
||||
if (!charRect.mSucceeded) {
|
||||
mLastFocusedWindow->DispatchEvent(&queryCaretOrTextRectEvent, status);
|
||||
if (queryCaretOrTextRectEvent.Failed()) {
|
||||
MOZ_LOG(gGtkIMLog, LogLevel::Error,
|
||||
("0x%p SetCursorPosition(), FAILED, %s was failed", this,
|
||||
useCaret ? "eQueryCaretRect" : "eQueryTextRect"));
|
||||
@ -2819,7 +2822,8 @@ void IMContextWrapper::SetCursorPosition(GtkIMContext* aContext) {
|
||||
LayoutDeviceIntPoint owner = mOwnerWindow->WidgetToScreenOffset();
|
||||
|
||||
// Compute the caret position in the IM owner window.
|
||||
LayoutDeviceIntRect rect = charRect.mReply.mRect + root - owner;
|
||||
LayoutDeviceIntRect rect =
|
||||
queryCaretOrTextRectEvent.mReply->mRect + root - owner;
|
||||
rect.width = 0;
|
||||
GdkRectangle area = rootWindow->DevicePixelsToGdkRectRoundOut(rect);
|
||||
|
||||
@ -2882,20 +2886,22 @@ nsresult IMContextWrapper::GetCurrentParagraph(nsAString& aText,
|
||||
mLastFocusedWindow);
|
||||
queryTextContentEvent.InitForQueryTextContent(0, UINT32_MAX);
|
||||
mLastFocusedWindow->DispatchEvent(&queryTextContentEvent, status);
|
||||
NS_ENSURE_TRUE(queryTextContentEvent.mSucceeded, NS_ERROR_FAILURE);
|
||||
if (NS_WARN_IF(queryTextContentEvent.Failed())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoString textContent(queryTextContentEvent.mReply.mString);
|
||||
if (selOffset + selLength > textContent.Length()) {
|
||||
if (selOffset + selLength > queryTextContentEvent.mReply->DataLength()) {
|
||||
MOZ_LOG(gGtkIMLog, LogLevel::Error,
|
||||
("0x%p GetCurrentParagraph(), FAILED, The selection is "
|
||||
"invalid, textContent.Length()=%u",
|
||||
this, textContent.Length()));
|
||||
"invalid, queryTextContentEvent={ mReply=%s }",
|
||||
this, ToString(queryTextContentEvent.mReply).c_str()));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Remove composing string and restore the selected string because
|
||||
// GtkEntry doesn't remove selected string until committing, however,
|
||||
// our editor does it. We should emulate the behavior for IME.
|
||||
nsAutoString textContent(queryTextContentEvent.mReply->DataRef());
|
||||
if (EditorHasCompositionString() &&
|
||||
mDispatchedCompositionString != mSelectedStringRemovedByComposition) {
|
||||
textContent.Replace(mCompositionStart,
|
||||
@ -2976,15 +2982,17 @@ nsresult IMContextWrapper::DeleteText(GtkIMContext* aContext, int32_t aOffset,
|
||||
mLastFocusedWindow);
|
||||
queryTextContentEvent.InitForQueryTextContent(0, UINT32_MAX);
|
||||
mLastFocusedWindow->DispatchEvent(&queryTextContentEvent, status);
|
||||
NS_ENSURE_TRUE(queryTextContentEvent.mSucceeded, NS_ERROR_FAILURE);
|
||||
if (queryTextContentEvent.mReply.mString.IsEmpty()) {
|
||||
if (NS_WARN_IF(queryTextContentEvent.Failed())) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (queryTextContentEvent.mReply->IsDataEmpty()) {
|
||||
MOZ_LOG(gGtkIMLog, LogLevel::Error,
|
||||
("0x%p DeleteText(), FAILED, there is no contents", this));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ConvertUTF16toUTF8 utf8Str(
|
||||
nsDependentSubstring(queryTextContentEvent.mReply.mString, 0, selOffset));
|
||||
NS_ConvertUTF16toUTF8 utf8Str(nsDependentSubstring(
|
||||
queryTextContentEvent.mReply->DataRef(), 0, selOffset));
|
||||
glong offsetInUTF8Characters =
|
||||
g_utf8_strlen(utf8Str.get(), utf8Str.Length()) + aOffset;
|
||||
if (offsetInUTF8Characters < 0) {
|
||||
@ -2996,7 +3004,7 @@ nsresult IMContextWrapper::DeleteText(GtkIMContext* aContext, int32_t aOffset,
|
||||
}
|
||||
|
||||
AppendUTF16toUTF8(
|
||||
nsDependentSubstring(queryTextContentEvent.mReply.mString, selOffset),
|
||||
nsDependentSubstring(queryTextContentEvent.mReply->DataRef(), selOffset),
|
||||
utf8Str);
|
||||
glong countOfCharactersInUTF8 =
|
||||
g_utf8_strlen(utf8Str.get(), utf8Str.Length());
|
||||
@ -3116,11 +3124,11 @@ bool IMContextWrapper::EnsureToCacheSelection(nsAString* aSelectedString) {
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
WidgetQueryContentEvent selection(true, eQuerySelectedText,
|
||||
mLastFocusedWindow);
|
||||
InitEvent(selection);
|
||||
mLastFocusedWindow->DispatchEvent(&selection, status);
|
||||
if (NS_WARN_IF(!selection.mSucceeded)) {
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
mLastFocusedWindow);
|
||||
InitEvent(querySelectedTextEvent);
|
||||
mLastFocusedWindow->DispatchEvent(&querySelectedTextEvent, status);
|
||||
if (NS_WARN_IF(querySelectedTextEvent.Failed())) {
|
||||
MOZ_LOG(gGtkIMLog, LogLevel::Error,
|
||||
("0x%p EnsureToCacheSelection(), FAILED, due to "
|
||||
"failure of query selection event",
|
||||
@ -3128,7 +3136,7 @@ bool IMContextWrapper::EnsureToCacheSelection(nsAString* aSelectedString) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mSelection.Assign(selection);
|
||||
mSelection.Assign(querySelectedTextEvent);
|
||||
if (!mSelection.IsValid()) {
|
||||
MOZ_LOG(gGtkIMLog, LogLevel::Error,
|
||||
("0x%p EnsureToCacheSelection(), FAILED, due to "
|
||||
@ -3138,7 +3146,7 @@ bool IMContextWrapper::EnsureToCacheSelection(nsAString* aSelectedString) {
|
||||
}
|
||||
|
||||
if (!mSelection.Collapsed() && aSelectedString) {
|
||||
aSelectedString->Assign(selection.mReply.mString);
|
||||
aSelectedString->Assign(querySelectedTextEvent.mReply->DataRef());
|
||||
}
|
||||
|
||||
MOZ_LOG(gGtkIMLog, LogLevel::Debug,
|
||||
@ -3164,10 +3172,11 @@ void IMContextWrapper::Selection::Assign(
|
||||
void IMContextWrapper::Selection::Assign(
|
||||
const WidgetQueryContentEvent& aEvent) {
|
||||
MOZ_ASSERT(aEvent.mMessage == eQuerySelectedText);
|
||||
MOZ_ASSERT(aEvent.mSucceeded);
|
||||
mString = aEvent.mReply.mString;
|
||||
mOffset = aEvent.mReply.mOffset;
|
||||
mWritingMode = aEvent.GetWritingMode();
|
||||
MOZ_ASSERT(aEvent.Succeeded());
|
||||
MOZ_ASSERT(aEvent.mReply->mOffsetAndData.isSome());
|
||||
mString = aEvent.mReply->DataRef();
|
||||
mOffset = aEvent.mReply->StartOffset();
|
||||
mWritingMode = aEvent.mReply->WritingModeRef();
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
|
@ -7200,16 +7200,18 @@ bool nsWindow::GetEditCommands(NativeKeyBindingsType aType,
|
||||
// Check if we're targeting content with vertical writing mode,
|
||||
// and if so remap the arrow keys.
|
||||
// XXX This may be expensive.
|
||||
WidgetQueryContentEvent query(true, eQuerySelectedText, this);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
this);
|
||||
nsEventStatus status;
|
||||
DispatchEvent(&query, status);
|
||||
DispatchEvent(&querySelectedTextEvent, status);
|
||||
|
||||
if (query.mSucceeded && query.mReply.mWritingMode.IsVertical()) {
|
||||
if (querySelectedTextEvent.FoundSelection() &&
|
||||
querySelectedTextEvent.mReply->mWritingMode.IsVertical()) {
|
||||
uint32_t geckoCode = 0;
|
||||
uint32_t gdkCode = 0;
|
||||
switch (aEvent.mKeyCode) {
|
||||
case NS_VK_LEFT:
|
||||
if (query.mReply.mWritingMode.IsVerticalLR()) {
|
||||
if (querySelectedTextEvent.mReply->mWritingMode.IsVerticalLR()) {
|
||||
geckoCode = NS_VK_UP;
|
||||
gdkCode = GDK_Up;
|
||||
} else {
|
||||
@ -7219,7 +7221,7 @@ bool nsWindow::GetEditCommands(NativeKeyBindingsType aType,
|
||||
break;
|
||||
|
||||
case NS_VK_RIGHT:
|
||||
if (query.mReply.mWritingMode.IsVerticalLR()) {
|
||||
if (querySelectedTextEvent.mReply->mWritingMode.IsVerticalLR()) {
|
||||
geckoCode = NS_VK_DOWN;
|
||||
gdkCode = GDK_Down;
|
||||
} else {
|
||||
|
@ -627,67 +627,6 @@ struct ParamTraits<mozilla::FontRange> {
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::WidgetQueryContentEvent::Input> {
|
||||
typedef mozilla::WidgetQueryContentEvent::Input paramType;
|
||||
typedef mozilla::WidgetQueryContentEvent event;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam) {
|
||||
WriteParam(aMsg, aParam.mOffset);
|
||||
WriteParam(aMsg, aParam.mLength);
|
||||
WriteParam(aMsg, mozilla::ToRawSelectionType(aParam.mSelectionType));
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter,
|
||||
paramType* aResult) {
|
||||
mozilla::RawSelectionType rawSelectionType = 0;
|
||||
bool ok = ReadParam(aMsg, aIter, &aResult->mOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mLength) &&
|
||||
ReadParam(aMsg, aIter, &rawSelectionType);
|
||||
aResult->mSelectionType = mozilla::ToSelectionType(rawSelectionType);
|
||||
return ok;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::WidgetQueryContentEvent> {
|
||||
typedef mozilla::WidgetQueryContentEvent paramType;
|
||||
|
||||
static void Write(Message* aMsg, const paramType& aParam) {
|
||||
WriteParam(aMsg, static_cast<const mozilla::WidgetGUIEvent&>(aParam));
|
||||
WriteParam(aMsg, aParam.mSucceeded);
|
||||
WriteParam(aMsg, aParam.mUseNativeLineBreak);
|
||||
WriteParam(aMsg, aParam.mWithFontRanges);
|
||||
WriteParam(aMsg, aParam.mInput);
|
||||
WriteParam(aMsg, aParam.mReply.mOffset);
|
||||
WriteParam(aMsg, aParam.mReply.mTentativeCaretOffset);
|
||||
WriteParam(aMsg, aParam.mReply.mString);
|
||||
WriteParam(aMsg, aParam.mReply.mRect);
|
||||
WriteParam(aMsg, aParam.mReply.mReversed);
|
||||
WriteParam(aMsg, aParam.mReply.mHasSelection);
|
||||
WriteParam(aMsg, aParam.mReply.mWidgetIsHit);
|
||||
WriteParam(aMsg, aParam.mReply.mFontRanges);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter,
|
||||
paramType* aResult) {
|
||||
return ReadParam(aMsg, aIter,
|
||||
static_cast<mozilla::WidgetGUIEvent*>(aResult)) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mSucceeded) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mUseNativeLineBreak) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mWithFontRanges) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mInput) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mReply.mOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mReply.mTentativeCaretOffset) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mReply.mString) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mReply.mRect) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mReply.mReversed) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mReply.mHasSelection) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mReply.mWidgetIsHit) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mReply.mFontRanges);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::WidgetSelectionEvent> {
|
||||
typedef mozilla::WidgetSelectionEvent paramType;
|
||||
|
@ -1554,19 +1554,19 @@ bool IMMHandler::HandleQueryCharPosition(nsWindow* aWindow, LPARAM lParam,
|
||||
|
||||
pCharPosition->cLineHeight = r.Height();
|
||||
|
||||
WidgetQueryContentEvent editorRect(true, eQueryEditorRect, aWindow);
|
||||
aWindow->InitEvent(editorRect);
|
||||
DispatchEvent(aWindow, editorRect);
|
||||
if (NS_WARN_IF(!editorRect.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryEditorRectEvent(true, eQueryEditorRect, aWindow);
|
||||
aWindow->InitEvent(queryEditorRectEvent);
|
||||
DispatchEvent(aWindow, queryEditorRectEvent);
|
||||
if (NS_WARN_IF(queryEditorRectEvent.Failed())) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("HandleQueryCharPosition, eQueryEditorRect failed"));
|
||||
::GetWindowRect(aWindow->GetWindowHandle(), &pCharPosition->rcDocument);
|
||||
} else {
|
||||
LayoutDeviceIntRect editorRectInWindow = editorRect.mReply.mRect;
|
||||
nsWindow* window =
|
||||
editorRect.mReply.mFocusedWidget
|
||||
? static_cast<nsWindow*>(editorRect.mReply.mFocusedWidget)
|
||||
: aWindow;
|
||||
LayoutDeviceIntRect editorRectInWindow = queryEditorRectEvent.mReply->mRect;
|
||||
nsWindow* window = !!queryEditorRectEvent.mReply->mFocusedWidget
|
||||
? static_cast<nsWindow*>(
|
||||
queryEditorRectEvent.mReply->mFocusedWidget)
|
||||
: aWindow;
|
||||
LayoutDeviceIntRect editorRectInScreen;
|
||||
ResolveIMECaretPos(window, editorRectInWindow, nullptr, editorRectInScreen);
|
||||
::SetRect(&pCharPosition->rcDocument, editorRectInScreen.X(),
|
||||
@ -1623,18 +1623,19 @@ bool IMMHandler::HandleDocumentFeed(nsWindow* aWindow, LPARAM lParam,
|
||||
}
|
||||
|
||||
// Get all contents of the focused editor.
|
||||
WidgetQueryContentEvent textContent(true, eQueryTextContent, aWindow);
|
||||
textContent.InitForQueryTextContent(0, UINT32_MAX);
|
||||
aWindow->InitEvent(textContent, &point);
|
||||
DispatchEvent(aWindow, textContent);
|
||||
if (!textContent.mSucceeded) {
|
||||
WidgetQueryContentEvent queryTextContentEvent(true, eQueryTextContent,
|
||||
aWindow);
|
||||
queryTextContentEvent.InitForQueryTextContent(0, UINT32_MAX);
|
||||
aWindow->InitEvent(queryTextContentEvent, &point);
|
||||
DispatchEvent(aWindow, queryTextContentEvent);
|
||||
if (NS_WARN_IF(queryTextContentEvent.Failed())) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("HandleDocumentFeed, FAILED, due to eQueryTextContent failure"));
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString str(textContent.mReply.mString);
|
||||
if (targetOffset > int32_t(str.Length())) {
|
||||
nsAutoString str(queryTextContentEvent.mReply->DataRef());
|
||||
if (targetOffset > static_cast<int32_t>(str.Length())) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("HandleDocumentFeed, FAILED, due to the caret offset is invalid"));
|
||||
return false;
|
||||
@ -2037,24 +2038,24 @@ bool IMMHandler::GetCharacterRectOfSelectedTextAt(
|
||||
// If there is a caret and retrieving offset is same as the caret offset,
|
||||
// we should use the caret rect.
|
||||
if (aOffset != caretOffset) {
|
||||
WidgetQueryContentEvent charRect(true, eQueryTextRect, aWindow);
|
||||
WidgetQueryContentEvent queryTextRectEvent(true, eQueryTextRect, aWindow);
|
||||
WidgetQueryContentEvent::Options options;
|
||||
options.mRelativeToInsertionPoint = true;
|
||||
charRect.InitForQueryTextRect(aOffset, 1, options);
|
||||
aWindow->InitEvent(charRect, &point);
|
||||
DispatchEvent(aWindow, charRect);
|
||||
if (charRect.mSucceeded) {
|
||||
aCharRect = charRect.mReply.mRect;
|
||||
queryTextRectEvent.InitForQueryTextRect(aOffset, 1, options);
|
||||
aWindow->InitEvent(queryTextRectEvent, &point);
|
||||
DispatchEvent(aWindow, queryTextRectEvent);
|
||||
if (queryTextRectEvent.Succeeded()) {
|
||||
aCharRect = queryTextRectEvent.mReply->mRect;
|
||||
if (aWritingMode) {
|
||||
*aWritingMode = charRect.GetWritingMode();
|
||||
*aWritingMode = queryTextRectEvent.mReply->WritingModeRef();
|
||||
}
|
||||
MOZ_LOG(gIMMLog, LogLevel::Debug,
|
||||
("GetCharacterRectOfSelectedTextAt, Succeeded, aOffset=%u, "
|
||||
"aCharRect={ x: %ld, y: %ld, width: %ld, height: %ld }, "
|
||||
"charRect.GetWritingMode()=%s",
|
||||
aOffset, aCharRect.X(), aCharRect.Y(), aCharRect.Width(),
|
||||
aCharRect.Height(),
|
||||
GetWritingModeName(charRect.GetWritingMode()).get()));
|
||||
MOZ_LOG(
|
||||
gIMMLog, LogLevel::Debug,
|
||||
("GetCharacterRectOfSelectedTextAt, Succeeded, aOffset=%u, "
|
||||
"aCharRect={ x: %ld, y: %ld, width: %ld, height: %ld }, "
|
||||
"queryTextRectEvent={ mReply=%s }",
|
||||
aOffset, aCharRect.X(), aCharRect.Y(), aCharRect.Width(),
|
||||
aCharRect.Height(), ToString(queryTextRectEvent.mReply).c_str()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2067,28 +2068,27 @@ bool IMMHandler::GetCaretRect(nsWindow* aWindow,
|
||||
WritingMode* aWritingMode) {
|
||||
LayoutDeviceIntPoint point(0, 0);
|
||||
|
||||
WidgetQueryContentEvent caretRect(true, eQueryCaretRect, aWindow);
|
||||
WidgetQueryContentEvent queryCaretRectEvent(true, eQueryCaretRect, aWindow);
|
||||
WidgetQueryContentEvent::Options options;
|
||||
options.mRelativeToInsertionPoint = true;
|
||||
caretRect.InitForQueryCaretRect(0, options);
|
||||
aWindow->InitEvent(caretRect, &point);
|
||||
DispatchEvent(aWindow, caretRect);
|
||||
if (!caretRect.mSucceeded) {
|
||||
queryCaretRectEvent.InitForQueryCaretRect(0, options);
|
||||
aWindow->InitEvent(queryCaretRectEvent, &point);
|
||||
DispatchEvent(aWindow, queryCaretRectEvent);
|
||||
if (queryCaretRectEvent.Failed()) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("GetCaretRect, FAILED, due to eQueryCaretRect failure"));
|
||||
return false;
|
||||
}
|
||||
aCaretRect = caretRect.mReply.mRect;
|
||||
aCaretRect = queryCaretRectEvent.mReply->mRect;
|
||||
if (aWritingMode) {
|
||||
*aWritingMode = caretRect.GetWritingMode();
|
||||
*aWritingMode = queryCaretRectEvent.mReply->WritingModeRef();
|
||||
}
|
||||
MOZ_LOG(
|
||||
gIMMLog, LogLevel::Info,
|
||||
("GetCaretRect, SUCCEEDED, "
|
||||
"aCaretRect={ x: %ld, y: %ld, width: %ld, height: %ld }, "
|
||||
"caretRect.GetWritingMode()=%s",
|
||||
aCaretRect.X(), aCaretRect.Y(), aCaretRect.Width(), aCaretRect.Height(),
|
||||
GetWritingModeName(caretRect.GetWritingMode()).get()));
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("GetCaretRect, SUCCEEDED, "
|
||||
"aCaretRect={ x: %ld, y: %ld, width: %ld, height: %ld }, "
|
||||
"queryCaretRectEvent={ mReply=%s }",
|
||||
aCaretRect.X(), aCaretRect.Y(), aCaretRect.Width(),
|
||||
aCaretRect.Height(), ToString(queryCaretRectEvent.mReply).c_str()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2239,10 +2239,10 @@ bool IMMHandler::SetIMERelatedWindowsPos(nsWindow* aWindow,
|
||||
|
||||
void IMMHandler::SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
|
||||
const IMEContext& aContext) {
|
||||
WidgetQueryContentEvent editorRectEvent(true, eQueryEditorRect, aWindow);
|
||||
aWindow->InitEvent(editorRectEvent);
|
||||
DispatchEvent(aWindow, editorRectEvent);
|
||||
if (!editorRectEvent.mSucceeded) {
|
||||
WidgetQueryContentEvent queryEditorRectEvent(true, eQueryEditorRect, aWindow);
|
||||
aWindow->InitEvent(queryEditorRectEvent);
|
||||
DispatchEvent(aWindow, queryEditorRectEvent);
|
||||
if (queryEditorRectEvent.Failed()) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("SetIMERelatedWindowsPosOnPlugin, "
|
||||
"FAILED, due to eQueryEditorRect failure"));
|
||||
@ -2253,7 +2253,8 @@ void IMMHandler::SetIMERelatedWindowsPosOnPlugin(nsWindow* aWindow,
|
||||
// window needs to be specified the position in the client area.
|
||||
nsWindow* toplevelWindow = aWindow->GetTopLevelWindow(false);
|
||||
LayoutDeviceIntRect pluginRectInScreen =
|
||||
editorRectEvent.mReply.mRect + toplevelWindow->WidgetToScreenOffset();
|
||||
queryEditorRectEvent.mReply->mRect +
|
||||
toplevelWindow->WidgetToScreenOffset();
|
||||
LayoutDeviceIntRect winRectInScreen = aWindow->GetClientBounds();
|
||||
// composition window cannot be positioned on the edge of client area.
|
||||
winRectInScreen.SizeTo(winRectInScreen.Width() - 1,
|
||||
@ -2646,11 +2647,12 @@ bool IMMHandler::Selection::Update(const IMENotification& aIMENotification) {
|
||||
bool IMMHandler::Selection::Init(nsWindow* aWindow) {
|
||||
Clear();
|
||||
|
||||
WidgetQueryContentEvent selection(true, eQuerySelectedText, aWindow);
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
aWindow);
|
||||
LayoutDeviceIntPoint point(0, 0);
|
||||
aWindow->InitEvent(selection, &point);
|
||||
DispatchEvent(aWindow, selection);
|
||||
if (NS_WARN_IF(!selection.mSucceeded)) {
|
||||
aWindow->InitEvent(querySelectedTextEvent, &point);
|
||||
DispatchEvent(aWindow, querySelectedTextEvent);
|
||||
if (NS_WARN_IF(querySelectedTextEvent.DidNotFindSelection())) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
("Selection::Init, FAILED, due to eQuerySelectedText failure"));
|
||||
return false;
|
||||
@ -2663,15 +2665,15 @@ bool IMMHandler::Selection::Init(nsWindow* aWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mOffset = selection.mReply.mOffset;
|
||||
mString = selection.mReply.mString;
|
||||
mWritingMode = selection.GetWritingMode();
|
||||
MOZ_ASSERT(querySelectedTextEvent.mReply->mOffsetAndData.isSome());
|
||||
mOffset = querySelectedTextEvent.mReply->StartOffset();
|
||||
mString = querySelectedTextEvent.mReply->DataRef();
|
||||
mWritingMode = querySelectedTextEvent.mReply->WritingModeRef();
|
||||
mIsValid = true;
|
||||
|
||||
MOZ_LOG(gIMMLog, LogLevel::Info,
|
||||
("Selection::Init, selection={ mReply={ mOffset=%u, "
|
||||
"mString.Length()=%u, mWritingMode=%s } }",
|
||||
mOffset, mString.Length(), GetWritingModeName(mWritingMode).get()));
|
||||
("Selection::Init, querySelectedTextEvent={ mReply=%s }",
|
||||
ToString(querySelectedTextEvent.mReply).c_str()));
|
||||
|
||||
if (!IsValid()) {
|
||||
MOZ_LOG(gIMMLog, LogLevel::Error,
|
||||
|
@ -2894,11 +2894,12 @@ bool TSFTextStore::GetCurrentText(nsAString& aTextContent) {
|
||||
"retrieving text from the content...",
|
||||
this));
|
||||
|
||||
WidgetQueryContentEvent queryText(true, eQueryTextContent, mWidget);
|
||||
queryText.InitForQueryTextContent(0, UINT32_MAX);
|
||||
mWidget->InitEvent(queryText);
|
||||
DispatchEvent(queryText);
|
||||
if (NS_WARN_IF(!queryText.mSucceeded)) {
|
||||
WidgetQueryContentEvent queryTextContentEvent(true, eQueryTextContent,
|
||||
mWidget);
|
||||
queryTextContentEvent.InitForQueryTextContent(0, UINT32_MAX);
|
||||
mWidget->InitEvent(queryTextContentEvent);
|
||||
DispatchEvent(queryTextContentEvent);
|
||||
if (NS_WARN_IF(queryTextContentEvent.Failed())) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::GetCurrentText(), FAILED, due to "
|
||||
"eQueryTextContent failure",
|
||||
@ -2907,7 +2908,7 @@ bool TSFTextStore::GetCurrentText(nsAString& aTextContent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aTextContent = queryText.mReply.mString;
|
||||
aTextContent = queryTextContentEvent.mReply->DataRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2920,16 +2921,19 @@ Maybe<TSFTextStore::Selection>& TSFTextStore::SelectionForTSF() {
|
||||
MOZ_ASSERT_UNREACHABLE("There should be non-destroyed widget");
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent querySelection(true, eQuerySelectedText, mWidget);
|
||||
mWidget->InitEvent(querySelection);
|
||||
DispatchEvent(querySelection);
|
||||
if (NS_WARN_IF(!querySelection.mSucceeded)) {
|
||||
WidgetQueryContentEvent querySelectedTextEvent(true, eQuerySelectedText,
|
||||
mWidget);
|
||||
mWidget->InitEvent(querySelectedTextEvent);
|
||||
DispatchEvent(querySelectedTextEvent);
|
||||
if (NS_WARN_IF(querySelectedTextEvent.DidNotFindSelection())) {
|
||||
return mSelectionForTSF;
|
||||
}
|
||||
|
||||
mSelectionForTSF = Some(Selection(
|
||||
querySelection.mReply.mOffset, querySelection.mReply.mString.Length(),
|
||||
querySelection.mReply.mReversed, querySelection.GetWritingMode()));
|
||||
MOZ_ASSERT(querySelectedTextEvent.mReply->mOffsetAndData.isSome());
|
||||
mSelectionForTSF =
|
||||
Some(Selection(querySelectedTextEvent.mReply->StartOffset(),
|
||||
querySelectedTextEvent.mReply->DataLength(),
|
||||
querySelectedTextEvent.mReply->mReversed,
|
||||
querySelectedTextEvent.mReply->WritingModeRef()));
|
||||
}
|
||||
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Debug,
|
||||
@ -4257,13 +4261,14 @@ TSFTextStore::GetACPFromPoint(TsViewCookie vcView, const POINT* pt,
|
||||
// NOTE: Don't check if the point is in the widget since the point can be
|
||||
// outside of the widget if focused editor is in a XUL <panel>.
|
||||
|
||||
WidgetQueryContentEvent charAtPt(true, eQueryCharacterAtPoint, mWidget);
|
||||
mWidget->InitEvent(charAtPt, &ourPt);
|
||||
WidgetQueryContentEvent queryCharAtPointEvent(true, eQueryCharacterAtPoint,
|
||||
mWidget);
|
||||
mWidget->InitEvent(queryCharAtPointEvent, &ourPt);
|
||||
|
||||
// FYI: WidgetQueryContentEvent may cause flushing pending layout and it
|
||||
// may cause focus change or something.
|
||||
RefPtr<TSFTextStore> kungFuDeathGrip(this);
|
||||
DispatchEvent(charAtPt);
|
||||
DispatchEvent(queryCharAtPointEvent);
|
||||
if (!mWidget || mWidget->Destroyed()) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::GetACPFromPoint() FAILED due to "
|
||||
@ -4273,12 +4278,11 @@ TSFTextStore::GetACPFromPoint(TsViewCookie vcView, const POINT* pt,
|
||||
}
|
||||
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Debug,
|
||||
("0x%p TSFTextStore::GetACPFromPoint(), charAtPt={ "
|
||||
"mSucceeded=%s, mReply={ mOffset=%u, mTentativeCaretOffset=%u }}",
|
||||
this, GetBoolName(charAtPt.mSucceeded), charAtPt.mReply.mOffset,
|
||||
charAtPt.mReply.mTentativeCaretOffset));
|
||||
("0x%p TSFTextStore::GetACPFromPoint(), queryCharAtPointEvent={ "
|
||||
"mReply=%s }",
|
||||
this, ToString(queryCharAtPointEvent.mReply).c_str()));
|
||||
|
||||
if (NS_WARN_IF(!charAtPt.mSucceeded)) {
|
||||
if (NS_WARN_IF(queryCharAtPointEvent.Failed())) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::GetACPFromPoint() FAILED due to "
|
||||
"eQueryCharacterAtPoint failure",
|
||||
@ -4288,8 +4292,7 @@ TSFTextStore::GetACPFromPoint(TsViewCookie vcView, const POINT* pt,
|
||||
|
||||
// If dwFlags isn't set and the point isn't in any character's bounding box,
|
||||
// we should return TS_E_INVALIDPOINT.
|
||||
if (!(dwFlags & GXFPF_NEAREST) &&
|
||||
charAtPt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
|
||||
if (!(dwFlags & GXFPF_NEAREST) && queryCharAtPointEvent.DidNotFindChar()) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::GetACPFromPoint() FAILED due to the "
|
||||
"point contained by no bounding box",
|
||||
@ -4299,21 +4302,19 @@ TSFTextStore::GetACPFromPoint(TsViewCookie vcView, const POINT* pt,
|
||||
|
||||
// Although, we're not sure if mTentativeCaretOffset becomes NOT_FOUND,
|
||||
// let's assume that there is no content in such case.
|
||||
if (NS_WARN_IF(charAtPt.mReply.mTentativeCaretOffset ==
|
||||
WidgetQueryContentEvent::NOT_FOUND)) {
|
||||
charAtPt.mReply.mTentativeCaretOffset = 0;
|
||||
}
|
||||
NS_WARNING_ASSERTION(queryCharAtPointEvent.DidNotFindTentativeCaretOffset(),
|
||||
"Tentative caret offset was not found");
|
||||
|
||||
uint32_t offset;
|
||||
|
||||
// If dwFlags includes GXFPF_ROUND_NEAREST, we should return tentative
|
||||
// caret offset (MSDN calls it "range position").
|
||||
if (dwFlags & GXFPF_ROUND_NEAREST) {
|
||||
offset = charAtPt.mReply.mTentativeCaretOffset;
|
||||
} else if (charAtPt.mReply.mOffset != WidgetQueryContentEvent::NOT_FOUND) {
|
||||
offset = queryCharAtPointEvent.mReply->mTentativeCaretOffset.valueOr(0);
|
||||
} else if (queryCharAtPointEvent.FoundChar()) {
|
||||
// Otherwise, we should return character offset whose bounding box contains
|
||||
// the point.
|
||||
offset = charAtPt.mReply.mOffset;
|
||||
offset = queryCharAtPointEvent.mReply->StartOffset();
|
||||
} else {
|
||||
// If the point isn't in any character's bounding box but we need to return
|
||||
// the nearest character from the point, we should *guess* the character
|
||||
@ -4323,7 +4324,7 @@ TSFTextStore::GetACPFromPoint(TsViewCookie vcView, const POINT* pt,
|
||||
// However, dispatching 2 eQueryTextRect may be expensive.
|
||||
|
||||
// So, use tentative offset for now.
|
||||
offset = charAtPt.mReply.mTentativeCaretOffset;
|
||||
offset = queryCharAtPointEvent.mReply->mTentativeCaretOffset.valueOr(0);
|
||||
|
||||
// However, if it's after the last character, we need to decrement the
|
||||
// offset.
|
||||
@ -4457,8 +4458,8 @@ TSFTextStore::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd,
|
||||
}
|
||||
|
||||
// use eQueryTextRect to get rect in system, screen coordinates
|
||||
WidgetQueryContentEvent event(true, eQueryTextRect, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
WidgetQueryContentEvent queryTextRectEvent(true, eQueryTextRect, mWidget);
|
||||
mWidget->InitEvent(queryTextRectEvent);
|
||||
|
||||
WidgetQueryContentEvent::Options options;
|
||||
int64_t startOffset = acpStart;
|
||||
@ -4491,10 +4492,10 @@ TSFTextStore::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd,
|
||||
// case, users see "dancing" of candidate or suggest window of TIP.
|
||||
// For preventing it, we should query text rect with at least 1 length.
|
||||
uint32_t length = std::max(static_cast<int32_t>(acpEnd - acpStart), 1);
|
||||
event.InitForQueryTextRect(startOffset, length, options);
|
||||
queryTextRectEvent.InitForQueryTextRect(startOffset, length, options);
|
||||
|
||||
DispatchEvent(event);
|
||||
if (NS_WARN_IF(!event.mSucceeded)) {
|
||||
DispatchEvent(queryTextRectEvent);
|
||||
if (NS_WARN_IF(queryTextRectEvent.Failed())) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::GetTextExt() FAILED due to "
|
||||
"eQueryTextRect failure",
|
||||
@ -4503,12 +4504,18 @@ TSFTextStore::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd,
|
||||
}
|
||||
|
||||
// IMEs don't like empty rects, fix here
|
||||
if (event.mReply.mRect.Width() <= 0) event.mReply.mRect.SetWidth(1);
|
||||
if (event.mReply.mRect.Height() <= 0) event.mReply.mRect.SetHeight(1);
|
||||
if (queryTextRectEvent.mReply->mRect.Width() <= 0) {
|
||||
queryTextRectEvent.mReply->mRect.SetWidth(1);
|
||||
}
|
||||
if (queryTextRectEvent.mReply->mRect.Height() <= 0) {
|
||||
queryTextRectEvent.mReply->mRect.SetHeight(1);
|
||||
}
|
||||
|
||||
// convert to unclipped screen rect
|
||||
nsWindow* refWindow = static_cast<nsWindow*>(
|
||||
event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWidget);
|
||||
nsWindow* refWindow =
|
||||
static_cast<nsWindow*>(!!queryTextRectEvent.mReply->mFocusedWidget
|
||||
? queryTextRectEvent.mReply->mFocusedWidget
|
||||
: static_cast<nsIWidget*>(mWidget.get()));
|
||||
// Result rect is in top level widget coordinates
|
||||
refWindow = refWindow->GetTopLevelWindow(false);
|
||||
if (!refWindow) {
|
||||
@ -4519,7 +4526,7 @@ TSFTextStore::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd,
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
event.mReply.mRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
queryTextRectEvent.mReply->mRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
|
||||
// get bounding screen rect to test for clipping
|
||||
if (!GetScreenExtInternal(*prc)) {
|
||||
@ -4532,8 +4539,10 @@ TSFTextStore::GetTextExt(TsViewCookie vcView, LONG acpStart, LONG acpEnd,
|
||||
|
||||
// clip text rect to bounding rect
|
||||
RECT textRect;
|
||||
::SetRect(&textRect, event.mReply.mRect.X(), event.mReply.mRect.Y(),
|
||||
event.mReply.mRect.XMost(), event.mReply.mRect.YMost());
|
||||
::SetRect(&textRect, queryTextRectEvent.mReply->mRect.X(),
|
||||
queryTextRectEvent.mReply->mRect.Y(),
|
||||
queryTextRectEvent.mReply->mRect.XMost(),
|
||||
queryTextRectEvent.mReply->mRect.YMost());
|
||||
if (!::IntersectRect(prc, prc, &textRect))
|
||||
// Text is not visible
|
||||
::SetRectEmpty(prc);
|
||||
@ -4906,10 +4915,10 @@ bool TSFTextStore::GetScreenExtInternal(RECT& aScreenExt) {
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
|
||||
// use NS_QUERY_EDITOR_RECT to get rect in system, screen coordinates
|
||||
WidgetQueryContentEvent event(true, eQueryEditorRect, mWidget);
|
||||
mWidget->InitEvent(event);
|
||||
DispatchEvent(event);
|
||||
if (!event.mSucceeded) {
|
||||
WidgetQueryContentEvent queryEditorRectEvent(true, eQueryEditorRect, mWidget);
|
||||
mWidget->InitEvent(queryEditorRectEvent);
|
||||
DispatchEvent(queryEditorRectEvent);
|
||||
if (queryEditorRectEvent.Failed()) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::GetScreenExtInternal() FAILED due to "
|
||||
"eQueryEditorRect failure",
|
||||
@ -4917,8 +4926,10 @@ bool TSFTextStore::GetScreenExtInternal(RECT& aScreenExt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsWindow* refWindow = static_cast<nsWindow*>(
|
||||
event.mReply.mFocusedWidget ? event.mReply.mFocusedWidget : mWidget);
|
||||
nsWindow* refWindow =
|
||||
static_cast<nsWindow*>(!!queryEditorRectEvent.mReply->mFocusedWidget
|
||||
? queryEditorRectEvent.mReply->mFocusedWidget
|
||||
: static_cast<nsIWidget*>(mWidget.get()));
|
||||
// Result rect is in top level widget coordinates
|
||||
refWindow = refWindow->GetTopLevelWindow(false);
|
||||
if (!refWindow) {
|
||||
@ -4933,7 +4944,7 @@ bool TSFTextStore::GetScreenExtInternal(RECT& aScreenExt) {
|
||||
boundRect.MoveTo(0, 0);
|
||||
|
||||
// Clip frame rect to window rect
|
||||
boundRect.IntersectRect(event.mReply.mRect, boundRect);
|
||||
boundRect.IntersectRect(queryEditorRectEvent.mReply->mRect, boundRect);
|
||||
if (!boundRect.IsEmpty()) {
|
||||
boundRect.MoveBy(refWindow->WidgetToScreenOffset());
|
||||
::SetRect(&aScreenExt, boundRect.X(), boundRect.Y(), boundRect.XMost(),
|
||||
@ -6384,8 +6395,8 @@ void TSFTextStore::CreateNativeCaret() {
|
||||
return;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent queryCaretRect(true, eQueryCaretRect, mWidget);
|
||||
mWidget->InitEvent(queryCaretRect);
|
||||
WidgetQueryContentEvent queryCaretRectEvent(true, eQueryCaretRect, mWidget);
|
||||
mWidget->InitEvent(queryCaretRectEvent);
|
||||
|
||||
WidgetQueryContentEvent::Options options;
|
||||
// XXX If this is called without composition and the selection isn't
|
||||
@ -6405,10 +6416,10 @@ void TSFTextStore::CreateNativeCaret() {
|
||||
options.mRelativeToInsertionPoint = true;
|
||||
caretOffset -= selectionForTSF->StartOffset();
|
||||
}
|
||||
queryCaretRect.InitForQueryCaretRect(caretOffset, options);
|
||||
queryCaretRectEvent.InitForQueryCaretRect(caretOffset, options);
|
||||
|
||||
DispatchEvent(queryCaretRect);
|
||||
if (NS_WARN_IF(!queryCaretRect.mSucceeded)) {
|
||||
DispatchEvent(queryCaretRectEvent);
|
||||
if (NS_WARN_IF(queryCaretRectEvent.Failed())) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::CreateNativeCaret() FAILED due to "
|
||||
"eQueryCaretRect failure (offset=%d)",
|
||||
@ -6417,7 +6428,7 @@ void TSFTextStore::CreateNativeCaret() {
|
||||
}
|
||||
|
||||
if (!IMEHandler::CreateNativeCaret(static_cast<nsWindow*>(mWidget.get()),
|
||||
queryCaretRect.mReply.mRect)) {
|
||||
queryCaretRectEvent.mReply->mRect)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::CreateNativeCaret() FAILED due to "
|
||||
"IMEHandler::CreateNativeCaret() failure",
|
||||
|
@ -1164,19 +1164,19 @@ bool IMEHandler::MaybeCreateNativeCaret(nsWindow* aWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WidgetQueryContentEvent queryCaretRect(true, eQueryCaretRect, aWindow);
|
||||
aWindow->InitEvent(queryCaretRect);
|
||||
WidgetQueryContentEvent queryCaretRectEvent(true, eQueryCaretRect, aWindow);
|
||||
aWindow->InitEvent(queryCaretRectEvent);
|
||||
|
||||
WidgetQueryContentEvent::Options options;
|
||||
options.mRelativeToInsertionPoint = true;
|
||||
queryCaretRect.InitForQueryCaretRect(0, options);
|
||||
queryCaretRectEvent.InitForQueryCaretRect(0, options);
|
||||
|
||||
aWindow->DispatchWindowEvent(&queryCaretRect);
|
||||
if (NS_WARN_IF(!queryCaretRect.mSucceeded)) {
|
||||
aWindow->DispatchWindowEvent(&queryCaretRectEvent);
|
||||
if (NS_WARN_IF(queryCaretRectEvent.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return CreateNativeCaret(aWindow, queryCaretRect.mReply.mRect);
|
||||
return CreateNativeCaret(aWindow, queryCaretRectEvent.mReply->mRect);
|
||||
}
|
||||
|
||||
bool IMEHandler::CreateNativeCaret(nsWindow* aWindow,
|
||||
|
Loading…
Reference in New Issue
Block a user