Reviewed by Hyatt.
authorantti <antti@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Apr 2007 01:01:09 +0000 (01:01 +0000)
committerantti <antti@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 3 Apr 2007 01:01:09 +0000 (01:01 +0000)
        Render tree memory savings, part 3

        These changes shrink all RenderBlocks by additional 28 bytes. Together with parts 1 and 2
        RenderBlock goes from 172 bytes to 128 bytes, a saving of 26%.

        - Pack bitfields together in RenderFlow
        - Move top/bottom min/max margin values to a struct that is only allocated in case these
          variables have non default values. Usually this is <5% of all blocks.
        - Move rarely used column variables to hash

        * rendering/RenderBlock.cpp:
        (WebCore::ColumnInfo::ColumnInfo):
        (WebCore::RenderBlock::RenderBlock):
        (WebCore::RenderBlock::~RenderBlock):
        (WebCore::RenderBlock::layoutBlock):
        (WebCore::RenderBlock::collapseMargins):
        (WebCore::RenderBlock::clearFloatsIfNeeded):
        (WebCore::RenderBlock::setCollapsedBottomMargin):
        (WebCore::RenderBlock::layoutBlockChildren):
        (WebCore::RenderBlock::paintColumns):
        (WebCore::RenderBlock::paintObject):
        (WebCore::RenderBlock::fillSelectionGaps):
        (WebCore::RenderBlock::lowestPosition):
        (WebCore::RenderBlock::rightmostPosition):
        (WebCore::RenderBlock::leftmostPosition):
        (WebCore::RenderBlock::nodeAtPoint):
        (WebCore::RenderBlock::hitTestColumns):
        (WebCore::RenderBlock::positionForCoordinates):
        (WebCore::RenderBlock::availableWidth):
        (WebCore::RenderBlock::calcColumnWidth):
        (WebCore::RenderBlock::setDesiredColumnCountAndWidth):
        (WebCore::RenderBlock::desiredColumnWidth):
        (WebCore::RenderBlock::desiredColumnCount):
        (WebCore::RenderBlock::columnRects):
        (WebCore::RenderBlock::layoutColumns):
        (WebCore::RenderBlock::adjustPointToColumnContents):
        (WebCore::RenderBlock::adjustRectForColumns):
        (WebCore::RenderBlock::setMaxTopMargins):
        (WebCore::RenderBlock::setMaxBottomMargins):
        * rendering/RenderBlock.h:
        (WebCore::RenderBlock::maxTopMargin):
        (WebCore::RenderBlock::maxBottomMargin):
        (WebCore::RenderBlock::maxTopPosMargin):
        (WebCore::RenderBlock::maxTopNegMargin):
        (WebCore::RenderBlock::maxBottomPosMargin):
        (WebCore::RenderBlock::maxBottomNegMargin):
        (WebCore::RenderBlock::initMaxMarginValues):
        (WebCore::RenderBlock::MaxMargin::MaxMargin):
        (WebCore::RenderBlock::MaxMargin::topPosDefault):
        (WebCore::RenderBlock::MaxMargin::topNegDefault):
        (WebCore::RenderBlock::MaxMargin::bottomPosDefault):
        (WebCore::RenderBlock::MaxMargin::bottomNegDefault):
        * rendering/RenderFlexibleBox.cpp:
        (WebCore::RenderFlexibleBox::layoutBlock):
        * rendering/RenderFlow.h:
        (WebCore::RenderFlow::RenderFlow):
        (WebCore::RenderFlow::hasColumns):
        * rendering/RenderInline.cpp:
        (WebCore::RenderInline::RenderInline):
        * rendering/RenderInline.h:

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

WebCore/ChangeLog
WebCore/rendering/RenderBlock.cpp
WebCore/rendering/RenderBlock.h
WebCore/rendering/RenderFlexibleBox.cpp
WebCore/rendering/RenderFlow.h
WebCore/rendering/RenderInline.cpp
WebCore/rendering/RenderInline.h

index b913fca8cc4787cc512439118033c3c83a1d7f5f..ba2364ac2230afafda84084c9c37307441c0f6fe 100644 (file)
@@ -1,3 +1,68 @@
+2007-04-03  Antti Koivisto  <antti@apple.com>
+
+        Reviewed by Hyatt.
+
+        Render tree memory savings, part 3
+        
+        These changes shrink all RenderBlocks by additional 28 bytes. Together with parts 1 and 2
+        RenderBlock goes from 172 bytes to 128 bytes, a saving of 26%.
+        
+        - Pack bitfields together in RenderFlow
+        - Move top/bottom min/max margin values to a struct that is only allocated in case these
+          variables have non default values. Usually this is <5% of all blocks. 
+        - Move rarely used column variables to hash
+
+        * rendering/RenderBlock.cpp:
+        (WebCore::ColumnInfo::ColumnInfo):
+        (WebCore::RenderBlock::RenderBlock):
+        (WebCore::RenderBlock::~RenderBlock):
+        (WebCore::RenderBlock::layoutBlock):
+        (WebCore::RenderBlock::collapseMargins):
+        (WebCore::RenderBlock::clearFloatsIfNeeded):
+        (WebCore::RenderBlock::setCollapsedBottomMargin):
+        (WebCore::RenderBlock::layoutBlockChildren):
+        (WebCore::RenderBlock::paintColumns):
+        (WebCore::RenderBlock::paintObject):
+        (WebCore::RenderBlock::fillSelectionGaps):
+        (WebCore::RenderBlock::lowestPosition):
+        (WebCore::RenderBlock::rightmostPosition):
+        (WebCore::RenderBlock::leftmostPosition):
+        (WebCore::RenderBlock::nodeAtPoint):
+        (WebCore::RenderBlock::hitTestColumns):
+        (WebCore::RenderBlock::positionForCoordinates):
+        (WebCore::RenderBlock::availableWidth):
+        (WebCore::RenderBlock::calcColumnWidth):
+        (WebCore::RenderBlock::setDesiredColumnCountAndWidth):
+        (WebCore::RenderBlock::desiredColumnWidth):
+        (WebCore::RenderBlock::desiredColumnCount):
+        (WebCore::RenderBlock::columnRects):
+        (WebCore::RenderBlock::layoutColumns):
+        (WebCore::RenderBlock::adjustPointToColumnContents):
+        (WebCore::RenderBlock::adjustRectForColumns):
+        (WebCore::RenderBlock::setMaxTopMargins):
+        (WebCore::RenderBlock::setMaxBottomMargins):
+        * rendering/RenderBlock.h:
+        (WebCore::RenderBlock::maxTopMargin):
+        (WebCore::RenderBlock::maxBottomMargin):
+        (WebCore::RenderBlock::maxTopPosMargin):
+        (WebCore::RenderBlock::maxTopNegMargin):
+        (WebCore::RenderBlock::maxBottomPosMargin):
+        (WebCore::RenderBlock::maxBottomNegMargin):
+        (WebCore::RenderBlock::initMaxMarginValues):
+        (WebCore::RenderBlock::MaxMargin::MaxMargin):
+        (WebCore::RenderBlock::MaxMargin::topPosDefault):
+        (WebCore::RenderBlock::MaxMargin::topNegDefault):
+        (WebCore::RenderBlock::MaxMargin::bottomPosDefault):
+        (WebCore::RenderBlock::MaxMargin::bottomNegDefault):
+        * rendering/RenderFlexibleBox.cpp:
+        (WebCore::RenderFlexibleBox::layoutBlock):
+        * rendering/RenderFlow.h:
+        (WebCore::RenderFlow::RenderFlow):
+        (WebCore::RenderFlow::hasColumns):
+        * rendering/RenderInline.cpp:
+        (WebCore::RenderInline::RenderInline):
+        * rendering/RenderInline.h:
+
 2007-04-03  Antti Koivisto  <antti@apple.com>
 
         Reviewed by Hyatt.
index 69a03b1b58587461a8494fca8dd078b45e8bab57..3cd18a14784bc7cefc96e3b64c94c423693a54d1 100644 (file)
@@ -52,6 +52,19 @@ const int verticalLineClickFudgeFactor= 3;
 
 using namespace HTMLNames;
 
+struct ColumnInfo {
+    ColumnInfo()
+        : m_desiredColumnWidth(0)
+        , m_desiredColumnCount(1)
+        { }
+    int m_desiredColumnWidth;
+    unsigned m_desiredColumnCount;
+    Vector<IntRect> m_columnRects;
+};
+
+typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
+static ColumnInfoMap* gColumnInfoMap = 0;
+
 // Our MarginInfo state used when laying out block children.
 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom)
 {
@@ -87,29 +100,28 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom)
 // -------------------------------------------------------------------------------------------------------
 
 RenderBlock::RenderBlock(Node* node)
-:RenderFlow(node)
-{
-    m_childrenInline = true;
-    m_floatingObjects = 0;
-    m_positionedObjects = 0;
-    m_firstLine = false;
-    m_hasMarkupTruncation = false;
-    m_selectionState = SelectionNone;
-    m_clearStatus = CNONE;
-    m_maxTopPosMargin = m_maxTopNegMargin = m_maxBottomPosMargin = m_maxBottomNegMargin = 0;
-    m_topMarginQuirk = m_bottomMarginQuirk = false;
-    m_overflowHeight = m_overflowWidth = 0;
-    m_overflowLeft = m_overflowTop = 0;
-    m_desiredColumnCount = 1;
-    m_desiredColumnWidth = 0;
-    m_columnRects = 0;
+      : RenderFlow(node)
+      , m_floatingObjects(0)
+      , m_positionedObjects(0)
+      , m_maxMargin(0)
+      , m_overflowHeight(0)
+      , m_overflowWidth(0)
+      , m_overflowLeft(0)
+      , m_overflowTop(0)
+{
 }
 
 RenderBlock::~RenderBlock()
 {
     delete m_floatingObjects;
     delete m_positionedObjects;
-    delete m_columnRects;
+    delete m_maxMargin;
+    
+    if (m_hasColumns) {
+        ColumnInfoMap::iterator it = gColumnInfoMap->find(this);
+        delete it->second;
+        gColumnInfoMap->remove(it);
+    }
 }
 
 void RenderBlock::setStyle(RenderStyle* _style)
@@ -494,7 +506,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
     }
 
     int oldWidth = m_width;
-    int oldColumnWidth = m_desiredColumnWidth;
+    int oldColumnWidth = desiredColumnWidth();
 
     calcWidth();
     calcColumnWidth();
@@ -502,7 +514,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
     m_overflowWidth = m_width;
     m_overflowLeft = 0;
 
-    if (oldWidth != m_width || oldColumnWidth != m_desiredColumnWidth)
+    if (oldWidth != m_width || oldColumnWidth != desiredColumnWidth())
         relayoutChildren = true;
 
     clearFloats();
@@ -531,7 +543,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
         if (element() && element()->hasTagName(formTag) && element()->isMalformed())
             // See if this form is malformed (i.e., unclosed). If so, don't give the form
             // a bottom margin.
-            m_maxBottomPosMargin = m_maxBottomNegMargin = 0;
+            setMaxBottomMargins(0, 0);
     }
 
     // For overflow:scroll blocks, ensure we have both scrollbars in place always.
@@ -552,7 +564,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren)
     // Expand our intrinsic height to encompass floats.
     int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
     if (floatBottom() > (m_height - toAdd) && (isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() ||
-                                    (parent() && parent()->isFlexibleBox() || hasColumns())))
+                                    (parent() && parent()->isFlexibleBox() || m_hasColumns)))
         m_height = floatBottom() + toAdd;
     
     // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as
@@ -832,10 +844,8 @@ void RenderBlock::collapseMargins(RenderObject* child, MarginInfo& marginInfo, i
         // This child is collapsing with the top of the
         // block.  If it has larger margin values, then we need to update
         // our own maximal values.
-        if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) {
-            m_maxTopPosMargin = max(posTop, m_maxTopPosMargin);
-            m_maxTopNegMargin = max(negTop, m_maxTopNegMargin);
-        }
+        if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk)
+            setMaxTopMargins(max(posTop, maxTopPosMargin()), max(negTop, maxTopNegMargin()));
 
         // The minute any of the margins involved isn't a quirk, don't
         // collapse it away, even if the margin is smaller (www.webreference.com
@@ -952,8 +962,7 @@ void RenderBlock::clearFloatsIfNeeded(RenderObject* child, MarginInfo& marginInf
             // FIXME: This isn't quite correct.  Need clarification for what to do
             // if the height the cleared block is offset by is smaller than the
             // margins involved.
-            m_maxTopPosMargin = oldTopPosMargin;
-            m_maxTopNegMargin = oldTopNegMargin;
+            setMaxTopMargins(oldTopPosMargin, oldTopNegMargin);
             marginInfo.setAtTopOfBlock(false);
         }
 
@@ -1042,8 +1051,7 @@ void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
     if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) {
         // Update our max pos/neg bottom margins, since we collapsed our bottom margins
         // with our children.
-        m_maxBottomPosMargin = max(m_maxBottomPosMargin, marginInfo.posMargin());
-        m_maxBottomNegMargin = max(m_maxBottomNegMargin, marginInfo.negMargin());
+        setMaxBottomMargins(max(maxBottomPosMargin(), marginInfo.posMargin()), max(maxBottomNegMargin(), marginInfo.negMargin()));
 
         if (!marginInfo.bottomQuirk())
             m_bottomMarginQuirk = false;
@@ -1113,8 +1121,8 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren)
             continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
         }
 
-        int oldTopPosMargin = m_maxTopPosMargin;
-        int oldTopNegMargin = m_maxTopNegMargin;
+        int oldTopPosMargin = maxTopPosMargin();
+        int oldTopNegMargin = maxTopNegMargin();
 
         // Make sure we layout children if they need it.
         // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
@@ -1341,10 +1349,11 @@ void RenderBlock::paintColumns(PaintInfo& paintInfo, int tx, int ty, bool painti
     EBorderStyle ruleStyle = style()->columnRuleStyle();
     int ruleWidth = style()->columnRuleWidth();
     bool renderRule = !paintingFloats && ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap;
-    unsigned colCount = m_columnRects->size();
+    Vector<IntRect>* colRects = columnRects();
+    unsigned colCount = colRects->size();
     for (unsigned i = 0; i < colCount; i++) {
         // For each rect, we clip to the rect, and then we adjust our coords.
-        IntRect colRect = m_columnRects->at(i);
+        IntRect colRect = colRects->at(i);
         colRect.move(tx, ty);
         context->save();
         
@@ -1479,7 +1488,7 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
 
     // 2. paint contents
     if (paintPhase != PaintPhaseSelfOutline) {
-        if (hasColumns())
+        if (m_hasColumns)
             paintColumns(paintInfo, scrolledX, scrolledY);
         else
             paintContents(paintInfo, scrolledX, scrolledY);
@@ -1488,12 +1497,12 @@ void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
     // 3. paint selection
     // FIXME: Make this work with multi column layouts.  For now don't fill gaps.
     bool isPrinting = document()->printing();
-    if (!inlineFlow && !isPrinting && !hasColumns())
+    if (!inlineFlow && !isPrinting && !m_hasColumns)
         paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
 
     // 4. paint floats.
     if (!inlineFlow && (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection)) {
-        if (hasColumns())
+        if (m_hasColumns)
             paintColumns(paintInfo, scrolledX, scrolledY, true);
         else
             paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection);
@@ -1649,7 +1658,7 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int
     if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
         return result;
 
-    if (hasColumns()) {
+    if (m_hasColumns) {
         // FIXME: We should learn how to gap fill multiple columns eventually.
         lastTop = (ty - blockY) + height();
         lastLeft = leftSelectionOffset(rootBlock, height());
@@ -2264,9 +2273,10 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf)
         }
     }
 
-    if (hasColumns()) {
-        for (unsigned i = 0; i < m_columnRects->size(); i++)
-            bottom = max(bottom, m_columnRects->at(i).bottom());
+    if (m_hasColumns) {
+        Vector<IntRect>* colRects = columnRects();
+        for (unsigned i = 0; i < colRects->size(); i++)
+            bottom = max(bottom, colRects->at(i).bottom());
         return bottom;
     }
 
@@ -2312,10 +2322,10 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel
         }
     }
 
-    if (hasColumns()) {
+    if (m_hasColumns) {
         // This only matters for LTR
         if (style()->direction() == LTR)
-            right = max(m_columnRects->last().right(), right);
+            right = max(columnRects()->last().right(), right);
         return right;
     }
 
@@ -2366,10 +2376,10 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf
         }
     }
 
-    if (hasColumns()) {
+    if (m_hasColumns) {
         // This only matters for RTL
         if (style()->direction() == RTL)
-            left = min(m_columnRects->last().x(), left);
+            left = min(columnRects()->last().x(), left);
         return left;
     }
 
@@ -2702,11 +2712,11 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu
             m_layer->subtractScrollOffset(scrolledX, scrolledY);
 
         // Hit test contents if we don't have columns.
-        if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
+        if (!m_hasColumns && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
             return true;
             
         // Hit test our columns if we do have them.
-        if (hasColumns() && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
+        if (m_hasColumns && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
             return true;
 
         // Hit test floats.
@@ -2752,8 +2762,9 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r
     int currXOffset = 0;
     int currYOffset = 0;
     int colGap = columnGap();
-    for (unsigned i = 0; i < m_columnRects->size(); i++) {
-        IntRect colRect = m_columnRects->at(i);
+    Vector<IntRect>* colRects = columnRects();
+    for (unsigned i = 0; i < colRects->size(); i++) {
+        IntRect colRect = colRects->at(i);
         colRect.move(tx, ty);
         
         if (colRect.contains(x, y)) {
@@ -2848,7 +2859,7 @@ VisiblePosition RenderBlock::positionForCoordinates(int x, int y)
     int contentsY = y - borderTopExtra();
     if (hasOverflowClip())
         m_layer->scrollOffset(contentsX, contentsY);
-    if (hasColumns()) {
+    if (m_hasColumns) {
         IntPoint contentsPoint(contentsX, contentsY);
         adjustPointToColumnContents(contentsPoint);
         contentsX = contentsPoint.x();
@@ -2956,8 +2967,8 @@ VisiblePosition RenderBlock::positionForCoordinates(int x, int y)
 int RenderBlock::availableWidth() const
 {
     // If we have multiple columns, then the available width is reduced to our column width.
-    if (hasColumns())
-        return m_desiredColumnWidth;
+    if (m_hasColumns)
+        return desiredColumnWidth();
     return contentWidth();
 }
 
@@ -2971,30 +2982,32 @@ int RenderBlock::columnGap() const
 void RenderBlock::calcColumnWidth()
 {    
     // Calculate our column width and column count.
-    m_desiredColumnCount = 1;
-    m_desiredColumnWidth = contentWidth();
+    unsigned desiredColumnCount = 1;
+    int desiredColumnWidth = contentWidth();
     
     // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
-    if (document()->printing() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()))
+    if (document()->printing() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth())) {
+        setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
         return;
+    }
         
-    int availWidth = m_desiredColumnWidth;
+    int availWidth = desiredColumnWidth;
     int colGap = columnGap();
 
     if (style()->hasAutoColumnWidth()) {
         int colCount = style()->columnCount();
         if ((colCount - 1) * colGap < availWidth) {
-            m_desiredColumnCount = colCount;
-            m_desiredColumnWidth = (availWidth - (m_desiredColumnCount - 1) * colGap) / m_desiredColumnCount;
+            desiredColumnCount = colCount;
+            desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
         } else if (colGap < availWidth) {
-            m_desiredColumnCount = availWidth / colGap;
-            m_desiredColumnWidth = (availWidth - (m_desiredColumnCount - 1) * colGap) / m_desiredColumnCount;
+            desiredColumnCount = availWidth / colGap;
+            desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
         }
     } else if (style()->hasAutoColumnCount()) {
         int colWidth = static_cast<int>(style()->columnWidth());
         if (colWidth < availWidth) {
-            m_desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
-            m_desiredColumnWidth = (availWidth - (m_desiredColumnCount - 1) * colGap) / m_desiredColumnCount;
+            desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
+            desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
         }
     } else {
         // Both are set.
@@ -3002,30 +3015,82 @@ void RenderBlock::calcColumnWidth()
         int colCount = style()->columnCount();
     
         if (colCount * colWidth + (colCount - 1) * colGap <= availWidth) {
-            m_desiredColumnCount = colCount;
-            m_desiredColumnWidth = colWidth;
+            desiredColumnCount = colCount;
+            desiredColumnWidth = colWidth;
         } else if (colWidth < availWidth) {
-            m_desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
-            m_desiredColumnWidth = (availWidth - (m_desiredColumnCount - 1) * colGap) / m_desiredColumnCount;
+            desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
+            desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
+        }
+    }
+    setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
+}
+
+void RenderBlock::setDesiredColumnCountAndWidth(int count, int width)
+{
+    if (count == 1) {
+        if (m_hasColumns) {
+            ColumnInfoMap::iterator it = gColumnInfoMap->find(this);
+            delete it->second;
+            gColumnInfoMap->remove(it);
+            m_hasColumns = false;
+        }
+    } else {
+        ColumnInfo* info;
+        if (m_hasColumns)
+            info = gColumnInfoMap->get(this);
+        else {
+            if (!gColumnInfoMap)
+                gColumnInfoMap = new ColumnInfoMap;
+            info = new ColumnInfo;
+            gColumnInfoMap->add(this, info);
+            m_hasColumns = true;
         }
+        info->m_desiredColumnCount = count;
+        info->m_desiredColumnWidth = width;   
     }
 }
 
+int RenderBlock::desiredColumnWidth() const
+{
+    if (!m_hasColumns)
+        return contentWidth();
+    return gColumnInfoMap->get(this)->m_desiredColumnWidth;
+}
+
+unsigned RenderBlock::desiredColumnCount() const
+{
+    if (!m_hasColumns)
+        return 1;
+    return gColumnInfoMap->get(this)->m_desiredColumnCount;
+}
+
+Vector<IntRect>* RenderBlock::columnRects() const
+{
+    if (!m_hasColumns)
+        return 0;
+    return &gColumnInfoMap->get(this)->m_columnRects;    
+}
+
 int RenderBlock::layoutColumns(int endOfContent)
 {
     // Don't do anything if we have no columns
-    if (!hasColumns())
+    if (!m_hasColumns)
         return -1;
 
+    ColumnInfo* info = gColumnInfoMap->get(this);
+    int desiredColumnWidth = info->m_desiredColumnWidth;
+    int desiredColumnCount = info->m_desiredColumnCount;
+    Vector<IntRect>* columnRects = &info->m_columnRects;
+    
     bool computeIntrinsicHeight = (endOfContent == -1);
 
     // Fill the columns in to the available height.  Attempt to balance the height of the columns
     int availableHeight = contentHeight();
-    int colHeight = computeIntrinsicHeight ? availableHeight / m_desiredColumnCount : availableHeight;
+    int colHeight = computeIntrinsicHeight ? availableHeight / desiredColumnCount : availableHeight;
     
     // Add in half our line-height to help with best-guess initial balancing.
     int columnSlop = lineHeight(false) / 2;
-    int remainingSlopSpace = columnSlop * m_desiredColumnCount;
+    int remainingSlopSpace = columnSlop * desiredColumnCount;
 
     if (computeIntrinsicHeight)
         colHeight += columnSlop;
@@ -3033,8 +3098,7 @@ int RenderBlock::layoutColumns(int endOfContent)
     int colGap = columnGap();
 
     // Compute a collection of column rects.
-    delete m_columnRects;
-    m_columnRects = new Vector<IntRect>();
+    columnRects->clear();
     
     // Then we do a simulated "paint" into the column slices and allow the content to slightly adjust our individual column rects.
     // FIXME: We need to take into account layers that are affected by the columns as well here so that they can have an opportunity
@@ -3042,9 +3106,9 @@ int RenderBlock::layoutColumns(int endOfContent)
     RenderView* v = view();
     int left = borderLeft() + paddingLeft();
     int top = borderTop() + paddingTop();
-    int currX = style()->direction() == LTR ? borderLeft() + paddingLeft() : borderLeft() + paddingLeft() + contentWidth() - m_desiredColumnWidth;
+    int currX = style()->direction() == LTR ? borderLeft() + paddingLeft() : borderLeft() + paddingLeft() + contentWidth() - desiredColumnWidth;
     int currY = top;
-    unsigned colCount = m_desiredColumnCount;
+    unsigned colCount = desiredColumnCount;
     int maxColBottom = borderTop() + paddingTop();
     int contentBottom = top + availableHeight; 
     for (unsigned i = 0; i < colCount; i++) {
@@ -3053,19 +3117,18 @@ int RenderBlock::layoutColumns(int endOfContent)
             colHeight = availableHeight;
 
         // This represents the real column position.
-        IntRect colRect(currX, top, m_desiredColumnWidth, colHeight);
+        IntRect colRect(currX, top, desiredColumnWidth, colHeight);
         
         // For the simulated paint, we pretend like everything is in one long strip.
-        IntRect pageRect(left, currY, m_desiredColumnWidth, colHeight);
+        IntRect pageRect(left, currY, desiredColumnWidth, colHeight);
         v->setPrintRect(pageRect);
         v->setTruncatedAt(currY + colHeight);
         GraphicsContext context((PlatformGraphicsContext*)0);
         RenderObject::PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0);
         
-        int oldColCount = m_desiredColumnCount;
-        m_desiredColumnCount = 1;
+        m_hasColumns = false;
         paintObject(paintInfo, 0, 0);
-        m_desiredColumnCount = oldColCount;
+        m_hasColumns = true;
 
         int adjustedBottom = v->bestTruncatedAt();
         if (adjustedBottom <= currY)
@@ -3087,16 +3150,16 @@ int RenderBlock::layoutColumns(int endOfContent)
         }
         
         if (style()->direction() == LTR)
-            currX += m_desiredColumnWidth + colGap;
+            currX += desiredColumnWidth + colGap;
         else
-            currX -= (m_desiredColumnWidth + colGap);
+            currX -= (desiredColumnWidth + colGap);
 
         currY += colRect.height();
         availableHeight -= colRect.height();
 
         maxColBottom = max(colRect.bottom(), maxColBottom);
 
-        m_columnRects->append(colRect);
+        columnRects->append(colRect);
         
         // Start adding in more columns as long as there's still content left.
         if (currY < endOfContent && i == colCount - 1)
@@ -3104,7 +3167,7 @@ int RenderBlock::layoutColumns(int endOfContent)
     }
 
     m_overflowWidth = max(m_width, currX - colGap);
-    m_overflowLeft = min(0, currX + m_desiredColumnWidth + colGap);
+    m_overflowLeft = min(0, currX + desiredColumnWidth + colGap);
 
     m_overflowHeight = maxColBottom;
     int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
@@ -3115,7 +3178,7 @@ int RenderBlock::layoutColumns(int endOfContent)
     v->setPrintRect(IntRect());
     v->setTruncatedAt(0);
     
-    ASSERT(m_columnRects && colCount == m_columnRects->size());
+    ASSERT(colCount == columnRects->size());
     
     return contentBottom;
 }
@@ -3123,17 +3186,19 @@ int RenderBlock::layoutColumns(int endOfContent)
 void RenderBlock::adjustPointToColumnContents(IntPoint& point) const
 {
     // Just bail if we have no columns.
-    if (!hasColumns() || !m_columnRects)
+    if (!m_hasColumns)
         return;
+    
+    Vector<IntRect>* colRects = columnRects();
 
     // Determine which columns we intersect.
     int colGap = columnGap();
     int leftGap = colGap / 2;
-    IntPoint columnPoint(m_columnRects->at(0).location());
+    IntPoint columnPoint(colRects->at(0).location());
     int yOffset = 0;
-    for (unsigned i = 0; i < m_columnRects->size(); i++) {
+    for (unsigned i = 0; i < colRects->size(); i++) {
         // Add in half the column gap to the left and right of the rect.
-        IntRect colRect = m_columnRects->at(i);
+        IntRect colRect = colRects->at(i);
         IntRect gapAndColumnRect(colRect.x() - leftGap, colRect.y(), colRect.width() + colGap, colRect.height());
         
         if (gapAndColumnRect.contains(point)) {
@@ -3150,8 +3215,10 @@ void RenderBlock::adjustPointToColumnContents(IntPoint& point) const
 void RenderBlock::adjustRectForColumns(IntRect& r) const
 {
     // Just bail if we have no columns.
-    if (!hasColumns() || !m_columnRects)
+    if (!m_hasColumns)
         return;
+    
+    Vector<IntRect>* colRects = columnRects();
 
     // Begin with a result rect that is empty.
     IntRect result;
@@ -3160,8 +3227,8 @@ void RenderBlock::adjustRectForColumns(IntRect& r) const
     int currXOffset = 0;
     int currYOffset = 0;
     int colGap = columnGap();
-    for (unsigned i = 0; i < m_columnRects->size(); i++) {
-        IntRect colRect = m_columnRects->at(i);
+    for (unsigned i = 0; i < colRects->size(); i++) {
+        IntRect colRect = colRects->at(i);
         
         IntRect repaintRect = r;
         repaintRect.move(currXOffset, currYOffset);
@@ -4154,6 +4221,28 @@ void RenderBlock::clearTruncation()
     }
 }
 
+void RenderBlock::setMaxTopMargins(int pos, int neg)
+{
+    if (!m_maxMargin) {
+        if (pos == MaxMargin::topPosDefault(this) && neg == MaxMargin::topNegDefault(this))
+            return;
+        m_maxMargin = new MaxMargin(this);
+    }
+    m_maxMargin->m_topPos = pos;
+    m_maxMargin->m_topNeg = neg;
+}
+
+void RenderBlock::setMaxBottomMargins(int pos, int neg)
+{
+    if (!m_maxMargin) {
+        if (pos == MaxMargin::bottomPosDefault(this) && neg == MaxMargin::bottomNegDefault(this))
+            return;
+        m_maxMargin = new MaxMargin(this);
+    }
+    m_maxMargin->m_bottomPos = pos;
+    m_maxMargin->m_bottomNeg = neg;
+}
+
 const char* RenderBlock::renderName() const
 {
     if (isBody())
index 5651ea498549ddeb696af291f8bda771e61a1458..6166a9f155ce81681ac1c14f54be655b49e83d24 100644 (file)
@@ -76,26 +76,23 @@ public:
     virtual bool isTopMarginQuirk() const { return m_topMarginQuirk; }
     virtual bool isBottomMarginQuirk() const { return m_bottomMarginQuirk; }
 
-    virtual int maxTopMargin(bool positive) const { return positive ? m_maxTopPosMargin : m_maxTopNegMargin; }
-    virtual int maxBottomMargin(bool positive) const { return positive ? m_maxBottomPosMargin : m_maxBottomNegMargin; }
-
+    virtual int maxTopMargin(bool positive) const { return positive ? maxTopPosMargin() : maxTopNegMargin(); }
+    virtual int maxBottomMargin(bool positive) const { return positive ? maxBottomPosMargin() : maxBottomNegMargin(); }
+
+    int maxTopPosMargin() const { return m_maxMargin ? m_maxMargin->m_topPos : MaxMargin::topPosDefault(this); }
+    int maxTopNegMargin() const { return m_maxMargin ? m_maxMargin->m_topNeg : MaxMargin::topNegDefault(this); }
+    int maxBottomPosMargin() const { return m_maxMargin ? m_maxMargin->m_bottomPos : MaxMargin::bottomPosDefault(this); }
+    int maxBottomNegMargin() const { return m_maxMargin ? m_maxMargin->m_bottomNeg : MaxMargin::bottomNegDefault(this); }
+    void setMaxTopMargins(int pos, int neg);
+    void setMaxBottomMargins(int pos, int neg);
+    
     void initMaxMarginValues()
     {
-        int margTop = marginTop();
-        if (margTop >= 0) {
-            m_maxTopPosMargin = margTop;
-            m_maxTopNegMargin = 0;
-        } else {
-            m_maxTopNegMargin = -margTop;
-            m_maxTopPosMargin = 0;
-        }
-        int margBottom = marginBottom();
-        if (margBottom >= 0) {
-            m_maxBottomPosMargin = margBottom;
-            m_maxBottomNegMargin = 0;
-        } else {
-            m_maxBottomNegMargin = -margBottom;
-            m_maxBottomPosMargin = 0;
+        if (m_maxMargin) {
+            m_maxMargin->m_topPos = MaxMargin::topPosDefault(this);
+            m_maxMargin->m_topNeg = MaxMargin::topNegDefault(this);
+            m_maxMargin->m_bottomPos = MaxMargin::bottomPosDefault(this);
+            m_maxMargin->m_bottomNeg = MaxMargin::bottomNegDefault(this);
         }
     }
 
@@ -285,7 +282,11 @@ public:
     int heightForLineCount(int);
     void clearTruncation();
 
-    virtual bool hasColumns() const { return m_desiredColumnCount > 1; }
+    int desiredColumnWidth() const;
+    unsigned desiredColumnCount() const;
+    Vector<IntRect>* columnRects() const;
+    void setDesiredColumnCountAndWidth(int count, int width);
+    
     void adjustRectForColumns(IntRect&) const;
 private:
     void adjustPointToColumnContents(IntPoint&) const;
@@ -436,33 +437,35 @@ protected:
 private:
     DeprecatedPtrList<FloatingObject>* m_floatingObjects;
     DeprecatedPtrList<RenderObject>* m_positionedObjects;
-
-    bool m_childrenInline : 1;
-    bool m_firstLine : 1;
-    unsigned m_clearStatus  : 2; // EClear
-    bool m_topMarginQuirk : 1;
-    bool m_bottomMarginQuirk : 1;
-    bool m_hasMarkupTruncation : 1;
-    unsigned m_selectionState : 3; // SelectionState
+         
+     // Allocated only when some of these fields have non-default values
+     struct MaxMargin {
+         MaxMargin(const RenderBlock* o) 
+             : m_topPos(topPosDefault(o))
+             , m_topNeg(topNegDefault(o))
+             , m_bottomPos(bottomPosDefault(o))
+             , m_bottomNeg(bottomNegDefault(o))
+             { 
+             }
+         static int topPosDefault(const RenderBlock* o) { return o->marginTop() > 0 ? o->marginTop() : 0; }
+         static int topNegDefault(const RenderBlock* o) { return o->marginTop() < 0 ? -o->marginTop() : 0; }
+         static int bottomPosDefault(const RenderBlock* o) { return o->marginBottom() > 0 ? o->marginBottom() : 0; }
+         static int bottomNegDefault(const RenderBlock* o) { return o->marginBottom() < 0 ? -o->marginBottom() : 0; }
+         
+         int m_topPos;
+         int m_topNeg;
+         int m_bottomPos;
+         int m_bottomNeg;
+     };
+
+    MaxMargin* m_maxMargin;
 
 protected:
-    int m_maxTopPosMargin;
-    int m_maxTopNegMargin;
-    int m_maxBottomPosMargin;
-    int m_maxBottomNegMargin;
-
     // How much content overflows out of our block vertically or horizontally.
     int m_overflowHeight;
     int m_overflowWidth;
     int m_overflowLeft;
     int m_overflowTop;
-
-private:
-
-    // Column information.
-    int m_desiredColumnWidth;
-    unsigned m_desiredColumnCount;
-    Vector<IntRect>* m_columnRects;
 };
 
 } // namespace WebCore
index 984c70b451f7b32d86b9fafba74c51a6270376cc..2300edc92e564eb321851b4ae70944eb77ce0e9e 100644 (file)
@@ -314,11 +314,14 @@ void RenderFlexibleBox::layoutBlock(bool relayoutChildren)
         // bottom margin max values to 0.  This way we don't factor in the values
         // twice when we collapse with our previous vertically adjacent and
         // following vertically adjacent blocks.
-        if (m_maxBottomPosMargin > m_maxTopPosMargin)
-            m_maxTopPosMargin = m_maxBottomPosMargin;
-        if (m_maxBottomNegMargin > m_maxTopNegMargin)
-            m_maxTopNegMargin = m_maxBottomNegMargin;
-        m_maxBottomNegMargin = m_maxBottomPosMargin = 0;
+        int pos = maxTopPosMargin();
+        int neg = maxTopNegMargin();
+        if (maxBottomPosMargin() > pos)
+            pos = maxBottomPosMargin();
+        if (maxBottomNegMargin() > neg)
+            neg = maxBottomNegMargin();
+        setMaxTopMargins(pos, neg);
+        setMaxBottomMargins(0, 0);
     }
 
     // Always ensure our overflow width is at least as large as our width.
index e913a000ea1f8480754433cde3639b4fbd4d042b..113d2d10f2570657a5d4ee1e85a01f5c66a305a7 100644 (file)
@@ -46,6 +46,15 @@ public:
         , m_firstLineBox(0)
         , m_lastLineBox(0)
         , m_lineHeight(-1)
+        , m_childrenInline(true)
+        , m_firstLine(false)
+        , m_clearStatus(CNONE)
+        , m_topMarginQuirk(false) 
+        , m_bottomMarginQuirk(false)
+        , m_hasMarkupTruncation(false)
+        , m_selectionState(SelectionNone)
+        , m_hasColumns(false)
+        , m_isContinuation(false)
     {
     }
 
@@ -90,7 +99,7 @@ public:
     void paintOutlineForLine(GraphicsContext*, int tx, int ty, const IntRect& prevLine, const IntRect& thisLine, const IntRect& nextLine);
     void paintOutline(GraphicsContext*, int tx, int ty);
 
-    virtual bool hasColumns() const { return false; }
+    virtual bool hasColumns() const { return m_hasColumns; }
 
 private:
     // An inline can be split with blocks occurring in between the inline content.
@@ -107,6 +116,20 @@ protected:
     InlineFlowBox* m_lastLineBox;
 
     mutable short m_lineHeight;
+    
+    // These bitfields are moved here from subclasses to pack them together
+    // from RenderBlock
+    bool m_childrenInline : 1;
+    bool m_firstLine : 1;
+    unsigned m_clearStatus  : 2; // EClear
+    bool m_topMarginQuirk : 1;
+    bool m_bottomMarginQuirk : 1;
+    bool m_hasMarkupTruncation : 1;
+    unsigned m_selectionState : 3; // SelectionState
+    bool m_hasColumns : 1;
+    
+    // from RenderInline
+    bool m_isContinuation : 1; // Whether or not we're a continuation of an inline.
 };
 
 } // namespace WebCore
index 9921e30569128666fbff5d829cfcb56089889621..49eb512ed1fad2253e228f55e5b2859ffda11976 100644 (file)
@@ -34,7 +34,6 @@ namespace WebCore {
 
 RenderInline::RenderInline(Node* node)
     : RenderFlow(node)
-    , m_isContinuation(false)
 {
 }
 
index f3ef6e1f2f2a4b987c5c4c75c31ddf9e27657459..3db42f49c8f61f1d826d00c6c4f2872efe06a7f5 100644 (file)
@@ -78,8 +78,6 @@ public:
 protected:
     static RenderInline* cloneInline(RenderFlow* src);
 
-private:
-    bool m_isContinuation : 1; // Whether or not we're a continuation of an inline.
 };
 
 } // namespace WebCore