[iOS] Implement idempotent mode for text autosizing
[WebKit-https.git] / Source / WebCore / page / FrameViewLayoutContext.cpp
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
54 namespace WebCore {
55
56 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
57 static 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
69 static 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
79 class RenderTreeNeedsLayoutChecker {
80 public :
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
108 private:
109     const RenderElement& m_layoutRoot;
110 };
111 #endif
112
113 class LayoutScope {
114 public:
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         
129 private:
130     FrameView& m_view;
131     SetForScope<FrameViewLayoutContext::LayoutNestedState> m_nestedState;
132     SetForScope<bool> m_schedulingIsEnabled;
133     ScrollType m_previousScrollType;
134 };
135
136 FrameViewLayoutContext::FrameViewLayoutContext(FrameView& frameView)
137     : m_frameView(frameView)
138     , m_layoutTimer(*this, &FrameViewLayoutContext::layoutTimerFired)
139     , m_asynchronousTasksTimer(*this, &FrameViewLayoutContext::runAsynchronousTasks)
140 {
141 }
142
143 FrameViewLayoutContext::~FrameViewLayoutContext()
144 {
145 }
146
147 void 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
246 void 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
275 void 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
284 void FrameViewLayoutContext::flushAsynchronousTasks()
285 {
286     if (!m_asynchronousTasksTimer.isActive())
287         return;
288     runAsynchronousTasks();
289 }
290
291 void 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
304 bool 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
316 void 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
330 void 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
337 void FrameViewLayoutContext::disableSetNeedsLayout()
338 {
339     ++m_disableSetNeedsLayoutCount;
340 }
341
342 void 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
379 void 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
396 void 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
452 void 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
461 void FrameViewLayoutContext::convertSubtreeLayoutToFullLayout()
462 {
463     ASSERT(subtreeLayoutRoot());
464     subtreeLayoutRoot()->markContainingBlocksForLayout(ScheduleRelayout::No);
465     clearSubtreeLayoutRoot();
466 }
467
468 void FrameViewLayoutContext::setSubtreeLayoutRoot(RenderElement& layoutRoot)
469 {
470     m_subtreeLayoutRoot = makeWeakPtr(layoutRoot);
471 }
472
473 bool 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)
491 void 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
513 void 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
533 bool 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
543 void 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
567 LayoutSize FrameViewLayoutContext::layoutDelta() const
568 {
569     if (auto* layoutState = this->layoutState())
570         return layoutState->layoutDelta();
571     return { };
572 }
573     
574 void FrameViewLayoutContext::addLayoutDelta(const LayoutSize& delta)
575 {
576     if (auto* layoutState = this->layoutState())
577         layoutState->addLayoutDelta(delta);
578 }
579     
580 #if !ASSERT_DISABLED
581 bool FrameViewLayoutContext::layoutDeltaMatches(const LayoutSize& delta)
582 {
583     if (auto* layoutState = this->layoutState())
584         return layoutState->layoutDeltaMatches(delta);
585     return false;
586 }
587 #endif
588
589 RenderLayoutState* FrameViewLayoutContext::layoutState() const
590 {
591     if (m_layoutStateStack.isEmpty())
592         return nullptr;
593     return m_layoutStateStack.last().get();
594 }
595
596 void FrameViewLayoutContext::pushLayoutState(RenderElement& root)
597 {
598     ASSERT(!m_paintOffsetCacheDisableCount);
599     ASSERT(!layoutState());
600
601     m_layoutStateStack.append(std::make_unique<RenderLayoutState>(root));
602 }
603
604 bool 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     
612 bool 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     
624 void FrameViewLayoutContext::popLayoutState()
625 {
626     m_layoutStateStack.removeLast();
627 }
628
629 #ifndef NDEBUG
630 void FrameViewLayoutContext::checkLayoutState()
631 {
632     ASSERT(layoutDeltaMatches(LayoutSize()));
633     ASSERT(!m_paintOffsetCacheDisableCount);
634 }
635 #endif
636
637 Frame& FrameViewLayoutContext::frame() const
638 {
639     return view().frame();
640 }
641
642 FrameView& FrameViewLayoutContext::view() const
643 {
644     return m_frameView;
645 }
646
647 RenderView* FrameViewLayoutContext::renderView() const
648 {
649     return view().renderView();
650 }
651
652 Document* FrameViewLayoutContext::document() const
653 {
654     return frame().document();
655 }
656
657 } // namespace WebCore