• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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