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