[Settings] Remove all custom code from Settings.h/cpp
[WebKit-https.git] / Source / WebCore / rendering / RenderFrameSet.cpp
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, 2013 Apple 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 "RenderFrameSet.h"
26
27 #include "Cursor.h"
28 #include "Document.h"
29 #include "EventHandler.h"
30 #include "EventNames.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLFrameSetElement.h"
35 #include "HitTestRequest.h"
36 #include "HitTestResult.h"
37 #include "MouseEvent.h"
38 #include "PaintInfo.h"
39 #include "RenderFrame.h"
40 #include "RenderIterator.h"
41 #include "RenderLayer.h"
42 #include "RenderView.h"
43 #include "Settings.h"
44 #include <wtf/StackStats.h>
45
46 namespace WebCore {
47
48 RenderFrameSet::RenderFrameSet(HTMLFrameSetElement& frameSet, RenderStyle&& style)
49     : RenderBox(frameSet, WTFMove(style), 0)
50     , m_isResizing(false)
51     , m_isChildResizing(false)
52 {
53     setInline(false);
54 }
55
56 RenderFrameSet::~RenderFrameSet()
57 {
58 }
59
60 HTMLFrameSetElement& RenderFrameSet::frameSetElement() const
61 {
62     return downcast<HTMLFrameSetElement>(nodeForNonAnonymous());
63 }
64
65 RenderFrameSet::GridAxis::GridAxis()
66     : m_splitBeingResized(noSplit)
67 {
68 }
69
70 static const Color& borderStartEdgeColor()
71 {
72     static NeverDestroyed<Color> color(170, 170, 170);
73     return color;
74 }
75
76 static const Color& borderEndEdgeColor()
77 {
78     static NeverDestroyed<Color> color = Color::black;
79     return color;
80 }
81
82 static const Color& borderFillColor()
83 {
84     static NeverDestroyed<Color> color(208, 208, 208);
85     return color;
86 }
87
88 void RenderFrameSet::paintColumnBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
89 {
90     if (!paintInfo.rect.intersects(borderRect))
91         return;
92         
93     // FIXME: We should do something clever when borders from distinct framesets meet at a join.
94     
95     // Fill first.
96     GraphicsContext& context = paintInfo.context();
97     context.fillRect(borderRect, frameSetElement().hasBorderColor() ? style().visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor());
98     
99     // Now stroke the edges but only if we have enough room to paint both edges with a little
100     // bit of the fill color showing through.
101     if (borderRect.width() >= 3) {
102         context.fillRect(IntRect(borderRect.location(), IntSize(1, height())), borderStartEdgeColor());
103         context.fillRect(IntRect(IntPoint(borderRect.maxX() - 1, borderRect.y()), IntSize(1, height())), borderEndEdgeColor());
104     }
105 }
106
107 void RenderFrameSet::paintRowBorder(const PaintInfo& paintInfo, const IntRect& borderRect)
108 {
109     if (!paintInfo.rect.intersects(borderRect))
110         return;
111
112     // FIXME: We should do something clever when borders from distinct framesets meet at a join.
113     
114     // Fill first.
115     GraphicsContext& context = paintInfo.context();
116     context.fillRect(borderRect, frameSetElement().hasBorderColor() ? style().visitedDependentColor(CSSPropertyBorderLeftColor) : borderFillColor());
117
118     // Now stroke the edges but only if we have enough room to paint both edges with a little
119     // bit of the fill color showing through.
120     if (borderRect.height() >= 3) {
121         context.fillRect(IntRect(borderRect.location(), IntSize(width(), 1)), borderStartEdgeColor());
122         context.fillRect(IntRect(IntPoint(borderRect.x(), borderRect.maxY() - 1), IntSize(width(), 1)), borderEndEdgeColor());
123     }
124 }
125
126 void RenderFrameSet::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
127 {
128     if (paintInfo.phase != PaintPhaseForeground)
129         return;
130     
131     RenderObject* child = firstChild();
132     if (!child)
133         return;
134
135     LayoutPoint adjustedPaintOffset = paintOffset + location();
136
137     size_t rows = m_rows.m_sizes.size();
138     size_t cols = m_cols.m_sizes.size();
139     LayoutUnit borderThickness = frameSetElement().border();
140     
141     LayoutUnit yPos = 0;
142     for (size_t r = 0; r < rows; r++) {
143         LayoutUnit xPos = 0;
144         for (size_t c = 0; c < cols; c++) {
145             downcast<RenderElement>(*child).paint(paintInfo, adjustedPaintOffset);
146             xPos += m_cols.m_sizes[c];
147             if (borderThickness && m_cols.m_allowBorder[c + 1]) {
148                 paintColumnBorder(paintInfo, snappedIntRect(LayoutRect(adjustedPaintOffset.x() + xPos, adjustedPaintOffset.y() + yPos, borderThickness, height())));
149                 xPos += borderThickness;
150             }
151             child = child->nextSibling();
152             if (!child)
153                 return;
154         }
155         yPos += m_rows.m_sizes[r];
156         if (borderThickness && m_rows.m_allowBorder[r + 1]) {
157             paintRowBorder(paintInfo, snappedIntRect(LayoutRect(adjustedPaintOffset.x(), adjustedPaintOffset.y() + yPos, width(), borderThickness)));
158             yPos += borderThickness;
159         }
160     }
161 }
162
163 void RenderFrameSet::GridAxis::resize(int size)
164 {
165     m_sizes.resize(size);
166     m_deltas.resize(size);
167     m_deltas.fill(0);
168     
169     // To track edges for resizability and borders, we need to be (size + 1). This is because a parent frameset
170     // may ask us for information about our left/top/right/bottom edges in order to make its own decisions about
171     // what to do. We are capable of tainting that parent frameset's borders, so we have to cache this info.
172     m_preventResize.resize(size + 1);
173     m_allowBorder.resize(size + 1);
174 }
175
176 void RenderFrameSet::layOutAxis(GridAxis& axis, const Length* grid, int availableLen)
177 {
178     availableLen = std::max(availableLen, 0);
179
180     int* gridLayout = axis.m_sizes.data();
181
182     if (!grid) {
183         gridLayout[0] = availableLen;
184         return;
185     }
186
187     int gridLen = axis.m_sizes.size();
188     ASSERT(gridLen);
189
190     int totalRelative = 0;
191     int totalFixed = 0;
192     int totalPercent = 0;
193     int countRelative = 0;
194     int countFixed = 0;
195     int countPercent = 0;
196
197     // First we need to investigate how many columns of each type we have and
198     // how much space these columns are going to require.
199     for (int i = 0; i < gridLen; ++i) {
200         // Count the total length of all of the fixed columns/rows -> totalFixed
201         // Count the number of columns/rows which are fixed -> countFixed
202         if (grid[i].isFixed()) {
203             gridLayout[i] = std::max(grid[i].intValue(), 0);
204             totalFixed += gridLayout[i];
205             countFixed++;
206         }
207         
208         // Count the total percentage of all of the percentage columns/rows -> totalPercent
209         // Count the number of columns/rows which are percentages -> countPercent
210         if (grid[i].isPercentOrCalculated()) {
211             gridLayout[i] = std::max(intValueForLength(grid[i], availableLen), 0);
212             totalPercent += gridLayout[i];
213             countPercent++;
214         }
215
216         // Count the total relative of all the relative columns/rows -> totalRelative
217         // Count the number of columns/rows which are relative -> countRelative
218         if (grid[i].isRelative()) {
219             totalRelative += std::max(grid[i].intValue(), 1);
220             countRelative++;
221         }            
222     }
223
224     int remainingLen = availableLen;
225
226     // Fixed columns/rows are our first priority. If there is not enough space to fit all fixed
227     // columns/rows we need to proportionally adjust their size. 
228     if (totalFixed > remainingLen) {
229         int remainingFixed = remainingLen;
230
231         for (int i = 0; i < gridLen; ++i) {
232             if (grid[i].isFixed()) {
233                 gridLayout[i] = (gridLayout[i] * remainingFixed) / totalFixed;
234                 remainingLen -= gridLayout[i];
235             }
236         }
237     } else
238         remainingLen -= totalFixed;
239
240     // Percentage columns/rows are our second priority. Divide the remaining space proportionally 
241     // over all percentage columns/rows. IMPORTANT: the size of each column/row is not relative 
242     // to 100%, but to the total percentage. For example, if there are three columns, each of 75%,
243     // and the available space is 300px, each column will become 100px in width.
244     if (totalPercent > remainingLen) {
245         int remainingPercent = remainingLen;
246
247         for (int i = 0; i < gridLen; ++i) {
248             if (grid[i].isPercentOrCalculated()) {
249                 gridLayout[i] = (gridLayout[i] * remainingPercent) / totalPercent;
250                 remainingLen -= gridLayout[i];
251             }
252         }
253     } else
254         remainingLen -= totalPercent;
255
256     // Relative columns/rows are our last priority. Divide the remaining space proportionally
257     // over all relative columns/rows. IMPORTANT: the relative value of 0* is treated as 1*.
258     if (countRelative) {
259         int lastRelative = 0;
260         int remainingRelative = remainingLen;
261
262         for (int i = 0; i < gridLen; ++i) {
263             if (grid[i].isRelative()) {
264                 gridLayout[i] = (std::max(grid[i].intValue(), 1) * remainingRelative) / totalRelative;
265                 remainingLen -= gridLayout[i];
266                 lastRelative = i;
267             }
268         }
269         
270         // If we could not evenly distribute the available space of all of the relative  
271         // columns/rows, the remainder will be added to the last column/row.
272         // For example: if we have a space of 100px and three columns (*,*,*), the remainder will
273         // be 1px and will be added to the last column: 33px, 33px, 34px.
274         if (remainingLen) {
275             gridLayout[lastRelative] += remainingLen;
276             remainingLen = 0;
277         }
278     }
279
280     // If we still have some left over space we need to divide it over the already existing
281     // columns/rows
282     if (remainingLen) {
283         // Our first priority is to spread if over the percentage columns. The remaining
284         // space is spread evenly, for example: if we have a space of 100px, the columns 
285         // definition of 25%,25% used to result in two columns of 25px. After this the 
286         // columns will each be 50px in width. 
287         if (countPercent && totalPercent) {
288             int remainingPercent = remainingLen;
289             int changePercent = 0;
290
291             for (int i = 0; i < gridLen; ++i) {
292                 if (grid[i].isPercentOrCalculated()) {
293                     changePercent = (remainingPercent * gridLayout[i]) / totalPercent;
294                     gridLayout[i] += changePercent;
295                     remainingLen -= changePercent;
296                 }
297             }
298         } else if (totalFixed) {
299             // Our last priority is to spread the remaining space over the fixed columns.
300             // For example if we have 100px of space and two column of each 40px, both
301             // columns will become exactly 50px.
302             int remainingFixed = remainingLen;
303             int changeFixed = 0;
304
305             for (int i = 0; i < gridLen; ++i) {
306                 if (grid[i].isFixed()) {
307                     changeFixed = (remainingFixed * gridLayout[i]) / totalFixed;
308                     gridLayout[i] += changeFixed;
309                     remainingLen -= changeFixed;
310                 } 
311             }
312         }
313     }
314     
315     // If we still have some left over space we probably ended up with a remainder of
316     // a division. We cannot spread it evenly anymore. If we have any percentage 
317     // columns/rows simply spread the remainder equally over all available percentage columns, 
318     // regardless of their size.
319     if (remainingLen && countPercent) {
320         int remainingPercent = remainingLen;
321         int changePercent = 0;
322
323         for (int i = 0; i < gridLen; ++i) {
324             if (grid[i].isPercentOrCalculated()) {
325                 changePercent = remainingPercent / countPercent;
326                 gridLayout[i] += changePercent;
327                 remainingLen -= changePercent;
328             }
329         }
330     } else if (remainingLen && countFixed) {
331         // If we don't have any percentage columns/rows we only have
332         // fixed columns. Spread the remainder equally over all fixed
333         // columns/rows.
334         int remainingFixed = remainingLen;
335         int changeFixed = 0;
336         
337         for (int i = 0; i < gridLen; ++i) {
338             if (grid[i].isFixed()) {
339                 changeFixed = remainingFixed / countFixed;
340                 gridLayout[i] += changeFixed;
341                 remainingLen -= changeFixed;
342             }
343         }
344     }
345
346     // Still some left over. Add it to the last column, because it is impossible
347     // spread it evenly or equally.
348     if (remainingLen)
349         gridLayout[gridLen - 1] += remainingLen;
350
351     // now we have the final layout, distribute the delta over it
352     bool worked = true;
353     int* gridDelta = axis.m_deltas.data();
354     for (int i = 0; i < gridLen; ++i) {
355         if (gridLayout[i] && gridLayout[i] + gridDelta[i] <= 0)
356             worked = false;
357         gridLayout[i] += gridDelta[i];
358     }
359     // if the deltas broke something, undo them
360     if (!worked) {
361         for (int i = 0; i < gridLen; ++i)
362             gridLayout[i] -= gridDelta[i];
363         axis.m_deltas.fill(0);
364     }
365 }
366
367 void RenderFrameSet::notifyFrameEdgeInfoChanged()
368 {
369     if (needsLayout())
370         return;
371     // FIXME: We should only recompute the edge info with respect to the frame that changed
372     // and its adjacent frame(s) instead of recomputing the edge info for the entire frameset.
373     computeEdgeInfo();
374 }
375
376 void RenderFrameSet::fillFromEdgeInfo(const FrameEdgeInfo& edgeInfo, int r, int c)
377 {
378     if (edgeInfo.allowBorder(LeftFrameEdge))
379         m_cols.m_allowBorder[c] = true;
380     if (edgeInfo.allowBorder(RightFrameEdge))
381         m_cols.m_allowBorder[c + 1] = true;
382     if (edgeInfo.preventResize(LeftFrameEdge))
383         m_cols.m_preventResize[c] = true;
384     if (edgeInfo.preventResize(RightFrameEdge))
385         m_cols.m_preventResize[c + 1] = true;
386     
387     if (edgeInfo.allowBorder(TopFrameEdge))
388         m_rows.m_allowBorder[r] = true;
389     if (edgeInfo.allowBorder(BottomFrameEdge))
390         m_rows.m_allowBorder[r + 1] = true;
391     if (edgeInfo.preventResize(TopFrameEdge))
392         m_rows.m_preventResize[r] = true;
393     if (edgeInfo.preventResize(BottomFrameEdge))
394         m_rows.m_preventResize[r + 1] = true;
395 }
396
397 void RenderFrameSet::computeEdgeInfo()
398 {
399     m_rows.m_preventResize.fill(frameSetElement().noResize());
400     m_rows.m_allowBorder.fill(false);
401     m_cols.m_preventResize.fill(frameSetElement().noResize());
402     m_cols.m_allowBorder.fill(false);
403     
404     RenderObject* child = firstChild();
405     if (!child)
406         return;
407
408     size_t rows = m_rows.m_sizes.size();
409     size_t cols = m_cols.m_sizes.size();
410     for (size_t r = 0; r < rows; ++r) {
411         for (size_t c = 0; c < cols; ++c) {
412             FrameEdgeInfo edgeInfo;
413             if (is<RenderFrameSet>(*child))
414                 edgeInfo = downcast<RenderFrameSet>(*child).edgeInfo();
415             else
416                 edgeInfo = downcast<RenderFrame>(*child).edgeInfo();
417             fillFromEdgeInfo(edgeInfo, r, c);
418             child = child->nextSibling();
419             if (!child)
420                 return;
421         }
422     }
423 }
424
425 FrameEdgeInfo RenderFrameSet::edgeInfo() const
426 {
427     FrameEdgeInfo result(frameSetElement().noResize(), true);
428     
429     int rows = frameSetElement().totalRows();
430     int cols = frameSetElement().totalCols();
431     if (rows && cols) {
432         result.setPreventResize(LeftFrameEdge, m_cols.m_preventResize[0]);
433         result.setAllowBorder(LeftFrameEdge, m_cols.m_allowBorder[0]);
434         result.setPreventResize(RightFrameEdge, m_cols.m_preventResize[cols]);
435         result.setAllowBorder(RightFrameEdge, m_cols.m_allowBorder[cols]);
436         result.setPreventResize(TopFrameEdge, m_rows.m_preventResize[0]);
437         result.setAllowBorder(TopFrameEdge, m_rows.m_allowBorder[0]);
438         result.setPreventResize(BottomFrameEdge, m_rows.m_preventResize[rows]);
439         result.setAllowBorder(BottomFrameEdge, m_rows.m_allowBorder[rows]);
440     }
441     
442     return result;
443 }
444
445 void RenderFrameSet::layout()
446 {
447     StackStats::LayoutCheckPoint layoutCheckPoint;
448     ASSERT(needsLayout());
449
450     bool doFullRepaint = selfNeedsLayout() && checkForRepaintDuringLayout();
451     LayoutRect oldBounds;
452     RenderLayerModelObject* repaintContainer = 0;
453     if (doFullRepaint) {
454         repaintContainer = containerForRepaint();
455         oldBounds = clippedOverflowRectForRepaint(repaintContainer);
456     }
457
458     if (!parent()->isFrameSet() && !document().printing()) {
459         setWidth(view().viewWidth());
460         setHeight(view().viewHeight());
461     }
462
463     unsigned cols = frameSetElement().totalCols();
464     unsigned rows = frameSetElement().totalRows();
465
466     if (m_rows.m_sizes.size() != rows || m_cols.m_sizes.size() != cols) {
467         m_rows.resize(rows);
468         m_cols.resize(cols);
469     }
470
471     LayoutUnit borderThickness = frameSetElement().border();
472     layOutAxis(m_rows, frameSetElement().rowLengths(), height() - (rows - 1) * borderThickness);
473     layOutAxis(m_cols, frameSetElement().colLengths(), width() - (cols - 1) * borderThickness);
474
475     if (flattenFrameSet())
476         positionFramesWithFlattening();
477     else
478         positionFrames();
479
480     RenderBox::layout();
481
482     computeEdgeInfo();
483
484     updateLayerTransform();
485
486     if (doFullRepaint) {
487         repaintUsingContainer(repaintContainer, snappedIntRect(oldBounds));
488         LayoutRect newBounds = clippedOverflowRectForRepaint(repaintContainer);
489         if (newBounds != oldBounds)
490             repaintUsingContainer(repaintContainer, snappedIntRect(newBounds));
491     }
492
493     clearNeedsLayout();
494 }
495
496 void RenderFrameSet::positionFrames()
497 {
498     RenderBox* child = firstChildBox();
499     if (!child)
500         return;
501
502     int rows = frameSetElement().totalRows();
503     int cols = frameSetElement().totalCols();
504
505     int yPos = 0;
506     int borderThickness = frameSetElement().border();
507     for (int r = 0; r < rows; r++) {
508         int xPos = 0;
509         int height = m_rows.m_sizes[r];
510         for (int c = 0; c < cols; c++) {
511             child->setLocation(IntPoint(xPos, yPos));
512             int width = m_cols.m_sizes[c];
513
514             // has to be resized and itself resize its contents
515             if (width != child->width() || height != child->height()) {
516                 child->setWidth(width);
517                 child->setHeight(height);
518 #if PLATFORM(IOS)
519                 // FIXME: Is this iOS-specific?
520                 child->setNeedsLayout(MarkOnlyThis);
521 #else
522                 child->setNeedsLayout();
523 #endif
524                 child->layout();
525             }
526
527             xPos += width + borderThickness;
528
529             child = child->nextSiblingBox();
530             if (!child)
531                 return;
532         }
533         yPos += height + borderThickness;
534     }
535
536     // all the remaining frames are hidden to avoid ugly spurious unflowed frames
537     for (auto* descendant = child; descendant; descendant = downcast<RenderBox>(RenderObjectTraversal::next(*descendant, this))) {
538         descendant->setWidth(0);
539         descendant->setHeight(0);
540         descendant->clearNeedsLayout();
541     }
542 }
543
544 void RenderFrameSet::positionFramesWithFlattening()
545 {
546     RenderBox* child = firstChildBox();
547     if (!child)
548         return;
549
550     int rows = frameSetElement().totalRows();
551     int cols = frameSetElement().totalCols();
552
553     int borderThickness = frameSetElement().border();
554     bool repaintNeeded = false;
555
556     // calculate frameset height based on actual content height to eliminate scrolling
557     bool out = false;
558     for (int r = 0; r < rows && !out; ++r) {
559         int extra = 0;
560         int height = m_rows.m_sizes[r];
561
562         for (int c = 0; c < cols; ++c) {
563             IntRect oldFrameRect = snappedIntRect(child->frameRect());
564
565             int width = m_cols.m_sizes[c];
566
567             bool fixedWidth = frameSetElement().colLengths() && frameSetElement().colLengths()[c].isFixed();
568             bool fixedHeight = frameSetElement().rowLengths() && frameSetElement().rowLengths()[r].isFixed();
569
570             // has to be resized and itself resize its contents
571             if (!fixedWidth)
572                 child->setWidth(width ? width + extra / (cols - c) : 0);
573             else
574                 child->setWidth(width);
575             child->setHeight(height);
576
577             child->setNeedsLayout();
578
579             if (is<RenderFrameSet>(*child))
580                 downcast<RenderFrameSet>(*child).layout();
581             else
582                 downcast<RenderFrame>(*child).layoutWithFlattening(fixedWidth, fixedHeight);
583
584             if (child->height() > m_rows.m_sizes[r])
585                 m_rows.m_sizes[r] = child->height();
586             if (child->width() > m_cols.m_sizes[c])
587                 m_cols.m_sizes[c] = child->width();
588
589             if (child->frameRect() != oldFrameRect)
590                 repaintNeeded = true;
591
592             // difference between calculated frame width and the width it actually decides to have
593             extra += width - m_cols.m_sizes[c];
594
595             child = child->nextSiblingBox();
596             if (!child) {
597                 out = true;
598                 break;
599             }
600         }
601     }
602
603     int xPos = 0;
604     int yPos = 0;
605     out = false;
606     child = firstChildBox();
607     for (int r = 0; r < rows && !out; ++r) {
608         xPos = 0;
609         for (int c = 0; c < cols; ++c) {
610             // ensure the rows and columns are filled
611             IntRect oldRect = snappedIntRect(child->frameRect());
612
613             child->setLocation(IntPoint(xPos, yPos));
614             child->setHeight(m_rows.m_sizes[r]);
615             child->setWidth(m_cols.m_sizes[c]);
616
617             if (child->frameRect() != oldRect) {
618                 repaintNeeded = true;
619
620                 // update to final size
621                 child->setNeedsLayout();
622                 if (is<RenderFrameSet>(*child))
623                     downcast<RenderFrameSet>(*child).layout();
624                 else
625                     downcast<RenderFrame>(*child).layoutWithFlattening(true, true);
626             }
627
628             xPos += m_cols.m_sizes[c] + borderThickness;
629             child = child->nextSiblingBox();
630             if (!child) {
631                 out = true;
632                 break;
633             }
634         }
635         yPos += m_rows.m_sizes[r] + borderThickness;
636     }
637
638     setWidth(xPos - borderThickness);
639     setHeight(yPos - borderThickness);
640
641     if (repaintNeeded)
642         repaint();
643
644     // all the remaining frames are hidden to avoid ugly spurious unflowed frames
645     for (; child; child = child->nextSiblingBox()) {
646         child->setWidth(0);
647         child->setHeight(0);
648         child->clearNeedsLayout();
649     }
650 }
651
652 bool RenderFrameSet::flattenFrameSet() const
653 {
654     return view().frameView().effectiveFrameFlattening() != FrameFlattening::Disabled;
655 }
656
657 void RenderFrameSet::startResizing(GridAxis& axis, int position)
658 {
659     int split = hitTestSplit(axis, position);
660     if (split == noSplit || axis.m_preventResize[split]) {
661         axis.m_splitBeingResized = noSplit;
662         return;
663     }
664     axis.m_splitBeingResized = split;
665     axis.m_splitResizeOffset = position - splitPosition(axis, split);
666 }
667
668 void RenderFrameSet::continueResizing(GridAxis& axis, int position)
669 {
670     if (needsLayout())
671         return;
672     if (axis.m_splitBeingResized == noSplit)
673         return;
674     int currentSplitPosition = splitPosition(axis, axis.m_splitBeingResized);
675     int delta = (position - currentSplitPosition) - axis.m_splitResizeOffset;
676     if (!delta)
677         return;
678     axis.m_deltas[axis.m_splitBeingResized - 1] += delta;
679     axis.m_deltas[axis.m_splitBeingResized] -= delta;
680     setNeedsLayout();
681 }
682
683 bool RenderFrameSet::userResize(MouseEvent& event)
684 {
685     if (flattenFrameSet())
686         return false;
687
688     if (!m_isResizing) {
689         if (needsLayout())
690             return false;
691         if (event.type() == eventNames().mousedownEvent && event.button() == LeftButton) {
692             FloatPoint localPos = absoluteToLocal(event.absoluteLocation(), UseTransforms);
693             startResizing(m_cols, localPos.x());
694             startResizing(m_rows, localPos.y());
695             if (m_cols.m_splitBeingResized != noSplit || m_rows.m_splitBeingResized != noSplit) {
696                 setIsResizing(true);
697                 return true;
698             }
699         }
700     } else {
701         if (event.type() == eventNames().mousemoveEvent || (event.type() == eventNames().mouseupEvent && event.button() == LeftButton)) {
702             FloatPoint localPos = absoluteToLocal(event.absoluteLocation(), UseTransforms);
703             continueResizing(m_cols, localPos.x());
704             continueResizing(m_rows, localPos.y());
705             if (event.type() == eventNames().mouseupEvent && event.button() == LeftButton) {
706                 setIsResizing(false);
707                 return true;
708             }
709         }
710     }
711
712     return false;
713 }
714
715 void RenderFrameSet::setIsResizing(bool isResizing)
716 {
717     m_isResizing = isResizing;
718     for (auto& ancestor : ancestorsOfType<RenderFrameSet>(*this))
719         ancestor.m_isChildResizing = isResizing;
720     frame().eventHandler().setResizingFrameSet(isResizing ? &frameSetElement() : nullptr);
721 }
722
723 bool RenderFrameSet::isResizingRow() const
724 {
725     return m_isResizing && m_rows.m_splitBeingResized != noSplit;
726 }
727
728 bool RenderFrameSet::isResizingColumn() const
729 {
730     return m_isResizing && m_cols.m_splitBeingResized != noSplit;
731 }
732
733 bool RenderFrameSet::canResizeRow(const IntPoint& p) const
734 {
735     int r = hitTestSplit(m_rows, p.y());
736     return r != noSplit && !m_rows.m_preventResize[r];
737 }
738
739 bool RenderFrameSet::canResizeColumn(const IntPoint& p) const
740 {
741     int c = hitTestSplit(m_cols, p.x());
742     return c != noSplit && !m_cols.m_preventResize[c];
743 }
744
745 int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const
746 {
747     if (needsLayout())
748         return 0;
749
750     int borderThickness = frameSetElement().border();
751
752     int size = axis.m_sizes.size();
753     if (!size)
754         return 0;
755
756     int position = 0;
757     for (int i = 0; i < split && i < size; ++i)
758         position += axis.m_sizes[i] + borderThickness;
759     return position - borderThickness;
760 }
761
762 int RenderFrameSet::hitTestSplit(const GridAxis& axis, int position) const
763 {
764     if (needsLayout())
765         return noSplit;
766
767     int borderThickness = frameSetElement().border();
768     if (borderThickness <= 0)
769         return noSplit;
770
771     size_t size = axis.m_sizes.size();
772     if (!size)
773         return noSplit;
774
775     int splitPosition = axis.m_sizes[0];
776     for (size_t i = 1; i < size; ++i) {
777         if (position >= splitPosition && position < splitPosition + borderThickness)
778             return i;
779         splitPosition += borderThickness + axis.m_sizes[i];
780     }
781     return noSplit;
782 }
783
784 bool RenderFrameSet::isChildAllowed(const RenderObject& child, const RenderStyle&) const
785 {
786     return child.isFrame() || child.isFrameSet();
787 }
788
789 CursorDirective RenderFrameSet::getCursor(const LayoutPoint& point, Cursor& cursor) const
790 {
791     IntPoint roundedPoint = roundedIntPoint(point);
792     if (canResizeRow(roundedPoint)) {
793         cursor = rowResizeCursor();
794         return SetCursor;
795     }
796     if (canResizeColumn(roundedPoint)) {
797         cursor = columnResizeCursor();
798         return SetCursor;
799     }
800     return RenderBox::getCursor(point, cursor);
801 }
802
803 } // namespace WebCore