Changeset 18762 in webkit


Ignore:
Timestamp:
Jan 11, 2007, 4:21:22 AM (18 years ago)
Author:
hyatt
Message:

Fix two bugs in positionForCoordinates. (Make it work when you have a margin in between your border and
your first child block.)

Rewrite column rebalancing to have two modes: constrained and unconstrained. In unconstrained mode,
the system will dynamically rebalance as it loses space to breaks and compute a final intrinsic height
for the overall block. In constrained mode, columns flow into the fixed height block, and extra columns
spill out horizontally in the appropriate direction (RTL/LTR).

Make columns work properly with both LTR and RTL overflow blocks.

Initial column test suite coming soon now that the basic layout is right.

Reviewed by darin

  • rendering/RenderBlock.cpp: (WebCore:::RenderFlow): (WebCore::RenderBlock::layoutBlock): (WebCore::RenderBlock::paintColumns): (WebCore::RenderBlock::lowestPosition): (WebCore::RenderBlock::rightmostPosition): (WebCore::RenderBlock::leftmostPosition): (WebCore::RenderBlock::hitTestColumns): (WebCore::RenderBlock::positionForCoordinates): (WebCore::RenderBlock::availableWidth): (WebCore::RenderBlock::calcColumnWidth): (WebCore::RenderBlock::layoutColumns): (WebCore::RenderBlock::adjustPointToColumnContents):
  • rendering/RenderBlock.h: (WebCore::RenderBlock::hasColumns):
Location:
trunk/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r18760 r18762  
     12007-01-11  David Hyatt  <hyatt@apple.com>
     2
     3        Fix two bugs in positionForCoordinates.  (Make it work when you have a margin in between your border and
     4        your first child block.)
     5
     6        Rewrite column rebalancing to have two modes: constrained and unconstrained.  In unconstrained mode,
     7        the system will dynamically rebalance as it loses space to breaks and compute a final intrinsic height
     8        for the overall block.  In constrained mode, columns flow into the fixed height block, and extra columns
     9        spill out horizontally in the appropriate direction (RTL/LTR).
     10
     11        Make columns work properly with both LTR and RTL overflow blocks.
     12
     13        Initial column test suite coming soon now that the basic layout is right.
     14
     15        Reviewed by darin
     16
     17        * rendering/RenderBlock.cpp:
     18        (WebCore:::RenderFlow):
     19        (WebCore::RenderBlock::layoutBlock):
     20        (WebCore::RenderBlock::paintColumns):
     21        (WebCore::RenderBlock::lowestPosition):
     22        (WebCore::RenderBlock::rightmostPosition):
     23        (WebCore::RenderBlock::leftmostPosition):
     24        (WebCore::RenderBlock::hitTestColumns):
     25        (WebCore::RenderBlock::positionForCoordinates):
     26        (WebCore::RenderBlock::availableWidth):
     27        (WebCore::RenderBlock::calcColumnWidth):
     28        (WebCore::RenderBlock::layoutColumns):
     29        (WebCore::RenderBlock::adjustPointToColumnContents):
     30        * rendering/RenderBlock.h:
     31        (WebCore::RenderBlock::hasColumns):
     32
    1332007-01-10  Rob Buis  <buis@kde.org>
    234
  • trunk/WebCore/rendering/RenderBlock.cpp

    r18759 r18762  
    101101    m_overflowLeft = m_overflowTop = 0;
    102102    m_tabWidth = -1;
    103     m_columnCount = 1;
    104     m_columnWidth = 0;
     103    m_desiredColumnCount = 1;
     104    m_desiredColumnWidth = 0;
    105105    m_columnRects = 0;
    106106}
     
    462462
    463463    int oldWidth = m_width;
    464     int oldColumnWidth = m_columnWidth;
     464    int oldColumnWidth = m_desiredColumnWidth;
    465465
    466466    calcWidth();
     
    468468
    469469    m_overflowWidth = m_width;
    470 
    471     if (oldWidth != m_width || oldColumnWidth != m_columnWidth)
     470    m_overflowLeft = 0;
     471
     472    if (oldWidth != m_width || oldColumnWidth != m_desiredColumnWidth)
    472473        relayoutChildren = true;
    473474
     
    525526    // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as
    526527    // we adjust for clean column breaks.
    527     layoutColumns();
     528    int singleColumnBottom = layoutColumns();
    528529
    529530    // Calculate our new height.
     
    531532    calcHeight();
    532533    if (oldHeight != m_height) {
     534        // We have to rebalance columns to the new height.
     535        layoutColumns(singleColumnBottom);
     536
    533537        // If the block got expanded in size, then increase our overflowheight to match.
    534538        if (m_overflowHeight > m_height)
     
    13091313    int currYOffset = 0;
    13101314    int colGap = columnGap();
    1311     for (unsigned i = 0; i < m_columnCount; i++) {
     1315    for (unsigned i = 0; i < m_columnRects->size(); i++) {
    13121316        // For each rect, we clip to the rect, and then we adjust our coords.
    13131317        IntRect colRect = m_columnRects->at(i);
     
    21992203}
    22002204
    2201 int
    2202 RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
     2205int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
    22032206{
    22042207    int bottom = RenderFlow::lowestPosition(includeOverflowInterior, includeSelf);
     
    22062209        return bottom;
    22072210
    2208     if (m_overflowHeight > m_height)
    2209         bottom = max(m_overflowHeight, bottom);
    2210    
    2211     if (m_floatingObjects && !hasColumns()) {
    2212         FloatingObject* r;
    2213         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
    2214         for ( ; (r = it.current()); ++it ) {
    2215             if (!r->noPaint || r->node->layer()) {
    2216                 int lp = r->startY + r->node->marginTop() + r->node->lowestPosition(false);
    2217                 bottom = max(bottom, lp);
    2218             }
    2219         }
    2220     }
    2221 
     2211    if (includeSelf && m_overflowHeight > bottom)
     2212        bottom = m_overflowHeight;
     2213       
    22222214    if (m_positionedObjects) {
    22232215        RenderObject* r;
     
    22332225    }
    22342226
    2235     if (!includeSelf && lastLineBox() && !hasColumns()) {
    2236         int lp = lastLineBox()->yPos() + lastLineBox()->height();
    2237         bottom = max(bottom, lp);
    2238     }
    2239    
    2240     return bottom;
    2241 }
    2242 
    2243 int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
    2244 {
    2245     int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf);
    2246     if (!includeOverflowInterior && hasOverflowClip())
    2247         return right;
    2248     if (includeSelf && m_overflowWidth > right)
    2249         right = m_overflowWidth;
    2250    
    2251     if (m_floatingObjects && !hasColumns()) {
     2227    if (hasColumns()) {
     2228        for (unsigned i = 0; i < m_columnRects->size(); i++)
     2229            bottom = max(bottom, m_columnRects->at(i).bottom());
     2230        return bottom;
     2231    }
     2232
     2233    if (m_floatingObjects) {
    22522234        FloatingObject* r;
    22532235        DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
    22542236        for ( ; (r = it.current()); ++it ) {
    22552237            if (!r->noPaint || r->node->layer()) {
    2256                 int rp = r->left + r->node->marginLeft() + r->node->rightmostPosition(false);
    2257                 right = max(right, rp);
    2258             }
    2259         }
    2260     }
     2238                int lp = r->startY + r->node->marginTop() + r->node->lowestPosition(false);
     2239                bottom = max(bottom, lp);
     2240            }
     2241        }
     2242    }
     2243
     2244
     2245    if (!includeSelf && lastLineBox()) {
     2246        int lp = lastLineBox()->yPos() + lastLineBox()->height();
     2247        bottom = max(bottom, lp);
     2248    }
     2249   
     2250    return bottom;
     2251}
     2252
     2253int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
     2254{
     2255    int right = RenderFlow::rightmostPosition(includeOverflowInterior, includeSelf);
     2256    if (!includeOverflowInterior && hasOverflowClip())
     2257        return right;
     2258
     2259    if (includeSelf && m_overflowWidth > right)
     2260        right = m_overflowWidth;
    22612261
    22622262    if (m_positionedObjects) {
     
    22732273    }
    22742274
    2275     if (!includeSelf && firstLineBox() && !hasColumns()) {
     2275    if (hasColumns()) {
     2276        // This only matters for LTR
     2277        if (style()->direction() == LTR)
     2278            right = max(m_columnRects->last().right(), right);
     2279        return right;
     2280    }
     2281
     2282    if (m_floatingObjects) {
     2283        FloatingObject* r;
     2284        DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
     2285        for ( ; (r = it.current()); ++it ) {
     2286            if (!r->noPaint || r->node->layer()) {
     2287                int rp = r->left + r->node->marginLeft() + r->node->rightmostPosition(false);
     2288                right = max(right, rp);
     2289            }
     2290        }
     2291    }
     2292
     2293    if (!includeSelf && firstLineBox()) {
    22762294        for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) {
    22772295            int rp = currBox->xPos() + currBox->width();
     
    22922310    if (!includeOverflowInterior && hasOverflowClip())
    22932311        return left;
     2312   
    22942313    if (includeSelf && m_overflowLeft < left)
    22952314        left = m_overflowLeft;
    2296    
    2297     if (m_floatingObjects && !hasColumns()) {
    2298         FloatingObject* r;
    2299         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
    2300         for ( ; (r = it.current()); ++it ) {
    2301             if (!r->noPaint || r->node->layer()) {
    2302                 int lp = r->left + r->node->marginLeft() + r->node->leftmostPosition(false);
    2303                 left = min(left, lp);
    2304             }
    2305         }
    2306     }
    2307    
     2315
    23082316    if (m_positionedObjects) {
    23092317        RenderObject* r;
     
    23182326        }
    23192327    }
    2320    
    2321     if (!includeSelf && firstLineBox() && !hasColumns()) {
     2328
     2329    if (hasColumns()) {
     2330        // This only matters for RTL
     2331        if (style()->direction() == RTL)
     2332            left = min(m_columnRects->last().x(), left);
     2333        return left;
     2334    }
     2335
     2336    if (m_floatingObjects) {
     2337        FloatingObject* r;
     2338        DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
     2339        for ( ; (r = it.current()); ++it ) {
     2340            if (!r->noPaint || r->node->layer()) {
     2341                int lp = r->left + r->node->marginLeft() + r->node->leftmostPosition(false);
     2342                left = min(left, lp);
     2343            }
     2344        }
     2345    }
     2346
     2347    if (!includeSelf && firstLineBox()) {
    23222348        for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox())
    23232349            left = min(left, (int)currBox->xPos());
     
    26902716    int currYOffset = 0;
    26912717    int colGap = columnGap();
    2692     for (unsigned i = 0; i < m_columnCount; i++) {
     2718    for (unsigned i = 0; i < m_columnRects->size(); i++) {
    26932719        IntRect colRect = m_columnRects->at(i);
    26942720        colRect.move(tx, ty);
     
    28012827
    28022828    // If we start inside the shadow tree, we will stay inside (even if the point is above or below).
    2803     if (!(n && n->isShadowNode())) {
     2829    if (!(n && n->isShadowNode()) && !childrenInline()) {
    28042830        // Don't return positions inside editable roots for coordinates outside those roots, except for coordinates outside
    28052831        // a document that is entirely editable.
     
    28722898   
    28732899    // See if any child blocks exist at this y coordinate.
     2900    if (firstChild() && contentsY < firstChild()->yPos())
     2901        return VisiblePosition(n, 0, DOWNSTREAM);
    28742902    for (RenderObject* renderer = firstChild(); renderer; renderer = renderer->nextSibling()) {
    28752903        if (renderer->height() == 0 || renderer->style()->visibility() != VISIBLE || renderer->isFloatingOrPositioned())
     
    28922920{
    28932921    // If we have multiple columns, then the available width is reduced to our column width.
    2894     if (m_columnCount > 1)
    2895         return m_columnWidth;
     2922    if (hasColumns())
     2923        return m_desiredColumnWidth;
    28962924    return contentWidth();
    28972925}
     
    29072935{   
    29082936    // Calculate our column width and column count.
    2909     m_columnCount = 1;
    2910     m_columnWidth = contentWidth();
     2937    m_desiredColumnCount = 1;
     2938    m_desiredColumnWidth = contentWidth();
    29112939   
    29122940    // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
     
    29142942        return;
    29152943       
    2916     int availWidth = m_columnWidth;
     2944    int availWidth = m_desiredColumnWidth;
    29172945    int colGap = columnGap();
    29182946
     
    29202948        int colCount = style()->columnCount();
    29212949        if ((colCount - 1) * colGap < availWidth) {
    2922             m_columnCount = colCount;
    2923             m_columnWidth = (availWidth - (m_columnCount - 1) * colGap) / m_columnCount;
     2950            m_desiredColumnCount = colCount;
     2951            m_desiredColumnWidth = (availWidth - (m_desiredColumnCount - 1) * colGap) / m_desiredColumnCount;
    29242952        } else if (colGap < availWidth) {
    2925             m_columnCount = availWidth / colGap;
    2926             m_columnWidth = (availWidth - (m_columnCount - 1) * colGap) / m_columnCount;
     2953            m_desiredColumnCount = availWidth / colGap;
     2954            m_desiredColumnWidth = (availWidth - (m_desiredColumnCount - 1) * colGap) / m_desiredColumnCount;
    29272955        }
    29282956    } else if (style()->hasAutoColumnCount()) {
    29292957        int colWidth = static_cast<int>(style()->columnWidth());
    29302958        if (colWidth < availWidth) {
    2931             m_columnCount = (availWidth + colGap) / (colWidth + colGap);
    2932             m_columnWidth = (availWidth - (m_columnCount - 1) * colGap) / m_columnCount;
     2959            m_desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
     2960            m_desiredColumnWidth = (availWidth - (m_desiredColumnCount - 1) * colGap) / m_desiredColumnCount;
    29332961        }
    29342962    } else {
     
    29382966   
    29392967        if (colCount * colWidth + (colCount - 1) * colGap <= availWidth) {
    2940             m_columnCount = colCount;
    2941             m_columnWidth = colWidth;
     2968            m_desiredColumnCount = colCount;
     2969            m_desiredColumnWidth = colWidth;
    29422970        } else if (colWidth < availWidth) {
    2943             m_columnCount = (availWidth + colGap) / (colWidth + colGap);
    2944             m_columnWidth = (availWidth - (m_columnCount - 1) * colGap) / m_columnCount;
    2945         }
    2946     }
    2947 }
    2948 
    2949 void RenderBlock::layoutColumns()
     2971            m_desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
     2972            m_desiredColumnWidth = (availWidth - (m_desiredColumnCount - 1) * colGap) / m_desiredColumnCount;
     2973        }
     2974    }
     2975}
     2976
     2977int RenderBlock::layoutColumns(int endOfContent)
    29502978{
    29512979    // Don't do anything if we have no columns
    29522980    if (!hasColumns())
    2953         return;
     2981        return -1;
     2982
     2983    bool computeIntrinsicHeight = (endOfContent == -1);
    29542984
    29552985    // Fill the columns in to the available height.  Attempt to balance the height of the columns
    29562986    int availableHeight = contentHeight();
    2957     int colHeight = availableHeight / m_columnCount + lineHeight(false) / 2;  // Add in half our line-height to help with best-guess initial balancing.
     2987    int colHeight = computeIntrinsicHeight ? availableHeight / m_desiredColumnCount : availableHeight;
     2988   
     2989    // Add in half our line-height to help with best-guess initial balancing.
     2990    int columnSlop = lineHeight(false) / 2;
     2991    int remainingSlopSpace = columnSlop * m_desiredColumnCount;
     2992
     2993    if (computeIntrinsicHeight)
     2994        colHeight += columnSlop;
    29582995                                                                           
    29592996    int colGap = columnGap();
     
    29693006    int left = borderLeft() + paddingLeft();
    29703007    int top = borderTop() + paddingTop();
    2971     int currX = style()->direction() == LTR ? borderLeft() + paddingLeft() : borderLeft() + paddingLeft() + contentWidth() - m_columnWidth;
     3008    int currX = style()->direction() == LTR ? borderLeft() + paddingLeft() : borderLeft() + paddingLeft() + contentWidth() - m_desiredColumnWidth;
    29723009    int currY = top;
    2973     int colCount = m_columnCount;
     3010    unsigned colCount = m_desiredColumnCount;
    29743011    int maxColBottom = borderTop() + paddingTop();
    2975     for (unsigned i = 0; i < m_columnCount; i++) {
    2976         // The last column just gets all the remaining space.
    2977         if (i == m_columnCount - 1)
     3012    int contentBottom = top + availableHeight;
     3013    for (unsigned i = 0; i < colCount; i++) {
     3014        // If we aren't constrained, then the last column can just get all the remaining space.
     3015        if (computeIntrinsicHeight && i == colCount - 1)
    29783016            colHeight = availableHeight;
    29793017
    29803018        // This represents the real column position.
    2981         IntRect colRect(currX, top, m_columnWidth, colHeight);
     3019        IntRect colRect(currX, top, m_desiredColumnWidth, colHeight);
    29823020       
    29833021        // For the simulated paint, we pretend like everything is in one long strip.
    2984         IntRect pageRect(left, currY, m_columnWidth, colHeight);
     3022        IntRect pageRect(left, currY, m_desiredColumnWidth, colHeight);
    29853023        v->setPrintRect(pageRect);
    29863024        v->setTruncatedAt(currY + colHeight);
    29873025        GraphicsContext context((PlatformGraphicsContext*)0);
    29883026        RenderObject::PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0);
    2989         m_columnCount = 1;
     3027       
     3028        int oldColCount = m_desiredColumnCount;
     3029        m_desiredColumnCount = 1;
    29903030        paintObject(paintInfo, 0, 0);
    2991         m_columnCount = colCount;
     3031        m_desiredColumnCount = oldColCount;
    29923032
    29933033        int adjustedBottom = v->bestTruncatedAt();
     
    29973037        colRect.setHeight(adjustedBottom - currY);
    29983038       
     3039        // Add in the lost space to the subsequent columns.
     3040        // FIXME: This will create a "staircase" effect if there are enough columns, but the effect should be pretty subtle.
     3041        if (computeIntrinsicHeight) {
     3042            int lostSpace = colHeight - colRect.height();
     3043            if (lostSpace > remainingSlopSpace) {
     3044                // Redestribute the space among the remaining columns.
     3045                int spaceToRedistribute = lostSpace - remainingSlopSpace;
     3046                int remainingColumns = colCount - i + 1;
     3047                colHeight += spaceToRedistribute / remainingColumns;
     3048            }
     3049            remainingSlopSpace = max(0, remainingSlopSpace - lostSpace);
     3050        }
     3051       
    29993052        if (style()->direction() == LTR)
    3000             currX += m_columnWidth + colGap;
     3053            currX += m_desiredColumnWidth + colGap;
    30013054        else
    3002             currX -= (m_columnWidth + colGap);
     3055            currX -= (m_desiredColumnWidth + colGap);
    30033056
    30043057        currY += colRect.height();
     
    30083061
    30093062        m_columnRects->append(colRect);
    3010     }
     3063       
     3064        // Start adding in more columns as long as there's still content left.
     3065        if (currY < endOfContent && i == colCount - 1)
     3066            colCount++;
     3067    }
     3068
     3069    m_overflowWidth = max(m_width, currX - colGap);
     3070    m_overflowLeft = min(0, currX + m_desiredColumnWidth + colGap);
    30113071
    30123072    m_overflowHeight = maxColBottom;
     
    30143074    if (includeHorizontalScrollbarSize())
    30153075        toAdd += m_layer->horizontalScrollbarHeight();
    3016     m_height =  m_overflowHeight + toAdd;
    3017     m_overflowWidth = m_width;
     3076       
     3077    if (computeIntrinsicHeight)
     3078        m_height = m_overflowHeight + toAdd;
    30183079
    30193080    v->setPrintRect(IntRect());
    30203081    v->setTruncatedAt(0);
    30213082   
    3022     ASSERT(m_columnRects && m_columnCount == m_columnRects->size());
     3083    ASSERT(m_columnRects && colCount == m_columnRects->size());
     3084   
     3085    return contentBottom;
    30233086}
    30243087
     
    30333096    int leftGap = colGap / 2;
    30343097    IntPoint columnPoint(m_columnRects->at(0).location());
     3098    int yOffset = 0;
    30353099    for (unsigned i = 0; i < m_columnRects->size(); i++) {
    30363100        // Add in half the column gap to the left and right of the rect.
     
    30383102        IntRect gapAndColumnRect(colRect.x() - leftGap, colRect.y(), colRect.width() + colGap, colRect.height());
    30393103       
    3040         if (gapAndColumnRect.contains(point))
     3104        if (gapAndColumnRect.contains(point)) {
    30413105            // We're inside the column.  Translate the x and y into our column coordinate space.
    3042             point -= columnPoint - colRect.location();
     3106            point.move(columnPoint.x() - colRect.x(), yOffset);
     3107            return;
     3108        }
    30433109
    30443110        // Move to the next position.
    3045         columnPoint.setY(columnPoint.y() + colRect.height());
     3111        yOffset += colRect.height();
    30463112    }
    30473113}
  • trunk/WebCore/rendering/RenderBlock.h

    r18758 r18762  
    281281    void clearTruncation();
    282282
    283     virtual bool hasColumns() const { return m_columnCount > 1; }
     283    virtual bool hasColumns() const { return m_desiredColumnCount > 1; }
    284284    void adjustRectForColumns(IntRect&) const;
    285285private:
     
    296296    int columnGap() const;
    297297    void calcColumnWidth();
    298     void layoutColumns();
     298    int layoutColumns(int endOfContent = -1);
    299299
    300300protected:
     
    462462   
    463463    // Column information.
    464     int m_columnWidth;
    465     unsigned m_columnCount;
     464    int m_desiredColumnWidth;
     465    unsigned m_desiredColumnCount;
    466466    Vector<IntRect>* m_columnRects;
    467467};
Note: See TracChangeset for help on using the changeset viewer.