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