Reviewed by Hyatt.
authorantti <antti@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 11 Mar 2007 11:14:34 +0000 (11:14 +0000)
committerantti <antti@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 11 Mar 2007 11:14:34 +0000 (11:14 +0000)
        Optimize linebox memory consumption:
        - move all bitfields to baseclass compacting them
        - make InlineTextBox::m_truncation unsigned short and make it relative to m_start
        - remove extremely rarely used EllipsisBox pointer from RootInlineBox and instead
          use a global hashmap to store it if needed
        - use minimum required number of bits to store BidiStatus enum variables in RootInlineBox
        - move overflow variables in RootInlineBox to a separate struct that is instantiated
          only if any of the variables is set to a value that can't trivially be derived from
          box x, y, width and height

        As a result line box objects shrink:
            InlineBox: 44 -> 44 bytes
            InlineTextBox: 68 -> 60 bytes
            InlineFlowBox: 68 -> 64 bytes
            RootInlineBox: 128 -> 88 bytes

        The optimizations possiblity was noticed when debugging http://bugs.webkit.org/show_bug.cgi?id=12833
        Bug 12833: REGRESSION: Selecting text in 6.6MB txt file is sluggish as of the Feb 19th nightly
        <rdar://problem/5028159>

        On that page the patch saves 11.5MB or some 21% of linebox memory consumption. It also
        actually improves selection performance somewhat by improving memory locality.

        * rendering/InlineBox.h:
        (WebCore::InlineBox::InlineBox):
        * rendering/InlineFlowBox.h:
        (WebCore::InlineFlowBox::InlineFlowBox):
        * rendering/InlineTextBox.cpp:
        (WebCore::InlineTextBox::placeEllipsisBox):
        (WebCore::InlineTextBox::nodeAtPoint):
        (WebCore::InlineTextBox::paint):
        (WebCore::InlineTextBox::paintDecoration):
        (WebCore::InlineTextBox::paintSpellingOrGrammarMarker):
        (WebCore::InlineTextBox::paintMarkedTextUnderline):
        * rendering/InlineTextBox.h:
        (WebCore::InlineTextBox::InlineTextBox):
        * rendering/RootInlineBox.cpp:
        (WebCore::throw):
        (WebCore::RootInlineBox::Overflow::operator delete):
        (WebCore::RootInlineBox::Overflow::destroy):
        (WebCore::RootInlineBox::destroy):
        (WebCore::RootInlineBox::detachEllipsisBox):
        (WebCore::RootInlineBox::clearTruncation):
        (WebCore::RootInlineBox::placeEllipsis):
        (WebCore::RootInlineBox::paintEllipsisBox):
        (WebCore::RootInlineBox::addHighlightOverflow):
        (WebCore::RootInlineBox::nodeAtPoint):
        (WebCore::RootInlineBox::adjustPosition):
        (WebCore::RootInlineBox::selectionTop):
        (WebCore::RootInlineBox::setLineBreakInfo):
        (WebCore::RootInlineBox::ellipsisBox):
        (WebCore::RootInlineBox::setVerticalOverflowPositions):
        (WebCore::RootInlineBox::setHorizontalOverflowPositions):
        (WebCore::RootInlineBox::setVerticalSelectionPositions):
        * rendering/RootInlineBox.h:
        (WebCore::RootInlineBox::RootInlineBox):
        (WebCore::RootInlineBox::topOverflow):
        (WebCore::RootInlineBox::bottomOverflow):
        (WebCore::RootInlineBox::leftOverflow):
        (WebCore::RootInlineBox::rightOverflow):
        (WebCore::RootInlineBox::lineBreakBidiStatus):
        (WebCore::RootInlineBox::selectionBottom):
        (WebCore::RootInlineBox::Overflow::Overflow):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@20103 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/rendering/InlineBox.h
WebCore/rendering/InlineFlowBox.h
WebCore/rendering/InlineTextBox.cpp
WebCore/rendering/InlineTextBox.h
WebCore/rendering/RootInlineBox.cpp
WebCore/rendering/RootInlineBox.h

index e279f49d64b3c9441ceaf021bc7bec20145fab1c..1911480ab5eea4eefd533af254ed6924264aee0d 100644 (file)
@@ -1,3 +1,71 @@
+2007-03-11  Antti Koivisto  <antti@apple.com>
+
+        Reviewed by Hyatt.
+
+        Optimize linebox memory consumption:
+        - move all bitfields to baseclass compacting them
+        - make InlineTextBox::m_truncation unsigned short and make it relative to m_start
+        - remove extremely rarely used EllipsisBox pointer from RootInlineBox and instead
+          use a global hashmap to store it if needed
+        - use minimum required number of bits to store BidiStatus enum variables in RootInlineBox
+        - move overflow variables in RootInlineBox to a separate struct that is instantiated
+          only if any of the variables is set to a value that can't trivially be derived from 
+          box x, y, width and height
+          
+        As a result line box objects shrink:
+            InlineBox: 44 -> 44 bytes
+            InlineTextBox: 68 -> 60 bytes
+            InlineFlowBox: 68 -> 64 bytes
+            RootInlineBox: 128 -> 88 bytes
+            
+        The optimizations possiblity was noticed when debugging http://bugs.webkit.org/show_bug.cgi?id=12833
+        Bug 12833: REGRESSION: Selecting text in 6.6MB txt file is sluggish as of the Feb 19th nightly
+        <rdar://problem/5028159>
+        
+        On that page the patch saves 11.5MB or some 21% of linebox memory consumption. It also
+        actually improves selection performance somewhat by improving memory locality.
+
+        * rendering/InlineBox.h:
+        (WebCore::InlineBox::InlineBox):
+        * rendering/InlineFlowBox.h:
+        (WebCore::InlineFlowBox::InlineFlowBox):
+        * rendering/InlineTextBox.cpp:
+        (WebCore::InlineTextBox::placeEllipsisBox):
+        (WebCore::InlineTextBox::nodeAtPoint):
+        (WebCore::InlineTextBox::paint):
+        (WebCore::InlineTextBox::paintDecoration):
+        (WebCore::InlineTextBox::paintSpellingOrGrammarMarker):
+        (WebCore::InlineTextBox::paintMarkedTextUnderline):
+        * rendering/InlineTextBox.h:
+        (WebCore::InlineTextBox::InlineTextBox):
+        * rendering/RootInlineBox.cpp:
+        (WebCore::throw):
+        (WebCore::RootInlineBox::Overflow::operator delete):
+        (WebCore::RootInlineBox::Overflow::destroy):
+        (WebCore::RootInlineBox::destroy):
+        (WebCore::RootInlineBox::detachEllipsisBox):
+        (WebCore::RootInlineBox::clearTruncation):
+        (WebCore::RootInlineBox::placeEllipsis):
+        (WebCore::RootInlineBox::paintEllipsisBox):
+        (WebCore::RootInlineBox::addHighlightOverflow):
+        (WebCore::RootInlineBox::nodeAtPoint):
+        (WebCore::RootInlineBox::adjustPosition):
+        (WebCore::RootInlineBox::selectionTop):
+        (WebCore::RootInlineBox::setLineBreakInfo):
+        (WebCore::RootInlineBox::ellipsisBox):
+        (WebCore::RootInlineBox::setVerticalOverflowPositions):
+        (WebCore::RootInlineBox::setHorizontalOverflowPositions):
+        (WebCore::RootInlineBox::setVerticalSelectionPositions):
+        * rendering/RootInlineBox.h:
+        (WebCore::RootInlineBox::RootInlineBox):
+        (WebCore::RootInlineBox::topOverflow):
+        (WebCore::RootInlineBox::bottomOverflow):
+        (WebCore::RootInlineBox::leftOverflow):
+        (WebCore::RootInlineBox::rightOverflow):
+        (WebCore::RootInlineBox::lineBreakBidiStatus):
+        (WebCore::RootInlineBox::selectionBottom):
+        (WebCore::RootInlineBox::Overflow::Overflow):
+
 2007-03-11  Alexey Proskuryakov  <ap@webkit.org>
 
         Reviewed by Darin.
index 5ed37d3d8d4327db6da5f2919d595696066f606c..69a0afc3dc4a3c5d22b788f75ffb1b532afeee41 100644 (file)
@@ -43,13 +43,22 @@ public:
         , m_width(0)
         , m_height(0)
         , m_baseline(0)
+        , m_next(0)
+        , m_prev(0)
+        , m_parent(0)
         , m_firstLine(false)
         , m_constructed(false)
         , m_dirty(false)
         , m_extracted(false)
-        , m_next(0)
-        , m_prev(0)
-        , m_parent(0)
+        , m_includeLeftEdge(false)
+        , m_includeRightEdge(false)
+        , m_hasTextChildren(false)
+        , m_endsWithBreak(false)
+        , m_hasSelectedChildren(false)
+        , m_hasEllipsisBox(false)
+        , m_reversed(false)
+        , m_treatAsText(true)
+        , m_toAdd(0)
     {
     }
 
@@ -61,13 +70,22 @@ public:
         , m_width(width)
         , m_height(height)
         , m_baseline(baseline)
+        , m_next(next)
+        , m_prev(prev)
+        , m_parent(parent)
         , m_firstLine(firstLine)
         , m_constructed(constructed)
         , m_dirty(dirty)
         , m_extracted(extracted)
-        , m_next(next)
-        , m_prev(prev)
-        , m_parent(parent)
+        , m_includeLeftEdge(false)
+        , m_includeRightEdge(false)
+        , m_hasTextChildren(false)
+        , m_endsWithBreak(false)
+        , m_hasSelectedChildren(false)   
+        , m_hasEllipsisBox(false)
+        , m_reversed(false)
+        , m_treatAsText(true)
+        , m_toAdd(0)
     {
     }
 
@@ -192,15 +210,30 @@ public: // FIXME: Would like to make this protected, but methods are accessing t
     int m_height;
     int m_baseline;
 
+    InlineBox* m_next; // The next element on the same line as us.
+    InlineBox* m_prev; // The previous element on the same line as us.
+    
+    InlineFlowBox* m_parent; // The box that contains us.
+    
+    // Some of these bits are actually for subclasses and moved here to compact the structures.
+    // for this class
     bool m_firstLine : 1;
     bool m_constructed : 1;
     bool m_dirty : 1;
     bool m_extracted : 1;
-
-    InlineBox* m_next; // The next element on the same line as us.
-    InlineBox* m_prev; // The previous element on the same line as us.
-
-    InlineFlowBox* m_parent; // The box that contains us.
+    // for InlineFlowBox
+    bool m_includeLeftEdge : 1;
+    bool m_includeRightEdge : 1;
+    bool m_hasTextChildren : 1;
+    // for RootInlineBox
+    bool m_endsWithBreak : 1;  // Whether the line ends with a <br>.
+    bool m_hasSelectedChildren : 1; // Whether we have any children selected (this bit will also be set if the <br> that terminates our line is selected).
+    bool m_hasEllipsisBox : 1; 
+    // for InlineTextBox
+    bool m_reversed : 1;
+    bool m_dirOverride : 1;
+    bool m_treatAsText : 1; // Whether or not to treat a <br> as text for the purposes of line height.
+    int m_toAdd : 13; // for justified text
 };
 
 } // namespace WebCore
index b86672a491858ab5759b4f06d91cc060d7e39c7d..edf99466f026cdfb002f347f6c3ead32c6d3645f 100644 (file)
@@ -38,9 +38,6 @@ public:
         , m_firstChild(0)
         , m_lastChild(0)
         , m_maxHorizontalVisualOverflow(0)
-        , m_includeLeftEdge(false)
-        , m_includeRightEdge(false)
-        , m_hasTextChildren(false)
     {
     }
 
@@ -132,9 +129,6 @@ protected:
     InlineBox* m_firstChild;
     InlineBox* m_lastChild;
     int m_maxHorizontalVisualOverflow;
-    bool m_includeLeftEdge : 1;
-    bool m_includeRightEdge : 1;
-    bool m_hasTextChildren : 1;
 };
 
 } // namespace WebCore
index fb53d2db43c34e5d8a0fdb9815bba85fdcf39760..adf2fce13a18e6e94cffe862f1bd91e188fb7772 100644 (file)
@@ -186,7 +186,7 @@ int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth,
             }
             
             // Set the truncation index on the text run.  The ellipsis needs to be placed just after the last visible character.
-            m_truncation = offset + m_start;
+            m_truncation = offset;
             return m_x + static_cast<RenderText*>(m_object)->width(m_start, offset, textPos(), m_firstLine);
         }
     }
@@ -414,7 +414,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
         // for non-reversed LTR strings.
         int endPoint = m_len;
         if (m_truncation != cNoTruncation)
-            endPoint = m_truncation - m_start;
+            endPoint = m_truncation;
         paintInfo.context->drawText(TextRun(textStr, m_start, endPoint), IntPoint(m_x + tx, m_y + ty + m_baseline), textStyle);
     } else {
         int sPos, ePos;
@@ -576,7 +576,7 @@ void InlineTextBox::paintDecoration(GraphicsContext* context, int tx, int ty, in
         return;
     
     int width = (m_truncation == cNoTruncation) ? m_width
-        : static_cast<RenderText*>(m_object)->width(m_start, m_truncation - m_start, textPos(), m_firstLine);
+        : static_cast<RenderText*>(m_object)->width(m_start, m_truncation, textPos(), m_firstLine);
     
     // Get the text decoration colors.
     Color underline, overline, linethrough;
@@ -623,7 +623,7 @@ void InlineTextBox::paintSpellingOrGrammarMarker(GraphicsContext* pt, int tx, in
         useWholeWidth = false;
     }
     if (m_truncation != cNoTruncation) {
-        paintEnd = min(paintEnd, (unsigned)m_truncation);
+        paintEnd = min(paintEnd, (unsigned)m_start + m_truncation);
         useWholeWidth = false;
     }
     if (!useWholeWidth) {
@@ -771,7 +771,7 @@ void InlineTextBox::paintMarkedTextUnderline(GraphicsContext* ctx, int tx, int t
         useWholeWidth = false;
     }
     if (m_truncation != cNoTruncation) {
-        paintEnd = min(paintEnd, (unsigned)m_truncation);
+        paintEnd = min(paintEnd, (unsigned)m_start + m_truncation);
         useWholeWidth = false;
     }
     if (!useWholeWidth) {
index 9bf6a9f2afea7017beffeea0dc1a99be25b4dd4b..fb5ded3a6309648bcd6530680cff7a9047f3fafd 100644 (file)
@@ -31,8 +31,8 @@
 
 namespace WebCore {
 
-const int cNoTruncation = -1;
-const int cFullTruncation = -2;
+const unsigned short cNoTruncation = USHRT_MAX;
+const unsigned short cFullTruncation = USHRT_MAX - 1;
 
 class String;
 class StringImpl;
@@ -47,9 +47,6 @@ public:
         , m_start(0)
         , m_len(0)
         , m_truncation(cNoTruncation)
-        , m_reversed(false)
-        , m_treatAsText(true)
-        , m_toAdd(0)
     {
     }
 
@@ -132,14 +129,9 @@ public:
     int m_start;
     unsigned short m_len;
 
-    int m_truncation; // Where to truncate when text overflow is applied.  We use special constants to
+    unsigned short m_truncation; // Where to truncate when text overflow is applied.  We use special constants to
                       // denote no truncation (the whole run paints) and full truncation (nothing paints at all).
 
-    bool m_reversed : 1;
-    bool m_dirOverride : 1;
-    bool m_treatAsText : 1; // Whether or not to treat a <br> as text for the purposes of line height.
-    int m_toAdd : 13; // for justified text
-
 private:
     friend class RenderText;
 };
index d369ba32b147617383483a38df2c840aab591a68..702c5dd5ad57d4362c6bd3f7e0e7e9928db5125d 100644 (file)
 #include "Frame.h"
 #include "GraphicsContext.h"
 #include "HitTestResult.h"
+#include "RenderArena.h"
 #include "RenderBlock.h"
 
 using namespace std;
 
 namespace WebCore {
+    
+typedef WTF::HashMap<const RootInlineBox*, EllipsisBox*> EllipsisBoxMap;
+static EllipsisBoxMap* gEllipsisBoxMap = 0;
+
+void* RootInlineBox::Overflow::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+    return renderArena->allocate(sz);
+}
+
+void RootInlineBox::Overflow::operator delete(void* ptr, size_t sz)
+{
+    // Stash size where destroy can find it.
+    *(size_t *)ptr = sz;
+}
+
+void RootInlineBox::Overflow::destroy(RenderArena* renderArena)
+{
+    delete this;
+    // Recover the size left there for us by operator delete and free the memory.
+    renderArena->free(*(size_t *)this, this);
+}
 
 void RootInlineBox::destroy(RenderArena* arena)
 {
+    if (m_overflow)
+        m_overflow->destroy(arena);
     detachEllipsisBox(arena);
     InlineFlowBox::destroy(arena);
 }
 
 void RootInlineBox::detachEllipsisBox(RenderArena* arena)
 {
-    if (m_ellipsisBox) {
-        m_ellipsisBox->destroy(arena);
-        m_ellipsisBox = 0;
+    if (m_hasEllipsisBox) {
+        EllipsisBoxMap::iterator it = gEllipsisBoxMap->find(this);
+        it->second->destroy(arena);
+        gEllipsisBoxMap->remove(it);
+        m_hasEllipsisBox = false;
     }
 }
 
 void RootInlineBox::clearTruncation()
 {
-    if (m_ellipsisBox) {
+    if (m_hasEllipsisBox) {
         detachEllipsisBox(m_object->renderArena());
         InlineFlowBox::clearTruncation();
     }
@@ -71,13 +97,18 @@ void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr,  bool ltr, in
                                   InlineBox* markupBox)
 {
     // Create an ellipsis box.
-    m_ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this,
+    EllipsisBox* ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this,
                                                               ellipsisWidth - (markupBox ? markupBox->width() : 0),
                                                               yPos(), height(), baseline(), !prevRootBox(),
                                                               markupBox);
+    
+    if (!gEllipsisBoxMap)
+        gEllipsisBoxMap = new EllipsisBoxMap();
+    gEllipsisBoxMap->add(this, ellipsisBox);
+    m_hasEllipsisBox = true;
 
     if (ltr && (xPos() + width() + ellipsisWidth) <= blockEdge) {
-        m_ellipsisBox->m_x = xPos() + width();
+        ellipsisBox->m_x = xPos() + width();
         return;
     }
 
@@ -85,7 +116,7 @@ void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr,  bool ltr, in
     // of that glyph.  Mark all of the objects that intersect the ellipsis box as not painting (as being
     // truncated).
     bool foundBox = false;
-    m_ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
+    ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
 }
 
 int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
@@ -98,9 +129,9 @@ int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth,
 
 void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo& paintInfo, int tx, int ty) const
 {
-    if (m_ellipsisBox && object()->shouldPaintWithinRoot(paintInfo) && object()->style()->visibility() == VISIBLE &&
+    if (m_hasEllipsisBox && object()->shouldPaintWithinRoot(paintInfo) && object()->style()->visibility() == VISIBLE &&
             paintInfo.phase == PaintPhaseForeground)
-        m_ellipsisBox->paint(paintInfo, tx, ty);
+        ellipsisBox()->paint(paintInfo, tx, ty);
 }
 
 #if PLATFORM(MAC)
@@ -109,10 +140,8 @@ void RootInlineBox::addHighlightOverflow()
     // Highlight acts as a selection inflation.
     FloatRect rootRect(0, selectionTop(), width(), selectionHeight());
     IntRect inflatedRect = enclosingIntRect(object()->document()->frame()->customHighlightLineRect(object()->style()->highlight(), rootRect, object()->node()));
-    m_leftOverflow = min(m_leftOverflow, inflatedRect.x());
-    m_rightOverflow = max(m_rightOverflow, inflatedRect.right());
-    m_topOverflow = min(m_topOverflow, inflatedRect.y());
-    m_bottomOverflow = max(m_bottomOverflow, inflatedRect.bottom());
+    setVerticalOverflowPositions(min(leftOverflow(), inflatedRect.x()), max(rightOverflow(), inflatedRect.right()));
+    setHorizontalOverflowPositions(min(topOverflow(), inflatedRect.y()), max(bottomOverflow(), inflatedRect.bottom()));
 }
 
 void RootInlineBox::paintCustomHighlight(RenderObject::PaintInfo& paintInfo, int tx, int ty, const AtomicString& highlightType)
@@ -141,8 +170,8 @@ void RootInlineBox::paint(RenderObject::PaintInfo& paintInfo, int tx, int ty)
 
 bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
 {
-    if (m_ellipsisBox && object()->style()->visibility() == VISIBLE) {
-        if (m_ellipsisBox->nodeAtPoint(request, result, x, y, tx, ty)) {
+    if (m_hasEllipsisBox && object()->style()->visibility() == VISIBLE) {
+        if (ellipsisBox()->nodeAtPoint(request, result, x, y, tx, ty)) {
             object()->updateHitTestResult(result, IntPoint(x - tx, y - ty));
             return true;
         }
@@ -153,11 +182,13 @@ bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re
 void RootInlineBox::adjustPosition(int dx, int dy)
 {
     InlineFlowBox::adjustPosition(dx, dy);
-    m_topOverflow += dy;
-    m_bottomOverflow += dy;
+    if (m_overflow) {
+        m_overflow->m_topOverflow += dy;
+        m_overflow->m_bottomOverflow += dy;
+        m_overflow->m_selectionTop += dy;
+        m_overflow->m_selectionBottom += dy;
+    }
     m_blockHeight += dy;
-    m_selectionTop += dy;
-    m_selectionBottom += dy;
 }
 
 void RootInlineBox::childRemoved(InlineBox* box)
@@ -259,20 +290,21 @@ InlineBox* RootInlineBox::lastSelectedBox()
 
 int RootInlineBox::selectionTop()
 {
+    int selectionTop = m_overflow ? m_overflow->m_selectionTop : m_y;
     if (!prevRootBox())
-        return m_selectionTop;
+        return selectionTop;
 
     int prevBottom = prevRootBox()->selectionBottom();
-    if (prevBottom < m_selectionTop && block()->containsFloats()) {
+    if (prevBottom < selectionTop && block()->containsFloats()) {
         // This line has actually been moved further down, probably from a large line-height, but possibly because the
         // line was forced to clear floats.  If so, let's check the offsets, and only be willing to use the previous
         // line's bottom overflow if the offsets are greater on both sides.
         int prevLeft = block()->leftOffset(prevBottom);
         int prevRight = block()->rightOffset(prevBottom);
-        int newLeft = block()->leftOffset(m_selectionTop);
-        int newRight = block()->rightOffset(m_selectionTop);
+        int newLeft = block()->leftOffset(selectionTop);
+        int newRight = block()->rightOffset(selectionTop);
         if (prevLeft > newLeft || prevRight < newRight)
-            return m_selectionTop;
+            return selectionTop;
     }
 
     return prevBottom;
@@ -319,8 +351,51 @@ void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, BidiS
     m_lineBreakObj = obj;
     m_lineBreakPos = breakPos;
     m_lineBreakContext = context;
-    if (status)
-        m_lineBreakBidiStatus = *status;
+    if (status) {
+        m_lineBreakBidiStatusEor = status->eor;
+        m_lineBreakBidiStatusLastStrong = status->lastStrong;
+        m_lineBreakBidiStatusLast = status->last;
+    }
+}
+
+EllipsisBox* RootInlineBox::ellipsisBox() const
+{
+    if (!m_hasEllipsisBox)
+        return false;
+    return gEllipsisBoxMap->get(this);
+}
+
+void RootInlineBox::setVerticalOverflowPositions(int top, int bottom) 
+{ 
+    if (!m_overflow) {
+        if (top == m_y && bottom == m_y + m_height)
+            return;
+        m_overflow = new (m_object->renderArena()) Overflow(this);
+    }
+    m_overflow->m_topOverflow = top; 
+    m_overflow->m_bottomOverflow = bottom; 
+}
+
+void RootInlineBox::setHorizontalOverflowPositions(int left, int right) 
+{ 
+    if (!m_overflow) {
+        if (left == m_x && right == m_x + m_width)
+            return;
+        m_overflow = new (m_object->renderArena()) Overflow(this);       
+    }
+    m_overflow->m_leftOverflow = left; 
+    m_overflow->m_rightOverflow = right; 
+}
+
+void RootInlineBox::setVerticalSelectionPositions(int top, int bottom) 
+{ 
+    if (!m_overflow) {
+        if (top == m_y && bottom == m_y + m_height)
+            return;
+        m_overflow = new (m_object->renderArena()) Overflow(this);
+    }
+    m_overflow->m_selectionTop = top; 
+    m_overflow->m_selectionBottom = bottom; 
 }
 
 } // namespace WebCore
index 6e674f3eeb5731b2c5afd8a629e4e93044c05621..c5e06f2317edadf30500402a504adb2e4c78d4bd 100644 (file)
@@ -36,17 +36,10 @@ class RootInlineBox : public InlineFlowBox {
 public:
     RootInlineBox(RenderObject* obj)
         : InlineFlowBox(obj)
-        , m_topOverflow(0)
-        , m_bottomOverflow(0)
-        , m_leftOverflow(0)
-        , m_rightOverflow(0)
+        , m_overflow(0)
         , m_lineBreakObj(0)
         , m_lineBreakPos(0)
         , m_lineBreakContext(0)
-        , m_blockHeight(0)
-        , m_endsWithBreak(false)
-        , m_hasSelectedChildren(false)
-        , m_ellipsisBox(0)
     {
     }
 
@@ -60,18 +53,24 @@ public:
 
     virtual void adjustPosition(int dx, int dy);
 
-    virtual int topOverflow() { return m_topOverflow; }
-    virtual int bottomOverflow() { return m_bottomOverflow; }
-    virtual int leftOverflow() { return m_leftOverflow; }
-    virtual int rightOverflow() { return m_rightOverflow; }
+    virtual int topOverflow() { return m_overflow ? m_overflow->m_topOverflow : m_y; }
+    virtual int bottomOverflow() { return m_overflow ? m_overflow->m_bottomOverflow : m_y + m_height; }
+    virtual int leftOverflow() { return m_overflow ? m_overflow->m_leftOverflow : m_x; }
+    virtual int rightOverflow() { return m_overflow ? m_overflow->m_rightOverflow : m_x + m_width; }
 
-    virtual void setVerticalOverflowPositions(int top, int bottom) { m_topOverflow = top; m_bottomOverflow = bottom; }
-    void setHorizontalOverflowPositions(int left, int right) { m_leftOverflow = left; m_rightOverflow = right; }
+    virtual void setVerticalOverflowPositions(int top, int bottom);
+    void setHorizontalOverflowPositions(int left, int right);
 
-    virtual void setVerticalSelectionPositions(int top, int bottom) { m_selectionTop = top; m_selectionBottom = bottom; }
+    virtual void setVerticalSelectionPositions(int top, int bottom);
 
     RenderObject* lineBreakObj() const { return m_lineBreakObj; }
-    BidiStatus lineBreakBidiStatus() const { return m_lineBreakBidiStatus; }
+    BidiStatus lineBreakBidiStatus() const { 
+        BidiStatus status;
+        status.eor = m_lineBreakBidiStatusEor;
+        status.lastStrong = m_lineBreakBidiStatusLastStrong;
+        status.last = m_lineBreakBidiStatusLast;
+        return status;
+    }
     BidiContext* lineBreakBidiContext() const { return m_lineBreakContext.get(); }
     void setLineBreakInfo(RenderObject*, unsigned breakPos, BidiStatus*, BidiContext*);
 
@@ -90,7 +89,7 @@ public:
     void placeEllipsis(const AtomicString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth, InlineBox* markupBox = 0);
     virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox);
 
-    EllipsisBox* ellipsisBox() const { return m_ellipsisBox; }
+    EllipsisBox* ellipsisBox() const;
 
     void paintEllipsisBox(RenderObject::PaintInfo&, int tx, int ty) const;
     bool hitTestEllipsisBox(HitTestResult&, int x, int y, int tx, int ty, HitTestAction, bool);
@@ -118,7 +117,7 @@ public:
     RenderBlock* block() const;
 
     int selectionTop();
-    int selectionBottom() { return m_selectionBottom; }
+    int selectionBottom() { return m_overflow ? m_overflow->m_selectionBottom : m_y + m_height; }
     int selectionHeight() { return max(0, selectionBottom() - selectionTop()); }
 
     InlineBox* closestLeafChildForXPos(int x);
@@ -127,34 +126,47 @@ protected:
     // Normally we are only as tall as the style on our block dictates, but we might have content
     // that spills out above the height of our font (e.g, a tall image), or something that extends further
     // below our line (e.g., a child whose font has a huge descent).
-    int m_topOverflow;
-    int m_bottomOverflow;
-    int m_leftOverflow;
-    int m_rightOverflow;
-
-    int m_selectionTop;
-    int m_selectionBottom;
+        
+    // Allocated only when some of these fields have non-default values
+    struct Overflow {
+        Overflow(RootInlineBox* box) 
+            : m_topOverflow(box->m_y)
+            , m_bottomOverflow(box->m_y + box->m_height)
+            , m_leftOverflow(box->m_x)
+            , m_rightOverflow(box->m_x + box->m_width)
+            , m_selectionTop(box->m_y)
+            , m_selectionBottom(box->m_y + box->m_height)
+            {
+            }
+        void destroy(RenderArena*);
+        void* operator new(size_t, RenderArena*) throw();
+        void operator delete(void*, size_t);
+        
+        int m_topOverflow;
+        int m_bottomOverflow;
+        int m_leftOverflow;
+        int m_rightOverflow;
+        int m_selectionTop;
+        int m_selectionBottom;
+    private:
+        void* operator new(size_t) throw();
+    };
+    
+    Overflow* m_overflow;
 
     // Where this line ended.  The exact object and the position within that object are stored so that
     // we can create a BidiIterator beginning just after the end of this line.
     RenderObject* m_lineBreakObj;
     unsigned m_lineBreakPos;
 
-    BidiStatus m_lineBreakBidiStatus;
     RefPtr<BidiContext> m_lineBreakContext;
 
     // The height of the block at the end of this line.  This is where the next line starts.
     int m_blockHeight;
 
-    // Whether the line ends with a <br>.
-    bool m_endsWithBreak : 1;
-
-    // Whether we have any children selected (this bit will also be set if the <br> that terminates our
-    // line is selected).
-    bool m_hasSelectedChildren : 1;
-
-    // An inline text box that represents our text truncation string.
-    EllipsisBox* m_ellipsisBox;
+    WTF::Unicode::Direction m_lineBreakBidiStatusEor : 5;
+    WTF::Unicode::Direction m_lineBreakBidiStatusLastStrong : 5;
+    WTF::Unicode::Direction m_lineBreakBidiStatusLast : 5;
 };
 
 } // namespace WebCore