• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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 
RenderFrameSet(HTMLFrameSetElement * frameSet)42 RenderFrameSet::RenderFrameSet(HTMLFrameSetElement* frameSet)
43     : RenderBox(frameSet)
44     , m_isResizing(false)
45     , m_isChildResizing(false)
46 {
47     setInline(false);
48 }
49 
~RenderFrameSet()50 RenderFrameSet::~RenderFrameSet()
51 {
52 }
53 
GridAxis()54 RenderFrameSet::GridAxis::GridAxis()
55     : m_splitBeingResized(noSplit)
56 {
57 }
58 
frameSet() const59 inline HTMLFrameSetElement* RenderFrameSet::frameSet() const
60 {
61     return toHTMLFrameSetElement(node());
62 }
63 
borderStartEdgeColor()64 static Color borderStartEdgeColor()
65 {
66     return Color(170, 170, 170);
67 }
68 
borderEndEdgeColor()69 static Color borderEndEdgeColor()
70 {
71     return Color::black;
72 }
73 
borderFillColor()74 static Color borderFillColor()
75 {
76     return Color(208, 208, 208);
77 }
78 
paintColumnBorder(const PaintInfo & paintInfo,const IntRect & borderRect)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 
paintRowBorder(const PaintInfo & paintInfo,const IntRect & borderRect)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 
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)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 
resize(int size)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 
layOutAxis(GridAxis & axis,const Vector<HTMLDimension> & grid,int availableLen)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 
notifyFrameEdgeInfoChanged()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 
fillFromEdgeInfo(const FrameEdgeInfo & edgeInfo,int r,int c)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 
computeEdgeInfo()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 
edgeInfo() const418 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 
layout()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 
clearNeedsLayoutOnHiddenFrames(RenderBox * frame)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 
positionFrames()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 
startResizing(GridAxis & axis,int position)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 
continueResizing(GridAxis & axis,int position)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 
userResize(MouseEvent * evt)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 
setIsResizing(bool isResizing)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 
canResizeRow(const IntPoint & p) const600 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 
canResizeColumn(const IntPoint & p) const606 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 
splitPosition(const GridAxis & axis,int split) const612 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 
hitTestSplit(const GridAxis & axis,int position) const629 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 
isChildAllowed(RenderObject * child,RenderStyle *) const651 bool RenderFrameSet::isChildAllowed(RenderObject* child, RenderStyle*) const
652 {
653     return child->isFrame() || child->isFrameSet();
654 }
655 
getCursor(const LayoutPoint & point,Cursor & cursor) const656 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