source: webkit/trunk/Source/WebCore/rendering/RenderFragmentedFlow.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: 45.6 KB
Line 
1/*
2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials
14 * provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "RenderFragmentedFlow.h"
32
33#include "HitTestRequest.h"
34#include "HitTestResult.h"
35#include "LegacyInlineElementBox.h"
36#include "Node.h"
37#include "RenderBoxFragmentInfo.h"
38#include "RenderFragmentContainer.h"
39#include "RenderInline.h"
40#include "RenderLayer.h"
41#include "RenderLayerCompositor.h"
42#include "RenderLayoutState.h"
43#include "RenderTableCell.h"
44#include "RenderTableSection.h"
45#include "RenderTheme.h"
46#include "RenderView.h"
47#include "TransformState.h"
48#include <wtf/IsoMallocInlines.h>
49#include <wtf/StackStats.h>
50
51namespace WebCore {
52
53WTF_MAKE_ISO_ALLOCATED_IMPL(RenderFragmentedFlow);
54
55RenderFragmentedFlow::RenderFragmentedFlow(Document& document, RenderStyle&& style)
56 : RenderBlockFlow(document, WTFMove(style))
57 , m_currentFragmentMaintainer(nullptr)
58 , m_fragmentsInvalidated(false)
59 , m_fragmentsHaveUniformLogicalWidth(true)
60 , m_fragmentsHaveUniformLogicalHeight(true)
61 , m_pageLogicalSizeChanged(false)
62{
63 setIsRenderFragmentedFlow(true);
64}
65
66void RenderFragmentedFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
67{
68 RenderBlockFlow::styleDidChange(diff, oldStyle);
69
70 if (oldStyle && oldStyle->writingMode() != style().writingMode())
71 invalidateFragments();
72}
73
74void RenderFragmentedFlow::removeFlowChildInfo(RenderElement& child)
75{
76 if (is<RenderBlockFlow>(child))
77 removeLineFragmentInfo(downcast<RenderBlockFlow>(child));
78 if (is<RenderBox>(child))
79 removeRenderBoxFragmentInfo(downcast<RenderBox>(child));
80}
81
82void RenderFragmentedFlow::removeFragmentFromThread(RenderFragmentContainer* RenderFragmentContainer)
83{
84 ASSERT(RenderFragmentContainer);
85 m_fragmentList.remove(RenderFragmentContainer);
86}
87
88void RenderFragmentedFlow::invalidateFragments(MarkingBehavior markingParents)
89{
90 if (m_fragmentsInvalidated) {
91 ASSERT(selfNeedsLayout());
92 return;
93 }
94
95 m_fragmentRangeMap.clear();
96 m_breakBeforeToFragmentMap.clear();
97 m_breakAfterToFragmentMap.clear();
98 if (m_lineToFragmentMap)
99 m_lineToFragmentMap->clear();
100 setNeedsLayout(markingParents);
101
102 m_fragmentsInvalidated = true;
103}
104
105void RenderFragmentedFlow::validateFragments()
106{
107 if (m_fragmentsInvalidated) {
108 m_fragmentsInvalidated = false;
109 m_fragmentsHaveUniformLogicalWidth = true;
110 m_fragmentsHaveUniformLogicalHeight = true;
111
112 if (hasFragments()) {
113 LayoutUnit previousFragmentLogicalWidth;
114 LayoutUnit previousFragmentLogicalHeight;
115 bool firstFragmentVisited = false;
116
117 for (auto& fragment : m_fragmentList) {
118 ASSERT(!fragment->needsLayout() || fragment->isRenderFragmentContainerSet());
119
120 fragment->deleteAllRenderBoxFragmentInfo();
121
122 LayoutUnit fragmentLogicalWidth = fragment->pageLogicalWidth();
123 LayoutUnit fragmentLogicalHeight = fragment->pageLogicalHeight();
124
125 if (!firstFragmentVisited)
126 firstFragmentVisited = true;
127 else {
128 if (m_fragmentsHaveUniformLogicalWidth && previousFragmentLogicalWidth != fragmentLogicalWidth)
129 m_fragmentsHaveUniformLogicalWidth = false;
130 if (m_fragmentsHaveUniformLogicalHeight && previousFragmentLogicalHeight != fragmentLogicalHeight)
131 m_fragmentsHaveUniformLogicalHeight = false;
132 }
133
134 previousFragmentLogicalWidth = fragmentLogicalWidth;
135 }
136
137 setFragmentRangeForBox(*this, m_fragmentList.first(), m_fragmentList.last());
138 }
139 }
140
141 updateLogicalWidth(); // Called to get the maximum logical width for the fragment.
142 updateFragmentsFragmentedFlowPortionRect();
143}
144
145void RenderFragmentedFlow::layout()
146{
147 StackStats::LayoutCheckPoint layoutCheckPoint;
148
149 m_pageLogicalSizeChanged = m_fragmentsInvalidated && everHadLayout();
150
151 validateFragments();
152
153 RenderBlockFlow::layout();
154
155 m_pageLogicalSizeChanged = false;
156}
157
158void RenderFragmentedFlow::updateLogicalWidth()
159{
160 LayoutUnit logicalWidth = initialLogicalWidth();
161 for (auto& fragment : m_fragmentList) {
162 ASSERT(!fragment->needsLayout() || fragment->isRenderFragmentContainerSet());
163 logicalWidth = std::max(fragment->pageLogicalWidth(), logicalWidth);
164 }
165 setLogicalWidth(logicalWidth);
166
167 // If the fragments have non-uniform logical widths, then insert inset information for the RenderFragmentedFlow.
168 for (auto& fragment : m_fragmentList) {
169 LayoutUnit fragmentLogicalWidth = fragment->pageLogicalWidth();
170 LayoutUnit logicalLeft = style().direction() == TextDirection::LTR ? 0_lu : logicalWidth - fragmentLogicalWidth;
171 fragment->setRenderBoxFragmentInfo(this, logicalLeft, fragmentLogicalWidth, false);
172 }
173}
174
175RenderBox::LogicalExtentComputedValues RenderFragmentedFlow::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop) const
176{
177 LogicalExtentComputedValues computedValues;
178 computedValues.m_position = logicalTop;
179 computedValues.m_extent = 0;
180
181 const LayoutUnit maxFlowSize = RenderFragmentedFlow::maxLogicalHeight();
182 for (auto& fragment : m_fragmentList) {
183 ASSERT(!fragment->needsLayout() || fragment->isRenderFragmentContainerSet());
184
185 LayoutUnit distanceToMaxSize = maxFlowSize - computedValues.m_extent;
186 computedValues.m_extent += std::min(distanceToMaxSize, fragment->logicalHeightOfAllFragmentedFlowContent());
187
188 // If we reached the maximum size there's no point in going further.
189 if (computedValues.m_extent == maxFlowSize)
190 return computedValues;
191 }
192 return computedValues;
193}
194
195bool RenderFragmentedFlow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
196{
197 if (hitTestAction == HitTestBlockBackground)
198 return false;
199 return RenderBlockFlow::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction);
200}
201
202bool RenderFragmentedFlow::shouldRepaint(const LayoutRect& r) const
203{
204 if (view().printing() || r.isEmpty())
205 return false;
206
207 return true;
208}
209
210void RenderFragmentedFlow::repaintRectangleInFragments(const LayoutRect& repaintRect) const
211{
212 if (!shouldRepaint(repaintRect) || !hasValidFragmentInfo())
213 return;
214
215 LayoutStateDisabler layoutStateDisabler(view().frameView().layoutContext()); // We can't use layout state to repaint, since the fragments are somewhere else.
216
217 for (auto& fragment : m_fragmentList)
218 fragment->repaintFragmentedFlowContent(repaintRect);
219}
220
221bool RenderFragmentedFlow::absoluteQuadsForBox(Vector<FloatQuad>& quads, bool* wasFixed, const RenderBox* box) const
222{
223 if (!hasValidFragmentInfo())
224 return false;
225
226 auto boxRect = FloatRect { { }, box->size() };
227 auto boxRectInFlowCoordinates = LayoutRect { box->localToContainerQuad(boxRect, this).boundingBox() };
228
229 RenderFragmentContainer* startFragment = nullptr;
230 RenderFragmentContainer* endFragment = nullptr;
231 if (!computedFragmentRangeForBox(box, startFragment, endFragment))
232 return false;
233
234 for (auto it = m_fragmentList.find(startFragment), end = m_fragmentList.end(); it != end; ++it) {
235 auto* fragment = *it;
236 auto rectsInFragment = fragment->fragmentRectsForFlowContentRect(boxRectInFlowCoordinates);
237 for (auto rect : rectsInFragment) {
238 auto absoluteQuad = fragment->localToAbsoluteQuad(FloatRect(rect), UseTransforms, wasFixed);
239 quads.append(absoluteQuad);
240 }
241
242 if (fragment == endFragment)
243 break;
244 }
245
246 return true;
247}
248
249class RenderFragmentedFlow::FragmentSearchAdapter {
250public:
251 explicit FragmentSearchAdapter(LayoutUnit offset)
252 : m_offset(offset)
253 {
254 }
255
256 const LayoutUnit& lowValue() const { return m_offset; }
257 const LayoutUnit& highValue() const { return m_offset; }
258
259 void collectIfNeeded(const PODInterval<LayoutUnit, WeakPtr<RenderFragmentContainer>>& interval)
260 {
261 if (m_result)
262 return;
263 if (interval.low() <= m_offset && interval.high() > m_offset)
264 m_result = interval.data();
265 }
266
267 RenderFragmentContainer* result() const { return m_result.get(); }
268
269private:
270 LayoutUnit m_offset;
271 WeakPtr<RenderFragmentContainer> m_result;
272};
273
274RenderFragmentContainer* RenderFragmentedFlow::fragmentAtBlockOffset(const RenderBox* clampBox, LayoutUnit offset, bool extendLastFragment) const
275{
276 ASSERT(!m_fragmentsInvalidated);
277
278 if (m_fragmentList.isEmpty())
279 return nullptr;
280
281 if (m_fragmentList.size() == 1 && extendLastFragment)
282 return m_fragmentList.first();
283
284 auto clamp = [clampBox](RenderFragmentContainer* fragment) {
285 return clampBox ? clampBox->clampToStartAndEndFragments(fragment) : fragment;
286 };
287
288 if (offset <= 0)
289 return clamp(m_fragmentList.first());
290
291 FragmentSearchAdapter adapter(offset);
292 m_fragmentIntervalTree.allOverlapsWithAdapter(adapter);
293 if (auto* fragment = adapter.result())
294 return clamp(fragment);
295
296 // If no fragment was found, the offset is in the flow thread overflow.
297 // The last fragment will contain the offset if extendLastFragment is set or if the last fragment is a set.
298 if (extendLastFragment || m_fragmentList.last()->isRenderFragmentContainerSet())
299 return clamp(m_fragmentList.last());
300
301 return nullptr;
302}
303
304LayoutPoint RenderFragmentedFlow::adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject& boxModelObject, const LayoutPoint& startPoint) const
305{
306 LayoutPoint referencePoint = startPoint;
307
308 const RenderBlock* objContainingBlock = boxModelObject.containingBlock();
309 // FIXME: This needs to be adapted for different writing modes inside the flow thread.
310 RenderFragmentContainer* startFragment = fragmentAtBlockOffset(objContainingBlock, referencePoint.y());
311 if (startFragment) {
312 // Take into account the offset coordinates of the fragment.
313 RenderBoxModelObject* startFragmentBox = startFragment;
314 RenderBoxModelObject* currObject = startFragmentBox;
315 RenderBoxModelObject* currOffsetParent;
316 while ((currOffsetParent = currObject->offsetParent())) {
317 referencePoint.move(currObject->offsetLeft(), currObject->offsetTop());
318
319 // Since we're looking for the offset relative to the body, we must also
320 // take into consideration the borders of the fragment's offsetParent.
321 if (is<RenderBox>(*currOffsetParent) && !currOffsetParent->isBody())
322 referencePoint.move(downcast<RenderBox>(*currOffsetParent).borderLeft(), downcast<RenderBox>(*currOffsetParent).borderTop());
323
324 currObject = currOffsetParent;
325 }
326
327 // We need to check if any of this box's containing blocks start in a different fragment
328 // and if so, drop the object's top position (which was computed relative to its containing block
329 // and is no longer valid) and recompute it using the fragment in which it flows as reference.
330 bool wasComputedRelativeToOtherFragment = false;
331 while (objContainingBlock && !is<RenderView>(*objContainingBlock)) {
332 // Check if this object is in a different fragment.
333 RenderFragmentContainer* parentStartFragment = nullptr;
334 RenderFragmentContainer* parentEndFragment = nullptr;
335 if (getFragmentRangeForBox(objContainingBlock, parentStartFragment, parentEndFragment) && parentStartFragment != startFragment) {
336 wasComputedRelativeToOtherFragment = true;
337 break;
338 }
339 objContainingBlock = objContainingBlock->containingBlock();
340 }
341
342 if (wasComputedRelativeToOtherFragment) {
343 if (is<RenderBox>(boxModelObject)) {
344 // Use borderBoxRectInFragment to account for variations such as percentage margins.
345 LayoutRect borderBoxRect = downcast<RenderBox>(boxModelObject).borderBoxRectInFragment(startFragment, RenderBox::DoNotCacheRenderBoxFragmentInfo);
346 referencePoint.move(borderBoxRect.location().x(), 0_lu);
347 }
348
349 // Get the logical top coordinate of the current object.
350 LayoutUnit top;
351 if (is<RenderBlock>(boxModelObject))
352 top = downcast<RenderBlock>(boxModelObject).offsetFromLogicalTopOfFirstPage();
353 else {
354 if (boxModelObject.containingBlock())
355 top = boxModelObject.containingBlock()->offsetFromLogicalTopOfFirstPage();
356
357 if (is<RenderBox>(boxModelObject))
358 top += downcast<RenderBox>(boxModelObject).topLeftLocation().y();
359 else if (is<RenderInline>(boxModelObject))
360 top -= downcast<RenderInline>(boxModelObject).borderTop();
361 }
362
363 // Get the logical top of the fragment this object starts in
364 // and compute the object's top, relative to the fragment's top.
365 LayoutUnit fragmentLogicalTop = startFragment->pageLogicalTopForOffset(top);
366 LayoutUnit topRelativeToFragment = top - fragmentLogicalTop;
367 referencePoint.setY(startFragmentBox->offsetTop() + topRelativeToFragment);
368
369 // Since the top has been overridden, check if the
370 // relative/sticky positioning must be reconsidered.
371 if (boxModelObject.isRelativelyPositioned())
372 referencePoint.move(0_lu, boxModelObject.relativePositionOffset().height());
373 else if (boxModelObject.isStickilyPositioned())
374 referencePoint.move(0_lu, boxModelObject.stickyPositionOffset().height());
375 }
376
377 // Since we're looking for the offset relative to the body, we must also
378 // take into consideration the borders of the fragment.
379 referencePoint.move(startFragmentBox->borderLeft(), startFragmentBox->borderTop());
380 }
381
382 return referencePoint;
383}
384
385LayoutUnit RenderFragmentedFlow::pageLogicalTopForOffset(LayoutUnit offset) const
386{
387 RenderFragmentContainer* fragment = fragmentAtBlockOffset(0, offset, false);
388 return fragment ? fragment->pageLogicalTopForOffset(offset) : 0_lu;
389}
390
391LayoutUnit RenderFragmentedFlow::pageLogicalWidthForOffset(LayoutUnit offset) const
392{
393 RenderFragmentContainer* fragment = fragmentAtBlockOffset(0, offset, true);
394 return fragment ? fragment->pageLogicalWidth() : contentLogicalWidth();
395}
396
397LayoutUnit RenderFragmentedFlow::pageLogicalHeightForOffset(LayoutUnit offset) const
398{
399 RenderFragmentContainer* fragment = fragmentAtBlockOffset(0, offset, false);
400 if (!fragment)
401 return 0;
402
403 return fragment->pageLogicalHeight();
404}
405
406LayoutUnit RenderFragmentedFlow::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
407{
408 RenderFragmentContainer* fragment = fragmentAtBlockOffset(0, offset, false);
409 if (!fragment)
410 return 0;
411
412 LayoutUnit pageLogicalTop = fragment->pageLogicalTopForOffset(offset);
413 LayoutUnit pageLogicalHeight = fragment->pageLogicalHeight();
414 LayoutUnit pageLogicalBottom = pageLogicalTop + pageLogicalHeight;
415 LayoutUnit remainingHeight = pageLogicalBottom - offset;
416 if (pageBoundaryRule == IncludePageBoundary) {
417 // If IncludePageBoundary is set, the line exactly on the top edge of a
418 // fragment will act as being part of the previous fragment.
419 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
420 }
421 return remainingHeight;
422}
423
424RenderFragmentContainer* RenderFragmentedFlow::mapFromFlowToFragment(TransformState& transformState) const
425{
426 if (!hasValidFragmentInfo())
427 return nullptr;
428
429 RenderFragmentContainer* RenderFragmentContainer = currentFragment();
430 if (!RenderFragmentContainer) {
431 LayoutRect boxRect = transformState.mappedQuad().enclosingBoundingBox();
432 flipForWritingMode(boxRect);
433
434 LayoutPoint center = boxRect.center();
435 RenderFragmentContainer = fragmentAtBlockOffset(this, isHorizontalWritingMode() ? center.y() : center.x(), true);
436 if (!RenderFragmentContainer)
437 return nullptr;
438 }
439
440 LayoutRect flippedFragmentRect(RenderFragmentContainer->fragmentedFlowPortionRect());
441 flipForWritingMode(flippedFragmentRect);
442
443 transformState.move(RenderFragmentContainer->contentBoxRect().location() - flippedFragmentRect.location());
444
445 return RenderFragmentContainer;
446}
447
448void RenderFragmentedFlow::removeRenderBoxFragmentInfo(RenderBox& box)
449{
450 if (!hasFragments())
451 return;
452
453 // If the fragment chain was invalidated the next layout will clear the box information from all the fragments.
454 if (m_fragmentsInvalidated) {
455 ASSERT(selfNeedsLayout());
456 return;
457 }
458
459 RenderFragmentContainer* startFragment = nullptr;
460 RenderFragmentContainer* endFragment = nullptr;
461 if (getFragmentRangeForBox(&box, startFragment, endFragment)) {
462 for (auto it = m_fragmentList.find(startFragment), end = m_fragmentList.end(); it != end; ++it) {
463 RenderFragmentContainer* fragment = *it;
464 fragment->removeRenderBoxFragmentInfo(box);
465 if (fragment == endFragment)
466 break;
467 }
468 }
469
470#ifndef NDEBUG
471 // We have to make sure we did not leave any RenderBoxFragmentInfo attached.
472 for (auto& fragment : m_fragmentList)
473 ASSERT(!fragment->renderBoxFragmentInfo(&box));
474#endif
475
476 m_fragmentRangeMap.remove(&box);
477}
478
479void RenderFragmentedFlow::removeLineFragmentInfo(const RenderBlockFlow& blockFlow)
480{
481 if (!m_lineToFragmentMap)
482 return;
483
484 for (auto* curr = blockFlow.firstRootBox(); curr; curr = curr->nextRootBox())
485 m_lineToFragmentMap->remove(curr);
486
487 ASSERT_WITH_SECURITY_IMPLICATION(checkLinesConsistency(blockFlow));
488}
489
490void RenderFragmentedFlow::logicalWidthChangedInFragmentsForBlock(const RenderBlock* block, bool& relayoutChildren)
491{
492 if (!hasValidFragmentInfo())
493 return;
494
495 auto it = m_fragmentRangeMap.find(block);
496 if (it == m_fragmentRangeMap.end())
497 return;
498
499 RenderFragmentContainerRange& range = it->value;
500 bool rangeInvalidated = range.rangeInvalidated();
501 range.clearRangeInvalidated();
502
503 // If there will be a relayout anyway skip the next steps because they only verify
504 // the state of the ranges.
505 if (relayoutChildren)
506 return;
507
508 // Not necessary for the flow thread, since we already computed the correct info for it.
509 // If the fragments have changed invalidate the children.
510 if (block == this) {
511 relayoutChildren = m_pageLogicalSizeChanged;
512 return;
513 }
514
515 RenderFragmentContainer* startFragment = nullptr;
516 RenderFragmentContainer* endFragment = nullptr;
517 if (!getFragmentRangeForBox(block, startFragment, endFragment))
518 return;
519
520 for (auto it = m_fragmentList.find(startFragment), end = m_fragmentList.end(); it != end; ++it) {
521 RenderFragmentContainer* fragment = *it;
522 ASSERT(!fragment->needsLayout() || fragment->isRenderFragmentContainerSet());
523
524 // We have no information computed for this fragment so we need to do it.
525 std::unique_ptr<RenderBoxFragmentInfo> oldInfo = fragment->takeRenderBoxFragmentInfo(block);
526 if (!oldInfo) {
527 relayoutChildren = rangeInvalidated;
528 return;
529 }
530
531 LayoutUnit oldLogicalWidth = oldInfo->logicalWidth();
532 RenderBoxFragmentInfo* newInfo = block->renderBoxFragmentInfo(fragment);
533 if (!newInfo || newInfo->logicalWidth() != oldLogicalWidth) {
534 relayoutChildren = true;
535 return;
536 }
537
538 if (fragment == endFragment)
539 break;
540 }
541}
542
543LayoutUnit RenderFragmentedFlow::contentLogicalWidthOfFirstFragment() const
544{
545 RenderFragmentContainer* firstValidFragmentInFlow = firstFragment();
546 if (!firstValidFragmentInFlow)
547 return 0;
548 return isHorizontalWritingMode() ? firstValidFragmentInFlow->contentWidth() : firstValidFragmentInFlow->contentHeight();
549}
550
551LayoutUnit RenderFragmentedFlow::contentLogicalHeightOfFirstFragment() const
552{
553 RenderFragmentContainer* firstValidFragmentInFlow = firstFragment();
554 if (!firstValidFragmentInFlow)
555 return 0;
556 return isHorizontalWritingMode() ? firstValidFragmentInFlow->contentHeight() : firstValidFragmentInFlow->contentWidth();
557}
558
559LayoutUnit RenderFragmentedFlow::contentLogicalLeftOfFirstFragment() const
560{
561 RenderFragmentContainer* firstValidFragmentInFlow = firstFragment();
562 if (!firstValidFragmentInFlow)
563 return 0;
564 return isHorizontalWritingMode() ? firstValidFragmentInFlow->fragmentedFlowPortionRect().x() : firstValidFragmentInFlow->fragmentedFlowPortionRect().y();
565}
566
567RenderFragmentContainer* RenderFragmentedFlow::firstFragment() const
568{
569 if (!hasFragments())
570 return nullptr;
571 return m_fragmentList.first();
572}
573
574RenderFragmentContainer* RenderFragmentedFlow::lastFragment() const
575{
576 if (!hasFragments())
577 return nullptr;
578 return m_fragmentList.last();
579}
580
581void RenderFragmentedFlow::clearRenderBoxFragmentInfoAndCustomStyle(const RenderBox& box,
582 const RenderFragmentContainer* newStartFragment, const RenderFragmentContainer* newEndFragment,
583 const RenderFragmentContainer* oldStartFragment, const RenderFragmentContainer* oldEndFragment)
584{
585 ASSERT(newStartFragment && newEndFragment && oldStartFragment && oldEndFragment);
586
587 bool insideOldFragmentRange = false;
588 bool insideNewFragmentRange = false;
589 for (auto& fragment : m_fragmentList) {
590 if (oldStartFragment == fragment)
591 insideOldFragmentRange = true;
592 if (newStartFragment == fragment)
593 insideNewFragmentRange = true;
594
595 if (!(insideOldFragmentRange && insideNewFragmentRange)) {
596 if (fragment->renderBoxFragmentInfo(&box))
597 fragment->removeRenderBoxFragmentInfo(box);
598 }
599
600 if (oldEndFragment == fragment)
601 insideOldFragmentRange = false;
602 if (newEndFragment == fragment)
603 insideNewFragmentRange = false;
604 }
605}
606
607void RenderFragmentedFlow::setFragmentRangeForBox(const RenderBox& box, RenderFragmentContainer* startFragment, RenderFragmentContainer* endFragment)
608{
609 ASSERT(hasFragments());
610 ASSERT(startFragment && endFragment && startFragment->fragmentedFlow() == this && endFragment->fragmentedFlow() == this);
611 auto result = m_fragmentRangeMap.set(&box, RenderFragmentContainerRange(startFragment, endFragment));
612 if (result.isNewEntry)
613 return;
614
615 // If nothing changed, just bail.
616 auto& range = result.iterator->value;
617 if (range.startFragment() == startFragment && range.endFragment() == endFragment)
618 return;
619 clearRenderBoxFragmentInfoAndCustomStyle(box, startFragment, endFragment, range.startFragment(), range.endFragment());
620}
621
622bool RenderFragmentedFlow::hasCachedFragmentRangeForBox(const RenderBox& box) const
623{
624 return m_fragmentRangeMap.contains(&box);
625}
626
627bool RenderFragmentedFlow::getFragmentRangeForBoxFromCachedInfo(const RenderBox* box, RenderFragmentContainer*& startFragment, RenderFragmentContainer*& endFragment) const
628{
629 ASSERT(box);
630 ASSERT(hasValidFragmentInfo());
631 ASSERT((startFragment == nullptr) && (endFragment == nullptr));
632
633 auto it = m_fragmentRangeMap.find(box);
634 if (it != m_fragmentRangeMap.end()) {
635 const RenderFragmentContainerRange& range = it->value;
636 startFragment = range.startFragment();
637 endFragment = range.endFragment();
638 ASSERT(m_fragmentList.contains(startFragment) && m_fragmentList.contains(endFragment));
639 return true;
640 }
641
642 return false;
643}
644
645bool RenderFragmentedFlow::getFragmentRangeForBox(const RenderBox* box, RenderFragmentContainer*& startFragment, RenderFragmentContainer*& endFragment) const
646{
647 ASSERT(box);
648
649 startFragment = endFragment = nullptr;
650 if (!hasValidFragmentInfo()) // We clear the ranges when we invalidate the fragments.
651 return false;
652
653 if (m_fragmentList.size() == 1) {
654 startFragment = endFragment = m_fragmentList.first();
655 return true;
656 }
657
658 if (getFragmentRangeForBoxFromCachedInfo(box, startFragment, endFragment))
659 return true;
660
661 return false;
662}
663
664bool RenderFragmentedFlow::computedFragmentRangeForBox(const RenderBox* box, RenderFragmentContainer*& startFragment, RenderFragmentContainer*& endFragment) const
665{
666 ASSERT(box);
667
668 startFragment = endFragment = nullptr;
669 if (!hasValidFragmentInfo()) // We clear the ranges when we invalidate the fragments.
670 return false;
671
672 if (getFragmentRangeForBox(box, startFragment, endFragment))
673 return true;
674
675 // Search the fragment range using the information provided by the containing block chain.
676 auto* containingBlock = const_cast<RenderBox*>(box);
677 while (!containingBlock->isRenderFragmentedFlow()) {
678 LegacyInlineElementBox* boxWrapper = containingBlock->inlineBoxWrapper();
679 if (boxWrapper && boxWrapper->root().containingFragment()) {
680 startFragment = endFragment = boxWrapper->root().containingFragment();
681 ASSERT(m_fragmentList.contains(startFragment));
682 return true;
683 }
684
685 // FIXME: Use the containingBlock() value once we patch all the layout systems to be fragment range aware
686 // (e.g. if we use containingBlock() the shadow controls of a video element won't get the range from the
687 // video box because it's not a block; they need to be patched separately).
688 ASSERT(containingBlock->parent());
689 containingBlock = &containingBlock->parent()->enclosingBox();
690 ASSERT(containingBlock);
691
692 // If a box doesn't have a cached fragment range it usually means the box belongs to a line so startFragment should be equal with endFragment.
693 // FIXME: Find the cases when this startFragment should not be equal with endFragment and make sure these boxes have cached fragment ranges.
694 if (containingBlock && hasCachedFragmentRangeForBox(*containingBlock)) {
695 startFragment = endFragment = fragmentAtBlockOffset(containingBlock, containingBlock->offsetFromLogicalTopOfFirstPage(), true);
696 return true;
697 }
698 }
699 ASSERT_NOT_REACHED();
700 return false;
701}
702
703bool RenderFragmentedFlow::fragmentInRange(const RenderFragmentContainer* targetFragment, const RenderFragmentContainer* startFragment, const RenderFragmentContainer* endFragment) const
704{
705 ASSERT(targetFragment);
706
707 for (auto it = m_fragmentList.find(const_cast<RenderFragmentContainer*>(startFragment)), end = m_fragmentList.end(); it != end; ++it) {
708 const RenderFragmentContainer* currFragment = *it;
709 if (targetFragment == currFragment)
710 return true;
711 if (currFragment == endFragment)
712 break;
713 }
714
715 return false;
716}
717
718bool RenderFragmentedFlow::objectShouldFragmentInFlowFragment(const RenderObject* object, const RenderFragmentContainer* fragment) const
719{
720 ASSERT(object);
721 ASSERT(fragment);
722
723 RenderFragmentedFlow* fragmentedFlow = object->enclosingFragmentedFlow();
724 if (fragmentedFlow != this)
725 return false;
726
727 if (!m_fragmentList.contains(const_cast<RenderFragmentContainer*>(fragment)))
728 return false;
729
730 RenderFragmentContainer* enclosingBoxStartFragment = nullptr;
731 RenderFragmentContainer* enclosingBoxEndFragment = nullptr;
732 // If the box has no range, do not check fragmentInRange. Boxes inside inlines do not get ranges.
733 // Instead, the containing RootInlineBox will abort when trying to paint inside the wrong fragment.
734 if (computedFragmentRangeForBox(&object->enclosingBox(), enclosingBoxStartFragment, enclosingBoxEndFragment)
735 && !fragmentInRange(fragment, enclosingBoxStartFragment, enclosingBoxEndFragment))
736 return false;
737
738 return object->isBox() || object->isRenderInline();
739}
740
741bool RenderFragmentedFlow::objectInFlowFragment(const RenderObject* object, const RenderFragmentContainer* fragment) const
742{
743 ASSERT(object);
744 ASSERT(fragment);
745
746 RenderFragmentedFlow* fragmentedFlow = object->enclosingFragmentedFlow();
747 if (fragmentedFlow != this)
748 return false;
749
750 if (!m_fragmentList.contains(const_cast<RenderFragmentContainer*>(fragment)))
751 return false;
752
753 RenderFragmentContainer* enclosingBoxStartFragment = nullptr;
754 RenderFragmentContainer* enclosingBoxEndFragment = nullptr;
755 if (!getFragmentRangeForBox(&object->enclosingBox(), enclosingBoxStartFragment, enclosingBoxEndFragment))
756 return false;
757
758 if (!fragmentInRange(fragment, enclosingBoxStartFragment, enclosingBoxEndFragment))
759 return false;
760
761 if (object->isBox())
762 return true;
763
764 LayoutRect objectABBRect = object->absoluteBoundingBoxRect(true);
765 if (!objectABBRect.width())
766 objectABBRect.setWidth(1);
767 if (!objectABBRect.height())
768 objectABBRect.setHeight(1);
769 if (objectABBRect.intersects(fragment->absoluteBoundingBoxRect(true)))
770 return true;
771
772 if (fragment == lastFragment()) {
773 // If the object does not intersect any of the enclosing box fragments
774 // then the object is in last fragment.
775 for (auto it = m_fragmentList.find(enclosingBoxStartFragment), end = m_fragmentList.end(); it != end; ++it) {
776 const RenderFragmentContainer* currFragment = *it;
777 if (currFragment == fragment)
778 break;
779 if (objectABBRect.intersects(currFragment->absoluteBoundingBoxRect(true)))
780 return false;
781 }
782 return true;
783 }
784
785 return false;
786}
787
788#if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED
789bool RenderFragmentedFlow::checkLinesConsistency(const RenderBlockFlow& removedBlock) const
790{
791 if (!m_lineToFragmentMap)
792 return true;
793
794 for (auto& linePair : *m_lineToFragmentMap.get()) {
795 const LegacyRootInlineBox* line = linePair.key;
796 RenderFragmentContainer* fragment = linePair.value;
797 if (&line->blockFlow() == &removedBlock)
798 return false;
799 if (line->blockFlow().fragmentedFlowState() == NotInsideFragmentedFlow)
800 return false;
801 if (!m_fragmentList.contains(fragment))
802 return false;
803 }
804
805 return true;
806}
807#endif
808
809void RenderFragmentedFlow::clearLinesToFragmentMap()
810{
811 if (m_lineToFragmentMap)
812 m_lineToFragmentMap->clear();
813}
814
815void RenderFragmentedFlow::deleteLines()
816{
817 clearLinesToFragmentMap();
818 RenderBlockFlow::deleteLines();
819}
820
821void RenderFragmentedFlow::willBeDestroyed()
822{
823 clearLinesToFragmentMap();
824 RenderBlockFlow::willBeDestroyed();
825}
826
827void RenderFragmentedFlow::markFragmentsForOverflowLayoutIfNeeded()
828{
829 if (!hasFragments())
830 return;
831
832 for (auto& fragment : m_fragmentList)
833 fragment->setNeedsSimplifiedNormalFlowLayout();
834}
835
836void RenderFragmentedFlow::updateFragmentsFragmentedFlowPortionRect()
837{
838 LayoutUnit logicalHeight;
839 // FIXME: Optimize not to clear the interval tree all the time. This would involve manually managing the tree nodes' lifecycle.
840 m_fragmentIntervalTree.clear();
841 for (auto& fragment : m_fragmentList) {
842 LayoutUnit fragmentLogicalWidth = fragment->pageLogicalWidth();
843 LayoutUnit fragmentLogicalHeight = std::min<LayoutUnit>(RenderFragmentedFlow::maxLogicalHeight() - logicalHeight, fragment->logicalHeightOfAllFragmentedFlowContent());
844
845 LayoutRect fragmentRect(style().direction() == TextDirection::LTR ? 0_lu : logicalWidth() - fragmentLogicalWidth, logicalHeight, fragmentLogicalWidth, fragmentLogicalHeight);
846
847 fragment->setFragmentedFlowPortionRect(isHorizontalWritingMode() ? fragmentRect : fragmentRect.transposedRect());
848
849 m_fragmentIntervalTree.add({ logicalHeight, logicalHeight + fragmentLogicalHeight, fragment });
850
851 logicalHeight += fragmentLogicalHeight;
852 }
853}
854
855// Even if we require the break to occur at offsetBreakInFragmentedFlow, because fragments may have min/max-height values,
856// it is possible that the break will occur at a different offset than the original one required.
857// offsetBreakAdjustment measures the different between the requested break offset and the current break offset.
858bool RenderFragmentedFlow::addForcedFragmentBreak(const RenderBlock* block, LayoutUnit offsetBreakInFragmentedFlow, RenderBox*, bool, LayoutUnit* offsetBreakAdjustment)
859{
860 // We need to update the fragments flow thread portion rect because we are going to process
861 // a break on these fragments.
862 updateFragmentsFragmentedFlowPortionRect();
863
864 // Simulate a fragment break at offsetBreakInFragmentedFlow. If it points inside an auto logical height fragment,
865 // then it determines the fragment computed auto height.
866 RenderFragmentContainer* fragment = fragmentAtBlockOffset(block, offsetBreakInFragmentedFlow);
867 if (!fragment)
868 return false;
869
870 LayoutUnit currentFragmentOffsetInFragmentedFlow = isHorizontalWritingMode() ? fragment->fragmentedFlowPortionRect().y() : fragment->fragmentedFlowPortionRect().x();
871
872 currentFragmentOffsetInFragmentedFlow += isHorizontalWritingMode() ? fragment->fragmentedFlowPortionRect().height() : fragment->fragmentedFlowPortionRect().width();
873
874 if (offsetBreakAdjustment)
875 *offsetBreakAdjustment = std::max<LayoutUnit>(0, currentFragmentOffsetInFragmentedFlow - offsetBreakInFragmentedFlow);
876
877 return false;
878}
879
880void RenderFragmentedFlow::collectLayerFragments(LayerFragments& layerFragments, const LayoutRect& layerBoundingBox, const LayoutRect& dirtyRect)
881{
882 ASSERT(!m_fragmentsInvalidated);
883
884 for (auto& fragment : m_fragmentList)
885 fragment->collectLayerFragments(layerFragments, layerBoundingBox, dirtyRect);
886}
887
888LayoutRect RenderFragmentedFlow::fragmentsBoundingBox(const LayoutRect& layerBoundingBox)
889{
890 ASSERT(!m_fragmentsInvalidated);
891
892 LayoutRect result;
893 for (auto& fragment : m_fragmentList) {
894 LayerFragments fragments;
895 fragment->collectLayerFragments(fragments, layerBoundingBox, LayoutRect::infiniteRect());
896 for (const auto& fragment : fragments) {
897 LayoutRect fragmentRect(layerBoundingBox);
898 fragmentRect.intersect(fragment.paginationClip);
899 fragmentRect.move(fragment.paginationOffset);
900 result.unite(fragmentRect);
901 }
902 }
903
904 return result;
905}
906
907LayoutUnit RenderFragmentedFlow::offsetFromLogicalTopOfFirstFragment(const RenderBlock* currentBlock) const
908{
909 // As a last resort, take the slow path.
910 LayoutRect blockRect(0_lu, 0_lu, currentBlock->width(), currentBlock->height());
911 while (currentBlock && !is<RenderView>(*currentBlock) && !currentBlock->isRenderFragmentedFlow()) {
912 RenderBlock* containerBlock = currentBlock->containingBlock();
913 ASSERT(containerBlock);
914 if (!containerBlock)
915 return 0;
916 LayoutPoint currentBlockLocation = currentBlock->location();
917 if (is<RenderTableCell>(*currentBlock)) {
918 if (auto* section = downcast<RenderTableCell>(*currentBlock).section())
919 currentBlockLocation.moveBy(section->location());
920 }
921
922 if (containerBlock->style().writingMode() != currentBlock->style().writingMode()) {
923 // We have to put the block rect in container coordinates
924 // and we have to take into account both the container and current block flipping modes
925 if (containerBlock->style().isFlippedBlocksWritingMode()) {
926 if (containerBlock->isHorizontalWritingMode())
927 blockRect.setY(currentBlock->height() - blockRect.maxY());
928 else
929 blockRect.setX(currentBlock->width() - blockRect.maxX());
930 }
931 currentBlock->flipForWritingMode(blockRect);
932 }
933 blockRect.moveBy(currentBlockLocation);
934 currentBlock = containerBlock;
935 }
936
937 return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x();
938}
939
940void RenderFragmentedFlow::mapLocalToContainer(const RenderLayerModelObject* ancestorContainer, TransformState& transformState, OptionSet<MapCoordinatesMode> mode, bool* wasFixed) const
941{
942 if (this == ancestorContainer)
943 return;
944
945 if (RenderFragmentContainer* fragment = mapFromFlowToFragment(transformState)) {
946 // FIXME: The cast below is probably not the best solution, we may need to find a better way.
947 const RenderObject* fragmentObject = static_cast<const RenderObject*>(fragment);
948
949 // If the repaint container is nullptr, we have to climb up to the RenderView, otherwise swap
950 // it with the fragment's repaint container.
951 ancestorContainer = ancestorContainer ? fragment->containerForRepaint().renderer : nullptr;
952
953 if (RenderFragmentedFlow* fragmentFragmentedFlow = fragment->enclosingFragmentedFlow()) {
954 RenderFragmentContainer* startFragment = nullptr;
955 RenderFragmentContainer* endFragment = nullptr;
956 if (fragmentFragmentedFlow->getFragmentRangeForBox(fragment, startFragment, endFragment)) {
957 CurrentRenderFragmentContainerMaintainer fragmentMaintainer(*startFragment);
958 fragmentObject->mapLocalToContainer(ancestorContainer, transformState, mode, wasFixed);
959 return;
960 }
961 }
962
963 fragmentObject->mapLocalToContainer(ancestorContainer, transformState, mode, wasFixed);
964 }
965}
966
967// FIXME: Make this function faster. Walking the render tree is slow, better use a caching mechanism (e.g. |cachedOffsetFromLogicalTopOfFirstFragment|).
968LayoutRect RenderFragmentedFlow::mapFromLocalToFragmentedFlow(const RenderBox* box, const LayoutRect& localRect) const
969{
970 LayoutRect boxRect = localRect;
971
972 while (box && box != this) {
973 RenderBlock* containerBlock = box->containingBlock();
974 ASSERT(containerBlock);
975 if (!containerBlock)
976 return LayoutRect();
977 LayoutPoint currentBoxLocation = box->location();
978
979 if (containerBlock->style().writingMode() != box->style().writingMode())
980 box->flipForWritingMode(boxRect);
981
982 boxRect.moveBy(currentBoxLocation);
983 box = containerBlock;
984 }
985
986 return boxRect;
987}
988
989// FIXME: Make this function faster. Walking the render tree is slow, better use a caching mechanism (e.g. |cachedOffsetFromLogicalTopOfFirstFragment|).
990LayoutRect RenderFragmentedFlow::mapFromFragmentedFlowToLocal(const RenderBox* box, const LayoutRect& rect) const
991{
992 LayoutRect localRect = rect;
993 if (box == this)
994 return localRect;
995
996 RenderBlock* containerBlock = box->containingBlock();
997 ASSERT(containerBlock);
998 if (!containerBlock)
999 return LayoutRect();
1000 localRect = mapFromFragmentedFlowToLocal(containerBlock, localRect);
1001
1002 LayoutPoint currentBoxLocation = box->location();
1003 localRect.moveBy(-currentBoxLocation);
1004
1005 if (containerBlock->style().writingMode() != box->style().writingMode())
1006 box->flipForWritingMode(localRect);
1007
1008 return localRect;
1009}
1010
1011void RenderFragmentedFlow::flipForWritingModeLocalCoordinates(LayoutRect& rect) const
1012{
1013 if (!style().isFlippedBlocksWritingMode())
1014 return;
1015
1016 if (isHorizontalWritingMode())
1017 rect.setY(0 - rect.maxY());
1018 else
1019 rect.setX(0 - rect.maxX());
1020}
1021
1022void RenderFragmentedFlow::addFragmentsVisualEffectOverflow(const RenderBox* box)
1023{
1024 RenderFragmentContainer* startFragment = nullptr;
1025 RenderFragmentContainer* endFragment = nullptr;
1026 if (!getFragmentRangeForBox(box, startFragment, endFragment))
1027 return;
1028
1029 for (auto iter = m_fragmentList.find(startFragment), end = m_fragmentList.end(); iter != end; ++iter) {
1030 RenderFragmentContainer* fragment = *iter;
1031
1032 LayoutRect borderBox = box->borderBoxRectInFragment(fragment);
1033 borderBox = box->applyVisualEffectOverflow(borderBox);
1034 borderBox = fragment->rectFlowPortionForBox(box, borderBox);
1035
1036 fragment->addVisualOverflowForBox(box, borderBox);
1037 if (fragment == endFragment)
1038 break;
1039 }
1040}
1041
1042void RenderFragmentedFlow::addFragmentsVisualOverflowFromTheme(const RenderBlock* block)
1043{
1044 RenderFragmentContainer* startFragment = nullptr;
1045 RenderFragmentContainer* endFragment = nullptr;
1046 if (!getFragmentRangeForBox(block, startFragment, endFragment))
1047 return;
1048
1049 for (auto iter = m_fragmentList.find(startFragment), end = m_fragmentList.end(); iter != end; ++iter) {
1050 RenderFragmentContainer* fragment = *iter;
1051
1052 LayoutRect borderBox = block->borderBoxRectInFragment(fragment);
1053 borderBox = fragment->rectFlowPortionForBox(block, borderBox);
1054
1055 FloatRect inflatedRect = borderBox;
1056 block->theme().adjustRepaintRect(*block, inflatedRect);
1057
1058 fragment->addVisualOverflowForBox(block, snappedIntRect(LayoutRect(inflatedRect)));
1059 if (fragment == endFragment)
1060 break;
1061 }
1062}
1063
1064void RenderFragmentedFlow::addFragmentsOverflowFromChild(const RenderBox* box, const RenderBox* child, const LayoutSize& delta)
1065{
1066 RenderFragmentContainer* startFragment = nullptr;
1067 RenderFragmentContainer* endFragment = nullptr;
1068 if (!getFragmentRangeForBox(child, startFragment, endFragment))
1069 return;
1070
1071 RenderFragmentContainer* containerStartFragment = nullptr;
1072 RenderFragmentContainer* containerEndFragment = nullptr;
1073 if (!getFragmentRangeForBox(box, containerStartFragment, containerEndFragment))
1074 return;
1075
1076 for (auto iter = m_fragmentList.find(startFragment), end = m_fragmentList.end(); iter != end; ++iter) {
1077 RenderFragmentContainer* fragment = *iter;
1078 if (!fragmentInRange(fragment, containerStartFragment, containerEndFragment)) {
1079 if (fragment == endFragment)
1080 break;
1081 continue;
1082 }
1083
1084 LayoutRect childLayoutOverflowRect = fragment->layoutOverflowRectForBoxForPropagation(child);
1085 childLayoutOverflowRect.move(delta);
1086
1087 fragment->addLayoutOverflowForBox(box, childLayoutOverflowRect);
1088
1089 if (child->hasSelfPaintingLayer() || box->hasNonVisibleOverflow()) {
1090 if (fragment == endFragment)
1091 break;
1092 continue;
1093 }
1094 LayoutRect childVisualOverflowRect = fragment->visualOverflowRectForBoxForPropagation(*child);
1095 childVisualOverflowRect.move(delta);
1096 fragment->addVisualOverflowForBox(box, childVisualOverflowRect);
1097
1098 if (fragment == endFragment)
1099 break;
1100 }
1101}
1102
1103void RenderFragmentedFlow::addFragmentsLayoutOverflow(const RenderBox* box, const LayoutRect& layoutOverflow)
1104{
1105 RenderFragmentContainer* startFragment = nullptr;
1106 RenderFragmentContainer* endFragment = nullptr;
1107 if (!getFragmentRangeForBox(box, startFragment, endFragment))
1108 return;
1109
1110 for (auto iter = m_fragmentList.find(startFragment), end = m_fragmentList.end(); iter != end; ++iter) {
1111 RenderFragmentContainer* fragment = *iter;
1112 LayoutRect layoutOverflowInFragment = fragment->rectFlowPortionForBox(box, layoutOverflow);
1113
1114 fragment->addLayoutOverflowForBox(box, layoutOverflowInFragment);
1115
1116 if (fragment == endFragment)
1117 break;
1118 }
1119}
1120
1121void RenderFragmentedFlow::addFragmentsVisualOverflow(const RenderBox* box, const LayoutRect& visualOverflow)
1122{
1123 RenderFragmentContainer* startFragment = nullptr;
1124 RenderFragmentContainer* endFragment = nullptr;
1125 if (!getFragmentRangeForBox(box, startFragment, endFragment))
1126 return;
1127
1128 for (RenderFragmentContainerList::iterator iter = m_fragmentList.find(startFragment); iter != m_fragmentList.end(); ++iter) {
1129 RenderFragmentContainer* fragment = *iter;
1130 LayoutRect visualOverflowInFragment = fragment->rectFlowPortionForBox(box, visualOverflow);
1131
1132 fragment->addVisualOverflowForBox(box, visualOverflowInFragment);
1133
1134 if (fragment == endFragment)
1135 break;
1136 }
1137}
1138
1139void RenderFragmentedFlow::clearFragmentsOverflow(const RenderBox* box)
1140{
1141 RenderFragmentContainer* startFragment = nullptr;
1142 RenderFragmentContainer* endFragment = nullptr;
1143 if (!getFragmentRangeForBox(box, startFragment, endFragment))
1144 return;
1145
1146 for (auto iter = m_fragmentList.find(startFragment), end = m_fragmentList.end(); iter != end; ++iter) {
1147 RenderFragmentContainer* fragment = *iter;
1148 RenderBoxFragmentInfo* boxInfo = fragment->renderBoxFragmentInfo(box);
1149 if (boxInfo && boxInfo->overflow())
1150 boxInfo->clearOverflow();
1151
1152 if (fragment == endFragment)
1153 break;
1154 }
1155}
1156
1157RenderFragmentContainer* RenderFragmentedFlow::currentFragment() const
1158{
1159 return m_currentFragmentMaintainer ? &m_currentFragmentMaintainer->fragment() : nullptr;
1160}
1161
1162ContainingFragmentMap& RenderFragmentedFlow::containingFragmentMap()
1163{
1164 if (!m_lineToFragmentMap)
1165 m_lineToFragmentMap = makeUnique<ContainingFragmentMap>();
1166
1167 return *m_lineToFragmentMap.get();
1168}
1169
1170
1171} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.