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