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