Bug 1177388 Create ContentCacheInParent and ContentCacheInChild for making their purpose clearer r=m_kato

This commit is contained in:
Masayuki Nakano 2015-06-26 08:21:13 +09:00
parent dfca5410f8
commit f34c89eecf
4 changed files with 442 additions and 508 deletions

View File

@ -469,7 +469,7 @@ protected:
// IME
static TabParent *mIMETabParent;
ContentCache mContentCache;
ContentCacheInParent mContentCache;
nsIntRect mRect;
ScreenIntSize mDimensions;

View File

@ -117,58 +117,26 @@ public:
PRLogModuleInfo* sContentCacheLog = nullptr;
ContentCache::ContentCache()
: mCompositionStart(UINT32_MAX)
, mCompositionEventsDuringRequest(0)
, mIsComposing(false)
, mRequestedToCommitOrCancelComposition(false)
, mIsChrome(XRE_GetProcessType() == GeckoProcessType_Default)
{
if (!sContentCacheLog) {
sContentCacheLog = PR_NewLogModule("ContentCacheWidgets");
}
}
void
ContentCache::AssignContent(const ContentCache& aOther,
const IMENotification* aNotification)
/*****************************************************************************
* mozilla::ContentCacheInChild
*****************************************************************************/
ContentCacheInChild::ContentCacheInChild()
: ContentCache()
{
if (NS_WARN_IF(!mIsChrome)) {
return;
}
mText = aOther.mText;
mSelection = aOther.mSelection;
mFirstCharRect = aOther.mFirstCharRect;
mCaret = aOther.mCaret;
mTextRectArray = aOther.mTextRectArray;
mEditorRect = aOther.mEditorRect;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) AssignContent(aNotification=%s), "
"Succeeded, mText.Length()=%u, mSelection={ mAnchor=%u, mFocus=%u, "
"mWritingMode=%s, mAnchorCharRect=%s, mFocusCharRect=%s, mRect=%s }, "
"mFirstCharRect=%s, mCaret={ mOffset=%u, mRect=%s }, mTextRectArray={ "
"mStart=%u, mRects.Length()=%u }, mEditorRect=%s",
this, GetBoolName(mIsChrome), GetNotificationName(aNotification),
mText.Length(), mSelection.mAnchor, mSelection.mFocus,
GetWritingModeName(mSelection.mWritingMode).get(),
GetRectText(mSelection.mAnchorCharRect).get(),
GetRectText(mSelection.mFocusCharRect).get(),
GetRectText(mSelection.mRect).get(), GetRectText(mFirstCharRect).get(),
mCaret.mOffset, GetRectText(mCaret.mRect).get(), mTextRectArray.mStart,
mTextRectArray.mRects.Length(), GetRectText(mEditorRect).get()));
}
void
ContentCache::Clear()
ContentCacheInChild::Clear()
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) Clear()",
this, GetBoolName(mIsChrome)));
if (NS_WARN_IF(mIsChrome)) {
return;
}
("ContentCacheInChild: 0x%p Clear()", this));
mText.Truncate();
mSelection.Clear();
@ -179,209 +147,13 @@ ContentCache::Clear()
}
bool
ContentCache::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
nsIWidget* aWidget) const
{
MOZ_ASSERT(aWidget);
if (NS_WARN_IF(!mIsChrome)) {
return false;
}
aEvent.mSucceeded = false;
aEvent.mWasAsync = false;
aEvent.mReply.mFocusedWidget = aWidget;
switch (aEvent.message) {
case NS_QUERY_SELECTED_TEXT:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_SELECTED_TEXT }, aWidget=0x%p)",
this, GetBoolName(mIsChrome), aWidget));
if (NS_WARN_IF(!IsSelectionValid())) {
// If content cache hasn't been initialized properly, make the query
// failed.
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"FAILED because mSelection is not valid",
this, GetBoolName(mIsChrome)));
return true;
}
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,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"FAILED because mSelection.EndOffset()=%u is larger than "
"mText.Length()=%u",
this, GetBoolName(mIsChrome), mSelection.EndOffset(),
mText.Length()));
return false;
}
aEvent.mReply.mString =
Substring(mText, aEvent.mReply.mOffset, mSelection.Length());
}
aEvent.mReply.mReversed = mSelection.Reversed();
aEvent.mReply.mHasSelection = true;
aEvent.mReply.mWritingMode = mSelection.mWritingMode;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mOffset=%u, mString=\"%s\", "
"mReversed=%s, mHasSelection=%s, mWritingMode=%s } }",
this, GetBoolName(mIsChrome), aEvent.mReply.mOffset,
NS_ConvertUTF16toUTF8(aEvent.mReply.mString).get(),
GetBoolName(aEvent.mReply.mReversed),
GetBoolName(aEvent.mReply.mHasSelection),
GetWritingModeName(aEvent.mReply.mWritingMode).get()));
break;
case NS_QUERY_TEXT_CONTENT: {
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_TEXT_CONTENT, mInput={ mOffset=%u, "
"mLength=%u } }, aWidget=0x%p), mText.Length()=%u",
this, GetBoolName(mIsChrome), aEvent.mInput.mOffset,
aEvent.mInput.mLength, aWidget, mText.Length()));
uint32_t inputOffset = aEvent.mInput.mOffset;
uint32_t inputEndOffset =
std::min(aEvent.mInput.EndOffset(), mText.Length());
if (NS_WARN_IF(inputEndOffset < inputOffset)) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"FAILED because inputOffset=%u is larger than inputEndOffset=%u",
this, GetBoolName(mIsChrome), inputOffset, inputEndOffset));
return false;
}
aEvent.mReply.mOffset = inputOffset;
aEvent.mReply.mString =
Substring(mText, inputOffset, inputEndOffset - inputOffset);
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mOffset=%u, mString.Length()=%u } }",
this, GetBoolName(mIsChrome), aEvent.mReply.mOffset,
aEvent.mReply.mString.Length()));
break;
}
case NS_QUERY_TEXT_RECT:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_TEXT_RECT, mInput={ mOffset=%u, "
"mLength=%u } }, aWidget=0x%p), mText.Length()=%u",
this, GetBoolName(mIsChrome), aEvent.mInput.mOffset,
aEvent.mInput.mLength, 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,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"FAILED because mSelection is not valid",
this, GetBoolName(mIsChrome)));
return true;
}
if (aEvent.mInput.mLength) {
if (NS_WARN_IF(!GetUnionTextRects(aEvent.mInput.mOffset,
aEvent.mInput.mLength,
aEvent.mReply.mRect))) {
// XXX We don't have cache for this request.
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"FAILED to get union rect",
this, GetBoolName(mIsChrome)));
return false;
}
} else {
// If the length is 0, we should return caret rect instead.
if (NS_WARN_IF(!GetCaretRect(aEvent.mInput.mOffset,
aEvent.mReply.mRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"FAILED to get caret rect",
this, GetBoolName(mIsChrome)));
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;
// XXX This may be wrong if storing range isn't in the selection range.
aEvent.mReply.mWritingMode = mSelection.mWritingMode;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mOffset=%u, mString=\"%s\", "
"mWritingMode=%s, mRect=%s } }",
this, GetBoolName(mIsChrome), aEvent.mReply.mOffset,
NS_ConvertUTF16toUTF8(aEvent.mReply.mString).get(),
GetWritingModeName(aEvent.mReply.mWritingMode).get(),
GetRectText(aEvent.mReply.mRect).get()));
break;
case NS_QUERY_CARET_RECT:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_CARET_RECT, mInput={ mOffset=%u } }, "
"aWidget=0x%p), mText.Length()=%u",
this, GetBoolName(mIsChrome), 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,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"FAILED because mSelection is not valid",
this, GetBoolName(mIsChrome)));
return true;
}
if (NS_WARN_IF(!GetCaretRect(aEvent.mInput.mOffset,
aEvent.mReply.mRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"FAILED to get caret rect",
this, GetBoolName(mIsChrome)));
return false;
}
aEvent.mReply.mOffset = aEvent.mInput.mOffset;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mOffset=%u, mRect=%s } }",
this, GetBoolName(mIsChrome), aEvent.mReply.mOffset,
GetRectText(aEvent.mReply.mRect).get()));
break;
case NS_QUERY_EDITOR_RECT:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_EDITOR_RECT }, aWidget=0x%p)",
this, GetBoolName(mIsChrome), aWidget));
aEvent.mReply.mRect = mEditorRect;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mRect=%s } }",
this, GetBoolName(mIsChrome), GetRectText(aEvent.mReply.mRect).get()));
break;
}
aEvent.mSucceeded = true;
return true;
}
bool
ContentCache::CacheAll(nsIWidget* aWidget,
const IMENotification* aNotification)
ContentCacheInChild::CacheAll(nsIWidget* aWidget,
const IMENotification* aNotification)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheAll(aWidget=0x%p, "
("ContentCacheInChild: 0x%p CacheAll(aWidget=0x%p, "
"aNotification=%s)",
this, GetBoolName(mIsChrome), aWidget,
GetNotificationName(aNotification)));
// CacheAll() must be called in content process.
if (NS_WARN_IF(mIsChrome)) {
return false;
}
this, aWidget, GetNotificationName(aNotification)));
if (NS_WARN_IF(!CacheText(aWidget, aNotification)) ||
NS_WARN_IF(!CacheEditorRect(aWidget, aNotification))) {
@ -391,19 +163,13 @@ ContentCache::CacheAll(nsIWidget* aWidget,
}
bool
ContentCache::CacheSelection(nsIWidget* aWidget,
const IMENotification* aNotification)
ContentCacheInChild::CacheSelection(nsIWidget* aWidget,
const IMENotification* aNotification)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheSelection(aWidget=0x%p, "
("ContentCacheInChild: 0x%p CacheSelection(aWidget=0x%p, "
"aNotification=%s)",
this, GetBoolName(mIsChrome), aWidget,
GetNotificationName(aNotification)));
// CacheSelection() must be called in content process.
if (NS_WARN_IF(mIsChrome)) {
return false;
}
this, aWidget, GetNotificationName(aNotification)));
mCaret.Clear();
mSelection.Clear();
@ -413,9 +179,8 @@ ContentCache::CacheSelection(nsIWidget* aWidget,
aWidget->DispatchEvent(&selection, status);
if (NS_WARN_IF(!selection.mSucceeded)) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheSelection(), FAILED, "
"couldn't retrieve the selected text",
this, GetBoolName(mIsChrome)));
("ContentCache: 0x%p CacheSelection(), FAILED, "
"couldn't retrieve the selected text", this));
return false;
}
if (selection.mReply.mReversed) {
@ -434,19 +199,13 @@ ContentCache::CacheSelection(nsIWidget* aWidget,
}
bool
ContentCache::CacheCaret(nsIWidget* aWidget,
const IMENotification* aNotification)
ContentCacheInChild::CacheCaret(nsIWidget* aWidget,
const IMENotification* aNotification)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheCaret(aWidget=0x%p, "
("ContentCacheInChild: 0x%p CacheCaret(aWidget=0x%p, "
"aNotification=%s)",
this, GetBoolName(mIsChrome), aWidget,
GetNotificationName(aNotification)));
// CacheCaret() must be called in content process.
if (NS_WARN_IF(mIsChrome)) {
return false;
}
this, aWidget, GetNotificationName(aNotification)));
mCaret.Clear();
@ -463,70 +222,56 @@ ContentCache::CacheCaret(nsIWidget* aWidget,
aWidget->DispatchEvent(&caretRect, status);
if (NS_WARN_IF(!caretRect.mSucceeded)) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheCaret(), FAILED, "
("ContentCacheInChild: 0x%p CacheCaret(), FAILED, "
"couldn't retrieve the caret rect at offset=%u",
this, GetBoolName(mIsChrome), mCaret.mOffset));
this, mCaret.mOffset));
mCaret.Clear();
return false;
}
mCaret.mRect = caretRect.mReply.mRect;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheCaret(), Succeeded, "
("ContentCacheInChild: 0x%p CacheCaret(), Succeeded, "
"mSelection={ mAnchor=%u, mFocus=%u, mWritingMode=%s }, "
"mCaret={ mOffset=%u, mRect=%s }",
this, GetBoolName(mIsChrome), mSelection.mAnchor, mSelection.mFocus,
this, mSelection.mAnchor, mSelection.mFocus,
GetWritingModeName(mSelection.mWritingMode).get(), mCaret.mOffset,
GetRectText(mCaret.mRect).get()));
return true;
}
bool
ContentCache::CacheEditorRect(nsIWidget* aWidget,
const IMENotification* aNotification)
ContentCacheInChild::CacheEditorRect(nsIWidget* aWidget,
const IMENotification* aNotification)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheEditorRect(aWidget=0x%p, "
("ContentCacheInChild: 0x%p CacheEditorRect(aWidget=0x%p, "
"aNotification=%s)",
this, GetBoolName(mIsChrome), aWidget,
GetNotificationName(aNotification)));
// CacheEditorRect() must be called in content process.
if (NS_WARN_IF(mIsChrome)) {
return false;
}
this, aWidget, GetNotificationName(aNotification)));
nsEventStatus status = nsEventStatus_eIgnore;
WidgetQueryContentEvent editorRectEvent(true, NS_QUERY_EDITOR_RECT, aWidget);
aWidget->DispatchEvent(&editorRectEvent, status);
if (NS_WARN_IF(!editorRectEvent.mSucceeded)) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheEditorRect(), FAILED, "
"couldn't retrieve the editor rect",
this, GetBoolName(mIsChrome)));
("ContentCacheInChild: 0x%p CacheEditorRect(), FAILED, "
"couldn't retrieve the editor rect", this));
return false;
}
mEditorRect = editorRectEvent.mReply.mRect;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheEditorRect(), Succeeded, "
"mEditorRect=%s",
this, GetBoolName(mIsChrome), GetRectText(mEditorRect).get()));
("ContentCacheInChild: 0x%p CacheEditorRect(), Succeeded, "
"mEditorRect=%s", this, GetRectText(mEditorRect).get()));
return true;
}
bool
ContentCache::CacheText(nsIWidget* aWidget,
const IMENotification* aNotification)
ContentCacheInChild::CacheText(nsIWidget* aWidget,
const IMENotification* aNotification)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheText(aWidget=0x%p, "
("ContentCacheInChild: 0x%p CacheText(aWidget=0x%p, "
"aNotification=%s)",
this, GetBoolName(mIsChrome), aWidget,
GetNotificationName(aNotification)));
// CacheText() must be called in content process.
if (NS_WARN_IF(mIsChrome)) {
return false;
}
this, aWidget, GetNotificationName(aNotification)));
nsEventStatus status = nsEventStatus_eIgnore;
WidgetQueryContentEvent queryText(true, NS_QUERY_TEXT_CONTENT, aWidget);
@ -534,32 +279,26 @@ ContentCache::CacheText(nsIWidget* aWidget,
aWidget->DispatchEvent(&queryText, status);
if (NS_WARN_IF(!queryText.mSucceeded)) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheText(), FAILED, "
"couldn't retrieve whole text",
this, GetBoolName(mIsChrome)));
("ContentCacheInChild: 0x%p CacheText(), FAILED, "
"couldn't retrieve whole text", this));
mText.Truncate();
return false;
}
mText = queryText.mReply.mString;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheText(), Succeeded, "
"mText.Length()=%u",
this, GetBoolName(mIsChrome), mText.Length()));
("ContentCacheInChild: 0x%p CacheText(), Succeeded, "
"mText.Length()=%u", this, mText.Length()));
return CacheSelection(aWidget, aNotification);
}
bool
ContentCache::QueryCharRect(nsIWidget* aWidget,
uint32_t aOffset,
LayoutDeviceIntRect& aCharRect) const
ContentCacheInChild::QueryCharRect(nsIWidget* aWidget,
uint32_t aOffset,
LayoutDeviceIntRect& aCharRect) const
{
aCharRect.SetEmpty();
if (NS_WARN_IF(mIsChrome)) {
return false;
}
nsEventStatus status = nsEventStatus_eIgnore;
WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aWidget);
textRect.InitForQueryTextRect(aOffset, 1);
@ -580,21 +319,15 @@ ContentCache::QueryCharRect(nsIWidget* aWidget,
}
bool
ContentCache::CacheTextRects(nsIWidget* aWidget,
const IMENotification* aNotification)
ContentCacheInChild::CacheTextRects(nsIWidget* aWidget,
const IMENotification* aNotification)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(aWidget=0x%p, "
("ContentCacheInChild: 0x%p CacheTextRects(aWidget=0x%p, "
"aNotification=%s), mCaret={ mOffset=%u, IsValid()=%s }",
this, GetBoolName(mIsChrome), aWidget,
GetNotificationName(aNotification), mCaret.mOffset,
this, aWidget, GetNotificationName(aNotification), mCaret.mOffset,
GetBoolName(mCaret.IsValid())));
// CacheTextRects() must be called in content process.
if (NS_WARN_IF(mIsChrome)) {
return false;
}
mTextRectArray.Clear();
mSelection.mAnchorCharRect.SetEmpty();
mSelection.mFocusCharRect.SetEmpty();
@ -620,9 +353,8 @@ ContentCache::CacheTextRects(nsIWidget* aWidget,
LayoutDeviceIntRect charRect;
if (NS_WARN_IF(!QueryCharRect(aWidget, i, charRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), FAILED, "
"couldn't retrieve text rect at offset=%u",
this, GetBoolName(mIsChrome), i));
("ContentCacheInChild: 0x%p CacheTextRects(), FAILED, "
"couldn't retrieve text rect at offset=%u", this, i));
mTextRectArray.Clear();
return false;
}
@ -636,9 +368,9 @@ ContentCache::CacheTextRects(nsIWidget* aWidget,
LayoutDeviceIntRect charRect;
if (NS_WARN_IF(!QueryCharRect(aWidget, mSelection.mAnchor, charRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), FAILED, "
("ContentCacheInChild: 0x%p CacheTextRects(), FAILED, "
"couldn't retrieve text rect at anchor of selection (%u)",
this, GetBoolName(mIsChrome), mSelection.mAnchor));
this, mSelection.mAnchor));
}
mSelection.mAnchorCharRect = charRect;
}
@ -651,9 +383,9 @@ ContentCache::CacheTextRects(nsIWidget* aWidget,
LayoutDeviceIntRect charRect;
if (NS_WARN_IF(!QueryCharRect(aWidget, mSelection.mFocus, charRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), FAILED, "
("ContentCacheInChild: 0x%p CacheTextRects(), FAILED, "
"couldn't retrieve text rect at focus of selection (%u)",
this, GetBoolName(mIsChrome), mSelection.mFocus));
this, mSelection.mFocus));
}
mSelection.mFocusCharRect = charRect;
}
@ -666,9 +398,8 @@ ContentCache::CacheTextRects(nsIWidget* aWidget,
aWidget->DispatchEvent(&textRect, status);
if (NS_WARN_IF(!textRect.mSucceeded)) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), FAILED, "
"couldn't retrieve text rect of whole selected text",
this, GetBoolName(mIsChrome)));
("ContentCacheInChild: 0x%p CacheTextRects(), FAILED, "
"couldn't retrieve text rect of whole selected text", this));
} else {
mSelection.mRect = textRect.mReply.mRect;
}
@ -684,20 +415,19 @@ ContentCache::CacheTextRects(nsIWidget* aWidget,
LayoutDeviceIntRect charRect;
if (NS_WARN_IF(!QueryCharRect(aWidget, 0, charRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), FAILED, "
"couldn't retrieve first char rect",
this, GetBoolName(mIsChrome)));
("ContentCacheInChild: 0x%p CacheTextRects(), FAILED, "
"couldn't retrieve first char rect", this));
} else {
mFirstCharRect = charRect;
}
}
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) CacheTextRects(), Succeeded, "
("ContentCacheInChild: 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",
this, GetBoolName(mIsChrome), mText.Length(), mTextRectArray.mStart,
this, mText.Length(), mTextRectArray.mStart,
mTextRectArray.mRects.Length(), mSelection.mAnchor,
GetRectText(mSelection.mAnchorCharRect).get(), mSelection.mFocus,
GetRectText(mSelection.mFocusCharRect).get(),
@ -706,22 +436,17 @@ ContentCache::CacheTextRects(nsIWidget* aWidget,
}
void
ContentCache::SetSelection(nsIWidget* aWidget,
uint32_t aStartOffset,
uint32_t aLength,
bool aReversed,
const WritingMode& aWritingMode)
ContentCacheInChild::SetSelection(nsIWidget* aWidget,
uint32_t aStartOffset,
uint32_t aLength,
bool aReversed,
const WritingMode& aWritingMode)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) SetSelection(aStartOffset=%u, "
("ContentCacheInChild: 0x%p SetSelection(aStartOffset=%u, "
"aLength=%u, aReversed=%s, aWritingMode=%s), mText.Length()=%u",
this, GetBoolName(mIsChrome), aStartOffset, aLength,
GetBoolName(aReversed), GetWritingModeName(aWritingMode).get(),
mText.Length()));
if (NS_WARN_IF(mIsChrome)) {
return;
}
this, aStartOffset, aLength, GetBoolName(aReversed),
GetWritingModeName(aWritingMode).get(), mText.Length()));
if (!aReversed) {
mSelection.mAnchor = aStartOffset;
@ -738,16 +463,232 @@ ContentCache::SetSelection(nsIWidget* aWidget,
NS_WARN_IF(!CacheTextRects(aWidget));
}
/*****************************************************************************
* mozilla::ContentCacheInParent
*****************************************************************************/
ContentCacheInParent::ContentCacheInParent()
: ContentCache()
, mCompositionStart(UINT32_MAX)
, mCompositionEventsDuringRequest(0)
, mIsComposing(false)
, mRequestedToCommitOrCancelComposition(false)
{
}
void
ContentCacheInParent::AssignContent(const ContentCache& aOther,
const IMENotification* aNotification)
{
mText = aOther.mText;
mSelection = aOther.mSelection;
mFirstCharRect = aOther.mFirstCharRect;
mCaret = aOther.mCaret;
mTextRectArray = aOther.mTextRectArray;
mEditorRect = aOther.mEditorRect;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p AssignContent(aNotification=%s), "
"Succeeded, mText.Length()=%u, mSelection={ mAnchor=%u, mFocus=%u, "
"mWritingMode=%s, mAnchorCharRect=%s, mFocusCharRect=%s, mRect=%s }, "
"mFirstCharRect=%s, mCaret={ mOffset=%u, mRect=%s }, mTextRectArray={ "
"mStart=%u, mRects.Length()=%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.mRect).get(), GetRectText(mFirstCharRect).get(),
mCaret.mOffset, GetRectText(mCaret.mRect).get(), mTextRectArray.mStart,
mTextRectArray.mRects.Length(), GetRectText(mEditorRect).get()));
}
bool
ContentCache::GetTextRect(uint32_t aOffset,
LayoutDeviceIntRect& aTextRect) const
ContentCacheInParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
nsIWidget* aWidget) const
{
MOZ_ASSERT(aWidget);
aEvent.mSucceeded = false;
aEvent.mWasAsync = false;
aEvent.mReply.mFocusedWidget = aWidget;
switch (aEvent.message) {
case NS_QUERY_SELECTED_TEXT:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_SELECTED_TEXT }, aWidget=0x%p)",
this, aWidget));
if (NS_WARN_IF(!IsSelectionValid())) {
// If content cache hasn't been initialized properly, make the query
// failed.
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"FAILED because mSelection is not valid", this));
return true;
}
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,
("ContentCacheInParent: 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());
}
aEvent.mReply.mReversed = mSelection.Reversed();
aEvent.mReply.mHasSelection = true;
aEvent.mReply.mWritingMode = mSelection.mWritingMode;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mOffset=%u, mString=\"%s\", "
"mReversed=%s, mHasSelection=%s, mWritingMode=%s } }",
this, aEvent.mReply.mOffset,
NS_ConvertUTF16toUTF8(aEvent.mReply.mString).get(),
GetBoolName(aEvent.mReply.mReversed),
GetBoolName(aEvent.mReply.mHasSelection),
GetWritingModeName(aEvent.mReply.mWritingMode).get()));
break;
case NS_QUERY_TEXT_CONTENT: {
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_TEXT_CONTENT, mInput={ mOffset=%u, "
"mLength=%u } }, aWidget=0x%p), mText.Length()=%u",
this, aEvent.mInput.mOffset,
aEvent.mInput.mLength, aWidget, mText.Length()));
uint32_t inputOffset = aEvent.mInput.mOffset;
uint32_t inputEndOffset =
std::min(aEvent.mInput.EndOffset(), mText.Length());
if (NS_WARN_IF(inputEndOffset < inputOffset)) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCacheInParent: 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,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mOffset=%u, mString.Length()=%u } }",
this, aEvent.mReply.mOffset, aEvent.mReply.mString.Length()));
break;
}
case NS_QUERY_TEXT_RECT:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_TEXT_RECT, mInput={ mOffset=%u, "
"mLength=%u } }, aWidget=0x%p), mText.Length()=%u",
this, aEvent.mInput.mOffset, aEvent.mInput.mLength, 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,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"FAILED because mSelection is not valid", this));
return true;
}
if (aEvent.mInput.mLength) {
if (NS_WARN_IF(!GetUnionTextRects(aEvent.mInput.mOffset,
aEvent.mInput.mLength,
aEvent.mReply.mRect))) {
// XXX We don't have cache for this request.
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCacheInParent: 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,
aEvent.mReply.mRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCacheInParent: 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;
// XXX This may be wrong if storing range isn't in the selection range.
aEvent.mReply.mWritingMode = mSelection.mWritingMode;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mOffset=%u, mString=\"%s\", "
"mWritingMode=%s, mRect=%s } }",
this, aEvent.mReply.mOffset,
NS_ConvertUTF16toUTF8(aEvent.mReply.mString).get(),
GetWritingModeName(aEvent.mReply.mWritingMode).get(),
GetRectText(aEvent.mReply.mRect).get()));
break;
case NS_QUERY_CARET_RECT:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_CARET_RECT, mInput={ mOffset=%u } }, "
"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,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"FAILED because mSelection is not valid", this));
return true;
}
if (NS_WARN_IF(!GetCaretRect(aEvent.mInput.mOffset,
aEvent.mReply.mRect))) {
MOZ_LOG(sContentCacheLog, LogLevel::Error,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"FAILED to get caret rect", this));
return false;
}
aEvent.mReply.mOffset = aEvent.mInput.mOffset;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mOffset=%u, mRect=%s } }",
this, aEvent.mReply.mOffset, GetRectText(aEvent.mReply.mRect).get()));
break;
case NS_QUERY_EDITOR_RECT:
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent("
"aEvent={ message=NS_QUERY_EDITOR_RECT }, aWidget=0x%p)",
this, aWidget));
aEvent.mReply.mRect = mEditorRect;
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCacheInParent: 0x%p HandleQueryContentEvent(), "
"Succeeded, aEvent={ mReply={ mRect=%s } }",
this, GetRectText(aEvent.mReply.mRect).get()));
break;
}
aEvent.mSucceeded = true;
return true;
}
bool
ContentCacheInParent::GetTextRect(uint32_t aOffset,
LayoutDeviceIntRect& aTextRect) const
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) GetTextRect(aOffset=%u), "
("ContentCacheInParent: 0x%p GetTextRect(aOffset=%u), "
"mTextRectArray={ mStart=%u, mRects.Length()=%u }, "
"mSelection={ mAnchor=%u, mFocus=%u }",
this, GetBoolName(mIsChrome), aOffset, mTextRectArray.mStart,
mTextRectArray.mRects.Length(), mSelection.mAnchor, mSelection.mFocus));
this, aOffset, mTextRectArray.mStart, mTextRectArray.mRects.Length(),
mSelection.mAnchor, mSelection.mFocus));
if (!aOffset) {
NS_WARN_IF(mFirstCharRect.IsEmpty());
@ -774,17 +715,17 @@ ContentCache::GetTextRect(uint32_t aOffset,
}
bool
ContentCache::GetUnionTextRects(uint32_t aOffset,
uint32_t aLength,
LayoutDeviceIntRect& aUnionTextRect) const
ContentCacheInParent::GetUnionTextRects(
uint32_t aOffset,
uint32_t aLength,
LayoutDeviceIntRect& aUnionTextRect) const
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) GetUnionTextRects(aOffset=%u, "
("ContentCacheInParent: 0x%p GetUnionTextRects(aOffset=%u, "
"aLength=%u), mTextRectArray={ mStart=%u, mRects.Length()=%u }, "
"mSelection={ mAnchor=%u, mFocus=%u }",
this, GetBoolName(mIsChrome), aOffset, aLength,
mTextRectArray.mStart, mTextRectArray.mRects.Length(),
mSelection.mAnchor, mSelection.mFocus));
this, aOffset, aLength, mTextRectArray.mStart,
mTextRectArray.mRects.Length(), mSelection.mAnchor, mSelection.mFocus));
CheckedInt<uint32_t> endOffset =
CheckedInt<uint32_t>(aOffset) + aLength;
@ -848,19 +789,18 @@ ContentCache::GetUnionTextRects(uint32_t aOffset,
}
bool
ContentCache::GetCaretRect(uint32_t aOffset,
LayoutDeviceIntRect& aCaretRect) const
ContentCacheInParent::GetCaretRect(uint32_t aOffset,
LayoutDeviceIntRect& aCaretRect) const
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) GetCaretRect(aOffset=%u), "
("ContentCacheInParent: 0x%p GetCaretRect(aOffset=%u), "
"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",
this, GetBoolName(mIsChrome), aOffset, mCaret.mOffset,
GetRectText(mCaret.mRect).get(), GetBoolName(mCaret.IsValid()),
mTextRectArray.mStart, mTextRectArray.mRects.Length(),
mSelection.mAnchor, mSelection.mFocus,
this, aOffset, 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(),
@ -900,21 +840,17 @@ ContentCache::GetCaretRect(uint32_t aOffset,
}
bool
ContentCache::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
ContentCacheInParent::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) OnCompositionEvent(aEvent={ "
("ContentCacheInParent: 0x%p OnCompositionEvent(aEvent={ "
"message=%s, mData=\"%s\" (Length()=%u), mRanges->Length()=%u }), "
"mIsComposing=%s, mRequestedToCommitOrCancelComposition=%s",
this, GetBoolName(mIsChrome), GetEventMessageName(aEvent.message),
this, GetEventMessageName(aEvent.message),
NS_ConvertUTF16toUTF8(aEvent.mData).get(), aEvent.mData.Length(),
aEvent.mRanges ? aEvent.mRanges->Length() : 0, GetBoolName(mIsComposing),
GetBoolName(mRequestedToCommitOrCancelComposition)));
if (NS_WARN_IF(!mIsChrome)) {
return false;
}
if (!aEvent.CausesDOMTextEvent()) {
MOZ_ASSERT(aEvent.message == NS_COMPOSITION_START);
mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
@ -953,23 +889,18 @@ ContentCache::OnCompositionEvent(const WidgetCompositionEvent& aEvent)
}
uint32_t
ContentCache::RequestToCommitComposition(nsIWidget* aWidget,
bool aCancel,
nsAString& aLastString)
ContentCacheInParent::RequestToCommitComposition(nsIWidget* aWidget,
bool aCancel,
nsAString& aLastString)
{
MOZ_LOG(sContentCacheLog, LogLevel::Info,
("ContentCache: 0x%p (mIsChrome=%s) RequestToCommitComposition(aWidget=%p, "
("ContentCacheInParent: 0x%p RequestToCommitComposition(aWidget=%p, "
"aCancel=%s), mIsComposing=%s, mRequestedToCommitOrCancelComposition=%s, "
"mCompositionEventsDuringRequest=%u",
this, GetBoolName(mIsChrome), aWidget, GetBoolName(aCancel),
GetBoolName(mIsComposing),
this, aWidget, GetBoolName(aCancel), GetBoolName(mIsComposing),
GetBoolName(mRequestedToCommitOrCancelComposition),
mCompositionEventsDuringRequest));
if (NS_WARN_IF(!mIsChrome)) {
return 0;
}
mRequestedToCommitOrCancelComposition = true;
mCompositionEventsDuringRequest = 0;
@ -983,7 +914,7 @@ ContentCache::RequestToCommitComposition(nsIWidget* aWidget,
}
void
ContentCache::InitNotification(IMENotification& aNotification) const
ContentCacheInParent::InitNotification(IMENotification& aNotification) const
{
if (NS_WARN_IF(aNotification.mMessage != NOTIFY_IME_OF_SELECTION_CHANGE)) {
return;

View File

@ -26,17 +26,15 @@ namespace widget {
struct IMENotification;
}
class ContentCacheInParent;
/**
* ContentCache stores various information of the child content both on
* PuppetWidget (child process) and TabParent (chrome process).
* When PuppetWidget receives some notifications of content state change,
* Cache*() are called. Then, stored data is modified for the latest content
* in PuppetWidget. After that, PuppetWidget sends the ContentCache to
* TabParent. In this time, TabParent stores the latest content data with
* AssignContent().
* ContentCache stores various information of the child content.
* This class has members which are necessary both in parent process and
* content process.
*/
class ContentCache final
class ContentCache
{
public:
typedef InfallibleTArray<LayoutDeviceIntRect> RectArray;
@ -44,119 +42,9 @@ public:
ContentCache();
/**
* When IME loses focus, this should be called and making this forget the
* content for reducing footprint.
* This must be called in content process.
*/
void Clear();
/**
* AssignContent() is called when TabParent receives ContentCache from
* the content process. This doesn't copy composition information because
* it's managed by TabParent itself.
* This must be called in chrome process.
*/
void AssignContent(const ContentCache& aOther,
const IMENotification* aNotification = nullptr);
/**
* HandleQueryContentEvent() sets content data to aEvent.mReply.
* This must be called in chrome process.
*
* For NS_QUERY_SELECTED_TEXT, fail if the cache doesn't contain the whole
* selected range. (This shouldn't happen because PuppetWidget should have
* already sent the whole selection.)
*
* For NS_QUERY_TEXT_CONTENT, fail only if the cache doesn't overlap with
* the queried range. Note the difference from above. We use
* this behavior because a normal NS_QUERY_TEXT_CONTENT event is allowed to
* have out-of-bounds offsets, so that widget can request content without
* knowing the exact length of text. It's up to widget to handle cases when
* the returned offset/length are different from the queried offset/length.
*
* For NS_QUERY_TEXT_RECT, fail if cached offset/length aren't equals to input.
* Cocoa widget always queries selected offset, so it works on it.
*
* For NS_QUERY_CARET_RECT, fail if cached offset isn't equals to input
*
* For NS_QUERY_EDITOR_RECT, always success
*/
bool HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
nsIWidget* aWidget) const;
/**
* Cache*() retrieves the latest content information and store them.
* Be aware, CacheSelection() calls CacheTextRects(), and also CacheText()
* calls CacheSelection(). So, related data is also retrieved automatically.
* These methods must be called in content process.
*/
bool CacheEditorRect(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheSelection(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheText(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheAll(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
/**
* OnCompositionEvent() should be called before sending composition string.
* This returns true if the event should be sent. Otherwise, false.
* This must be called in chrome process.
*/
bool OnCompositionEvent(const WidgetCompositionEvent& aCompositionEvent);
/**
* RequestToCommitComposition() requests to commit or cancel composition to
* the widget. If it's handled synchronously, this returns the number of
* composition events after that.
* This must be called in chrome process.
*
* @param aWidget The widget to be requested to commit or cancel
* the composition.
* @param aCancel When the caller tries to cancel the composition, true.
* Otherwise, i.e., tries to commit the composition, false.
* @param aLastString The last composition string before requesting to
* commit or cancel composition.
* @return The count of composition events ignored after a call of
* WillRequestToCommitOrCancelComposition().
*/
uint32_t RequestToCommitComposition(nsIWidget* aWidget,
bool aCancel,
nsAString& aLastString);
/**
* InitNotification() initializes aNotification with stored data.
*
* @param aNotification Must be NOTIFY_IME_OF_SELECTION_CHANGE.
*/
void InitNotification(IMENotification& aNotification) const;
/**
* SetSelection() modifies selection with specified raw data. And also this
* tries to retrieve text rects too.
* This must be called in content process.
*/
void SetSelection(nsIWidget* aWidget,
uint32_t aStartOffset,
uint32_t aLength,
bool aReversed,
const WritingMode& aWritingMode);
private:
protected:
// Whole text in the target
nsString mText;
// This is commit string which is caused by our request.
// This value is valid only in chrome process.
nsString mCommitStringByRequest;
// Start offset of the composition string.
// This value is valid only in chrome process.
uint32_t mCompositionStart;
// Count of composition events during requesting commit or cancel the
// composition.
// This value is valid only in chrome process.
uint32_t mCompositionEventsDuringRequest;
struct Selection final
{
@ -333,12 +221,47 @@ private:
LayoutDeviceIntRect mEditorRect;
// mIsComposing is valid only in chrome process.
bool mIsComposing;
// mRequestedToCommitOrCancelComposition is valid only in chrome process.
bool mRequestedToCommitOrCancelComposition;
bool mIsChrome;
friend class ContentCacheInParent;
friend struct IPC::ParamTraits<ContentCache>;
};
class ContentCacheInChild final : public ContentCache
{
public:
ContentCacheInChild();
/**
* When IME loses focus, this should be called and making this forget the
* content for reducing footprint.
*/
void Clear();
/**
* Cache*() retrieves the latest content information and store them.
* Be aware, CacheSelection() calls CacheTextRects(), and also CacheText()
* calls CacheSelection(). So, related data is also retrieved automatically.
*/
bool CacheEditorRect(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheSelection(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheText(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
bool CacheAll(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
/**
* SetSelection() modifies selection with specified raw data. And also this
* tries to retrieve text rects too.
*/
void SetSelection(nsIWidget* aWidget,
uint32_t aStartOffset,
uint32_t aLength,
bool aReversed,
const WritingMode& aWritingMode);
private:
bool QueryCharRect(nsIWidget* aWidget,
uint32_t aOffset,
LayoutDeviceIntRect& aCharRect) const;
@ -346,6 +269,87 @@ private:
const IMENotification* aNotification = nullptr);
bool CacheTextRects(nsIWidget* aWidget,
const IMENotification* aNotification = nullptr);
};
class ContentCacheInParent final : public ContentCache
{
public:
ContentCacheInParent();
/**
* AssignContent() is called when TabParent receives ContentCache from
* the content process. This doesn't copy composition information because
* it's managed by TabParent itself.
*/
void AssignContent(const ContentCache& aOther,
const IMENotification* aNotification = nullptr);
/**
* HandleQueryContentEvent() sets content data to aEvent.mReply.
*
* For NS_QUERY_SELECTED_TEXT, fail if the cache doesn't contain the whole
* selected range. (This shouldn't happen because PuppetWidget should have
* already sent the whole selection.)
*
* For NS_QUERY_TEXT_CONTENT, fail only if the cache doesn't overlap with
* the queried range. Note the difference from above. We use
* this behavior because a normal NS_QUERY_TEXT_CONTENT event is allowed to
* have out-of-bounds offsets, so that widget can request content without
* knowing the exact length of text. It's up to widget to handle cases when
* the returned offset/length are different from the queried offset/length.
*
* For NS_QUERY_TEXT_RECT, fail if cached offset/length aren't equals to input.
* Cocoa widget always queries selected offset, so it works on it.
*
* For NS_QUERY_CARET_RECT, fail if cached offset isn't equals to input
*
* For NS_QUERY_EDITOR_RECT, always success
*/
bool HandleQueryContentEvent(WidgetQueryContentEvent& aEvent,
nsIWidget* aWidget) const;
/**
* OnCompositionEvent() should be called before sending composition string.
* This returns true if the event should be sent. Otherwise, false.
*/
bool OnCompositionEvent(const WidgetCompositionEvent& aCompositionEvent);
/**
* RequestToCommitComposition() requests to commit or cancel composition to
* the widget. If it's handled synchronously, this returns the number of
* composition events after that.
*
* @param aWidget The widget to be requested to commit or cancel
* the composition.
* @param aCancel When the caller tries to cancel the composition, true.
* Otherwise, i.e., tries to commit the composition, false.
* @param aLastString The last composition string before requesting to
* commit or cancel composition.
* @return The count of composition events ignored after a call of
* WillRequestToCommitOrCancelComposition().
*/
uint32_t RequestToCommitComposition(nsIWidget* aWidget,
bool aCancel,
nsAString& aLastString);
/**
* InitNotification() initializes aNotification with stored data.
*
* @param aNotification Must be NOTIFY_IME_OF_SELECTION_CHANGE.
*/
void InitNotification(IMENotification& aNotification) const;
private:
// This is commit string which is caused by our request.
nsString mCommitStringByRequest;
// Start offset of the composition string.
uint32_t mCompositionStart;
// Count of composition events during requesting commit or cancel the
// composition.
uint32_t mCompositionEventsDuringRequest;
bool mIsComposing;
bool mRequestedToCommitOrCancelComposition;
bool GetCaretRect(uint32_t aOffset, LayoutDeviceIntRect& aCaretRect) const;
bool GetTextRect(uint32_t aOffset,
@ -354,7 +358,6 @@ private:
uint32_t aLength,
LayoutDeviceIntRect& aUnionTextRect) const;
friend struct IPC::ParamTraits<ContentCache>;
};
} // namespace mozilla

View File

@ -313,7 +313,7 @@ private:
mozilla::RefPtr<DrawTarget> mDrawTarget;
// IME
nsIMEUpdatePreference mIMEPreferenceOfParent;
ContentCache mContentCache;
ContentCacheInChild mContentCache;
bool mNeedIMEStateInit;
// The DPI of the screen corresponding to this widget