Bug 1173678 ContentCache should return union rect even if some character rects are not cached but the first character of the range is cached r=m_kato
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 17 Jun 2015 10:03:58 +0900
changeset 249247 12afd3e6ae244c1df56f3eadf07a15b8aa005442
parent 249246 5e35c779d79193d52fd20d5d73b7ff9a05642ae4
child 249248 eca8d9db5581148d45be58d0085fe3ab64c8876b
push id61184
push usermasayuki@d-toybox.com
push dateWed, 17 Jun 2015 01:04:11 +0000
treeherdermozilla-inbound@12afd3e6ae24 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersm_kato
bugs1173678
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1173678 ContentCache should return union rect even if some character rects are not cached but the first character of the range is cached r=m_kato
widget/ContentCache.cpp
widget/ContentCache.h
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -781,16 +781,22 @@ ContentCache::GetUnionTextRects(uint32_t
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("ContentCache: 0x%p (mIsChrome=%s) 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));
 
+  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) {
@@ -806,22 +812,44 @@ ContentCache::GetUnionTextRects(uint32_t
     }
     if (aOffset == mSelection.mFocus) {
       NS_WARN_IF(mSelection.mFocusCharRect.IsEmpty());
       aUnionTextRect = mSelection.mFocusCharRect;
       return !aUnionTextRect.IsEmpty();
     }
   }
 
-  if (!mTextRectArray.InRange(aOffset, aLength)) {
-    aUnionTextRect.SetEmpty();
+  // 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;
   }
-  aUnionTextRect = mTextRectArray.GetUnionRect(aOffset, aLength);
-  return true;
+
+  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();
 }
 
 bool
 ContentCache::GetCaretRect(uint32_t aOffset,
                            LayoutDeviceIntRect& aCaretRect) const
 {
   MOZ_LOG(sContentCacheLog, LogLevel::Info,
     ("ContentCache: 0x%p (mIsChrome=%s) GetCaretRect(aOffset=%u), "
@@ -989,9 +1017,26 @@ ContentCache::TextRectArray::GetUnionRec
     return rect;
   }
   for (uint32_t i = 0; i < aLength; i++) {
     rect = rect.Union(mRects[aOffset - mStart + i]);
   }
   return rect;
 }
 
+LayoutDeviceIntRect
+ContentCache::TextRectArray::GetUnionRectAsFarAsPossible(
+                               uint32_t aOffset,
+                               uint32_t aLength) const
+{
+  LayoutDeviceIntRect rect;
+  if (!IsOverlappingWith(aOffset, aLength)) {
+    return rect;
+  }
+  uint32_t startOffset = std::max(aOffset, mStart);
+  uint32_t endOffset = std::min(aOffset + aLength, EndOffset());
+  for (uint32_t i = 0; i < endOffset - startOffset; i++) {
+    rect = rect.Union(mRects[startOffset - mStart + i]);
+  }
+  return rect;
+}
+
 } // namespace mozilla
--- a/widget/ContentCache.h
+++ b/widget/ContentCache.h
@@ -308,18 +308,32 @@ private:
     {
       CheckedInt<uint32_t> endOffset =
         CheckedInt<uint32_t>(aOffset) + aLength;
       if (NS_WARN_IF(!endOffset.isValid())) {
         return false;
       }
       return InRange(aOffset) && aOffset + aLength <= EndOffset();
     }
+    bool IsOverlappingWith(uint32_t aOffset, uint32_t aLength) const
+    {
+      if (!IsValid() || aOffset == UINT32_MAX) {
+        return false;
+      }
+      CheckedInt<uint32_t> endOffset =
+        CheckedInt<uint32_t>(aOffset) + aLength;
+      if (NS_WARN_IF(!endOffset.isValid())) {
+        return false;
+      }
+      return aOffset <= EndOffset() && endOffset.value() >= mStart;
+    }
     LayoutDeviceIntRect GetRect(uint32_t aOffset) const;
     LayoutDeviceIntRect GetUnionRect(uint32_t aOffset, uint32_t aLength) const;
+    LayoutDeviceIntRect GetUnionRectAsFarAsPossible(uint32_t aOffset,
+                                                    uint32_t aLength) const;
   } mTextRectArray;
 
   LayoutDeviceIntRect mEditorRect;
 
   // mIsComposing is valid only in chrome process.
   bool mIsComposing;
   // mRequestedToCommitOrCancelComposition is valid only in chrome process.
   bool mRequestedToCommitOrCancelComposition;