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:
Masayuki Nakano 2020-12-02 05:32:19 +00:00
parent d9c63734d9
commit 912a5bc76d
22 changed files with 1053 additions and 820 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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:

View File

@ -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.

View File

@ -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(

View File

@ -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:

View File

@ -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,

View File

@ -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 {

View File

@ -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 };

View File

@ -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() {

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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 {

View File

@ -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;

View File

@ -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,

View File

@ -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",

View File

@ -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,