4fe0e1f808bc3a1de713ac4b5a326a33da4580b5
[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 (!m_layoutState)
534         return { };
535     return m_layoutState->layoutDelta();
536 }
537     
538 void LayoutContext::addLayoutDelta(const LayoutSize& delta)
539 {
540     if (!m_layoutState)
541         return;
542     m_layoutState->addLayoutDelta(delta);
543 }
544     
545 #if !ASSERT_DISABLED
546 bool LayoutContext::layoutDeltaMatches(const LayoutSize& delta)
547 {
548     if (!m_layoutState)
549         return false;
550     return m_layoutState->layoutDeltaMatches(delta);
551 }
552 #endif
553     
554 void LayoutContext::pushLayoutState(RenderElement& root)
555 {
556     ASSERT(!m_paintOffsetCacheDisableCount);
557     ASSERT(!m_layoutState);
558
559     m_layoutState = std::make_unique<LayoutState>(root);
560 }
561
562 bool LayoutContext::pushLayoutStateForPaginationIfNeeded(RenderBlockFlow& layoutRoot)
563 {
564     if (m_layoutState)
565         return false;
566     m_layoutState = std::make_unique<LayoutState>(layoutRoot);
567     m_layoutState->setIsPaginated();
568     // This is just a flag for known page height (see RenderBlockFlow::checkForPaginationLogicalHeightChange).
569     m_layoutState->setPageLogicalHeight(1);
570     return true;
571 }
572     
573 void LayoutContext::popLayoutState(RenderObject&)
574 {
575     return popLayoutState();
576 }
577     
578 bool LayoutContext::pushLayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageHeight, bool pageHeightChanged)
579 {
580     // We push LayoutState even if layoutState is disabled because it stores layoutDelta too.
581     if (!m_layoutState || !needsFullRepaint() || m_layoutState->isPaginated() || renderer.enclosingFragmentedFlow()
582         || m_layoutState->lineGrid() || (renderer.style().lineGrid() != RenderStyle::initialLineGrid() && renderer.isRenderBlockFlow())) {
583         m_layoutState = std::make_unique<LayoutState>(WTFMove(m_layoutState), renderer, offset, pageHeight, pageHeightChanged);
584         return true;
585     }
586     return false;
587 }
588     
589 void LayoutContext::popLayoutState()
590 {
591     m_layoutState = WTFMove(m_layoutState->m_ancestor);
592 }
593     
594 #ifndef NDEBUG
595 void LayoutContext::checkLayoutState()
596 {
597     ASSERT(layoutDeltaMatches(LayoutSize()));
598     ASSERT(!m_paintOffsetCacheDisableCount);
599 }
600 #endif
601
602 Frame& LayoutContext::frame() const
603 {
604     return view().frame();
605 }
606
607 FrameView& LayoutContext::view() const
608 {
609     return m_frameView;
610 }
611
612 RenderView* LayoutContext::renderView() const
613 {
614     return view().renderView();
615 }
616
617 Document* LayoutContext::document() const
618 {
619     return frame().document();
620 }
621
622 } // namespace WebCore