1/*
2 * Copyright (C) 2017 Apple Inc. 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 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "FrameViewLayoutContext.h"
28
29#include "CSSAnimationController.h"
30#include "DebugPageOverlays.h"
31#include "Document.h"
32#include "FrameView.h"
33#include "InspectorInstrumentation.h"
34#include "LayoutDisallowedScope.h"
35#include "Logging.h"
36#include "RenderElement.h"
37#include "RenderLayoutState.h"
38#include "RenderView.h"
39#include "RuntimeEnabledFeatures.h"
40#include "ScriptDisallowedScope.h"
41#include "Settings.h"
42
43#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
44#include "FormattingState.h"
45#include "LayoutContainer.h"
46#include "LayoutState.h"
47#include "LayoutTreeBuilder.h"
48#endif
49
50#include <wtf/SetForScope.h>
51#include <wtf/SystemTracing.h>
52#include <wtf/text/TextStream.h>
53
54namespace WebCore {
55
56#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
57static void layoutUsingFormattingContext(const RenderView& renderView)
58{
59 if (!RuntimeEnabledFeatures::sharedFeatures().layoutFormattingContextEnabled())
60 return;
61 auto initialContainingBlock = Layout::TreeBuilder::createLayoutTree(renderView);
62 auto layoutState = std::make_unique<Layout::LayoutState>(*initialContainingBlock);
63 layoutState->setInQuirksMode(renderView.document().inQuirksMode());
64 layoutState->updateLayout();
65 layoutState->verifyAndOutputMismatchingLayoutTree(renderView);
66}
67#endif
68
69static bool isObjectAncestorContainerOf(RenderElement& ancestor, RenderElement& descendant)
70{
71 for (auto* renderer = &descendant; renderer; renderer = renderer->container()) {
72 if (renderer == &ancestor)
73 return true;
74 }
75 return false;
76}
77
78#ifndef NDEBUG
79class RenderTreeNeedsLayoutChecker {
80public :
81 RenderTreeNeedsLayoutChecker(const RenderElement& layoutRoot)
82 : m_layoutRoot(layoutRoot)
83 {
84 }
85
86 ~RenderTreeNeedsLayoutChecker()
87 {
88 auto reportNeedsLayoutError = [] (const RenderObject& renderer) {
89 WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, "post-layout: dirty renderer(s)");
90 renderer.showRenderTreeForThis();
91 ASSERT_NOT_REACHED();
92 };
93
94 if (m_layoutRoot.needsLayout()) {
95 reportNeedsLayoutError(m_layoutRoot);
96 return;
97 }
98
99 for (auto* descendant = m_layoutRoot.firstChild(); descendant; descendant = descendant->nextInPreOrder(&m_layoutRoot)) {
100 if (!descendant->needsLayout())
101 continue;
102
103 reportNeedsLayoutError(*descendant);
104 return;
105 }
106 }
107
108private:
109 const RenderElement& m_layoutRoot;
110};
111#endif
112
113class LayoutScope {
114public:
115 LayoutScope(FrameViewLayoutContext& layoutContext)
116 : m_view(layoutContext.view())
117 , m_nestedState(layoutContext.m_layoutNestedState, layoutContext.m_layoutNestedState == FrameViewLayoutContext::LayoutNestedState::NotInLayout ? FrameViewLayoutContext::LayoutNestedState::NotNested : FrameViewLayoutContext::LayoutNestedState::Nested)
118 , m_schedulingIsEnabled(layoutContext.m_layoutSchedulingIsEnabled, false)
119 , m_previousScrollType(layoutContext.view().currentScrollType())
120 {
121 m_view.setCurrentScrollType(ScrollType::Programmatic);
122 }
123
124 ~LayoutScope()
125 {
126 m_view.setCurrentScrollType(m_previousScrollType);
127 }
128
129private:
130 FrameView& m_view;
131 SetForScope<FrameViewLayoutContext::LayoutNestedState> m_nestedState;
132 SetForScope<bool> m_schedulingIsEnabled;
133 ScrollType m_previousScrollType;
134};
135
136FrameViewLayoutContext::FrameViewLayoutContext(FrameView& frameView)
137 : m_frameView(frameView)
138 , m_layoutTimer(*this, &FrameViewLayoutContext::layoutTimerFired)
139 , m_asynchronousTasksTimer(*this, &FrameViewLayoutContext::runAsynchronousTasks)
140{
141}
142
143FrameViewLayoutContext::~FrameViewLayoutContext()
144{
145}
146
147void FrameViewLayoutContext::layout()
148{
149 LOG_WITH_STREAM(Layout, stream << "FrameView " << &view() << " FrameViewLayoutContext::layout() with size " << view().layoutSize());
150
151 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!frame().document()->inRenderTreeUpdate());
152 ASSERT(LayoutDisallowedScope::isLayoutAllowed());
153 ASSERT(!view().isPainting());
154 ASSERT(frame().view() == &view());
155 ASSERT(frame().document());
156 ASSERT(frame().document()->pageCacheState() == Document::NotInPageCache);
157 if (!canPerformLayout()) {
158 LOG(Layout, " is not allowed, bailing");
159 return;
160 }
161
162 Ref<FrameView> protectView(view());
163 LayoutScope layoutScope(*this);
164 TraceScope tracingScope(LayoutStart, LayoutEnd);
165 InspectorInstrumentationCookie inspectorLayoutScope(InspectorInstrumentation::willLayout(view().frame()));
166 AnimationUpdateBlock animationUpdateBlock(&view().frame().animation());
167 WeakPtr<RenderElement> layoutRoot;
168
169 m_layoutTimer.stop();
170 m_delayedLayout = false;
171 m_setNeedsLayoutWasDeferred = false;
172
173#if !LOG_DISABLED
174 if (m_firstLayout && !frame().ownerElement())
175 LOG(Layout, "FrameView %p elapsed time before first layout: %.3fs", this, document()->timeSinceDocumentCreation().value());
176#endif
177#if PLATFORM(IOS_FAMILY)
178 if (view().updateFixedPositionLayoutRect() && subtreeLayoutRoot())
179 convertSubtreeLayoutToFullLayout();
180#endif
181 if (handleLayoutWithFrameFlatteningIfNeeded())
182 return;
183
184 {
185 SetForScope<LayoutPhase> layoutPhase(m_layoutPhase, LayoutPhase::InPreLayout);
186
187 // If this is a new top-level layout and there are any remaining tasks from the previous layout, finish them now.
188 if (!isLayoutNested() && m_asynchronousTasksTimer.isActive() && !view().isInChildFrameWithFrameFlattening())
189 runAsynchronousTasks();
190
191 updateStyleForLayout();
192 if (view().hasOneRef())
193 return;
194
195 view().autoSizeIfEnabled();
196 if (!renderView())
197 return;
198
199 layoutRoot = makeWeakPtr(subtreeLayoutRoot() ? subtreeLayoutRoot() : renderView());
200 m_needsFullRepaint = is<RenderView>(layoutRoot.get()) && (m_firstLayout || renderView()->printing());
201 view().willDoLayout(layoutRoot);
202 m_firstLayout = false;
203 }
204 {
205 SetForScope<LayoutPhase> layoutPhase(m_layoutPhase, LayoutPhase::InRenderTreeLayout);
206 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
207 SubtreeLayoutStateMaintainer subtreeLayoutStateMaintainer(subtreeLayoutRoot());
208 RenderView::RepaintRegionAccumulator repaintRegionAccumulator(renderView());
209#ifndef NDEBUG
210 RenderTreeNeedsLayoutChecker checker(*layoutRoot);
211#endif
212 layoutRoot->layout();
213#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
214 layoutUsingFormattingContext(*renderView());
215#endif
216 ++m_layoutCount;
217#if ENABLE(TEXT_AUTOSIZING)
218 applyTextSizingIfNeeded(*layoutRoot.get());
219#endif
220 clearSubtreeLayoutRoot();
221 }
222 {
223 SetForScope<LayoutPhase> layoutPhase(m_layoutPhase, LayoutPhase::InViewSizeAdjust);
224 if (is<RenderView>(layoutRoot.get()) && !renderView()->printing()) {
225 // This is to protect m_needsFullRepaint's value when layout() is getting re-entered through adjustViewSize().
226 SetForScope<bool> needsFullRepaint(m_needsFullRepaint);
227 view().adjustViewSize();
228 // FIXME: Firing media query callbacks synchronously on nested frames could produced a detached FrameView here by
229 // navigating away from the current document (see webkit.org/b/173329).
230 if (view().hasOneRef())
231 return;
232 }
233 }
234 {
235 SetForScope<LayoutPhase> layoutPhase(m_layoutPhase, LayoutPhase::InPostLayout);
236 if (m_needsFullRepaint)
237 renderView()->repaintRootContents();
238 ASSERT(!layoutRoot->needsLayout());
239 view().didLayout(layoutRoot);
240 runOrScheduleAsynchronousTasks();
241 }
242 InspectorInstrumentation::didLayout(inspectorLayoutScope, *layoutRoot);
243 DebugPageOverlays::didLayout(view().frame());
244}
245
246void FrameViewLayoutContext::runOrScheduleAsynchronousTasks()
247{
248 if (m_asynchronousTasksTimer.isActive())
249 return;
250
251 if (view().isInChildFrameWithFrameFlattening()) {
252 // While flattening frames, we defer post layout tasks to avoid getting stuck in a cycle,
253 // except updateWidgetPositions() which is required to kick off subframe layout in certain cases.
254 if (!m_inAsynchronousTasks)
255 view().updateWidgetPositions();
256 m_asynchronousTasksTimer.startOneShot(0_s);
257 return;
258 }
259
260 // If we are already in performPostLayoutTasks(), defer post layout tasks until after we return
261 // to avoid re-entrancy.
262 if (m_inAsynchronousTasks) {
263 m_asynchronousTasksTimer.startOneShot(0_s);
264 return;
265 }
266
267 runAsynchronousTasks();
268 if (needsLayout()) {
269 // If runAsynchronousTasks() made us layout again, let's defer the tasks until after we return.
270 m_asynchronousTasksTimer.startOneShot(0_s);
271 layout();
272 }
273}
274
275void FrameViewLayoutContext::runAsynchronousTasks()
276{
277 m_asynchronousTasksTimer.stop();
278 if (m_inAsynchronousTasks)
279 return;
280 SetForScope<bool> inAsynchronousTasks(m_inAsynchronousTasks, true);
281 view().performPostLayoutTasks();
282}
283
284void FrameViewLayoutContext::flushAsynchronousTasks()
285{
286 if (!m_asynchronousTasksTimer.isActive())
287 return;
288 runAsynchronousTasks();
289}
290
291void FrameViewLayoutContext::reset()
292{
293 m_layoutPhase = LayoutPhase::OutsideLayout;
294 clearSubtreeLayoutRoot();
295 m_layoutCount = 0;
296 m_layoutSchedulingIsEnabled = true;
297 m_delayedLayout = false;
298 m_layoutTimer.stop();
299 m_firstLayout = true;
300 m_asynchronousTasksTimer.stop();
301 m_needsFullRepaint = true;
302}
303
304bool FrameViewLayoutContext::needsLayout() const
305{
306 // This can return true in cases where the document does not have a body yet.
307 // Document::shouldScheduleLayout takes care of preventing us from scheduling
308 // layout in that case.
309 auto* renderView = this->renderView();
310 return isLayoutPending()
311 || (renderView && renderView->needsLayout())
312 || subtreeLayoutRoot()
313 || (m_disableSetNeedsLayoutCount && m_setNeedsLayoutWasDeferred);
314}
315
316void FrameViewLayoutContext::setNeedsLayoutAfterViewConfigurationChange()
317{
318 if (m_disableSetNeedsLayoutCount) {
319 m_setNeedsLayoutWasDeferred = true;
320 return;
321 }
322
323 if (auto* renderView = this->renderView()) {
324 ASSERT(!renderView->inHitTesting());
325 renderView->setNeedsLayout();
326 scheduleLayout();
327 }
328}
329
330void FrameViewLayoutContext::enableSetNeedsLayout()
331{
332 ASSERT(m_disableSetNeedsLayoutCount);
333 if (!--m_disableSetNeedsLayoutCount)
334 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
335}
336
337void FrameViewLayoutContext::disableSetNeedsLayout()
338{
339 ++m_disableSetNeedsLayoutCount;
340}
341
342void FrameViewLayoutContext::scheduleLayout()
343{
344 // FIXME: We should assert the page is not in the page cache, but that is causing
345 // too many false assertions. See <rdar://problem/7218118>.
346 ASSERT(frame().view() == &view());
347
348 if (subtreeLayoutRoot())
349 convertSubtreeLayoutToFullLayout();
350 if (!isLayoutSchedulingEnabled())
351 return;
352 if (!needsLayout())
353 return;
354 if (!frame().document()->shouldScheduleLayout())
355 return;
356 InspectorInstrumentation::didInvalidateLayout(frame());
357 // When frame flattening is enabled, the contents of the frame could affect the layout of the parent frames.
358 // Also invalidate parent frame starting from the owner element of this frame.
359 if (frame().ownerRenderer() && view().isInChildFrameWithFrameFlattening())
360 frame().ownerRenderer()->setNeedsLayout(MarkContainingBlockChain);
361
362 Seconds delay = frame().document()->minimumLayoutDelay();
363 if (m_layoutTimer.isActive() && m_delayedLayout && !delay)
364 unscheduleLayout();
365
366 if (m_layoutTimer.isActive())
367 return;
368
369 m_delayedLayout = delay.value();
370
371#if !LOG_DISABLED
372 if (!frame().document()->ownerElement())
373 LOG(Layout, "FrameView %p scheduling layout for %.3fs", this, delay.value());
374#endif
375
376 m_layoutTimer.startOneShot(delay);
377}
378
379void FrameViewLayoutContext::unscheduleLayout()
380{
381 if (m_asynchronousTasksTimer.isActive())
382 m_asynchronousTasksTimer.stop();
383
384 if (!m_layoutTimer.isActive())
385 return;
386
387#if !LOG_DISABLED
388 if (!frame().document()->ownerElement())
389 LOG(Layout, "FrameView %p layout timer unscheduled at %.3fs", this, frame().document()->timeSinceDocumentCreation().value());
390#endif
391
392 m_layoutTimer.stop();
393 m_delayedLayout = false;
394}
395
396void FrameViewLayoutContext::scheduleSubtreeLayout(RenderElement& layoutRoot)
397{
398 ASSERT(renderView());
399 auto& renderView = *this->renderView();
400
401 // Try to catch unnecessary work during render tree teardown.
402 ASSERT(!renderView.renderTreeBeingDestroyed());
403 ASSERT(frame().view() == &view());
404
405 if (renderView.needsLayout() && !subtreeLayoutRoot()) {
406 layoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
407 return;
408 }
409
410 if (!isLayoutPending() && isLayoutSchedulingEnabled()) {
411 Seconds delay = renderView.document().minimumLayoutDelay();
412 ASSERT(!layoutRoot.container() || is<RenderView>(layoutRoot.container()) || !layoutRoot.container()->needsLayout());
413 setSubtreeLayoutRoot(layoutRoot);
414 InspectorInstrumentation::didInvalidateLayout(frame());
415 m_delayedLayout = delay.value();
416 m_layoutTimer.startOneShot(delay);
417 return;
418 }
419
420 auto* subtreeLayoutRoot = this->subtreeLayoutRoot();
421 if (subtreeLayoutRoot == &layoutRoot)
422 return;
423
424 if (!subtreeLayoutRoot) {
425 // We already have a pending (full) layout. Just mark the subtree for layout.
426 layoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
427 InspectorInstrumentation::didInvalidateLayout(frame());
428 return;
429 }
430
431 if (isObjectAncestorContainerOf(*subtreeLayoutRoot, layoutRoot)) {
432 // Keep the current root.
433 layoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No, subtreeLayoutRoot);
434 ASSERT(!subtreeLayoutRoot->container() || is<RenderView>(subtreeLayoutRoot->container()) || !subtreeLayoutRoot->container()->needsLayout());
435 return;
436 }
437
438 if (isObjectAncestorContainerOf(layoutRoot, *subtreeLayoutRoot)) {
439 // Re-root at newRelayoutRoot.
440 subtreeLayoutRoot->markContainingBlocksForLayout(ScheduleRelayout::No, &layoutRoot);
441 setSubtreeLayoutRoot(layoutRoot);
442 ASSERT(!layoutRoot.container() || is<RenderView>(layoutRoot.container()) || !layoutRoot.container()->needsLayout());
443 InspectorInstrumentation::didInvalidateLayout(frame());
444 return;
445 }
446 // Two disjoint subtrees need layout. Mark both of them and issue a full layout instead.
447 convertSubtreeLayoutToFullLayout();
448 layoutRoot.markContainingBlocksForLayout(ScheduleRelayout::No);
449 InspectorInstrumentation::didInvalidateLayout(frame());
450}
451
452void FrameViewLayoutContext::layoutTimerFired()
453{
454#if !LOG_DISABLED
455 if (!frame().document()->ownerElement())
456 LOG(Layout, "FrameView %p layout timer fired at %.3fs", this, frame().document()->timeSinceDocumentCreation().value());
457#endif
458 layout();
459}
460
461void FrameViewLayoutContext::convertSubtreeLayoutToFullLayout()
462{
463 ASSERT(subtreeLayoutRoot());
464 subtreeLayoutRoot()->markContainingBlocksForLayout(ScheduleRelayout::No);
465 clearSubtreeLayoutRoot();
466}
467
468void FrameViewLayoutContext::setSubtreeLayoutRoot(RenderElement& layoutRoot)
469{
470 m_subtreeLayoutRoot = makeWeakPtr(layoutRoot);
471}
472
473bool FrameViewLayoutContext::canPerformLayout() const
474{
475 if (isInRenderTreeLayout())
476 return false;
477
478 if (layoutDisallowed())
479 return false;
480
481 if (view().isPainting())
482 return false;
483
484 if (!subtreeLayoutRoot() && !frame().document()->renderView())
485 return false;
486
487 return true;
488}
489
490#if ENABLE(TEXT_AUTOSIZING)
491void FrameViewLayoutContext::applyTextSizingIfNeeded(RenderElement& layoutRoot)
492{
493 auto& settings = layoutRoot.settings();
494 if (!settings.textAutosizingEnabled() || renderView()->printing())
495 return;
496 bool idempotentMode = settings.textAutosizingUsesIdempotentMode();
497 auto minimumZoomFontSize = settings.minimumZoomFontSize();
498 if (!idempotentMode && !minimumZoomFontSize)
499 return;
500 auto textAutosizingWidth = layoutRoot.page().textAutosizingWidth();
501 if (auto overrideWidth = settings.textAutosizingWindowSizeOverride().width())
502 textAutosizingWidth = overrideWidth;
503 if (!idempotentMode && !textAutosizingWidth)
504 return;
505 layoutRoot.adjustComputedFontSizesOnBlocks(minimumZoomFontSize, textAutosizingWidth);
506 if (!layoutRoot.needsLayout())
507 return;
508 LOG(TextAutosizing, "Text Autosizing: minimumZoomFontSize=%.2f textAutosizingWidth=%.2f", minimumZoomFontSize, textAutosizingWidth);
509 layoutRoot.layout();
510}
511#endif
512
513void FrameViewLayoutContext::updateStyleForLayout()
514{
515 Document& document = *frame().document();
516
517 // FIXME: This shouldn't be necessary, but see rdar://problem/36670246.
518 if (!document.styleScope().resolverIfExists())
519 document.styleScope().didChangeStyleSheetEnvironment();
520
521 // Viewport-dependent media queries may cause us to need completely different style information.
522 document.styleScope().evaluateMediaQueriesForViewportChange();
523
524 document.evaluateMediaQueryList();
525 // If there is any pagination to apply, it will affect the RenderView's style, so we should
526 // take care of that now.
527 view().applyPaginationToViewport();
528 // Always ensure our style info is up-to-date. This can happen in situations where
529 // the layout beats any sort of style recalc update that needs to occur.
530 document.updateStyleIfNeeded();
531}
532
533bool FrameViewLayoutContext::handleLayoutWithFrameFlatteningIfNeeded()
534{
535 if (!view().isInChildFrameWithFrameFlattening())
536 return false;
537
538 startLayoutAtMainFrameViewIfNeeded();
539 auto* layoutRoot = subtreeLayoutRoot() ? subtreeLayoutRoot() : frame().document()->renderView();
540 return !layoutRoot || !layoutRoot->needsLayout();
541}
542
543void FrameViewLayoutContext::startLayoutAtMainFrameViewIfNeeded()
544{
545 // When we start a layout at the child level as opposed to the topmost frame view and this child
546 // frame requires flattening, we need to re-initiate the layout at the topmost view. Layout
547 // will hit this view eventually.
548 auto* parentView = view().parentFrameView();
549 if (!parentView)
550 return;
551
552 // In the middle of parent layout, no need to restart from topmost.
553 if (parentView->layoutContext().isInLayout())
554 return;
555
556 // Parent tree is clean. Starting layout from it would have no effect.
557 if (!parentView->needsLayout())
558 return;
559
560 while (parentView->parentFrameView())
561 parentView = parentView->parentFrameView();
562
563 LOG(Layout, " frame flattening, starting from root");
564 parentView->layoutContext().layout();
565}
566
567LayoutSize FrameViewLayoutContext::layoutDelta() const
568{
569 if (auto* layoutState = this->layoutState())
570 return layoutState->layoutDelta();
571 return { };
572}
573
574void FrameViewLayoutContext::addLayoutDelta(const LayoutSize& delta)
575{
576 if (auto* layoutState = this->layoutState())
577 layoutState->addLayoutDelta(delta);
578}
579
580#if !ASSERT_DISABLED
581bool FrameViewLayoutContext::layoutDeltaMatches(const LayoutSize& delta)
582{
583 if (auto* layoutState = this->layoutState())
584 return layoutState->layoutDeltaMatches(delta);
585 return false;
586}
587#endif
588
589RenderLayoutState* FrameViewLayoutContext::layoutState() const
590{
591 if (m_layoutStateStack.isEmpty())
592 return nullptr;
593 return m_layoutStateStack.last().get();
594}
595
596void FrameViewLayoutContext::pushLayoutState(RenderElement& root)
597{
598 ASSERT(!m_paintOffsetCacheDisableCount);
599 ASSERT(!layoutState());
600
601 m_layoutStateStack.append(std::make_unique<RenderLayoutState>(root));
602}
603
604bool FrameViewLayoutContext::pushLayoutStateForPaginationIfNeeded(RenderBlockFlow& layoutRoot)
605{
606 if (layoutState())
607 return false;
608 m_layoutStateStack.append(std::make_unique<RenderLayoutState>(layoutRoot, RenderLayoutState::IsPaginated::Yes));
609 return true;
610}
611
612bool FrameViewLayoutContext::pushLayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageHeight, bool pageHeightChanged)
613{
614 // We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
615 auto* layoutState = this->layoutState();
616 if (!layoutState || !needsFullRepaint() || layoutState->isPaginated() || renderer.enclosingFragmentedFlow()
617 || layoutState->lineGrid() || (renderer.style().lineGrid() != RenderStyle::initialLineGrid() && renderer.isRenderBlockFlow())) {
618 m_layoutStateStack.append(std::make_unique<RenderLayoutState>(m_layoutStateStack, renderer, offset, pageHeight, pageHeightChanged));
619 return true;
620 }
621 return false;
622}
623
624void FrameViewLayoutContext::popLayoutState()
625{
626 m_layoutStateStack.removeLast();
627}
628
629#ifndef NDEBUG
630void FrameViewLayoutContext::checkLayoutState()
631{
632 ASSERT(layoutDeltaMatches(LayoutSize()));
633 ASSERT(!m_paintOffsetCacheDisableCount);
634}
635#endif
636
637Frame& FrameViewLayoutContext::frame() const
638{
639 return view().frame();
640}
641
642FrameView& FrameViewLayoutContext::view() const
643{
644 return m_frameView;
645}
646
647RenderView* FrameViewLayoutContext::renderView() const
648{
649 return view().renderView();
650}
651
652Document* FrameViewLayoutContext::document() const
653{
654 return frame().document();
655}
656
657} // namespace WebCore
658