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