source: webkit/trunk/Source/WebCore/rendering/RenderFrameSet.cpp

Last change on this file was 294699, checked in by Alan Bujtas, 3 years ago

RenderObject::containerForRepaint should be able to tell if a full repaint has already been scheduled.
https://bugs.webkit.org/show_bug.cgi?id=240721

Reviewed by Simon Fraser.

This patch is in preparation for reducing redundant repaints when an ancestor layer (between the renderer and the repaint container) has already been scheduled for one.

  • Source/WebCore/editing/SelectionGeometryGatherer.cpp:

(WebCore::SelectionGeometryGatherer::addQuad):
(WebCore::SelectionGeometryGatherer::addGapRects):

  • Source/WebCore/editing/SelectionGeometryGatherer.h:
  • Source/WebCore/page/FrameView.cpp:

(WebCore::FrameView::isEnclosedInCompositingLayer const):

  • Source/WebCore/rendering/LayoutRepainter.cpp:

(WebCore::LayoutRepainter::LayoutRepainter):
(WebCore::LayoutRepainter::repaintAfterLayout):

  • Source/WebCore/rendering/LayoutRepainter.h:
  • Source/WebCore/rendering/LegacyLineLayout.cpp:

(WebCore::LegacyLineLayout::layoutRunsAndFloats):

  • Source/WebCore/rendering/RenderElement.cpp:

(WebCore::RenderElement::issueRepaintForOutlineAuto):

  • Source/WebCore/rendering/RenderFragmentedFlow.cpp:

(WebCore::RenderFragmentedFlow::mapLocalToContainer const):

  • Source/WebCore/rendering/RenderFrameSet.cpp:

(WebCore::RenderFrameSet::layout):

  • Source/WebCore/rendering/RenderLayer.cpp:

(WebCore::RenderLayer::recursiveUpdateLayerPositions):
(WebCore::RenderLayer::computeRepaintRectsIncludingDescendants):
(WebCore::RenderLayer::recursiveUpdateLayerPositionsAfterScroll):
(WebCore::RenderLayer::setHasVisibleContent):
(WebCore::RenderLayer::calculateClipRects const):

  • Source/WebCore/rendering/RenderLayer.h:
  • Source/WebCore/rendering/RenderLayerCompositor.cpp:

(WebCore::RenderLayerCompositor::repaintOnCompositingChange):

  • Source/WebCore/rendering/RenderLayerModelObject.cpp:

(WebCore::RenderLayerModelObject::styleDidChange):

  • Source/WebCore/rendering/RenderLayerScrollableArea.cpp:

(WebCore::RenderLayerScrollableArea::scrollTo):

  • Source/WebCore/rendering/RenderObject.cpp:

(WebCore::RenderObject::containerForRepaint const):
(WebCore::RenderObject::repaint const):
(WebCore::RenderObject::repaintRectangle const):
(WebCore::RenderObject::repaintSlowRepaintObject const):

  • Source/WebCore/rendering/RenderObject.h:
  • Source/WebCore/rendering/RenderSelectionInfo.cpp:

(WebCore::RenderSelectionInfoBase::RenderSelectionInfoBase):

  • Source/WebCore/rendering/RenderSelectionInfo.h:

(WebCore::RenderSelectionInfoBase::repaintContainer const):

  • Source/WebCore/rendering/RenderView.cpp:

(WebCore::RenderView::repaintRootContents):

Canonical link: https://commits.webkit.org/250898@main

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