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