Bug 1114297 - Improve performance of nsTreeBodyFrame::AdjustForCellText for very long strings; r=smontagu
authorGeoff Lankow <geoff@darktrojan.net>
Sun, 11 Jan 2015 00:07:58 +1300
changeset 223120 2552e114980df1e982aecaf7ebfbfffaab1be534
parent 223119 6a2b37d4c1e223f225b695b4a4d962a735877dac
child 223121 f5a5f74632247cbd336a486955a0c6aa1e141d89
push id28082
push usercbook@mozilla.com
push dateMon, 12 Jan 2015 10:44:52 +0000
treeherdermozilla-central@643589c3ef94 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmontagu
bugs1114297
milestone37.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 1114297 - Improve performance of nsTreeBodyFrame::AdjustForCellText for very long strings; r=smontagu
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/xul/tree/nsTreeBodyFrame.cpp
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5116,16 +5116,38 @@ nsLayoutUtils::AppUnitWidthOfStringBidi(
   }
   aFontMetrics.SetTextRunRTL(false);
   aFontMetrics.SetVertical(aFrame->GetWritingMode().IsVertical());
   aFontMetrics.SetTextOrientation(aFrame->StyleVisibility()->mTextOrientation);
   return nsLayoutUtils::AppUnitWidthOfString(aString, aLength, aFontMetrics,
                                              aContext);
 }
 
+bool
+nsLayoutUtils::StringWidthIsGreaterThan(const nsString& aString,
+                                        nsFontMetrics& aFontMetrics,
+                                        nsRenderingContext& aContext,
+                                        nscoord aWidth)
+{
+  const char16_t *string = aString.get();
+  uint32_t length = aString.Length();
+  uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
+  nscoord width = 0;
+  while (length > 0) {
+    int32_t len = FindSafeLength(string, length, maxChunkLength);
+    width += aFontMetrics.GetWidth(string, len, &aContext);
+    if (width > aWidth) {
+      return true;
+    }
+    length -= len;
+    string += len;
+  }
+  return false;
+}
+
 nsBoundingMetrics
 nsLayoutUtils::AppUnitBoundsOfString(const char16_t* aString,
                                      uint32_t aLength,
                                      nsFontMetrics& aFontMetrics,
                                      nsRenderingContext& aContext)
 {
   uint32_t maxChunkLength = GetMaxChunkLength(aFontMetrics);
   int32_t len = FindSafeLength(aString, aLength, maxChunkLength);
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1481,16 +1481,21 @@ public:
                                                    aFontMetrics, aContext);
   }
   static nscoord AppUnitWidthOfStringBidi(const char16_t* aString,
                                           uint32_t aLength,
                                           const nsIFrame* aFrame,
                                           nsFontMetrics& aFontMetrics,
                                           nsRenderingContext& aContext);
 
+  static bool StringWidthIsGreaterThan(const nsString& aString,
+                                       nsFontMetrics& aFontMetrics,
+                                       nsRenderingContext& aContext,
+                                       nscoord aWidth);
+
   static nsBoundingMetrics AppUnitBoundsOfString(const char16_t* aString,
                                                  uint32_t aLength,
                                                  nsFontMetrics& aFontMetrics,
                                                  nsRenderingContext& aContext);
 
   static void DrawString(const nsIFrame*       aFrame,
                          nsFontMetrics&        aFontMetrics,
                          nsRenderingContext*   aContext,
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -1314,25 +1314,26 @@ void
 nsTreeBodyFrame::AdjustForCellText(nsAutoString& aText,
                                    int32_t aRowIndex,  nsTreeColumn* aColumn,
                                    nsRenderingContext& aRenderingContext,
                                    nsFontMetrics& aFontMetrics,
                                    nsRect& aTextRect)
 {
   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
 
-  nscoord width = nsLayoutUtils::AppUnitWidthOfStringBidi(aText, this,
-                                                          aFontMetrics,
-                                                          aRenderingContext);
   nscoord maxWidth = aTextRect.width;
+  bool widthIsGreater = nsLayoutUtils::StringWidthIsGreaterThan(aText,
+                                                                aFontMetrics,
+                                                                aRenderingContext,
+                                                                maxWidth);
 
   if (aColumn->Overflow()) {
     DebugOnly<nsresult> rv;
     nsTreeColumn* nextColumn = aColumn->GetNext();
-    while (nextColumn && width > maxWidth) {
+    while (nextColumn && widthIsGreater) {
       while (nextColumn) {
         nscoord width;
         rv = nextColumn->GetWidthInTwips(this, &width);
         NS_ASSERTION(NS_SUCCEEDED(rv), "nextColumn is invalid");
 
         if (width != 0)
           break;
 
@@ -1346,27 +1347,32 @@ nsTreeBodyFrame::AdjustForCellText(nsAut
         // bidi-ness
 
         if (nextText.Length() == 0) {
           nscoord width;
           rv = nextColumn->GetWidthInTwips(this, &width);
           NS_ASSERTION(NS_SUCCEEDED(rv), "nextColumn is invalid");
 
           maxWidth += width;
+          widthIsGreater = nsLayoutUtils::StringWidthIsGreaterThan(aText,
+                                                                   aFontMetrics,
+                                                                   aRenderingContext,
+                                                                   maxWidth);
 
           nextColumn = nextColumn->GetNext();
         }
         else {
           nextColumn = nullptr;
         }
       }
     }
   }
 
-  if (width > maxWidth) {
+  nscoord width;
+  if (widthIsGreater) {
     // See if the width is even smaller than the ellipsis
     // If so, clear the text completely.
     const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
     aFontMetrics.SetTextRunRTL(false);
     nscoord ellipsisWidth =
       nsLayoutUtils::AppUnitWidthOfString(kEllipsis, aFontMetrics,
                                           aRenderingContext);
 
@@ -1453,21 +1459,21 @@ nsTreeBodyFrame::AdjustForCellText(nsAut
           }
           aText = leftStr;
           aText.Append(kEllipsis);
           aText += rightStr;
         }
         break;
       }
     }
-
-    width = nsLayoutUtils::AppUnitWidthOfStringBidi(aText, this, aFontMetrics,
-                                                    aRenderingContext);
   }
 
+  width = nsLayoutUtils::AppUnitWidthOfStringBidi(aText, this, aFontMetrics,
+                                                  aRenderingContext);
+
   switch (aColumn->GetTextAlignment()) {
     case NS_STYLE_TEXT_ALIGN_RIGHT: {
       aTextRect.x += aTextRect.width - width;
     }
     break;
     case NS_STYLE_TEXT_ALIGN_CENTER: {
       aTextRect.x += (aTextRect.width - width) / 2;
     }