Reviewed by Sam Weinig.

        - fix <rdar://problem/5842247> Single long breakable word takes O(n^2) to lay out

        Cache the next breakable position for text nodes in InlineIterator.

        * rendering/bidi.cpp:
        (WebCore::InlineIterator::InlineIterator):
        (WebCore::InlineIterator::increment):
        (WebCore::RenderBlock::findNextLineBreak):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@36447 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index 6b43af2..b4042c3 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,16 @@
+2008-09-15  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        - fix <rdar://problem/5842247> Single long breakable word takes O(n^2) to lay out
+
+        Cache the next breakable position for text nodes in InlineIterator.
+
+        * rendering/bidi.cpp:
+        (WebCore::InlineIterator::InlineIterator):
+        (WebCore::InlineIterator::increment):
+        (WebCore::RenderBlock::findNextLineBreak):
+
 2008-09-15  Simon Fraser  <simon.fraser@apple.com>
 
         Reviewed by Dan Bernstein
diff --git a/WebCore/rendering/bidi.cpp b/WebCore/rendering/bidi.cpp
index f1d3d5d..a64d632 100644
--- a/WebCore/rendering/bidi.cpp
+++ b/WebCore/rendering/bidi.cpp
@@ -52,6 +52,7 @@
         : block(0)
         , obj(0)
         , pos(0)
+        , nextBreakablePosition(-1)
     {
     }
 
@@ -59,6 +60,7 @@
         : block(b)
         , obj(o)
         , pos(p)
+        , nextBreakablePosition(-1)
     {
     }
 
@@ -71,6 +73,7 @@
     RenderBlock* block;
     RenderObject* obj;
     unsigned pos;
+    int nextBreakablePosition;
 };
 
 // Midpoint globals.  The goal is not to do any allocation when dealing with
@@ -270,10 +273,12 @@
         if (pos >= static_cast<RenderText*>(obj)->textLength()) {
             obj = bidiNext(block, obj, resolver);
             pos = 0;
+            nextBreakablePosition = -1;
         }
     } else {
         obj = bidiNext(block, obj, resolver);
         pos = 0;
+        nextBreakablePosition = -1;
     }
 }
 
@@ -1582,6 +1587,7 @@
     RenderObject *o = resolver.position().obj;
     RenderObject *last = o;
     unsigned pos = resolver.position().pos;
+    int nextBreakable = resolver.position().nextBreakablePosition;
     bool atStart = true;
 
     bool prevLineBrokeCleanly = previousLineBrokeCleanly;
@@ -1616,6 +1622,7 @@
             if (w + tmpW <= width) {
                 lBreak.obj = o;
                 lBreak.pos = 0;
+                lBreak.nextBreakablePosition = -1;
                 lBreak.increment();
 
                 // A <br> always breaks a line, so don't let the line be collapsed
@@ -1717,6 +1724,7 @@
                 tmpW = 0;
                 lBreak.obj = o;
                 lBreak.pos = 0;
+                lBreak.nextBreakablePosition = -1;
             }
 
             if (ignoringSpaces)
@@ -1758,7 +1766,6 @@
 
             int wrapW = tmpW + inlineWidth(o, !appliedStartWidth, true);
             int charWidth = 0;
-            int nextBreakable = -1;
             bool breakNBSP = autoWrap && o->style()->nbspMode() == SPACE;
             // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
             // which is only possible if the word is the first thing on the line, that is, if |w| is zero.
@@ -1771,6 +1778,7 @@
                 tmpW = 0;
                 lBreak.obj = o;
                 lBreak.pos = 0;
+                lBreak.nextBreakablePosition = -1;
                 ASSERT(!len);
             }
 
@@ -1876,6 +1884,7 @@
                                 lineWasTooWide = true;
                                 lBreak.obj = o;
                                 lBreak.pos = pos;
+                                lBreak.nextBreakablePosition = nextBreakable;
                                 skipTrailingWhitespace(lBreak);
                             }
                         }
@@ -1907,6 +1916,7 @@
                         }
                         lBreak.obj = o;
                         lBreak.pos = pos;
+                        lBreak.nextBreakablePosition = nextBreakable;
                         lBreak.increment();
                         previousLineBrokeCleanly = true;
                         return lBreak;
@@ -1918,6 +1928,7 @@
                         tmpW = 0;
                         lBreak.obj = o;
                         lBreak.pos = pos;
+                        lBreak.nextBreakablePosition = nextBreakable;
                         // Auto-wrapping text should not wrap in the middle of a word once it has had an
                         // opportunity to break after a word.
                         breakWords = false;
@@ -1928,6 +1939,7 @@
                         // adding the end width forces a break.
                         lBreak.obj = o;
                         lBreak.pos = pos;
+                        lBreak.nextBreakablePosition = nextBreakable;
                         midWordBreak &= (breakWords || breakAll);
                     }
 
@@ -1967,6 +1979,7 @@
                     if (autoWrap && o->style()->breakOnlyAfterWhiteSpace()) {
                         lBreak.obj = o;
                         lBreak.pos = pos;
+                        lBreak.nextBreakablePosition = nextBreakable;
                     }
                 }
                 
@@ -2018,6 +2031,7 @@
                         tmpW = 0;
                         lBreak.obj = next;
                         lBreak.pos = 0;
+                        lBreak.nextBreakablePosition = -1;
                     }
                 }
             }
@@ -2047,10 +2061,12 @@
                 tmpW = 0;
                 lBreak.obj = next;
                 lBreak.pos = 0;
+                lBreak.nextBreakablePosition = -1;
             }
         }
 
         o = next;
+        nextBreakable = -1;
 
         // Clear out our character space bool, since inline <pre>s don't collapse whitespace
         // with adjacent inline normal/nowrap spans.
@@ -2065,6 +2081,7 @@
     if (w + tmpW <= width || lastWS == NOWRAP) {
         lBreak.obj = 0;
         lBreak.pos = 0;
+        lBreak.nextBreakablePosition = -1;
     }
 
  end:
@@ -2079,18 +2096,21 @@
             } else {
                 lBreak.obj = last;
                 lBreak.pos = last->isText() ? last->length() : 0;
+                lBreak.nextBreakablePosition = -1;
             }
         } else if (lBreak.obj) {
             if (last != o && !last->isListMarker()) {
                 // better to break between object boundaries than in the middle of a word (except for list markers)
                 lBreak.obj = o;
                 lBreak.pos = 0;
+                lBreak.nextBreakablePosition = -1;
             } else {
                 // Don't ever break in the middle of a word if we can help it.
                 // There's no room at all. We just have to be on this line,
                 // even though we'll spill out.
                 lBreak.obj = o;
                 lBreak.pos = pos;
+                lBreak.nextBreakablePosition = -1;
             }
         }
     }