1/**
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 2000 Simon Hausmann <hausmann@kde.org>
4 *           (C) 2000 Stefan Schimanski (1Stein@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/dom/EventNames.h"
29#include "core/dom/MouseEvent.h"
30#include "core/html/HTMLDimension.h"
31#include "core/html/HTMLFrameSetElement.h"
32#include "core/page/EventHandler.h"
33#include "core/page/Frame.h"
34#include "core/platform/Cursor.h"
35#include "core/platform/graphics/GraphicsContext.h"
36#include "core/rendering/PaintInfo.h"
37#include "core/rendering/RenderFrame.h"
38#include "core/rendering/RenderView.h"
39
40namespace WebCore {
41
42RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
43    : RenderBox(frameSet)
44    , m_isResizing(false)
45    , m_isChildResizing(false)
46{
47    setInline(false);
48}
49
50RenderFrameSet::~RenderFrameSet()
51{
52}
53
54RenderFrameSet::GridAxis::GridAxis()
55    : m_splitBeingResized(noSplit)
56{
57}
58
59inline HTMLFrameSetElement* RenderFrameSet::frameSet() const
60{
61    return static_cast<HTMLFrameSetElement*>(node());
62}
63
64static Color borderStartEdgeColor()
65{
66    return Color(170, 170, 170);
67}
68
69static Color borderEndEdgeColor()
70{
71    return Color::black;
72}
73
74static Color borderFillColor()
75{
76    return Color(208, 208, 208);
77}
78
79void 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
98void 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
117void 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
156void 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
169void 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
360void 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
369void 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
390void 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
418FrameEdgeInfo 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
438void RenderFrameSet::layout()
439{
440    StackStats::LayoutCheckPoint layoutCheckPoint;
441    ASSERT(needsLayout());
442
443    bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout();
444    LayoutRect oldBounds;
445    RenderLayerModelObject* repaintContainer = 0;
446    if (doFullRepaint) {
447        repaintContainer = containerForRepaint();
448        oldBounds = clippedOverflowRectForRepaint(repaintContainer);
449    }
450
451    if (!parent()->isFrameSet() && !document()->printing()) {
452        setWidth(view()->viewWidth());
453        setHeight(view()->viewHeight());
454    }
455
456    unsigned cols = frameSet()->totalCols();
457    unsigned rows = frameSet()->totalRows();
458
459    if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) {
460        m_rows.resize(rows);
461        m_cols.resize(cols);
462    }
463
464    LayoutUnit borderThickness = frameSet()->border();
465    layOutAxis(m_rows, frameSet()->rowLengths(), height() - (rows - 1) * borderThickness);
466    layOutAxis(m_cols, frameSet()->colLengths(), width() - (cols - 1) * borderThickness);
467
468    positionFrames();
469
470    RenderBox::layout();
471
472    computeEdgeInfo();
473
474    updateLayerTransform();
475
476    if (doFullRepaint) {
477        repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds));
478        LayoutRect newBounds = clippedOverflowRectForRepaint(repaintContainer);
479        if (newBounds != oldBounds)
480            repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds));
481    }
482
483    clearNeedsLayout();
484}
485
486void RenderFrameSet::positionFrames()
487{
488    RenderBox* child = firstChildBox();
489    if (!child)
490        return;
491
492    int rows = frameSet()->totalRows();
493    int cols = frameSet()->totalCols();
494
495    int yPos = 0;
496    int borderThickness = frameSet()->border();
497    for (int r = 0; r < rows; r++) {
498        int xPos = 0;
499        int height = m_rows.m_sizes[r];
500        for (int c = 0; c < cols; c++) {
501            child->setLocation(IntPoint(xPos, yPos));
502            int width = m_cols.m_sizes[c];
503
504            // has to be resized and itself resize its contents
505            if (width != child->width() || height != child->height()) {
506                child->setWidth(width);
507                child->setHeight(height);
508                child->setNeedsLayout();
509                child->layout();
510            }
511
512            xPos += width + borderThickness;
513
514            child = child->nextSiblingBox();
515            if (!child)
516                return;
517        }
518        yPos += height + borderThickness;
519    }
520
521    // all the remaining frames are hidden to avoid ugly spurious unflowed frames
522    for (; child; child = child->nextSiblingBox()) {
523        child->setWidth(0);
524        child->setHeight(0);
525        child->clearNeedsLayout();
526    }
527}
528
529void RenderFrameSet::startResizing(GridAxis& axis, int position)
530{
531    int split = hitTestSplit(axis, position);
532    if (split == noSplit || axis.m_preventResize[split]) {
533        axis.m_splitBeingResized = noSplit;
534        return;
535    }
536    axis.m_splitBeingResized = split;
537    axis.m_splitResizeOffset = position - splitPosition(axis, split);
538}
539
540void RenderFrameSet::continueResizing(GridAxis& axis, int position)
541{
542    if (needsLayout())
543        return;
544    if (axis.m_splitBeingResized == noSplit)
545        return;
546    int currentSplitPosition = splitPosition(axis, axis.m_splitBeingResized);
547    int delta = (position - currentSplitPosition) - axis.m_splitResizeOffset;
548    if (!delta)
549        return;
550    axis.m_deltas[axis.m_splitBeingResized - 1] += delta;
551    axis.m_deltas[axis.m_splitBeingResized] -= delta;
552    setNeedsLayout();
553}
554
555bool RenderFrameSet::userResize(MouseEvent* evt)
556{
557    if (!m_isResizing) {
558        if (needsLayout())
559            return false;
560        if (evt->type() == eventNames().mousedownEvent && evt->button() == LeftButton) {
561            FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms);
562            startResizing(m_cols, localPos.x());
563            startResizing(m_rows, localPos.y());
564            if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
565                setIsResizing(true);
566                return true;
567            }
568        }
569    } else {
570        if (evt->type() == eventNames().mousemoveEvent || (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton)) {
571            FloatPoint localPos = absoluteToLocal(evt->absoluteLocation(), UseTransforms);
572            continueResizing(m_cols, localPos.x());
573            continueResizing(m_rows, localPos.y());
574            if (evt->type() == eventNames().mouseupEvent && evt->button() == LeftButton) {
575                setIsResizing(false);
576                return true;
577            }
578        }
579    }
580
581    return false;
582}
583
584void RenderFrameSet::setIsResizing(bool isResizing)
585{
586    m_isResizing = isResizing;
587    for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
588        if (ancestor->isFrameSet())
589            toRenderFrameSet(ancestor)->m_isChildResizing = isResizing;
590    }
591    if (Frame* frame = this->frame())
592        frame->eventHandler()->setResizingFrameSet(isResizing ? frameSet() : 0);
593}
594
595bool RenderFrameSet::isResizingRow() const
596{
597    return m_isResizing && m_rows.m_splitBeingResized != noSplit;
598}
599
600bool RenderFrameSet::isResizingColumn() const
601{
602    return m_isResizing && m_cols.m_splitBeingResized != noSplit;
603}
604
605bool RenderFrameSet::canResizeRow(const IntPoint& p) const
606{
607    int r = hitTestSplit(m_rows, p.y());
608    return r != noSplit && !m_rows.m_preventResize[r];
609}
610
611bool RenderFrameSet::canResizeColumn(const IntPoint& p) const
612{
613    int c = hitTestSplit(m_cols, p.x());
614    return c != noSplit && !m_cols.m_preventResize[c];
615}
616
617int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const
618{
619    if (needsLayout())
620        return 0;
621
622    int borderThickness = frameSet()->border();
623
624    int size = axis.m_sizes.size();
625    if (!size)
626        return 0;
627
628    int position = 0;
629    for (int i = 0; i < split && i < size; ++i)
630        position += axis.m_sizes[i] + borderThickness;
631    return position - borderThickness;
632}
633
634int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const
635{
636    if (needsLayout())
637        return noSplit;
638
639    int borderThickness = frameSet()->border();
640    if (borderThickness <= 0)
641        return noSplit;
642
643    size_t size = axis.m_sizes.size();
644    if (!size)
645        return noSplit;
646
647    int splitPosition = axis.m_sizes[0];
648    for (size_t i = 1; i < size; ++i) {
649        if (position >= splitPosition && position < splitPosition + borderThickness)
650            return i;
651        splitPosition += borderThickness + axis.m_sizes[i];
652    }
653    return noSplit;
654}
655
656bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const
657{
658    return child->isFrame() || child->isFrameSet();
659}
660
661CursorDirective RenderFrameSet::getCursor(const LayoutPoint& point, Cursor& cursor) const
662{
663    IntPoint roundedPoint = roundedIntPoint(point);
664    if (canResizeRow(roundedPoint)) {
665        cursor = rowResizeCursor();
666        return SetCursor;
667    }
668    if (canResizeColumn(roundedPoint)) {
669        cursor = columnResizeCursor();
670        return SetCursor;
671    }
672    return RenderBox::getCursor(point, cursor);
673}
674
675} // namespace WebCore
676