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