bool ContentCacheInParent::GetTextRect(uint32_t aOffset, LayoutDeviceIntRect& aTextRect) const { MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p GetTextRect(aOffset=%u), " "mTextRectArray={ mStart=%u, mRects.Length()=%u }, " "mSelection={ mAnchor=%u, mFocus=%u }", this, aOffset, mTextRectArray.mStart, mTextRectArray.mRects.Length(), 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; return !aTextRect.IsEmpty(); } if (aOffset == mSelection.mFocus) { NS_WARN_IF(mSelection.mFocusCharRect.IsEmpty()); aTextRect = mSelection.mFocusCharRect; return !aTextRect.IsEmpty(); } if (!mTextRectArray.InRange(aOffset)) { aTextRect.SetEmpty(); return false; } aTextRect = mTextRectArray.GetRect(aOffset); return true; }
bool ContentCacheInChild::QueryCharRect(nsIWidget* aWidget, uint32_t aOffset, LayoutDeviceIntRect& aCharRect) const { aCharRect.SetEmpty(); nsEventStatus status = nsEventStatus_eIgnore; WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aWidget); textRect.InitForQueryTextRect(aOffset, 1); aWidget->DispatchEvent(&textRect, status); if (NS_WARN_IF(!textRect.mSucceeded)) { return false; } aCharRect = textRect.mReply.mRect; // Guarantee the rect is not empty. if (NS_WARN_IF(!aCharRect.height)) { aCharRect.height = 1; } if (NS_WARN_IF(!aCharRect.width)) { aCharRect.width = 1; } return true; }
bool ContentCacheInParent::GetCaretRect(uint32_t aOffset, LayoutDeviceIntRect& aCaretRect) const { MOZ_LOG(sContentCacheLog, LogLevel::Info, ("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, 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(), 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. if (!GetTextRect(aOffset, aCaretRect)) { // There might be previous character rect in the cache. If so, we can // guess the caret rect with it. if (!aOffset || !GetTextRect(aOffset - 1, aCaretRect)) { aCaretRect.SetEmpty(); return false; } if (mSelection.mWritingMode.IsVertical()) { aCaretRect.y = aCaretRect.YMost(); } else { // XXX bidi-unaware. aCaretRect.x = aCaretRect.XMost(); } } // XXX This is not bidi aware because we don't cache each character's // direction. However, this is usually used by IME, so, assuming the // character is in LRT context must not cause any problem. if (mSelection.mWritingMode.IsVertical()) { aCaretRect.height = mCaret.IsValid() ? mCaret.mRect.height : 1; } else { aCaretRect.width = mCaret.IsValid() ? mCaret.mRect.width : 1; } return true; }
bool ContentCacheInParent::GetUnionTextRects( uint32_t aOffset, uint32_t aLength, LayoutDeviceIntRect& aUnionTextRect) const { MOZ_LOG(sContentCacheLog, LogLevel::Info, ("ContentCacheInParent: 0x%p GetUnionTextRects(aOffset=%u, " "aLength=%u), mTextRectArray={ mStart=%u, mRects.Length()=%u }, " "mSelection={ mAnchor=%u, mFocus=%u }", this, aOffset, aLength, mTextRectArray.mStart, mTextRectArray.mRects.Length(), mSelection.mAnchor, mSelection.mFocus)); CheckedInt<uint32_t> endOffset = CheckedInt<uint32_t>(aOffset) + aLength; if (!endOffset.isValid()) { return false; } if (!mSelection.Collapsed() && aOffset == mSelection.StartOffset() && aLength == mSelection.Length()) { NS_WARN_IF(mSelection.mRect.IsEmpty()); aUnionTextRect = mSelection.mRect; return !aUnionTextRect.IsEmpty(); } 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; return !aUnionTextRect.IsEmpty(); } if (aOffset == mSelection.mFocus) { NS_WARN_IF(mSelection.mFocusCharRect.IsEmpty()); aUnionTextRect = mSelection.mFocusCharRect; 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. if (!aOffset && aOffset != mSelection.mAnchor && aOffset != mSelection.mFocus && !mTextRectArray.InRange(aOffset)) { // The first character rect isn't cached. return false; } if (mTextRectArray.IsOverlappingWith(aOffset, aLength)) { aUnionTextRect = mTextRectArray.GetUnionRectAsFarAsPossible(aOffset, aLength); } else { aUnionTextRect.SetEmpty(); } if (!aOffset) { aUnionTextRect = aUnionTextRect.Union(mFirstCharRect); } if (aOffset <= mSelection.mAnchor && mSelection.mAnchor < endOffset.value()) { aUnionTextRect = aUnionTextRect.Union(mSelection.mAnchorCharRect); } if (aOffset <= mSelection.mFocus && mSelection.mFocus < endOffset.value()) { aUnionTextRect = aUnionTextRect.Union(mSelection.mFocusCharRect); } return !aUnionTextRect.IsEmpty(); }