--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -293,29 +293,47 @@ ContentCacheInChild::QueryCharRect(nsIWi
}
if (NS_WARN_IF(!aCharRect.width)) {
aCharRect.width = 1;
}
return true;
}
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)) {
+ aCharRectArray.Clear();
+ return false;
+ }
+ aCharRectArray = Move(textRects.mReply.mRectArray);
+ return true;
+}
+
+bool
ContentCacheInChild::CacheTextRects(nsIWidget* aWidget,
const IMENotification* aNotification)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p CacheTextRects(aWidget=0x%p, aNotification=%s), "
"mCaret={ mOffset=%u, IsValid()=%s }",
this, aWidget, GetNotificationName(aNotification), mCaret.mOffset,
GetBoolName(mCaret.IsValid())));
mCompositionStart = UINT32_MAX;
mTextRectArray.Clear();
- mSelection.mAnchorCharRect.SetEmpty();
- mSelection.mFocusCharRect.SetEmpty();
+ mSelection.ClearAnchorCharRects();
+ mSelection.ClearFocusCharRects();
mSelection.mRect.SetEmpty();
mFirstCharRect.SetEmpty();
if (NS_WARN_IF(!mSelection.IsValid())) {
return false;
}
// Retrieve text rects in composition string if there is.
@@ -325,51 +343,86 @@ ContentCacheInChild::CacheTextRects(nsIW
// mCompositionStart may be updated by some composition event handlers.
// So, let's update it with the latest information.
mCompositionStart = textComposition->NativeOffsetOfStartComposition();
// Note that TextComposition::String() may not be modified here because
// it's modified after all edit action listeners are performed but this
// is called while some of them are performed.
uint32_t length = textComposition->LastData().Length();
mTextRectArray.mStart = mCompositionStart;
-
- nsEventStatus status = nsEventStatus_eIgnore;
- WidgetQueryContentEvent textRects(true, eQueryTextRectArray, aWidget);
- textRects.InitForQueryTextRectArray(mTextRectArray.mStart, length);
- aWidget->DispatchEvent(&textRects, status);
-
- mTextRectArray.mRects = Move(textRects.mReply.mRectArray);
+ if (NS_WARN_IF(!QueryCharRectArray(aWidget, mTextRectArray.mStart, length,
+ mTextRectArray.mRects))) {
+ MOZ_LOG(sContentCacheLog, LogLevel::Error,
+ ("0x%p CacheTextRects(), FAILED, "
+ "couldn't retrieve text rect array of the composition string", this));
+ }
}
- if (mTextRectArray.InRange(mSelection.mAnchor)) {
- mSelection.mAnchorCharRect = mTextRectArray.GetRect(mSelection.mAnchor);
+ if (mTextRectArray.InRange(mSelection.mAnchor) &&
+ (!mSelection.mAnchor || mTextRectArray.InRange(mSelection.mAnchor - 1))) {
+ mSelection.mAnchorCharRects[eNextCharRect] =
+ mTextRectArray.GetRect(mSelection.mAnchor);
+ if (mSelection.mAnchor) {
+ mSelection.mAnchorCharRects[ePrevCharRect] =
+ mTextRectArray.GetRect(mSelection.mAnchor - 1);
+ }
} else {
- LayoutDeviceIntRect charRect;
- if (NS_WARN_IF(!QueryCharRect(aWidget, mSelection.mAnchor, charRect))) {
+ RectArray rects;
+ uint32_t startOffset = mSelection.mAnchor ? mSelection.mAnchor - 1 : 0;
+ uint32_t length = mSelection.mAnchor ? 2 : 1;
+ if (NS_WARN_IF(!QueryCharRectArray(aWidget, startOffset, length, rects))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("0x%p CacheTextRects(), FAILED, "
- "couldn't retrieve text rect at anchor of selection (%u)",
+ "couldn't retrieve text rect array around the selection anchor (%u)",
this, mSelection.mAnchor));
+ MOZ_ASSERT(mSelection.mAnchorCharRects[ePrevCharRect].IsEmpty());
+ MOZ_ASSERT(mSelection.mAnchorCharRects[eNextCharRect].IsEmpty());
+ } else {
+ if (rects.Length() > 1) {
+ mSelection.mAnchorCharRects[ePrevCharRect] = rects[0];
+ mSelection.mAnchorCharRects[eNextCharRect] = rects[1];
+ } else if (rects.Length()) {
+ mSelection.mAnchorCharRects[eNextCharRect] = rects[0];
+ MOZ_ASSERT(mSelection.mAnchorCharRects[ePrevCharRect].IsEmpty());
+ }
}
- mSelection.mAnchorCharRect = charRect;
}
if (mSelection.Collapsed()) {
- mSelection.mFocusCharRect = mSelection.mAnchorCharRect;
- } else if (mTextRectArray.InRange(mSelection.mFocus)) {
- mSelection.mFocusCharRect = mTextRectArray.GetRect(mSelection.mFocus);
+ mSelection.mFocusCharRects[0] = mSelection.mAnchorCharRects[0];
+ mSelection.mFocusCharRects[1] = mSelection.mAnchorCharRects[1];
+ } else if (mTextRectArray.InRange(mSelection.mFocus) &&
+ (!mSelection.mFocus ||
+ mTextRectArray.InRange(mSelection.mFocus - 1))) {
+ mSelection.mFocusCharRects[eNextCharRect] =
+ mTextRectArray.GetRect(mSelection.mFocus);
+ if (mSelection.mFocus) {
+ mSelection.mFocusCharRects[ePrevCharRect] =
+ mTextRectArray.GetRect(mSelection.mFocus - 1);
+ }
} else {
- LayoutDeviceIntRect charRect;
- if (NS_WARN_IF(!QueryCharRect(aWidget, mSelection.mFocus, charRect))) {
+ RectArray rects;
+ uint32_t startOffset = mSelection.mFocus ? mSelection.mFocus - 1 : 0;
+ uint32_t length = mSelection.mFocus ? 2 : 1;
+ if (NS_WARN_IF(!QueryCharRectArray(aWidget, startOffset, length, rects))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("0x%p CacheTextRects(), FAILED, "
- "couldn't retrieve text rect at focus of selection (%u)",
+ "couldn't retrieve text rect array around the selection focus (%u)",
this, mSelection.mFocus));
+ MOZ_ASSERT(mSelection.mFocusCharRects[ePrevCharRect].IsEmpty());
+ MOZ_ASSERT(mSelection.mFocusCharRects[eNextCharRect].IsEmpty());
+ } else {
+ if (rects.Length() > 1) {
+ mSelection.mFocusCharRects[ePrevCharRect] = rects[0];
+ mSelection.mFocusCharRects[eNextCharRect] = rects[1];
+ } else if (rects.Length()) {
+ mSelection.mFocusCharRects[eNextCharRect] = rects[0];
+ MOZ_ASSERT(mSelection.mFocusCharRects[ePrevCharRect].IsEmpty());
+ }
}
- mSelection.mFocusCharRect = charRect;
}
if (!mSelection.Collapsed()) {
nsEventStatus status = nsEventStatus_eIgnore;
WidgetQueryContentEvent textRect(true, eQueryTextRect, aWidget);
textRect.InitForQueryTextRect(mSelection.StartOffset(),
mSelection.Length());
aWidget->DispatchEvent(&textRect, status);
@@ -378,41 +431,50 @@ ContentCacheInChild::CacheTextRects(nsIW
("0x%p CacheTextRects(), FAILED, "
"couldn't retrieve text rect of whole selected text", this));
} else {
mSelection.mRect = textRect.mReply.mRect;
}
}
if (!mSelection.mFocus) {
- mFirstCharRect = mSelection.mFocusCharRect;
+ mFirstCharRect = mSelection.mFocusCharRects[eNextCharRect];
+ } else if (mSelection.mFocus == 1) {
+ mFirstCharRect = mSelection.mFocusCharRects[ePrevCharRect];
} else if (!mSelection.mAnchor) {
- mFirstCharRect = mSelection.mAnchorCharRect;
+ mFirstCharRect = mSelection.mAnchorCharRects[eNextCharRect];
+ } else if (mSelection.mAnchor == 1) {
+ mFirstCharRect = mSelection.mFocusCharRects[ePrevCharRect];
} else if (mTextRectArray.InRange(0)) {
mFirstCharRect = mTextRectArray.GetRect(0);
} else {
LayoutDeviceIntRect charRect;
if (NS_WARN_IF(!QueryCharRect(aWidget, 0, charRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("0x%p CacheTextRects(), FAILED, "
"couldn't retrieve first char rect", this));
} else {
mFirstCharRect = charRect;
}
}
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p CacheTextRects(), Succeeded, "
"mText.Length()=%u, mTextRectArray={ mStart=%u, mRects.Length()=%u }, "
- "mSelection={ mAnchor=%u, mAnchorCharRect=%s, mFocus=%u, "
- "mFocusCharRect=%s, mRect=%s }, mFirstCharRect=%s",
+ "mSelection={ mAnchor=%u, mAnchorCharRects[eNextCharRect]=%s, "
+ "mAnchorCharRects[ePrevCharRect]=%s, mFocus=%u, "
+ "mFocusCharRects[eNextCharRect]=%s, mFocusCharRects[ePrevCharRect]=%s, "
+ "mRect=%s }, mFirstCharRect=%s",
this, mText.Length(), mTextRectArray.mStart,
mTextRectArray.mRects.Length(), mSelection.mAnchor,
- GetRectText(mSelection.mAnchorCharRect).get(), mSelection.mFocus,
- GetRectText(mSelection.mFocusCharRect).get(),
+ GetRectText(mSelection.mAnchorCharRects[eNextCharRect]).get(),
+ GetRectText(mSelection.mAnchorCharRects[ePrevCharRect]).get(),
+ mSelection.mFocus,
+ GetRectText(mSelection.mFocusCharRects[eNextCharRect]).get(),
+ GetRectText(mSelection.mFocusCharRects[ePrevCharRect]).get(),
GetRectText(mSelection.mRect).get(), GetRectText(mFirstCharRect).get()));
return true;
}
void
ContentCacheInChild::SetSelection(nsIWidget* aWidget,
uint32_t aStartOffset,
uint32_t aLength,
@@ -470,25 +532,29 @@ ContentCacheInParent::AssignContent(cons
IMEStateManager::MaybeStartOffsetUpdatedInChild(aWidget, mCompositionStart);
} else {
NS_WARN_IF(mCompositionStart != UINT32_MAX);
}
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p AssignContent(aNotification=%s), "
"Succeeded, mText.Length()=%u, mSelection={ mAnchor=%u, mFocus=%u, "
- "mWritingMode=%s, mAnchorCharRect=%s, mFocusCharRect=%s, mRect=%s }, "
+ "mWritingMode=%s, mAnchorCharRects[eNextCharRect]=%s, "
+ "mAnchorCharRects[ePrevCharRect]=%s, mFocusCharRects[eNextCharRect]=%s, "
+ "mFocusCharRects[ePrevCharRect]=%s, mRect=%s }, "
"mFirstCharRect=%s, mCaret={ mOffset=%u, mRect=%s }, mTextRectArray={ "
"mStart=%u, mRects.Length()=%u }, mIsComposing=%s, mCompositionStart=%u, "
"mEditorRect=%s",
this, GetNotificationName(aNotification),
mText.Length(), mSelection.mAnchor, mSelection.mFocus,
GetWritingModeName(mSelection.mWritingMode).get(),
- GetRectText(mSelection.mAnchorCharRect).get(),
- GetRectText(mSelection.mFocusCharRect).get(),
+ GetRectText(mSelection.mAnchorCharRects[eNextCharRect]).get(),
+ GetRectText(mSelection.mAnchorCharRects[ePrevCharRect]).get(),
+ GetRectText(mSelection.mFocusCharRects[eNextCharRect]).get(),
+ GetRectText(mSelection.mFocusCharRects[ePrevCharRect]).get(),
GetRectText(mSelection.mRect).get(), GetRectText(mFirstCharRect).get(),
mCaret.mOffset, GetRectText(mCaret.mRect).get(), mTextRectArray.mStart,
mTextRectArray.mRects.Length(), GetBoolName(mIsComposing),
mCompositionStart, GetRectText(mEditorRect).get()));
}
bool
ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
@@ -770,23 +836,33 @@ ContentCacheInParent::GetTextRect(uint32
mSelection.mAnchor, mSelection.mFocus));
if (!aOffset) {
NS_WARN_IF(mFirstCharRect.IsEmpty());
aTextRect = mFirstCharRect;
return !aTextRect.IsEmpty();
}
if (aOffset == mSelection.mAnchor) {
- NS_WARN_IF(mSelection.mAnchorCharRect.IsEmpty());
- aTextRect = mSelection.mAnchorCharRect;
+ NS_WARN_IF(mSelection.mAnchorCharRects[eNextCharRect].IsEmpty());
+ aTextRect = mSelection.mAnchorCharRects[eNextCharRect];
+ return !aTextRect.IsEmpty();
+ }
+ if (mSelection.mAnchor && aOffset == mSelection.mAnchor - 1) {
+ NS_WARN_IF(mSelection.mAnchorCharRects[ePrevCharRect].IsEmpty());
+ aTextRect = mSelection.mAnchorCharRects[ePrevCharRect];
return !aTextRect.IsEmpty();
}
if (aOffset == mSelection.mFocus) {
- NS_WARN_IF(mSelection.mFocusCharRect.IsEmpty());
- aTextRect = mSelection.mFocusCharRect;
+ NS_WARN_IF(mSelection.mFocusCharRects[eNextCharRect].IsEmpty());
+ aTextRect = mSelection.mFocusCharRects[eNextCharRect];
+ return !aTextRect.IsEmpty();
+ }
+ if (mSelection.mFocus && aOffset == mSelection.mFocus - 1) {
+ NS_WARN_IF(mSelection.mFocusCharRects[ePrevCharRect].IsEmpty());
+ aTextRect = mSelection.mFocusCharRects[ePrevCharRect];
return !aTextRect.IsEmpty();
}
uint32_t offset = aOffset;
if (!mTextRectArray.InRange(aOffset)) {
if (!aRoundToExistingOffset) {
aTextRect.SetEmpty();
return false;
@@ -839,23 +915,33 @@ ContentCacheInParent::GetUnionTextRects(
if (aLength == 1) {
if (!aOffset) {
NS_WARN_IF(mFirstCharRect.IsEmpty());
aUnionTextRect = mFirstCharRect;
return !aUnionTextRect.IsEmpty();
}
if (aOffset == mSelection.mAnchor) {
- NS_WARN_IF(mSelection.mAnchorCharRect.IsEmpty());
- aUnionTextRect = mSelection.mAnchorCharRect;
+ NS_WARN_IF(mSelection.mAnchorCharRects[eNextCharRect].IsEmpty());
+ aUnionTextRect = mSelection.mAnchorCharRects[eNextCharRect];
+ return !aUnionTextRect.IsEmpty();
+ }
+ if (mSelection.mAnchor && aOffset == mSelection.mAnchor - 1) {
+ NS_WARN_IF(mSelection.mAnchorCharRects[ePrevCharRect].IsEmpty());
+ aUnionTextRect = mSelection.mAnchorCharRects[ePrevCharRect];
return !aUnionTextRect.IsEmpty();
}
if (aOffset == mSelection.mFocus) {
- NS_WARN_IF(mSelection.mFocusCharRect.IsEmpty());
- aUnionTextRect = mSelection.mFocusCharRect;
+ NS_WARN_IF(mSelection.mFocusCharRects[eNextCharRect].IsEmpty());
+ aUnionTextRect = mSelection.mFocusCharRects[eNextCharRect];
+ return !aUnionTextRect.IsEmpty();
+ }
+ if (mSelection.mFocus && aOffset == mSelection.mFocus - 1) {
+ NS_WARN_IF(mSelection.mFocusCharRects[ePrevCharRect].IsEmpty());
+ aUnionTextRect = mSelection.mFocusCharRects[ePrevCharRect];
return !aUnionTextRect.IsEmpty();
}
}
// Even if some text rects are not cached of the queried range,
// we should return union rect when the first character's rect is cached
// since the first character rect is important and the others are not so
// in most cases.
@@ -874,43 +960,59 @@ ContentCacheInParent::GetUnionTextRects(
} else {
aUnionTextRect.SetEmpty();
}
if (!aOffset) {
aUnionTextRect = aUnionTextRect.Union(mFirstCharRect);
}
if (aOffset <= mSelection.mAnchor && mSelection.mAnchor < endOffset.value()) {
- aUnionTextRect = aUnionTextRect.Union(mSelection.mAnchorCharRect);
+ aUnionTextRect =
+ aUnionTextRect.Union(mSelection.mAnchorCharRects[eNextCharRect]);
+ }
+ if (mSelection.mAnchor && aOffset <= mSelection.mAnchor - 1 &&
+ mSelection.mAnchor - 1 < endOffset.value()) {
+ aUnionTextRect =
+ aUnionTextRect.Union(mSelection.mAnchorCharRects[ePrevCharRect]);
}
if (aOffset <= mSelection.mFocus && mSelection.mFocus < endOffset.value()) {
- aUnionTextRect = aUnionTextRect.Union(mSelection.mFocusCharRect);
+ aUnionTextRect =
+ aUnionTextRect.Union(mSelection.mFocusCharRects[eNextCharRect]);
}
+ if (mSelection.mFocus && aOffset <= mSelection.mFocus - 1 &&
+ mSelection.mFocus - 1 < endOffset.value()) {
+ aUnionTextRect =
+ aUnionTextRect.Union(mSelection.mFocusCharRects[ePrevCharRect]);
+ }
+
return !aUnionTextRect.IsEmpty();
}
bool
ContentCacheInParent::GetCaretRect(uint32_t aOffset,
bool aRoundToExistingOffset,
LayoutDeviceIntRect& aCaretRect) const
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("0x%p GetCaretRect(aOffset=%u, "
"aRoundToExistingOffset=%s), "
"mCaret={ mOffset=%u, mRect=%s, IsValid()=%s }, mTextRectArray={ "
"mStart=%u, mRects.Length()=%u }, mSelection={ mAnchor=%u, mFocus=%u, "
- "mWritingMode=%s, mAnchorCharRect=%s, mFocusCharRect=%s }, "
- "mFirstCharRect=%s",
+ "mWritingMode=%s, mAnchorCharRects[eNextCharRect]=%s, "
+ "mAnchorCharRects[ePrevCharRect]=%s, mFocusCharRects[eNextCharRect]=%s, "
+ "mFocusCharRects[ePrevCharRect]=%s }, mFirstCharRect=%s",
this, aOffset, GetBoolName(aRoundToExistingOffset),
mCaret.mOffset, GetRectText(mCaret.mRect).get(),
GetBoolName(mCaret.IsValid()), mTextRectArray.mStart,
mTextRectArray.mRects.Length(), mSelection.mAnchor, mSelection.mFocus,
GetWritingModeName(mSelection.mWritingMode).get(),
- GetRectText(mSelection.mAnchorCharRect).get(),
- GetRectText(mSelection.mFocusCharRect).get(),
+ GetRectText(mSelection.mAnchorCharRects[eNextCharRect]).get(),
+ GetRectText(mSelection.mAnchorCharRects[ePrevCharRect]).get(),
+ GetRectText(mSelection.mFocusCharRects[eNextCharRect]).get(),
+ GetRectText(mSelection.mFocusCharRects[ePrevCharRect]).get(),
GetRectText(mFirstCharRect).get()));
if (mCaret.IsValid() && mCaret.mOffset == aOffset) {
aCaretRect = mCaret.mRect;
return true;
}
// Guess caret rect from the text rect if it's stored.
--- a/widget/nsGUIEventIPC.h
+++ b/widget/nsGUIEventIPC.h
@@ -976,36 +976,40 @@ struct ParamTraits<mozilla::ContentCache
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCompositionStart);
WriteParam(aMsg, aParam.mText);
WriteParam(aMsg, aParam.mSelection.mAnchor);
WriteParam(aMsg, aParam.mSelection.mFocus);
WriteParam(aMsg, aParam.mSelection.mWritingMode);
- WriteParam(aMsg, aParam.mSelection.mAnchorCharRect);
- WriteParam(aMsg, aParam.mSelection.mFocusCharRect);
+ WriteParam(aMsg, aParam.mSelection.mAnchorCharRects[0]);
+ WriteParam(aMsg, aParam.mSelection.mAnchorCharRects[1]);
+ WriteParam(aMsg, aParam.mSelection.mFocusCharRects[0]);
+ WriteParam(aMsg, aParam.mSelection.mFocusCharRects[1]);
WriteParam(aMsg, aParam.mSelection.mRect);
WriteParam(aMsg, aParam.mFirstCharRect);
WriteParam(aMsg, aParam.mCaret.mOffset);
WriteParam(aMsg, aParam.mCaret.mRect);
WriteParam(aMsg, aParam.mTextRectArray.mStart);
WriteParam(aMsg, aParam.mTextRectArray.mRects);
WriteParam(aMsg, aParam.mEditorRect);
}
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, &aResult->mCompositionStart) &&
ReadParam(aMsg, aIter, &aResult->mText) &&
ReadParam(aMsg, aIter, &aResult->mSelection.mAnchor) &&
ReadParam(aMsg, aIter, &aResult->mSelection.mFocus) &&
ReadParam(aMsg, aIter, &aResult->mSelection.mWritingMode) &&
- ReadParam(aMsg, aIter, &aResult->mSelection.mAnchorCharRect) &&
- ReadParam(aMsg, aIter, &aResult->mSelection.mFocusCharRect) &&
+ ReadParam(aMsg, aIter, &aResult->mSelection.mAnchorCharRects[0]) &&
+ ReadParam(aMsg, aIter, &aResult->mSelection.mAnchorCharRects[1]) &&
+ ReadParam(aMsg, aIter, &aResult->mSelection.mFocusCharRects[0]) &&
+ ReadParam(aMsg, aIter, &aResult->mSelection.mFocusCharRects[1]) &&
ReadParam(aMsg, aIter, &aResult->mSelection.mRect) &&
ReadParam(aMsg, aIter, &aResult->mFirstCharRect) &&
ReadParam(aMsg, aIter, &aResult->mCaret.mOffset) &&
ReadParam(aMsg, aIter, &aResult->mCaret.mRect) &&
ReadParam(aMsg, aIter, &aResult->mTextRectArray.mStart) &&
ReadParam(aMsg, aIter, &aResult->mTextRectArray.mRects) &&
ReadParam(aMsg, aIter, &aResult->mEditorRect);
}