Home | History | Annotate | Download | only in rendering
      1 /**
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 2000 Simon Hausmann <hausmann (at) kde.org>
      4  *           (C) 2000 Stefan Schimanski (1Stein (at) gmx.de)
      5  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
      6  *
      7  * This library is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU Library General Public
      9  * License as published by the Free Software Foundation; either
     10  * version 2 of the License, or (at your option) any later version.
     11  *
     12  * This library is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15  * Library General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU Library General Public License
     18  * along with this library; see the file COPYING.LIB.  If not, write to
     19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     20  * Boston, MA 02110-1301, USA.
     21  *
     22  */
     23 
     24 #include "config.h"
     25 #include "core/rendering/RenderFrameSet.h"
     26 
     27 #include "core/dom/Document.h"
     28 #include "core/events/MouseEvent.h"
     29 #include "core/events/ThreadLocalEventNames.h"
     30 #include "core/html/HTMLDimension.h"
     31 #include "core/html/HTMLFrameSetElement.h"
     32 #include "core/page/EventHandler.h"
     33 #include "core/frame/Frame.h"
     34 #include "core/rendering/GraphicsContextAnnotator.h"
     35 #include "core/rendering/LayoutRectRecorder.h"
     36 #include "core/rendering/PaintInfo.h"
     37 #include "core/rendering/RenderFrame.h"
     38 #include "core/rendering/RenderView.h"
     39 #include "platform/Cursor.h"
     40 #include "platform/graphics/GraphicsContext.h"
     41 
     42 namespace WebCore {
     43 
     44 RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
     45     : RenderBox(frameSet)
     46     , m_isResizing(false)
     47     , m_isChildResizing(false)
     48 {
     49     setInline(false);
     50 }
     51 
     52 RenderFrameSet::~RenderFrameSet()
     53 {
     54 }
     55 
     56 RenderFrameSet::GridAxis::GridAxis()
     57     : m_splitBeingResized(noSplit)
     58 {
     59 }
     60 
     61 inline HTMLFrameSetElement* RenderFrameSet::frameSet() const
     62 {
     63     return toHTMLFrameSetElement(node());
     64 }
     65 
     66 static Color borderStartEdgeColor()
     67 {
     68     return Color(170, 170, 170);
     69 }
     70 
     71 static Color borderEndEdgeColor()
     72 {
     73     return Color::black;
     74 }
     75 
     76 static Color borderFillColor()
     77 {
     78     return Color(208, 208, 208);
     79 }
     80 
     81 void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
     82 {
     83     if (!paintInfo.rect.intersects(borderRect))
     84         return;
     85 
     86     // FIXME: We should do something clever when borders from distinct framesets meet at a join.
     87 
     88     // Fill first.
     89     GraphicsContext* context = paintInfo.context;
     90     context->fillRect(borderRect, frameSet()->hasBorderColor() ? resolveColor(CSSPropertyBorderLeftColor) : borderFillColor());
     91 
     92     // Now stroke the edges but only if we have enough room to paint both edges with a little
     93     // bit of the fill color showing through.
     94     if (borderRect.width() >= 3) {
     95         context->fillRect(IntRect(borderRect.location(), IntSize(1, height())), borderStartEdgeColor());
     96         context->fillRect(IntRect(IntPoint(borderRect.maxX() - 1, borderRect.y()), IntSize(1, height())), borderEndEdgeColor());
     97     }
     98 }
     99 
    100 void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
    101 {
    102     if (!paintInfo.rect.intersects(borderRect))
    103         return;
    104 
    105     // FIXME: We should do something clever when borders from distinct framesets meet at a join.
    106 
    107     // Fill first.
    108     GraphicsContext* context = paintInfo.context;
    109     context->fillRect(borderRect, frameSet()->hasBorderColor() ? resolveColor(CSSPropertyBorderLeftColor) : borderFillColor());
    110 
    111     // Now stroke the edges but only if we have enough room to paint both edges with a little
    112     // bit of the fill color showing through.
    113     if (borderRect.height() >= 3) {
    114         context->fillRect(IntRect(borderRect.location(), IntSize(width(), 1)), borderStartEdgeColor());
    115         context->fillRect(IntRect(IntPoint(borderRect.x(), borderRect.maxY() - 1), IntSize(width(), 1)), borderEndEdgeColor());
    116     }
    117 }
    118 
    119 void RenderFrameSet::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    120 {
    121     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
    122 
    123     if (paintInfo.phase != PaintPhaseForeground)
    124         return;
    125 
    126     RenderObject* child = firstChild();
    127     if (!child)
    128         return;
    129 
    130     LayoutPoint adjustedPaintOffset = paintOffset + location();
    131 
    132     size_t rows = m_rows.m_sizes.size();
    133     size_t cols = m_cols.m_sizes.size();
    134     LayoutUnit borderThickness = frameSet()->border();
    135 
    136     LayoutUnit yPos = 0;
    137     for (size_t r = 0; r < rows; r++) {
    138         LayoutUnit xPos = 0;
    139         for (size_t c = 0; c < cols; c++) {
    140             child->paint(paintInfo, adjustedPaintOffset);
    141             xPos += m_cols.m_sizes[c];
    142             if (borderThickness && m_cols.m_allowBorder[c + 1]) {
    143                 paintColumnBorder(paintInfo, pixelSnappedIntRect(LayoutRect(adjustedPaintOffset.x() + xPos, adjustedPaintOffset.y() + yPos, borderThickness, height())));
    144                 xPos += borderThickness;
    145             }
    146             child = child->nextSibling();
    147             if (!child)
    148                 return;
    149         }
    150         yPos += m_rows.m_sizes[r];
    151         if (borderThickness && m_rows.m_allowBorder[r + 1]) {
    152             paintRowBorder(paintInfo, pixelSnappedIntRect(LayoutRect(adjustedPaintOffset.x(), adjustedPaintOffset.y() + yPos, width(), borderThickness)));
    153             yPos += borderThickness;
    154         }
    155     }
    156 }
    157 
    158 void RenderFrameSet::GridAxis::resize(int size)
    159 {
    160     m_sizes.resize(size);
    161     m_deltas.resize(size);
    162     m_deltas.fill(0);
    163 
    164     // To track edges for resizability and borders, we need to be (size + 1). This is because a parent frameset
    165     // may ask us for information about our left/top/right/bottom edges in order to make its own decisions about
    166     // what to do. We are capable of tainting that parent frameset's borders, so we have to cache this info.
    167     m_preventResize.resize(size + 1);
    168     m_allowBorder.resize(size + 1);
    169 }
    170 
    171 void RenderFrameSet::layOutAxis(GridAxis& axis, const Vector<HTMLDimension>& grid, int availableLen)
    172 {
    173     availableLen = max(availableLen, 0);
    174 
    175     int* gridLayout = axis.m_sizes.data();
    176 
    177     if (grid.isEmpty()) {
    178         gridLayout[0] = availableLen;
    179         return;
    180     }
    181 
    182     int gridLen = axis.m_sizes.size();
    183     ASSERT(gridLen);
    184 
    185     int totalRelative = 0;
    186     int totalFixed = 0;
    187     int totalPercent = 0;
    188     int countRelative = 0;
    189     int countFixed = 0;
    190     int countPercent = 0;
    191 
    192     // First we need to investigate how many columns of each type we have and
    193     // how much space these columns are going to require.
    194     for (int i = 0; i < gridLen; ++i) {
    195         // Count the total length of all of the fixed columns/rows -> totalFixed
    196         // Count the number of columns/rows which are fixed -> countFixed
    197         if (grid[i].isAbsolute()) {
    198             gridLayout[i] = max<int>(grid[i].value(), 0);
    199             totalFixed += gridLayout[i];
    200             countFixed++;
    201         }
    202 
    203         // Count the total percentage of all of the percentage columns/rows -> totalPercent
    204         // Count the number of columns/rows which are percentages -> countPercent
    205         if (grid[i].isPercentage()) {
    206             gridLayout[i] = max<int>(grid[i].value() * availableLen / 100., 0);
    207             totalPercent += gridLayout[i];
    208             countPercent++;
    209         }
    210 
    211         // Count the total relative of all the relative columns/rows -> totalRelative
    212         // Count the number of columns/rows which are relative -> countRelative
    213         if (grid[i].isRelative()) {
    214             totalRelative += max<int>(grid[i].value(), 1);
    215             countRelative++;
    216         }
    217     }
    218 
    219     int remainingLen = availableLen;
    220 
    221     // Fixed columns/rows are our first priority. If there is not enough space to fit all fixed
    222     // columns/rows we need to proportionally adjust their size.
    223     if (totalFixed > remainingLen) {
    224         int remainingFixed = remainingLen;
    225 
    226         for (int i = 0; i < gridLen; ++i) {
    227             if (grid[i].isAbsolute()) {
    228                 gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed;
    229                 remainingLen -= gridLayout[i];
    230             }
    231         }
    232     } else
    233         remainingLen -= totalFixed;
    234 
    235     // Percentage columns/rows are our second priority. Divide the remaining space proportionally
    236     // over all percentage columns/rows. IMPORTANT: the size of each column/row is not relative
    237     // to 100%, but to the total percentage. For example, if there are three columns, each of 75%,
    238     // and the available space is 300px, each column will become 100px in width.
    239     if (totalPercent > remainingLen) {
    240         int remainingPercent = remainingLen;
    241 
    242         for (int i = 0; i < gridLen; ++i) {
    243             if (grid[i].isPercentage()) {
    244                 gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent;
    245                 remainingLen -= gridLayout[i];
    246             }
    247         }
    248     } else
    249         remainingLen -= totalPercent;
    250 
    251     // Relative columns/rows are our last priority. Divide the remaining space proportionally
    252     // over all relative columns/rows. IMPORTANT: the relative value of 0* is treated as 1*.
    253     if (countRelative) {
    254         int lastRelative = 0;
    255         int remainingRelative = remainingLen;
    256 
    257         for (int i = 0; i < gridLen; ++i) {
    258             if (grid[i].isRelative()) {
    259                 gridLayout[i] = (max(grid[i].value(), 1.) * remainingRelative) / totalRelative;
    260                 remainingLen -= gridLayout[i];
    261                 lastRelative = i;
    262             }
    263         }
    264 
    265         // If we could not evenly distribute the available space of all of the relative
    266         // columns/rows, the remainder will be added to the last column/row.
    267         // For example: if we have a space of 100px and three columns (*,*,*), the remainder will
    268         // be 1px and will be added to the last column: 33px, 33px, 34px.
    269         if (remainingLen) {
    270             gridLayout[lastRelative] += remainingLen;
    271             remainingLen = 0;
    272         }
    273     }
    274 
    275     // If we still have some left over space we need to divide it over the already existing
    276     // columns/rows
    277     if (remainingLen) {
    278         // Our first priority is to spread if over the percentage columns. The remaining
    279         // space is spread evenly, for example: if we have a space of 100px, the columns
    280         // definition of 25%,25% used to result in two columns of 25px. After this the
    281         // columns will each be 50px in width.
    282         if (countPercent && totalPercent) {
    283             int remainingPercent = remainingLen;
    284             int changePercent = 0;
    285 
    286             for (int i = 0; i < gridLen; ++i) {
    287                 if (grid[i].isPercentage()) {
    288                     changePercent = (remainingPercent * gridLayout[i]) / totalPercent;
    289                     gridLayout[i] += changePercent;
    290                     remainingLen -= changePercent;
    291                 }
    292             }
    293         } else if (totalFixed) {
    294             // Our last priority is to spread the remaining space over the fixed columns.
    295             // For example if we have 100px of space and two column of each 40px, both
    296             // columns will become exactly 50px.
    297             int remainingFixed = remainingLen;
    298             int changeFixed = 0;
    299 
    300             for (int i = 0; i < gridLen; ++i) {
    301                 if (grid[i].isAbsolute()) {
    302                     changeFixed = (remainingFixed * gridLayout[i]) / totalFixed;
    303                     gridLayout[i] += changeFixed;
    304                     remainingLen -= changeFixed;
    305                 }
    306             }
    307         }
    308     }
    309 
    310     // If we still have some left over space we probably ended up with a remainder of
    311     // a division. We cannot spread it evenly anymore. If we have any percentage
    312     // columns/rows simply spread the remainder equally over all available percentage columns,
    313     // regardless of their size.
    314     if (remainingLen && countPercent) {
    315         int remainingPercent = remainingLen;
    316         int changePercent = 0;
    317 
    318         for (int i = 0; i < gridLen; ++i) {
    319             if (grid[i].isPercentage()) {
    320                 changePercent = remainingPercent / countPercent;
    321                 gridLayout[i] += changePercent;
    322                 remainingLen -= changePercent;
    323             }
    324         }
    325     } else if (remainingLen && countFixed) {
    326         // If we don't have any percentage columns/rows we only have
    327         // fixed columns. Spread the remainder equally over all fixed
    328         // columns/rows.
    329         int remainingFixed = remainingLen;
    330         int changeFixed = 0;
    331 
    332         for (int i = 0; i < gridLen; ++i) {
    333             if (grid[i].isAbsolute()) {
    334                 changeFixed = remainingFixed / countFixed;
    335                 gridLayout[i] += changeFixed;
    336                 remainingLen -= changeFixed;
    337             }
    338         }
    339     }
    340 
    341     // Still some left over. Add it to the last column, because it is impossible
    342     // spread it evenly or equally.
    343     if (remainingLen)
    344         gridLayout[gridLen - 1] += remainingLen;
    345 
    346     // now we have the final layout, distribute the delta over it
    347     bool worked = true;
    348     int* gridDelta = axis.m_deltas.data();
    349     for (int i = 0; i < gridLen; ++i) {
    350         if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0)
    351             worked = false;
    352         gridLayout[i] += gridDelta[i];
    353     }
    354     // if the deltas broke something, undo them
    355     if (!worked) {
    356         for (int i = 0; i < gridLen; ++i)
    357             gridLayout[i] -= gridDelta[i];
    358         axis.m_deltas.fill(0);
    359     }
    360 }
    361 
    362 void RenderFrameSet::notifyFrameEdgeInfoChanged()
    363 {
    364     if (needsLayout())
    365         return;
    366     // FIXME: We should only recompute the edge info with respect to the frame that changed
    367     // and its adjacent frame(s) instead of recomputing the edge info for the entire frameset.
    368     computeEdgeInfo();
    369 }
    370 
    371 void RenderFrameSet::fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c)
    372 {
    373     if (edgeInfo.allowBorder(LeftFrameEdge))
    374         m_cols.m_allowBorder[c] = true;
    375     if (edgeInfo.allowBorder(RightFrameEdge))
    376         m_cols.m_allowBorder[c + 1] = true;
    377     if (edgeInfo.preventResize(LeftFrameEdge))
    378         m_cols.m_preventResize[c] = true;
    379     if (edgeInfo.preventResize(RightFrameEdge))
    380         m_cols.m_preventResize[c + 1] = true;
    381 
    382     if (edgeInfo.allowBorder(TopFrameEdge))
    383         m_rows.m_allowBorder[r] = true;
    384     if (edgeInfo.allowBorder(BottomFrameEdge))
    385         m_rows.m_allowBorder[r + 1] = true;
    386     if (edgeInfo.preventResize(TopFrameEdge))
    387         m_rows.m_preventResize[r] = true;
    388     if (edgeInfo.preventResize(BottomFrameEdge))
    389         m_rows.m_preventResize[r + 1] = true;
    390 }
    391 
    392 void RenderFrameSet::computeEdgeInfo()
    393 {
    394     m_rows.m_preventResize.fill(frameSet()->noResize());
    395     m_rows.m_allowBorder.fill(false);
    396     m_cols.m_preventResize.fill(frameSet()->noResize());
    397     m_cols.m_allowBorder.fill(false);
    398 
    399     RenderObject* child = firstChild();
    400     if (!child)
    401         return;
    402 
    403     size_t rows = m_rows.m_sizes.size();
    404     size_t cols = m_cols.m_sizes.size();
    405     for (size_t r = 0; r < rows; ++r) {
    406         for (size_t c = 0; c < cols; ++c) {
    407             FrameEdgeInfo edgeInfo;
    408             if (child->isFrameSet())
    409                 edgeInfo = toRenderFrameSet(child)->edgeInfo();
    410             else
    411                 edgeInfo = toRenderFrame(child)->edgeInfo();
    412             fillFromEdgeInfo(edgeInfo, r, c);
    413             child = child->nextSibling();
    414             if (!child)
    415                 return;
    416         }
    417     }
    418 }
    419 
    420 FrameEdgeInfo RenderFrameSet::edgeInfo() const
    421 {
    422     FrameEdgeInfo result(frameSet()->noResize(), true);
    423 
    424     int rows = frameSet()->totalRows();
    425     int cols = frameSet()->totalCols();
    426     if (rows && cols) {
    427         result.setPreventResize(LeftFrameEdge, m_cols.m_preventResize[0]);
    428         result.setAllowBorder(LeftFrameEdge, m_cols.m_allowBorder[0]);
    429         result.setPreventResize(RightFrameEdge, m_cols.m_preventResize[cols]);
    430         result.setAllowBorder(RightFrameEdge, m_cols.m_allowBorder[cols]);
    431         result.setPreventResize(TopFrameEdge, m_rows.m_preventResize[0]);
    432         result.setAllowBorder(TopFrameEdge, m_rows.m_allowBorder[0]);
    433         result.setPreventResize(BottomFrameEdge, m_rows.m_preventResize[rows]);
    434         result.setAllowBorder(BottomFrameEdge, m_rows.m_allowBorder[rows]);
    435     }
    436 
    437     return result;
    438 }
    439 
    440 void RenderFrameSet::layout()
    441 {
    442     ASSERT(needsLayout());
    443 
    444     LayoutRectRecorder recorder(*this);
    445     bool doFullRepaint = !RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && selfNeedsLayout() && checkForRepaintDuringLayout();
    446     LayoutRect oldBounds;
    447     RenderLayerModelObject* repaintContainer = 0;
    448     if (doFullRepaint) {
    449         repaintContainer = containerForRepaint();
    450         oldBounds = clippedOverflowRectForRepaint(repaintContainer);
    451     }
    452 
    453     if (!parent()->isFrameSet() && !document().printing()) {
    454         setWidth(view()->viewWidth());
    455         setHeight(view()->viewHeight());
    456     }
    457 
    458     unsigned cols = frameSet()->totalCols();
    459     unsigned rows = frameSet()->totalRows();
    460 
    461     if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) {
    462         m_rows.resize(rows);
    463         m_cols.resize(cols);
    464     }
    465 
    466     LayoutUnit borderThickness = frameSet()->border();
    467     layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness);
    468     layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness);
    469 
    470     positionFrames();
    471 
    472     RenderBox::layout();
    473 
    474     computeEdgeInfo();
    475 
    476     updateLayerTransform();
    477 
    478     if (doFullRepaint) {
    479         repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds));
    480         LayoutRect newBounds = clippedOverflowRectForRepaint(repaintContainer);
    481         if (newBounds != oldBounds)
    482             repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds));
    483     }
    484 
    485     clearNeedsLayout();
    486 }
    487 
    488 static void clearNeedsLayoutOnHiddenFrames(RenderBox* frame)
    489 {
    490     for (; frame; frame = frame->nextSiblingBox()) {
    491         frame->setWidth(0);
    492         frame->setHeight(0);
    493         frame->clearNeedsLayout();
    494         clearNeedsLayoutOnHiddenFrames(frame->firstChildBox());
    495     }
    496 }
    497 
    498 void RenderFrameSet::positionFrames()
    499 {
    500     RenderBox* child = firstChildBox();
    501     if (!child)
    502         return;
    503 
    504     int rows = frameSet()->totalRows();
    505     int cols = frameSet()->totalCols();
    506 
    507     int yPos = 0;
    508     int borderThickness = frameSet()->border();
    509     for (int r = 0; r < rows; r++) {
    510         int xPos = 0;
    511         int height = m_rows.m_sizes[r];
    512         for (int c = 0; c < cols; c++) {
    513             child->setLocation(IntPoint(xPos, yPos));
    514             int width = m_cols.m_sizes[c];
    515 
    516             // has to be resized and itself resize its contents
    517             if (width != child->width() || height != child->height()) {
    518                 child->setWidth(width);
    519                 child->setHeight(height);
    520                 child->setNeedsLayout();
    521                 child->layout();
    522             }
    523 
    524             xPos += width + borderThickness;
    525 
    526             child = child->nextSiblingBox();
    527             if (!child)
    528                 return;
    529         }
    530         yPos += height + borderThickness;
    531     }
    532 
    533     // All the remaining frames are hidden to avoid ugly spurious unflowed frames.
    534     clearNeedsLayoutOnHiddenFrames(child);
    535 }
    536 
    537 void RenderFrameSet::startResizing(GridAxis& axis, int position)
    538 {
    539     int split = hitTestSplit(axis, position);
    540     if (split == noSplit || axis.m_preventResize[split]) {
    541         axis.m_splitBeingResized = noSplit;
    542         return;
    543     }
    544     axis.m_splitBeingResized = split;
    545     axis.m_splitResizeOffset = position - splitPosition(axis, split);
    546 }
    547 
    548 void RenderFrameSet::continueResizing(GridAxis& axis, int position)
    549 {
    550     if (needsLayout())
    551         return;
    552     if (axis.m_splitBeingResized == noSplit)
    553         return;
    554     int currentSplitPosition = splitPosition(axis, axis.m_splitBeingResized);
    555     int delta = (position - currentSplitPosition) - axis.m_splitResizeOffset;
    556     if (!delta)
    557         return;
    558     axis.m_deltas[axis.m_splitBeingResized - 1] += delta;
    559     axis.m_deltas[axis.m_splitBeingResized] -= delta;
    560     setNeedsLayout();
    561 }
    562 
    563 bool RenderFrameSet::userResize(MouseEvent* evt)
    564 {
    565     if (!m_isResizing) {
    566         if (needsLayout())
    567             return false;
    568         if (evt->type() == EventTypeNames::mousedown && evt->button() == LeftButton) {
    569             FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms);
    570             startResizing(m_cols, localPos.x());
    571             startResizing(m_rows, localPos.y());
    572             if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
    573                 setIsResizing(true);
    574                 return true;
    575             }
    576         }
    577     } else {
    578         if (evt->type() == EventTypeNames::mousemove || (evt->type() == EventTypeNames::mouseup && evt->button() == LeftButton)) {
    579             FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms);
    580             continueResizing(m_cols, localPos.x());
    581             continueResizing(m_rows, localPos.y());
    582             if (evt->type() == EventTypeNames::mouseup && evt->button() == LeftButton) {
    583                 setIsResizing(false);
    584                 return true;
    585             }
    586         }
    587     }
    588 
    589     return false;
    590 }
    591 
    592 void RenderFrameSet::setIsResizing(bool isResizing)
    593 {
    594     m_isResizing = isResizing;
    595     for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
    596         if (ancestor->isFrameSet())
    597             toRenderFrameSet(ancestor)->m_isChildResizing = isResizing;
    598     }
    599     if (Frame* frame = this->frame())
    600         frame->eventHandler().setResizingFrameSet(isResizing ? frameSet() : 0);
    601 }
    602 
    603 bool RenderFrameSet::isResizingRow() const
    604 {
    605     return m_isResizing && m_rows.m_splitBeingResized != noSplit;
    606 }
    607 
    608 bool RenderFrameSet::isResizingColumn() const
    609 {
    610     return m_isResizing && m_cols.m_splitBeingResized != noSplit;
    611 }
    612 
    613 bool RenderFrameSet::canResizeRow(const IntPoint& p) const
    614 {
    615     int r = hitTestSplit(m_rows, p.y());
    616     return r != noSplit && !m_rows.m_preventResize[r];
    617 }
    618 
    619 bool RenderFrameSet::canResizeColumn(const IntPoint& p) const
    620 {
    621     int c = hitTestSplit(m_cols, p.x());
    622     return c != noSplit && !m_cols.m_preventResize[c];
    623 }
    624 
    625 int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const
    626 {
    627     if (needsLayout())
    628         return 0;
    629 
    630     int borderThickness = frameSet()->border();
    631 
    632     int size = axis.m_sizes.size();
    633     if (!size)
    634         return 0;
    635 
    636     int position = 0;
    637     for (int i = 0; i < split && i < size; ++i)
    638         position += axis.m_sizes[i] + borderThickness;
    639     return position - borderThickness;
    640 }
    641 
    642 int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const
    643 {
    644     if (needsLayout())
    645         return noSplit;
    646 
    647     int borderThickness = frameSet()->border();
    648     if (borderThickness <= 0)
    649         return noSplit;
    650 
    651     size_t size = axis.m_sizes.size();
    652     if (!size)
    653         return noSplit;
    654 
    655     int splitPosition = axis.m_sizes[0];
    656     for (size_t i = 1; i < size; ++i) {
    657         if (position >= splitPosition && position < splitPosition + borderThickness)
    658             return i;
    659         splitPosition += borderThickness + axis.m_sizes[i];
    660     }
    661     return noSplit;
    662 }
    663 
    664 bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const
    665 {
    666     return child->isFrame() || child->isFrameSet();
    667 }
    668 
    669 CursorDirective RenderFrameSet::getCursor(const LayoutPoint& point, Cursor& cursor) const
    670 {
    671     IntPoint roundedPoint = roundedIntPoint(point);
    672     if (canResizeRow(roundedPoint)) {
    673         cursor = rowResizeCursor();
    674         return SetCursor;
    675     }
    676     if (canResizeColumn(roundedPoint)) {
    677         cursor = columnResizeCursor();
    678         return SetCursor;
    679     }
    680     return RenderBox::getCursor(point, cursor);
    681 }
    682 
    683 } // namespace WebCore
    684