• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3  *                     1999 Lars Knoll <knoll@kde.org>
4  *                     1999 Antti Koivisto <koivisto@kde.org>
5  *                     2000 Dirk Mueller <mueller@kde.org>
6  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7  *           (C) 2006 Graham Dennis (graham.dennis@gmail.com)
8  *           (C) 2006 Alexey Proskuryakov (ap@nypop.com)
9  * Copyright (C) 2009 Google Inc. All rights reserved.
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB.  If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26 
27 #include "config.h"
28 #include "core/frame/FrameView.h"
29 
30 #include "core/HTMLNames.h"
31 #include "core/MediaTypeNames.h"
32 #include "core/accessibility/AXObjectCache.h"
33 #include "core/css/FontFaceSet.h"
34 #include "core/css/resolver/StyleResolver.h"
35 #include "core/dom/DocumentMarkerController.h"
36 #include "core/editing/FrameSelection.h"
37 #include "core/editing/RenderedPosition.h"
38 #include "core/events/OverflowEvent.h"
39 #include "core/fetch/ResourceFetcher.h"
40 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
41 #include "core/frame/FrameHost.h"
42 #include "core/frame/LocalFrame.h"
43 #include "core/frame/Settings.h"
44 #include "core/html/HTMLFrameElement.h"
45 #include "core/html/HTMLPlugInElement.h"
46 #include "core/html/parser/TextResourceDecoder.h"
47 #include "core/inspector/InspectorInstrumentation.h"
48 #include "core/inspector/InspectorTraceEvents.h"
49 #include "core/loader/FrameLoader.h"
50 #include "core/loader/FrameLoaderClient.h"
51 #include "core/page/Chrome.h"
52 #include "core/page/ChromeClient.h"
53 #include "core/page/EventHandler.h"
54 #include "core/page/FocusController.h"
55 #include "core/page/FrameTree.h"
56 #include "core/page/Page.h"
57 #include "core/page/scrolling/ScrollingCoordinator.h"
58 #include "core/rendering/RenderCounter.h"
59 #include "core/rendering/RenderEmbeddedObject.h"
60 #include "core/rendering/RenderLayer.h"
61 #include "core/rendering/RenderListBox.h"
62 #include "core/rendering/RenderPart.h"
63 #include "core/rendering/RenderScrollbar.h"
64 #include "core/rendering/RenderScrollbarPart.h"
65 #include "core/rendering/RenderTheme.h"
66 #include "core/rendering/RenderView.h"
67 #include "core/rendering/RenderWidget.h"
68 #include "core/rendering/TextAutosizer.h"
69 #include "core/rendering/compositing/CompositedLayerMapping.h"
70 #include "core/rendering/compositing/CompositedSelectionBound.h"
71 #include "core/rendering/compositing/RenderLayerCompositor.h"
72 #include "core/rendering/style/RenderStyle.h"
73 #include "core/rendering/svg/RenderSVGRoot.h"
74 #include "core/svg/SVGDocumentExtensions.h"
75 #include "core/svg/SVGSVGElement.h"
76 #include "platform/RuntimeEnabledFeatures.h"
77 #include "platform/ScriptForbiddenScope.h"
78 #include "platform/TraceEvent.h"
79 #include "platform/fonts/FontCache.h"
80 #include "platform/geometry/FloatRect.h"
81 #include "platform/graphics/GraphicsContext.h"
82 #include "platform/graphics/GraphicsLayerDebugInfo.h"
83 #include "platform/scroll/ScrollAnimator.h"
84 #include "platform/scroll/ScrollbarTheme.h"
85 #include "platform/text/TextStream.h"
86 #include "wtf/CurrentTime.h"
87 #include "wtf/TemporaryChange.h"
88 
89 namespace blink {
90 
91 using namespace HTMLNames;
92 
93 double FrameView::s_currentFrameTimeStamp = 0.0;
94 bool FrameView::s_inPaintContents = false;
95 
96 // The maximum number of updateWidgets iterations that should be done before returning.
97 static const unsigned maxUpdateWidgetsIterations = 2;
98 static const double resourcePriorityUpdateDelayAfterScroll = 0.250;
99 
FrameView(LocalFrame * frame)100 FrameView::FrameView(LocalFrame* frame)
101     : m_frame(frame)
102     , m_canHaveScrollbars(true)
103     , m_slowRepaintObjectCount(0)
104     , m_hasPendingLayout(false)
105     , m_layoutSubtreeRoot(0)
106     , m_inSynchronousPostLayout(false)
107     , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
108     , m_updateWidgetsTimer(this, &FrameView::updateWidgetsTimerFired)
109     , m_isTransparent(false)
110     , m_baseBackgroundColor(Color::white)
111     , m_mediaType(MediaTypeNames::screen)
112     , m_overflowStatusDirty(true)
113     , m_viewportRenderer(0)
114     , m_wasScrolledByUser(false)
115     , m_inProgrammaticScroll(false)
116     , m_safeToPropagateScrollToParent(true)
117     , m_isTrackingPaintInvalidations(false)
118     , m_scrollCorner(nullptr)
119     , m_visibleContentScaleFactor(1)
120     , m_inputEventsScaleFactorForEmulation(1)
121     , m_layoutSizeFixedToFrameSize(true)
122     , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
123     , m_needsUpdateWidgetPositions(false)
124     , m_topControlsViewportAdjustment(0)
125 {
126     ASSERT(m_frame);
127     init();
128 
129     if (!m_frame->isMainFrame())
130         return;
131 
132     ScrollableArea::setVerticalScrollElasticity(ScrollElasticityAllowed);
133     ScrollableArea::setHorizontalScrollElasticity(ScrollElasticityAllowed);
134 }
135 
create(LocalFrame * frame)136 PassRefPtr<FrameView> FrameView::create(LocalFrame* frame)
137 {
138     RefPtr<FrameView> view = adoptRef(new FrameView(frame));
139     view->show();
140     return view.release();
141 }
142 
create(LocalFrame * frame,const IntSize & initialSize)143 PassRefPtr<FrameView> FrameView::create(LocalFrame* frame, const IntSize& initialSize)
144 {
145     RefPtr<FrameView> view = adoptRef(new FrameView(frame));
146     view->Widget::setFrameRect(IntRect(view->location(), initialSize));
147     view->setLayoutSizeInternal(initialSize);
148 
149     view->show();
150     return view.release();
151 }
152 
~FrameView()153 FrameView::~FrameView()
154 {
155     if (m_postLayoutTasksTimer.isActive())
156         m_postLayoutTasksTimer.stop();
157 
158     if (m_didScrollTimer.isActive())
159         m_didScrollTimer.stop();
160 
161     removeFromAXObjectCache();
162 
163     // Custom scrollbars should already be destroyed at this point
164     ASSERT(!horizontalScrollbar() || !horizontalScrollbar()->isCustomScrollbar());
165     ASSERT(!verticalScrollbar() || !verticalScrollbar()->isCustomScrollbar());
166 
167     setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
168     setHasVerticalScrollbar(false);
169 
170     ASSERT(!m_scrollCorner);
171 
172     ASSERT(m_frame);
173     ASSERT(m_frame->view() != this || !m_frame->contentRenderer());
174     // FIXME: Do we need to do something here for OOPI?
175     HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
176     if (ownerElement && ownerElement->ownedWidget() == this)
177         ownerElement->setWidget(nullptr);
178 }
179 
reset()180 void FrameView::reset()
181 {
182     m_hasPendingLayout = false;
183     m_layoutSubtreeRoot = 0;
184     m_doFullPaintInvalidation = false;
185     m_layoutSchedulingEnabled = true;
186     m_inPerformLayout = false;
187     m_canInvalidatePaintDuringPerformLayout = false;
188     m_inSynchronousPostLayout = false;
189     m_layoutCount = 0;
190     m_nestedLayoutCount = 0;
191     m_postLayoutTasksTimer.stop();
192     m_updateWidgetsTimer.stop();
193     m_firstLayout = true;
194     m_firstLayoutCallbackPending = false;
195     m_wasScrolledByUser = false;
196     m_safeToPropagateScrollToParent = true;
197     m_lastViewportSize = IntSize();
198     m_lastZoomFactor = 1.0f;
199     m_isTrackingPaintInvalidations = false;
200     m_trackedPaintInvalidationRects.clear();
201     m_lastPaintTime = 0;
202     m_paintBehavior = PaintBehaviorNormal;
203     m_isPainting = false;
204     m_visuallyNonEmptyCharacterCount = 0;
205     m_visuallyNonEmptyPixelCount = 0;
206     m_isVisuallyNonEmpty = false;
207     m_firstVisuallyNonEmptyLayoutCallbackPending = true;
208     m_maintainScrollPositionAnchor = nullptr;
209     m_viewportConstrainedObjects.clear();
210 }
211 
removeFromAXObjectCache()212 void FrameView::removeFromAXObjectCache()
213 {
214     if (AXObjectCache* cache = axObjectCache()) {
215         cache->remove(this);
216         cache->childrenChanged(m_frame->pagePopupOwner());
217     }
218 }
219 
init()220 void FrameView::init()
221 {
222     reset();
223 
224     m_size = LayoutSize();
225 
226     // Propagate the marginwidth/height and scrolling modes to the view.
227     // FIXME: Do we need to do this for OOPI?
228     Element* ownerElement = m_frame->deprecatedLocalOwner();
229     if (ownerElement && (isHTMLFrameElement(*ownerElement) || isHTMLIFrameElement(*ownerElement))) {
230         HTMLFrameElementBase* frameElt = toHTMLFrameElementBase(ownerElement);
231         if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
232             setCanHaveScrollbars(false);
233     }
234 }
235 
prepareForDetach()236 void FrameView::prepareForDetach()
237 {
238     RELEASE_ASSERT(!isInPerformLayout());
239 
240     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
241         scrollAnimator->cancelAnimations();
242     cancelProgrammaticScrollAnimation();
243 
244     detachCustomScrollbars();
245     // When the view is no longer associated with a frame, it needs to be removed from the ax object cache
246     // right now, otherwise it won't be able to reach the topDocument()'s axObject cache later.
247     removeFromAXObjectCache();
248 
249     if (m_frame->page()) {
250         if (ScrollingCoordinator* scrollingCoordinator = m_frame->page()->scrollingCoordinator())
251             scrollingCoordinator->willDestroyScrollableArea(this);
252     }
253 }
254 
detachCustomScrollbars()255 void FrameView::detachCustomScrollbars()
256 {
257     Scrollbar* horizontalBar = horizontalScrollbar();
258     if (horizontalBar && horizontalBar->isCustomScrollbar())
259         setHasHorizontalScrollbar(false);
260 
261     Scrollbar* verticalBar = verticalScrollbar();
262     if (verticalBar && verticalBar->isCustomScrollbar())
263         setHasVerticalScrollbar(false);
264 
265     if (m_scrollCorner) {
266         m_scrollCorner->destroy();
267         m_scrollCorner = nullptr;
268     }
269 }
270 
recalculateScrollbarOverlayStyle()271 void FrameView::recalculateScrollbarOverlayStyle()
272 {
273     ScrollbarOverlayStyle oldOverlayStyle = scrollbarOverlayStyle();
274     ScrollbarOverlayStyle overlayStyle = ScrollbarOverlayStyleDefault;
275 
276     Color backgroundColor = documentBackgroundColor();
277     // Reduce the background color from RGB to a lightness value
278     // and determine which scrollbar style to use based on a lightness
279     // heuristic.
280     double hue, saturation, lightness;
281     backgroundColor.getHSL(hue, saturation, lightness);
282     if (lightness <= .5)
283         overlayStyle = ScrollbarOverlayStyleLight;
284 
285     if (oldOverlayStyle != overlayStyle)
286         setScrollbarOverlayStyle(overlayStyle);
287 }
288 
clear()289 void FrameView::clear()
290 {
291     reset();
292     setScrollbarsSuppressed(true);
293 }
294 
didFirstLayout() const295 bool FrameView::didFirstLayout() const
296 {
297     return !m_firstLayout;
298 }
299 
invalidateRect(const IntRect & rect)300 void FrameView::invalidateRect(const IntRect& rect)
301 {
302     // For querying RenderLayer::compositingState() when invalidating scrollbars.
303     // FIXME: do all scrollbar invalidations after layout of all frames is complete. It's currently not recursively true.
304     DisableCompositingQueryAsserts disabler;
305     if (!parent()) {
306         if (HostWindow* window = hostWindow())
307             window->invalidateContentsAndRootView(rect);
308         return;
309     }
310 
311     RenderPart* renderer = m_frame->ownerRenderer();
312     if (!renderer)
313         return;
314 
315     IntRect paintInvalidationRect = rect;
316     paintInvalidationRect.move(renderer->borderLeft() + renderer->paddingLeft(),
317                      renderer->borderTop() + renderer->paddingTop());
318     renderer->invalidatePaintRectangle(paintInvalidationRect);
319 }
320 
setFrameRect(const IntRect & newRect)321 void FrameView::setFrameRect(const IntRect& newRect)
322 {
323     IntRect oldRect = frameRect();
324     if (newRect == oldRect)
325         return;
326 
327     // Autosized font sizes depend on the width of the viewing area.
328     bool autosizerNeedsUpdating = false;
329     if (newRect.width() != oldRect.width() && m_frame->isMainFrame() && m_frame->settings()->textAutosizingEnabled())
330         autosizerNeedsUpdating = true;
331 
332     ScrollView::setFrameRect(newRect);
333 
334     updateScrollableAreaSet();
335 
336     if (autosizerNeedsUpdating) {
337         // This needs to be after the call to ScrollView::setFrameRect, because it reads the new width.
338         if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer())
339             textAutosizer->updatePageInfoInAllFrames();
340     }
341 
342     if (RenderView* renderView = this->renderView()) {
343         if (renderView->usesCompositing())
344             renderView->compositor()->frameViewDidChangeSize();
345     }
346 
347     viewportConstrainedVisibleContentSizeChanged(newRect.width() != oldRect.width(), newRect.height() != oldRect.height());
348 
349     if (oldRect.size() != newRect.size()
350         && m_frame->isMainFrame()
351         && m_frame->settings()->pinchVirtualViewportEnabled())
352         page()->frameHost().pinchViewport().mainFrameDidChangeSize();
353 }
354 
page() const355 Page* FrameView::page() const
356 {
357     return frame().page();
358 }
359 
renderView() const360 RenderView* FrameView::renderView() const
361 {
362     return frame().contentRenderer();
363 }
364 
setCanHaveScrollbars(bool canHaveScrollbars)365 void FrameView::setCanHaveScrollbars(bool canHaveScrollbars)
366 {
367     m_canHaveScrollbars = canHaveScrollbars;
368     ScrollView::setCanHaveScrollbars(canHaveScrollbars);
369 }
370 
shouldUseCustomScrollbars(Element * & customScrollbarElement,LocalFrame * & customScrollbarFrame)371 bool FrameView::shouldUseCustomScrollbars(Element*& customScrollbarElement, LocalFrame*& customScrollbarFrame)
372 {
373     customScrollbarElement = 0;
374     customScrollbarFrame = 0;
375 
376     if (Settings* settings = m_frame->settings()) {
377         if (!settings->allowCustomScrollbarInMainFrame() && m_frame->isMainFrame())
378             return false;
379     }
380 
381     // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
382     Document* doc = m_frame->document();
383 
384     // Try the <body> element first as a scrollbar source.
385     Element* body = doc ? doc->body() : 0;
386     if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
387         customScrollbarElement = body;
388         return true;
389     }
390 
391     // If the <body> didn't have a custom style, then the root element might.
392     Element* docElement = doc ? doc->documentElement() : 0;
393     if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR)) {
394         customScrollbarElement = docElement;
395         return true;
396     }
397 
398     // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
399     RenderPart* frameRenderer = m_frame->ownerRenderer();
400     if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR)) {
401         customScrollbarFrame = m_frame.get();
402         return true;
403     }
404 
405     return false;
406 }
407 
createScrollbar(ScrollbarOrientation orientation)408 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
409 {
410     Element* customScrollbarElement = 0;
411     LocalFrame* customScrollbarFrame = 0;
412     if (shouldUseCustomScrollbars(customScrollbarElement, customScrollbarFrame))
413         return RenderScrollbar::createCustomScrollbar(this, orientation, customScrollbarElement, customScrollbarFrame);
414 
415     // Nobody set a custom style, so we just use a native scrollbar.
416     return ScrollView::createScrollbar(orientation);
417 }
418 
setContentsSize(const IntSize & size)419 void FrameView::setContentsSize(const IntSize& size)
420 {
421     if (size == contentsSize())
422         return;
423 
424     ScrollView::setContentsSize(size);
425     ScrollView::contentsResized();
426 
427     Page* page = frame().page();
428     if (!page)
429         return;
430 
431     updateScrollableAreaSet();
432 
433     page->chrome().contentsSizeChanged(m_frame.get(), size);
434 }
435 
clampOffsetAtScale(const IntPoint & offset,float scale) const436 IntPoint FrameView::clampOffsetAtScale(const IntPoint& offset, float scale) const
437 {
438     IntPoint maxScrollExtent(contentsSize().width() - scrollOrigin().x(), contentsSize().height() - scrollOrigin().y());
439     FloatSize scaledSize = unscaledVisibleContentSize();
440     if (scale)
441         scaledSize.scale(1 / scale);
442 
443     IntPoint clampedOffset = offset;
444     clampedOffset = clampedOffset.shrunkTo(maxScrollExtent - expandedIntSize(scaledSize));
445     clampedOffset = clampedOffset.expandedTo(-scrollOrigin());
446 
447     return clampedOffset;
448 }
449 
adjustViewSize()450 void FrameView::adjustViewSize()
451 {
452     RenderView* renderView = this->renderView();
453     if (!renderView)
454         return;
455 
456     ASSERT(m_frame->view() == this);
457 
458     const IntRect rect = renderView->documentRect();
459     const IntSize& size = rect.size();
460     ScrollView::setScrollOrigin(IntPoint(-rect.x(), -rect.y()), !m_frame->document()->printing(), size == contentsSize());
461 
462     setContentsSize(size);
463 }
464 
applyOverflowToViewportAndSetRenderer(RenderObject * o,ScrollbarMode & hMode,ScrollbarMode & vMode)465 void FrameView::applyOverflowToViewportAndSetRenderer(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
466 {
467     // Handle the overflow:hidden/scroll case for the body/html elements.  WinIE treats
468     // overflow:hidden and overflow:scroll on <body> as applying to the document's
469     // scrollbars.  The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
470     // use the root element.
471 
472     EOverflow overflowX = o->style()->overflowX();
473     EOverflow overflowY = o->style()->overflowY();
474 
475     if (o->isSVGRoot()) {
476         // Don't allow overflow to affect <img> and css backgrounds
477         if (toRenderSVGRoot(o)->isEmbeddedThroughSVGImage())
478             return;
479 
480         // FIXME: evaluate if we can allow overflow for these cases too.
481         // Overflow is always hidden when stand-alone SVG documents are embedded.
482         if (toRenderSVGRoot(o)->isEmbeddedThroughFrameContainingSVGDocument()) {
483             overflowX = OHIDDEN;
484             overflowY = OHIDDEN;
485         }
486     }
487 
488     bool ignoreOverflowHidden = false;
489     if (m_frame->settings()->ignoreMainFrameOverflowHiddenQuirk() && m_frame->isMainFrame())
490         ignoreOverflowHidden = true;
491 
492     switch (overflowX) {
493         case OHIDDEN:
494             if (!ignoreOverflowHidden)
495                 hMode = ScrollbarAlwaysOff;
496             break;
497         case OSCROLL:
498             hMode = ScrollbarAlwaysOn;
499             break;
500         case OAUTO:
501             hMode = ScrollbarAuto;
502             break;
503         default:
504             // Don't set it at all.
505             ;
506     }
507 
508      switch (overflowY) {
509         case OHIDDEN:
510             if (!ignoreOverflowHidden)
511                 vMode = ScrollbarAlwaysOff;
512             break;
513         case OSCROLL:
514             vMode = ScrollbarAlwaysOn;
515             break;
516         case OAUTO:
517             vMode = ScrollbarAuto;
518             break;
519         default:
520             // Don't set it at all.
521             ;
522     }
523 
524     m_viewportRenderer = o;
525 }
526 
calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode & hMode,ScrollbarMode & vMode,ScrollbarModesCalculationStrategy strategy)527 void FrameView::calculateScrollbarModesForLayoutAndSetViewportRenderer(ScrollbarMode& hMode, ScrollbarMode& vMode, ScrollbarModesCalculationStrategy strategy)
528 {
529     m_viewportRenderer = 0;
530 
531     // FIXME: How do we handle this for OOPI?
532     const HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
533     if (owner && (owner->scrollingMode() == ScrollbarAlwaysOff)) {
534         hMode = ScrollbarAlwaysOff;
535         vMode = ScrollbarAlwaysOff;
536         return;
537     }
538 
539     if (m_canHaveScrollbars || strategy == RulesFromWebContentOnly) {
540         hMode = ScrollbarAuto;
541         vMode = ScrollbarAuto;
542     } else {
543         hMode = ScrollbarAlwaysOff;
544         vMode = ScrollbarAlwaysOff;
545     }
546 
547     if (!isSubtreeLayout()) {
548         Document* document = m_frame->document();
549         Node* body = document->body();
550         if (isHTMLFrameSetElement(body) && body->renderer()) {
551             vMode = ScrollbarAlwaysOff;
552             hMode = ScrollbarAlwaysOff;
553         } else if (Element* viewportElement = document->viewportDefiningElement()) {
554             if (RenderObject* viewportRenderer = viewportElement->renderer()) {
555                 if (viewportRenderer->style())
556                     applyOverflowToViewportAndSetRenderer(viewportRenderer, hMode, vMode);
557             }
558         }
559     }
560 }
561 
updateAcceleratedCompositingSettings()562 void FrameView::updateAcceleratedCompositingSettings()
563 {
564     if (RenderView* renderView = this->renderView())
565         renderView->compositor()->updateAcceleratedCompositingSettings();
566 }
567 
recalcOverflowAfterStyleChange()568 void FrameView::recalcOverflowAfterStyleChange()
569 {
570     RenderView* renderView = this->renderView();
571     RELEASE_ASSERT(renderView);
572     if (!renderView->needsOverflowRecalcAfterStyleChange())
573         return;
574 
575     renderView->recalcOverflowAfterStyleChange();
576 
577     IntRect documentRect = renderView->documentRect();
578     if (scrollOrigin() == -documentRect.location() && contentsSize() == documentRect.size())
579         return;
580 
581     if (needsLayout())
582         return;
583 
584     InUpdateScrollbarsScope inUpdateScrollbarsScope(this);
585 
586     bool shouldHaveHorizontalScrollbar = false;
587     bool shouldHaveVerticalScrollbar = false;
588     computeScrollbarExistence(shouldHaveHorizontalScrollbar, shouldHaveVerticalScrollbar, documentRect.size());
589 
590     bool hasHorizontalScrollbar = horizontalScrollbar();
591     bool hasVerticalScrollbar = verticalScrollbar();
592     if (hasHorizontalScrollbar != shouldHaveHorizontalScrollbar
593         || hasVerticalScrollbar != shouldHaveVerticalScrollbar) {
594         setNeedsLayout();
595         return;
596     }
597 
598     adjustViewSize();
599     updateScrollbarGeometry();
600 }
601 
usesCompositedScrolling() const602 bool FrameView::usesCompositedScrolling() const
603 {
604     RenderView* renderView = this->renderView();
605     if (!renderView)
606         return false;
607     if (m_frame->settings() && m_frame->settings()->preferCompositingToLCDTextEnabled())
608         return renderView->compositor()->inCompositingMode();
609     return false;
610 }
611 
layerForScrolling() const612 GraphicsLayer* FrameView::layerForScrolling() const
613 {
614     RenderView* renderView = this->renderView();
615     if (!renderView)
616         return 0;
617     return renderView->compositor()->scrollLayer();
618 }
619 
layerForHorizontalScrollbar() const620 GraphicsLayer* FrameView::layerForHorizontalScrollbar() const
621 {
622     RenderView* renderView = this->renderView();
623     if (!renderView)
624         return 0;
625     return renderView->compositor()->layerForHorizontalScrollbar();
626 }
627 
layerForVerticalScrollbar() const628 GraphicsLayer* FrameView::layerForVerticalScrollbar() const
629 {
630     RenderView* renderView = this->renderView();
631     if (!renderView)
632         return 0;
633     return renderView->compositor()->layerForVerticalScrollbar();
634 }
635 
layerForScrollCorner() const636 GraphicsLayer* FrameView::layerForScrollCorner() const
637 {
638     RenderView* renderView = this->renderView();
639     if (!renderView)
640         return 0;
641     return renderView->compositor()->layerForScrollCorner();
642 }
643 
isEnclosedInCompositingLayer() const644 bool FrameView::isEnclosedInCompositingLayer() const
645 {
646     // FIXME: It's a bug that compositing state isn't always up to date when this is called. crbug.com/366314
647     DisableCompositingQueryAsserts disabler;
648 
649     RenderObject* frameOwnerRenderer = m_frame->ownerRenderer();
650     return frameOwnerRenderer && frameOwnerRenderer->enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries();
651 }
652 
layoutRoot(bool onlyDuringLayout) const653 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
654 {
655     return onlyDuringLayout && layoutPending() ? 0 : m_layoutSubtreeRoot;
656 }
657 
forceLayoutParentViewIfNeeded()658 inline void FrameView::forceLayoutParentViewIfNeeded()
659 {
660     RenderPart* ownerRenderer = m_frame->ownerRenderer();
661     if (!ownerRenderer || !ownerRenderer->frame())
662         return;
663 
664     RenderBox* contentBox = embeddedContentBox();
665     if (!contentBox)
666         return;
667 
668     RenderSVGRoot* svgRoot = toRenderSVGRoot(contentBox);
669     if (svgRoot->everHadLayout() && !svgRoot->needsLayout())
670         return;
671 
672     // If the embedded SVG document appears the first time, the ownerRenderer has already finished
673     // layout without knowing about the existence of the embedded SVG document, because RenderReplaced
674     // embeddedContentBox() returns 0, as long as the embedded document isn't loaded yet. Before
675     // bothering to lay out the SVG document, mark the ownerRenderer needing layout and ask its
676     // FrameView for a layout. After that the RenderEmbeddedObject (ownerRenderer) carries the
677     // correct size, which RenderSVGRoot::computeReplacedLogicalWidth/Height rely on, when laying
678     // out for the first time, or when the RenderSVGRoot size has changed dynamically (eg. via <script>).
679     RefPtr<FrameView> frameView = ownerRenderer->frame()->view();
680 
681     // Mark the owner renderer as needing layout.
682     ownerRenderer->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
683 
684     // Synchronously enter layout, to layout the view containing the host object/embed/iframe.
685     ASSERT(frameView);
686     frameView->layout();
687 }
688 
performPreLayoutTasks()689 void FrameView::performPreLayoutTasks()
690 {
691     TRACE_EVENT0("blink", "FrameView::performPreLayoutTasks");
692     lifecycle().advanceTo(DocumentLifecycle::InPreLayout);
693 
694     // Don't schedule more layouts, we're in one.
695     TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
696 
697     if (!m_nestedLayoutCount && !m_inSynchronousPostLayout && m_postLayoutTasksTimer.isActive()) {
698         // This is a new top-level layout. If there are any remaining tasks from the previous layout, finish them now.
699         m_inSynchronousPostLayout = true;
700         performPostLayoutTasks();
701         m_inSynchronousPostLayout = false;
702     }
703 
704     Document* document = m_frame->document();
705     if (wasViewportResized())
706         document->notifyResizeForViewportUnits();
707 
708     // Viewport-dependent media queries may cause us to need completely different style information.
709     if (!document->styleResolver() || document->styleResolver()->mediaQueryAffectedByViewportChange()) {
710         document->styleResolverChanged();
711         document->mediaQueryAffectingValueChanged();
712 
713         // FIXME: This instrumentation event is not strictly accurate since cached media query results
714         //        do not persist across StyleResolver rebuilds.
715         InspectorInstrumentation::mediaQueryResultChanged(document);
716     } else {
717         document->evaluateMediaQueryList();
718     }
719 
720     document->updateRenderTreeIfNeeded();
721     lifecycle().advanceTo(DocumentLifecycle::StyleClean);
722 }
723 
performLayout(RenderObject * rootForThisLayout,bool inSubtreeLayout)724 void FrameView::performLayout(RenderObject* rootForThisLayout, bool inSubtreeLayout)
725 {
726     TRACE_EVENT0("blink", "FrameView::performLayout");
727 
728     ScriptForbiddenScope forbidScript;
729 
730     ASSERT(!isInPerformLayout());
731     lifecycle().advanceTo(DocumentLifecycle::InPerformLayout);
732 
733     TemporaryChange<bool> changeInPerformLayout(m_inPerformLayout, true);
734 
735     // performLayout is the actual guts of layout().
736     // FIXME: The 300 other lines in layout() probably belong in other helper functions
737     // so that a single human could understand what layout() is actually doing.
738 
739     LayoutState layoutState(*rootForThisLayout);
740 
741     forceLayoutParentViewIfNeeded();
742 
743     // FIXME (crbug.com/256657): Do not do two layouts for text autosizing.
744     rootForThisLayout->layout();
745     gatherDebugLayoutRects(rootForThisLayout);
746 
747     ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
748 
749     lifecycle().advanceTo(DocumentLifecycle::AfterPerformLayout);
750 }
751 
scheduleOrPerformPostLayoutTasks()752 void FrameView::scheduleOrPerformPostLayoutTasks()
753 {
754     if (m_postLayoutTasksTimer.isActive())
755         return;
756 
757     if (!m_inSynchronousPostLayout) {
758         m_inSynchronousPostLayout = true;
759         // Calls resumeScheduledEvents()
760         performPostLayoutTasks();
761         m_inSynchronousPostLayout = false;
762     }
763 
764     if (!m_postLayoutTasksTimer.isActive() && (needsLayout() || m_inSynchronousPostLayout)) {
765         // If we need layout or are already in a synchronous call to postLayoutTasks(),
766         // defer widget updates and event dispatch until after we return. postLayoutTasks()
767         // can make us need to update again, and we can get stuck in a nasty cycle unless
768         // we call it through the timer here.
769         m_postLayoutTasksTimer.startOneShot(0, FROM_HERE);
770         if (needsLayout())
771             layout();
772     }
773 }
774 
layout(bool allowSubtree)775 void FrameView::layout(bool allowSubtree)
776 {
777     // We should never layout a Document which is not in a LocalFrame.
778     ASSERT(m_frame);
779     ASSERT(m_frame->view() == this);
780     ASSERT(m_frame->page());
781 
782     ScriptForbiddenScope forbidScript;
783 
784     if (isInPerformLayout() || !m_frame->document()->isActive())
785         return;
786 
787     TRACE_EVENT0("blink", "FrameView::layout");
788     TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "Layout");
789 
790     // Protect the view from being deleted during layout (in recalcStyle)
791     RefPtr<FrameView> protector(this);
792 
793     // Every scroll that happens during layout is programmatic.
794     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
795 
796     if (m_autoSizeInfo)
797         m_autoSizeInfo->autoSizeIfNeeded();
798 
799     m_hasPendingLayout = false;
800     DocumentLifecycle::Scope lifecycleScope(lifecycle(), DocumentLifecycle::LayoutClean);
801 
802     RELEASE_ASSERT(!isPainting());
803 
804     TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "beginData", InspectorLayoutEvent::beginData(this));
805     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
806     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
807     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willLayout(m_frame.get());
808 
809     if (!allowSubtree && isSubtreeLayout()) {
810         m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
811         m_layoutSubtreeRoot = 0;
812     }
813 
814     performPreLayoutTasks();
815 
816     // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
817     // so there's no point to continuing to layout
818     if (protector->hasOneRef())
819         return;
820 
821     Document* document = m_frame->document();
822     bool inSubtreeLayout = isSubtreeLayout();
823     RenderObject* rootForThisLayout = inSubtreeLayout ? m_layoutSubtreeRoot : document->renderView();
824     if (!rootForThisLayout) {
825         // FIXME: Do we need to set m_size here?
826         ASSERT_NOT_REACHED();
827         return;
828     }
829 
830     FontCachePurgePreventer fontCachePurgePreventer;
831     RenderLayer* layer;
832     {
833         TemporaryChange<bool> changeSchedulingEnabled(m_layoutSchedulingEnabled, false);
834 
835         m_nestedLayoutCount++;
836         if (!inSubtreeLayout) {
837             Document* document = m_frame->document();
838             Node* body = document->body();
839             if (body && body->renderer()) {
840                 if (isHTMLFrameSetElement(*body)) {
841                     body->renderer()->setChildNeedsLayout();
842                 } else if (isHTMLBodyElement(*body)) {
843                     if (!m_firstLayout && m_size.height() != layoutSize().height() && body->renderer()->enclosingBox()->stretchesToViewport())
844                         body->renderer()->setChildNeedsLayout();
845                 }
846             }
847         }
848         updateCounters();
849 
850         ScrollbarMode hMode;
851         ScrollbarMode vMode;
852         calculateScrollbarModesForLayoutAndSetViewportRenderer(hMode, vMode);
853 
854         if (!inSubtreeLayout) {
855             // Now set our scrollbar state for the layout.
856             ScrollbarMode currentHMode = horizontalScrollbarMode();
857             ScrollbarMode currentVMode = verticalScrollbarMode();
858 
859             if (m_firstLayout) {
860                 setScrollbarsSuppressed(true);
861 
862                 m_doFullPaintInvalidation = true;
863                 m_firstLayout = false;
864                 m_firstLayoutCallbackPending = true;
865                 m_lastViewportSize = layoutSize(IncludeScrollbars);
866                 m_lastZoomFactor = rootForThisLayout->style()->zoom();
867 
868                 // Set the initial vMode to AlwaysOn if we're auto.
869                 if (vMode == ScrollbarAuto)
870                     setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
871                 // Set the initial hMode to AlwaysOff if we're auto.
872                 if (hMode == ScrollbarAuto)
873                     setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
874 
875                 setScrollbarModes(hMode, vMode);
876                 setScrollbarsSuppressed(false, true);
877             } else if (hMode != currentHMode || vMode != currentVMode) {
878                 setScrollbarModes(hMode, vMode);
879             }
880 
881             LayoutSize oldSize = m_size;
882 
883             m_size = LayoutSize(layoutSize().width(), layoutSize().height());
884 
885             if (oldSize != m_size && !m_firstLayout) {
886                 RenderBox* rootRenderer = document->documentElement() ? document->documentElement()->renderBox() : 0;
887                 RenderBox* bodyRenderer = rootRenderer && document->body() ? document->body()->renderBox() : 0;
888                 if (bodyRenderer && bodyRenderer->stretchesToViewport())
889                     bodyRenderer->setChildNeedsLayout();
890                 else if (rootRenderer && rootRenderer->stretchesToViewport())
891                     rootRenderer->setChildNeedsLayout();
892             }
893 
894             // We need to set m_doFullPaintInvalidation before triggering layout as RenderObject::checkForPaintInvalidation
895             // checks the boolean to disable local paint invalidations.
896             m_doFullPaintInvalidation |= renderView()->shouldDoFullPaintInvalidationForNextLayout();
897         }
898 
899         layer = rootForThisLayout->enclosingLayer();
900 
901         performLayout(rootForThisLayout, inSubtreeLayout);
902 
903         m_layoutSubtreeRoot = 0;
904         // We need to ensure that we mark up all renderers up to the RenderView
905         // for paint invalidation. This simplifies our code as we just always
906         // do a full tree walk.
907         if (RenderObject* container = rootForThisLayout->container())
908             container->setMayNeedPaintInvalidation(true);
909     } // Reset m_layoutSchedulingEnabled to its previous value.
910 
911     if (!inSubtreeLayout && !toRenderView(rootForThisLayout)->document().printing())
912         adjustViewSize();
913 
914     layer->updateLayerPositionsAfterLayout();
915 
916     renderView()->compositor()->didLayout();
917 
918     m_layoutCount++;
919 
920     if (AXObjectCache* cache = rootForThisLayout->document().axObjectCache()) {
921         const KURL& url = rootForThisLayout->document().url();
922         if (url.isValid() && !url.isAboutBlankURL())
923             cache->handleLayoutComplete(rootForThisLayout);
924     }
925     updateAnnotatedRegions();
926 
927     ASSERT(!rootForThisLayout->needsLayout());
928 
929     if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
930         updateOverflowStatus(layoutSize().width() < contentsWidth(), layoutSize().height() < contentsHeight());
931 
932     scheduleOrPerformPostLayoutTasks();
933 
934     TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Layout", "endData", InspectorLayoutEvent::endData(rootForThisLayout));
935     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
936     InspectorInstrumentation::didLayout(cookie, rootForThisLayout);
937 
938     m_nestedLayoutCount--;
939     if (m_nestedLayoutCount)
940         return;
941 
942 #if ENABLE(ASSERT)
943     // Post-layout assert that nobody was re-marked as needing layout during layout.
944     document->renderView()->assertSubtreeIsLaidOut();
945 #endif
946 
947     // FIXME: It should be not possible to remove the FrameView from the frame/page during layout
948     // however m_inPerformLayout is not set for most of this function, so none of our RELEASE_ASSERTS
949     // in LocalFrame/Page will fire. One of the post-layout tasks is disconnecting the LocalFrame from
950     // the page in fast/frames/crash-remove-iframe-during-object-beforeload-2.html
951     // necessitating this check here.
952     // ASSERT(frame()->page());
953     if (frame().page())
954         frame().page()->chrome().client().layoutUpdated(m_frame.get());
955 }
956 
957 // The plan is to move to compositor-queried paint invalidation, in which case this
958 // method would setNeedsRedraw on the GraphicsLayers with invalidations and
959 // let the compositor pick which to actually draw.
960 // See http://crbug.com/306706
invalidateTreeIfNeeded()961 void FrameView::invalidateTreeIfNeeded()
962 {
963     ASSERT(renderView());
964     RenderView& rootForPaintInvalidation = *renderView();
965     ASSERT(!rootForPaintInvalidation.needsLayout());
966 
967     TRACE_EVENT1("blink", "FrameView::invalidateTree", "root", rootForPaintInvalidation.debugName().ascii());
968 
969     PaintInvalidationState rootPaintInvalidationState(rootForPaintInvalidation);
970 
971     if (m_doFullPaintInvalidation)
972         renderView()->compositor()->fullyInvalidatePaint();
973 
974     rootForPaintInvalidation.invalidateTreeIfNeeded(rootPaintInvalidationState);
975 
976     // Invalidate the paint of the frameviews scrollbars if needed
977     if (hasVerticalBarDamage())
978         invalidateRect(verticalBarDamage());
979     if (hasHorizontalBarDamage())
980         invalidateRect(horizontalBarDamage());
981     resetScrollbarDamage();
982 
983 
984 #ifndef NDEBUG
985     renderView()->assertSubtreeClearedPaintInvalidationState();
986 #endif
987 
988     if (m_frame->selection().isCaretBoundsDirty())
989         m_frame->selection().invalidateCaretRect();
990 }
991 
lifecycle() const992 DocumentLifecycle& FrameView::lifecycle() const
993 {
994     return m_frame->document()->lifecycle();
995 }
996 
gatherDebugLayoutRects(RenderObject * layoutRoot)997 void FrameView::gatherDebugLayoutRects(RenderObject* layoutRoot)
998 {
999     bool isTracing;
1000     TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("blink.debug.layout"), &isTracing);
1001     if (!isTracing)
1002         return;
1003     if (!layoutRoot->enclosingLayer()->hasCompositedLayerMapping())
1004         return;
1005     // For access to compositedLayerMapping().
1006     DisableCompositingQueryAsserts disabler;
1007     GraphicsLayer* graphicsLayer = layoutRoot->enclosingLayer()->compositedLayerMapping()->mainGraphicsLayer();
1008     if (!graphicsLayer)
1009         return;
1010 
1011     GraphicsLayerDebugInfo& debugInfo = graphicsLayer->debugInfo();
1012 
1013     debugInfo.currentLayoutRects().clear();
1014     for (RenderObject* renderer = layoutRoot; renderer; renderer = renderer->nextInPreOrder()) {
1015         if (renderer->layoutDidGetCalled()) {
1016             FloatQuad quad = renderer->localToAbsoluteQuad(FloatQuad(renderer->previousPaintInvalidationRect()));
1017             LayoutRect rect = quad.enclosingBoundingBox();
1018             debugInfo.currentLayoutRects().append(rect);
1019             renderer->setLayoutDidGetCalled(false);
1020         }
1021     }
1022 }
1023 
embeddedContentBox() const1024 RenderBox* FrameView::embeddedContentBox() const
1025 {
1026     RenderView* renderView = this->renderView();
1027     if (!renderView)
1028         return 0;
1029 
1030     RenderObject* firstChild = renderView->firstChild();
1031     if (!firstChild || !firstChild->isBox())
1032         return 0;
1033 
1034     // Curently only embedded SVG documents participate in the size-negotiation logic.
1035     if (firstChild->isSVGRoot())
1036         return toRenderBox(firstChild);
1037 
1038     return 0;
1039 }
1040 
1041 
addWidget(RenderWidget * object)1042 void FrameView::addWidget(RenderWidget* object)
1043 {
1044     m_widgets.add(object);
1045 }
1046 
removeWidget(RenderWidget * object)1047 void FrameView::removeWidget(RenderWidget* object)
1048 {
1049     m_widgets.remove(object);
1050 }
1051 
updateWidgetPositions()1052 void FrameView::updateWidgetPositions()
1053 {
1054     WillBeHeapVector<RefPtrWillBeMember<RenderWidget> > widgets;
1055     copyToVector(m_widgets, widgets);
1056 
1057     // Script or plugins could detach the frame so abort processing if that happens.
1058 
1059     for (size_t i = 0; i < widgets.size() && renderView(); ++i)
1060         widgets[i]->updateWidgetPosition();
1061 
1062     for (size_t i = 0; i < widgets.size() && renderView(); ++i)
1063         widgets[i]->widgetPositionsUpdated();
1064 }
1065 
addWidgetToUpdate(RenderEmbeddedObject & object)1066 void FrameView::addWidgetToUpdate(RenderEmbeddedObject& object)
1067 {
1068     ASSERT(isInPerformLayout());
1069     // Tell the DOM element that it needs a widget update.
1070     Node* node = object.node();
1071     ASSERT(node);
1072     if (isHTMLObjectElement(*node) || isHTMLEmbedElement(*node))
1073         toHTMLPlugInElement(node)->setNeedsWidgetUpdate(true);
1074 
1075     m_widgetUpdateSet.add(&object);
1076 }
1077 
setMediaType(const AtomicString & mediaType)1078 void FrameView::setMediaType(const AtomicString& mediaType)
1079 {
1080     ASSERT(m_frame->document());
1081     m_frame->document()->mediaQueryAffectingValueChanged();
1082     m_mediaType = mediaType;
1083 }
1084 
mediaType() const1085 AtomicString FrameView::mediaType() const
1086 {
1087     // See if we have an override type.
1088     String overrideType;
1089     InspectorInstrumentation::applyEmulatedMedia(m_frame.get(), &overrideType);
1090     if (!overrideType.isNull())
1091         return AtomicString(overrideType);
1092     return m_mediaType;
1093 }
1094 
adjustMediaTypeForPrinting(bool printing)1095 void FrameView::adjustMediaTypeForPrinting(bool printing)
1096 {
1097     if (printing) {
1098         if (m_mediaTypeWhenNotPrinting.isNull())
1099             m_mediaTypeWhenNotPrinting = mediaType();
1100             setMediaType(MediaTypeNames::print);
1101     } else {
1102         if (!m_mediaTypeWhenNotPrinting.isNull())
1103             setMediaType(m_mediaTypeWhenNotPrinting);
1104         m_mediaTypeWhenNotPrinting = nullAtom;
1105     }
1106 }
1107 
contentsInCompositedLayer() const1108 bool FrameView::contentsInCompositedLayer() const
1109 {
1110     RenderView* renderView = this->renderView();
1111     if (renderView && renderView->compositingState() == PaintsIntoOwnBacking) {
1112         GraphicsLayer* layer = renderView->layer()->compositedLayerMapping()->mainGraphicsLayer();
1113         if (layer && layer->drawsContent())
1114             return true;
1115     }
1116 
1117     return false;
1118 }
1119 
addSlowRepaintObject()1120 void FrameView::addSlowRepaintObject()
1121 {
1122     if (!m_slowRepaintObjectCount++) {
1123         if (Page* page = m_frame->page()) {
1124             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1125                 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1126         }
1127     }
1128 }
1129 
removeSlowRepaintObject()1130 void FrameView::removeSlowRepaintObject()
1131 {
1132     ASSERT(m_slowRepaintObjectCount > 0);
1133     m_slowRepaintObjectCount--;
1134     if (!m_slowRepaintObjectCount) {
1135         if (Page* page = m_frame->page()) {
1136             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1137                 scrollingCoordinator->frameViewHasSlowRepaintObjectsDidChange(this);
1138         }
1139     }
1140 }
1141 
addViewportConstrainedObject(RenderObject * object)1142 void FrameView::addViewportConstrainedObject(RenderObject* object)
1143 {
1144     if (!m_viewportConstrainedObjects)
1145         m_viewportConstrainedObjects = adoptPtr(new ViewportConstrainedObjectSet);
1146 
1147     if (!m_viewportConstrainedObjects->contains(object)) {
1148         m_viewportConstrainedObjects->add(object);
1149 
1150         if (Page* page = m_frame->page()) {
1151             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1152                 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1153         }
1154     }
1155 }
1156 
removeViewportConstrainedObject(RenderObject * object)1157 void FrameView::removeViewportConstrainedObject(RenderObject* object)
1158 {
1159     if (m_viewportConstrainedObjects && m_viewportConstrainedObjects->contains(object)) {
1160         m_viewportConstrainedObjects->remove(object);
1161 
1162         if (Page* page = m_frame->page()) {
1163             if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
1164                 scrollingCoordinator->frameViewFixedObjectsDidChange(this);
1165         }
1166     }
1167 }
1168 
viewportConstrainedVisibleContentRect() const1169 LayoutRect FrameView::viewportConstrainedVisibleContentRect() const
1170 {
1171     LayoutRect viewportRect = visibleContentRect();
1172     // Ignore overhang. No-op when not using rubber banding.
1173     viewportRect.setLocation(clampScrollPosition(scrollPosition()));
1174     return viewportRect;
1175 }
1176 
viewportConstrainedVisibleContentSizeChanged(bool widthChanged,bool heightChanged)1177 void FrameView::viewportConstrainedVisibleContentSizeChanged(bool widthChanged, bool heightChanged)
1178 {
1179     if (!hasViewportConstrainedObjects())
1180         return;
1181 
1182     // If viewport is not enabled, frameRect change will cause layout size change and then layout.
1183     // Otherwise, viewport constrained objects need their layout flags set separately to ensure
1184     // they are positioned correctly. In the virtual-viewport pinch mode frame rect changes wont
1185     // necessarily cause a layout size change so only take this early-out if we're in old-style
1186     // pinch.
1187     if (m_frame->settings()
1188         && !m_frame->settings()->viewportEnabled()
1189         && !m_frame->settings()->pinchVirtualViewportEnabled())
1190         return;
1191 
1192     ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1193     for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1194         RenderObject* renderer = *it;
1195         RenderStyle* style = renderer->style();
1196         if (widthChanged) {
1197             if (style->width().isFixed() && (style->left().isAuto() || style->right().isAuto()))
1198                 renderer->setNeedsPositionedMovementLayout();
1199             else
1200                 renderer->setNeedsLayoutAndFullPaintInvalidation();
1201         }
1202         if (heightChanged) {
1203             if (style->height().isFixed() && (style->top().isAuto() || style->bottom().isAuto()))
1204                 renderer->setNeedsPositionedMovementLayout();
1205             else
1206                 renderer->setNeedsLayoutAndFullPaintInvalidation();
1207         }
1208     }
1209 }
1210 
scrollOffsetForFixedPosition() const1211 IntSize FrameView::scrollOffsetForFixedPosition() const
1212 {
1213     return toIntSize(clampScrollPosition(scrollPosition()));
1214 }
1215 
lastKnownMousePosition() const1216 IntPoint FrameView::lastKnownMousePosition() const
1217 {
1218     return m_frame->eventHandler().lastKnownMousePosition();
1219 }
1220 
shouldSetCursor() const1221 bool FrameView::shouldSetCursor() const
1222 {
1223     Page* page = frame().page();
1224     return page && page->visibilityState() != PageVisibilityStateHidden && page->focusController().isActive() && page->settings().deviceSupportsMouse();
1225 }
1226 
scrollContentsIfNeededRecursive()1227 void FrameView::scrollContentsIfNeededRecursive()
1228 {
1229     scrollContentsIfNeeded();
1230 
1231     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
1232         if (!child->isLocalFrame())
1233             continue;
1234         if (FrameView* view = toLocalFrame(child)->view())
1235             view->scrollContentsIfNeededRecursive();
1236     }
1237 }
1238 
scrollContentsIfNeeded()1239 void FrameView::scrollContentsIfNeeded()
1240 {
1241     bool didScroll = !pendingScrollDelta().isZero();
1242     ScrollView::scrollContentsIfNeeded();
1243     if (didScroll)
1244         updateFixedElementPaintInvalidationRectsAfterScroll();
1245 }
1246 
paintInvalidationRectIncludingNonCompositingDescendants(const RenderLayer * layer)1247 static LayoutRect paintInvalidationRectIncludingNonCompositingDescendants(const RenderLayer* layer)
1248 {
1249     LayoutRect paintInvalidationRect = layer->renderer()->previousPaintInvalidationRect();
1250 
1251     for (const RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) {
1252         // Don't include paint invalidation rects for composited child layers; they will paint themselves and have a different origin.
1253         if (child->compositingState() == PaintsIntoOwnBacking || child->compositingState() == PaintsIntoGroupedBacking)
1254             continue;
1255 
1256         paintInvalidationRect.unite(paintInvalidationRectIncludingNonCompositingDescendants(child));
1257     }
1258     return paintInvalidationRect;
1259 }
1260 
scrollContentsFastPath(const IntSize & scrollDelta)1261 bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta)
1262 {
1263     if (!contentsInCompositedLayer() || hasSlowRepaintObjects())
1264         return false;
1265 
1266     if (!m_viewportConstrainedObjects || m_viewportConstrainedObjects->isEmpty()) {
1267         InspectorInstrumentation::didScroll(page());
1268         return true;
1269     }
1270 
1271     Region regionToUpdate;
1272     ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1273     for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1274         RenderObject* renderer = *it;
1275         ASSERT(renderer->style()->hasViewportConstrainedPosition());
1276         ASSERT(renderer->hasLayer());
1277         RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1278 
1279         CompositingState state = layer->compositingState();
1280         if (state == PaintsIntoOwnBacking || state == PaintsIntoGroupedBacking)
1281             continue;
1282 
1283         if (layer->subtreeIsInvisible())
1284             continue;
1285 
1286         // If the fixed layer has a blur/drop-shadow filter applied on at least one of its parents, we cannot
1287         // scroll using the fast path, otherwise the outsets of the filter will be moved around the page.
1288         if (layer->hasAncestorWithFilterOutsets())
1289             return false;
1290 
1291         IntRect updateRect = pixelSnappedIntRect(paintInvalidationRectIncludingNonCompositingDescendants(layer));
1292 
1293         const RenderLayerModelObject* repaintContainer = layer->renderer()->containerForPaintInvalidation();
1294         if (repaintContainer && !repaintContainer->isRenderView()) {
1295             // Invalidate the old and new locations of fixed position elements that are not drawn into the RenderView.
1296             updateRect.moveBy(scrollPosition());
1297             IntRect previousRect = updateRect;
1298             previousRect.move(scrollDelta);
1299             // FIXME: Rather than uniting the rects, we should just issue both invalidations.
1300             updateRect.unite(previousRect);
1301             layer->renderer()->invalidatePaintUsingContainer(repaintContainer, updateRect, InvalidationScroll);
1302         } else {
1303             // Coalesce the paint invalidations that will be issued to the renderView.
1304             updateRect = contentsToRootView(updateRect);
1305             if (!updateRect.isEmpty())
1306                 regionToUpdate.unite(updateRect);
1307         }
1308     }
1309 
1310     InspectorInstrumentation::didScroll(page());
1311 
1312     // Invalidate the old and new locations of fixed position elements that are drawn into the RenderView.
1313     Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
1314     size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
1315     for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
1316         IntRect updateRect = subRectsToUpdate[i];
1317         IntRect scrolledRect = updateRect;
1318         scrolledRect.move(-scrollDelta);
1319         updateRect.unite(scrolledRect);
1320         // FIXME: We should be able to issue these invalidations separately and before we actually scroll.
1321         renderView()->setBackingNeedsPaintInvalidationInRect(rootViewToContents(updateRect));
1322     }
1323 
1324     return true;
1325 }
1326 
scrollContentsSlowPath(const IntRect & updateRect)1327 void FrameView::scrollContentsSlowPath(const IntRect& updateRect)
1328 {
1329     if (contentsInCompositedLayer()) {
1330         IntRect updateRect = visibleContentRect();
1331         ASSERT(renderView());
1332         renderView()->invalidatePaintRectangle(updateRect);
1333     }
1334     if (RenderPart* frameRenderer = m_frame->ownerRenderer()) {
1335         if (isEnclosedInCompositingLayer()) {
1336             LayoutRect rect(frameRenderer->borderLeft() + frameRenderer->paddingLeft(),
1337                             frameRenderer->borderTop() + frameRenderer->paddingTop(),
1338                             visibleWidth(), visibleHeight());
1339             frameRenderer->invalidatePaintRectangle(rect);
1340             return;
1341         }
1342     }
1343 
1344     ScrollView::scrollContentsSlowPath(updateRect);
1345 }
1346 
restoreScrollbar()1347 void FrameView::restoreScrollbar()
1348 {
1349     setScrollbarsSuppressed(false);
1350 }
1351 
scrollToFragment(const KURL & url)1352 bool FrameView::scrollToFragment(const KURL& url)
1353 {
1354     // If our URL has no ref, then we have no place we need to jump to.
1355     // OTOH If CSS target was set previously, we want to set it to 0, recalc
1356     // and possibly paint invalidation because :target pseudo class may have been
1357     // set (see bug 11321).
1358     if (!url.hasFragmentIdentifier() && !m_frame->document()->cssTarget())
1359         return false;
1360 
1361     String fragmentIdentifier = url.fragmentIdentifier();
1362     if (scrollToAnchor(fragmentIdentifier))
1363         return true;
1364 
1365     // Try again after decoding the ref, based on the document's encoding.
1366     if (m_frame->document()->encoding().isValid())
1367         return scrollToAnchor(decodeURLEscapeSequences(fragmentIdentifier, m_frame->document()->encoding()));
1368 
1369     return false;
1370 }
1371 
scrollToAnchor(const String & name)1372 bool FrameView::scrollToAnchor(const String& name)
1373 {
1374     ASSERT(m_frame->document());
1375 
1376     if (!m_frame->document()->isRenderingReady()) {
1377         m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1378         return false;
1379     }
1380 
1381     m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1382 
1383     Element* anchorNode = m_frame->document()->findAnchor(name);
1384 
1385     // Setting to null will clear the current target.
1386     m_frame->document()->setCSSTarget(anchorNode);
1387 
1388     if (m_frame->document()->isSVGDocument()) {
1389         if (SVGSVGElement* svg = SVGDocumentExtensions::rootElement(*m_frame->document())) {
1390             svg->setupInitialView(name, anchorNode);
1391             if (!anchorNode)
1392                 return true;
1393         }
1394     }
1395 
1396     // Implement the rule that "" and "top" both mean top of page as in other browsers.
1397     if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1398         return false;
1399 
1400     maintainScrollPositionAtAnchor(anchorNode ? static_cast<Node*>(anchorNode) : m_frame->document());
1401 
1402     // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
1403     // If anchorNode is not focusable, setFocusedElement() will still clear focus, which matches the behavior of other browsers.
1404     if (anchorNode)
1405         m_frame->document()->setFocusedElement(anchorNode);
1406 
1407     return true;
1408 }
1409 
maintainScrollPositionAtAnchor(Node * anchorNode)1410 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
1411 {
1412     m_maintainScrollPositionAnchor = anchorNode;
1413     if (!m_maintainScrollPositionAnchor)
1414         return;
1415 
1416     // We need to update the layout before scrolling, otherwise we could
1417     // really mess things up if an anchor scroll comes at a bad moment.
1418     m_frame->document()->updateRenderTreeIfNeeded();
1419     // Only do a layout if changes have occurred that make it necessary.
1420     RenderView* renderView = this->renderView();
1421     if (renderView && renderView->needsLayout())
1422         layout();
1423     else
1424         scrollToAnchor();
1425 }
1426 
scrollElementToRect(Element * element,const IntRect & rect)1427 void FrameView::scrollElementToRect(Element* element, const IntRect& rect)
1428 {
1429     // FIXME(http://crbug.com/371896) - This method shouldn't be manually doing
1430     // coordinate transformations to the PinchViewport.
1431     IntRect targetRect(rect);
1432 
1433     m_frame->document()->updateLayoutIgnorePendingStylesheets();
1434 
1435     bool pinchVirtualViewportEnabled = m_frame->settings()->pinchVirtualViewportEnabled();
1436 
1437     if (pinchVirtualViewportEnabled) {
1438         PinchViewport& pinchViewport = m_frame->page()->frameHost().pinchViewport();
1439 
1440         IntSize pinchViewportSize = expandedIntSize(pinchViewport.visibleRect().size());
1441         targetRect.moveBy(ceiledIntPoint(pinchViewport.visibleRect().location()));
1442         targetRect.setSize(pinchViewportSize.shrunkTo(targetRect.size()));
1443     }
1444 
1445     LayoutRect bounds = element->boundingBox();
1446     int centeringOffsetX = (targetRect.width() - bounds.width()) / 2;
1447     int centeringOffsetY = (targetRect.height() - bounds.height()) / 2;
1448 
1449     IntPoint targetOffset(
1450         bounds.x() - centeringOffsetX - targetRect.x(),
1451         bounds.y() - centeringOffsetY - targetRect.y());
1452 
1453     setScrollPosition(targetOffset);
1454 
1455     if (pinchVirtualViewportEnabled) {
1456         IntPoint remainder = IntPoint(targetOffset - scrollPosition());
1457         m_frame->page()->frameHost().pinchViewport().move(remainder);
1458     }
1459 }
1460 
setScrollPosition(const IntPoint & scrollPoint,ScrollBehavior scrollBehavior)1461 void FrameView::setScrollPosition(const IntPoint& scrollPoint, ScrollBehavior scrollBehavior)
1462 {
1463     cancelProgrammaticScrollAnimation();
1464     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, true);
1465     m_maintainScrollPositionAnchor = nullptr;
1466 
1467     IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1468 
1469     if (newScrollPosition == scrollPosition())
1470         return;
1471 
1472     if (scrollBehavior == ScrollBehaviorAuto) {
1473         RenderObject* renderer = m_frame->document()->documentElement() ? m_frame->document()->documentElement()->renderer() : 0;
1474         if (renderer)
1475             scrollBehavior = renderer->style()->scrollBehavior();
1476         else
1477             scrollBehavior = ScrollBehaviorInstant;
1478     }
1479     ScrollView::setScrollPosition(newScrollPosition, scrollBehavior);
1480 }
1481 
setScrollPositionNonProgrammatically(const IntPoint & scrollPoint)1482 void FrameView::setScrollPositionNonProgrammatically(const IntPoint& scrollPoint)
1483 {
1484     IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
1485 
1486     if (newScrollPosition == scrollPosition())
1487         return;
1488 
1489     TemporaryChange<bool> changeInProgrammaticScroll(m_inProgrammaticScroll, false);
1490     notifyScrollPositionChanged(newScrollPosition);
1491 }
1492 
layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const1493 IntSize FrameView::layoutSize(IncludeScrollbarsInRect scrollbarInclusion) const
1494 {
1495     return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(m_layoutSize) : m_layoutSize;
1496 }
1497 
setLayoutSize(const IntSize & size)1498 void FrameView::setLayoutSize(const IntSize& size)
1499 {
1500     ASSERT(!layoutSizeFixedToFrameSize());
1501 
1502     setLayoutSizeInternal(size);
1503 }
1504 
scrollPositionChanged()1505 void FrameView::scrollPositionChanged()
1506 {
1507     setWasScrolledByUser(true);
1508 
1509     Document* document = m_frame->document();
1510     document->enqueueScrollEventForNode(document);
1511 
1512     m_frame->eventHandler().dispatchFakeMouseMoveEventSoon();
1513 
1514     if (RenderView* renderView = document->renderView()) {
1515         if (renderView->usesCompositing())
1516             renderView->compositor()->frameViewDidScroll();
1517     }
1518 
1519     if (m_didScrollTimer.isActive())
1520         m_didScrollTimer.stop();
1521     m_didScrollTimer.startOneShot(resourcePriorityUpdateDelayAfterScroll, FROM_HERE);
1522 
1523     if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1524         cache->handleScrollPositionChanged(this);
1525 
1526     frame().loader().saveScrollState();
1527 }
1528 
didScrollTimerFired(Timer<FrameView> *)1529 void FrameView::didScrollTimerFired(Timer<FrameView>*)
1530 {
1531     if (m_frame->document() && m_frame->document()->renderView()) {
1532         ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->updateAllImageResourcePriorities();
1533     }
1534 }
1535 
updateLayersAndCompositingAfterScrollIfNeeded()1536 void FrameView::updateLayersAndCompositingAfterScrollIfNeeded()
1537 {
1538     // Nothing to do after scrolling if there are no fixed position elements.
1539     if (!hasViewportConstrainedObjects())
1540         return;
1541 
1542     RefPtr<FrameView> protect(this);
1543 
1544     // If there fixed position elements, scrolling may cause compositing layers to change.
1545     // Update widget and layer positions after scrolling, but only if we're not inside of
1546     // layout.
1547     if (!m_nestedLayoutCount) {
1548         updateWidgetPositions();
1549         if (RenderView* renderView = this->renderView())
1550             renderView->layer()->setNeedsCompositingInputsUpdate();
1551     }
1552 }
1553 
computeCompositedSelectionBounds(LocalFrame & frame,CompositedSelectionBound & start,CompositedSelectionBound & end)1554 bool FrameView::computeCompositedSelectionBounds(LocalFrame& frame, CompositedSelectionBound& start, CompositedSelectionBound& end)
1555 {
1556     const VisibleSelection &selection = frame.selection().selection();
1557     if (!selection.isCaretOrRange())
1558         return false;
1559 
1560     VisiblePosition visibleStart(selection.visibleStart());
1561     VisiblePosition visibleEnd(selection.visibleEnd());
1562 
1563     RenderedPosition renderedStart(visibleStart);
1564     RenderedPosition renderedEnd(visibleEnd);
1565 
1566     renderedStart.positionInGraphicsLayerBacking(start);
1567     if (!start.layer)
1568         return false;
1569 
1570     renderedEnd.positionInGraphicsLayerBacking(end);
1571     if (!end.layer)
1572         return false;
1573 
1574     if (selection.isCaret()) {
1575         start.type = end.type = CompositedSelectionBound::Caret;
1576         return true;
1577     }
1578 
1579     TextDirection startDir = visibleStart.deepEquivalent().primaryDirection();
1580     TextDirection endDir = visibleEnd.deepEquivalent().primaryDirection();
1581     start.type = startDir == RTL ? CompositedSelectionBound::SelectionRight : CompositedSelectionBound::SelectionLeft;
1582     end.type = endDir == RTL ? CompositedSelectionBound::SelectionLeft : CompositedSelectionBound::SelectionRight;
1583     return true;
1584 }
1585 
computePaintInvalidationRectsIncludingNonCompositingDescendants(RenderLayer * layer)1586 static void computePaintInvalidationRectsIncludingNonCompositingDescendants(RenderLayer* layer)
1587 {
1588     // FIXME: boundsRectForPaintInvalidation() has to walk up the parent chain
1589     // for every layer to compute the rects. We should make this more efficient.
1590     // FIXME: it's wrong to call this when layout is not up-to-date, which we do.
1591     layer->renderer()->setPreviousPaintInvalidationRect(layer->renderer()->boundsRectForPaintInvalidation(layer->renderer()->containerForPaintInvalidation()));
1592     // FIXME: We are only updating the paint invalidation bounds but not
1593     // the positionFromPaintInvalidationContainer. This means that we may
1594     // forcing a full invaliation of the new position. Is this really correct?
1595 
1596     for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) {
1597         if (child->compositingState() != PaintsIntoOwnBacking && child->compositingState() != PaintsIntoGroupedBacking)
1598             computePaintInvalidationRectsIncludingNonCompositingDescendants(child);
1599     }
1600 }
1601 
updateFixedElementPaintInvalidationRectsAfterScroll()1602 void FrameView::updateFixedElementPaintInvalidationRectsAfterScroll()
1603 {
1604     if (!hasViewportConstrainedObjects())
1605         return;
1606 
1607     // Update the paint invalidation rects for fixed elements after scrolling and invalidation to reflect
1608     // the new scroll position.
1609     ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
1610     for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
1611         RenderObject* renderer = *it;
1612         // m_viewportConstrainedObjects should not contain non-viewport constrained objects.
1613         ASSERT(renderer->style()->hasViewportConstrainedPosition());
1614 
1615         // Fixed items should always have layers.
1616         ASSERT(renderer->hasLayer());
1617 
1618         RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
1619 
1620         // Don't need to do this for composited fixed items.
1621         if (layer->compositingState() == PaintsIntoOwnBacking)
1622             continue;
1623 
1624         computePaintInvalidationRectsIncludingNonCompositingDescendants(layer);
1625     }
1626 }
1627 
updateCompositedSelectionBoundsIfNeeded()1628 void FrameView::updateCompositedSelectionBoundsIfNeeded()
1629 {
1630     if (!RuntimeEnabledFeatures::compositedSelectionUpdateEnabled())
1631         return;
1632 
1633     Page* page = frame().page();
1634     ASSERT(page);
1635 
1636     CompositedSelectionBound start, end;
1637     LocalFrame* frame = toLocalFrame(page->focusController().focusedOrMainFrame());
1638     if (!frame || !computeCompositedSelectionBounds(*frame, start, end)) {
1639         page->chrome().client().clearCompositedSelectionBounds();
1640         return;
1641     }
1642 
1643     page->chrome().client().updateCompositedSelectionBounds(start, end);
1644 }
1645 
isRubberBandInProgress() const1646 bool FrameView::isRubberBandInProgress() const
1647 {
1648     if (scrollbarsSuppressed())
1649         return false;
1650 
1651     // If the main thread updates the scroll position for this FrameView, we should return
1652     // ScrollAnimator::isRubberBandInProgress().
1653     if (ScrollAnimator* scrollAnimator = existingScrollAnimator())
1654         return scrollAnimator->isRubberBandInProgress();
1655 
1656     return false;
1657 }
1658 
hostWindow() const1659 HostWindow* FrameView::hostWindow() const
1660 {
1661     Page* page = frame().page();
1662     if (!page)
1663         return 0;
1664     return &page->chrome();
1665 }
1666 
contentRectangleForPaintInvalidation(const IntRect & r)1667 void FrameView::contentRectangleForPaintInvalidation(const IntRect& r)
1668 {
1669     ASSERT(paintInvalidationIsAllowed());
1670     ASSERT(!m_frame->ownerRenderer());
1671 
1672     if (m_isTrackingPaintInvalidations) {
1673         IntRect paintInvalidationRect = r;
1674         paintInvalidationRect.move(-scrollOffset());
1675         m_trackedPaintInvalidationRects.append(paintInvalidationRect);
1676         // FIXME: http://crbug.com/368518. Eventually, invalidateContentRectangleForPaint
1677         // is going away entirely once all layout tests are FCM. In the short
1678         // term, no code should be tracking non-composited FrameView paint invalidations.
1679         RELEASE_ASSERT_NOT_REACHED();
1680     }
1681 
1682     ScrollView::contentRectangleForPaintInvalidation(r);
1683 }
1684 
contentsResized()1685 void FrameView::contentsResized()
1686 {
1687     if (m_frame->isMainFrame() && m_frame->document()) {
1688         if (TextAutosizer* textAutosizer = m_frame->document()->textAutosizer())
1689             textAutosizer->updatePageInfoInAllFrames();
1690     }
1691 
1692     ScrollView::contentsResized();
1693     setNeedsLayout();
1694 }
1695 
scrollbarExistenceDidChange()1696 void FrameView::scrollbarExistenceDidChange()
1697 {
1698     // We check to make sure the view is attached to a frame() as this method can
1699     // be triggered before the view is attached by LocalFrame::createView(...) setting
1700     // various values such as setScrollBarModes(...) for example.  An ASSERT is
1701     // triggered when a view is layout before being attached to a frame().
1702     if (!frame().view())
1703         return;
1704 
1705     // Note that simply having overlay scrollbars is not sufficient to be
1706     // certain that scrollbars' presence does not impact layout. This should
1707     // also check if custom scrollbars (as reported by shouldUseCustomScrollbars)
1708     // are in use as well.
1709     // http://crbug.com/269692
1710     bool useOverlayScrollbars = ScrollbarTheme::theme()->usesOverlayScrollbars();
1711 
1712     // FIXME: this call to layout() could be called within FrameView::layout(), but before performLayout(),
1713     // causing double-layout. See also crbug.com/429242.
1714     if (!useOverlayScrollbars && needsLayout())
1715         layout();
1716 
1717     if (renderView() && renderView()->usesCompositing()) {
1718         renderView()->compositor()->frameViewScrollbarsExistenceDidChange();
1719 
1720         if (!useOverlayScrollbars)
1721             renderView()->compositor()->frameViewDidChangeSize();
1722     }
1723 }
1724 
handleLoadCompleted()1725 void FrameView::handleLoadCompleted()
1726 {
1727     // Once loading has completed, allow autoSize one last opportunity to
1728     // reduce the size of the frame.
1729     if (m_autoSizeInfo)
1730         m_autoSizeInfo->autoSizeIfNeeded();
1731 }
1732 
scheduleRelayout()1733 void FrameView::scheduleRelayout()
1734 {
1735     ASSERT(m_frame->view() == this);
1736 
1737     if (isSubtreeLayout()) {
1738         m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1739         m_layoutSubtreeRoot = 0;
1740     }
1741     if (!m_layoutSchedulingEnabled)
1742         return;
1743     if (!needsLayout())
1744         return;
1745     if (!m_frame->document()->shouldScheduleLayout())
1746         return;
1747     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get());
1748     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
1749     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1750     InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1751 
1752     if (m_hasPendingLayout)
1753         return;
1754     m_hasPendingLayout = true;
1755 
1756     page()->animator().scheduleVisualUpdate();
1757     lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1758 }
1759 
isObjectAncestorContainerOf(RenderObject * ancestor,RenderObject * descendant)1760 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
1761 {
1762     for (RenderObject* r = descendant; r; r = r->container()) {
1763         if (r == ancestor)
1764             return true;
1765     }
1766     return false;
1767 }
1768 
scheduleRelayoutOfSubtree(RenderObject * relayoutRoot)1769 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
1770 {
1771     ASSERT(m_frame->view() == this);
1772 
1773     // FIXME: Should this call shouldScheduleLayout instead?
1774     if (!m_frame->document()->isActive())
1775         return;
1776 
1777     RenderView* renderView = this->renderView();
1778     if (renderView && renderView->needsLayout()) {
1779         if (relayoutRoot)
1780             relayoutRoot->markContainingBlocksForLayout(false);
1781         return;
1782     }
1783 
1784     if (layoutPending() || !m_layoutSchedulingEnabled) {
1785         if (m_layoutSubtreeRoot != relayoutRoot) {
1786             if (isObjectAncestorContainerOf(m_layoutSubtreeRoot, relayoutRoot)) {
1787                 // Keep the current root
1788                 relayoutRoot->markContainingBlocksForLayout(false, m_layoutSubtreeRoot);
1789                 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1790             } else if (isSubtreeLayout() && isObjectAncestorContainerOf(relayoutRoot, m_layoutSubtreeRoot)) {
1791                 // Re-root at relayoutRoot
1792                 m_layoutSubtreeRoot->markContainingBlocksForLayout(false, relayoutRoot);
1793                 m_layoutSubtreeRoot = relayoutRoot;
1794                 ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1795             } else {
1796                 // Just do a full relayout
1797                 if (isSubtreeLayout())
1798                     m_layoutSubtreeRoot->markContainingBlocksForLayout(false);
1799                 m_layoutSubtreeRoot = 0;
1800                 relayoutRoot->markContainingBlocksForLayout(false);
1801             }
1802         }
1803     } else if (m_layoutSchedulingEnabled) {
1804         m_layoutSubtreeRoot = relayoutRoot;
1805         ASSERT(!m_layoutSubtreeRoot->container() || !m_layoutSubtreeRoot->container()->needsLayout());
1806         m_hasPendingLayout = true;
1807 
1808         page()->animator().scheduleVisualUpdate();
1809         lifecycle().ensureStateAtMost(DocumentLifecycle::StyleClean);
1810     }
1811     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "InvalidateLayout", "frame", m_frame.get());
1812     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
1813     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
1814     InspectorInstrumentation::didInvalidateLayout(m_frame.get());
1815 }
1816 
layoutPending() const1817 bool FrameView::layoutPending() const
1818 {
1819     // FIXME: This should check Document::lifecycle instead.
1820     return m_hasPendingLayout;
1821 }
1822 
isInPerformLayout() const1823 bool FrameView::isInPerformLayout() const
1824 {
1825     ASSERT(m_inPerformLayout == (lifecycle().state() == DocumentLifecycle::InPerformLayout));
1826     return m_inPerformLayout;
1827 }
1828 
needsLayout() const1829 bool FrameView::needsLayout() const
1830 {
1831     // This can return true in cases where the document does not have a body yet.
1832     // Document::shouldScheduleLayout takes care of preventing us from scheduling
1833     // layout in that case.
1834 
1835     RenderView* renderView = this->renderView();
1836     return layoutPending()
1837         || (renderView && renderView->needsLayout())
1838         || isSubtreeLayout();
1839 }
1840 
setNeedsLayout()1841 void FrameView::setNeedsLayout()
1842 {
1843     if (RenderView* renderView = this->renderView())
1844         renderView->setNeedsLayout();
1845 }
1846 
isTransparent() const1847 bool FrameView::isTransparent() const
1848 {
1849     return m_isTransparent;
1850 }
1851 
setTransparent(bool isTransparent)1852 void FrameView::setTransparent(bool isTransparent)
1853 {
1854     m_isTransparent = isTransparent;
1855     DisableCompositingQueryAsserts disabler;
1856     if (renderView() && renderView()->layer()->hasCompositedLayerMapping())
1857         renderView()->layer()->compositedLayerMapping()->updateContentsOpaque();
1858 }
1859 
hasOpaqueBackground() const1860 bool FrameView::hasOpaqueBackground() const
1861 {
1862     return !m_isTransparent && !m_baseBackgroundColor.hasAlpha();
1863 }
1864 
baseBackgroundColor() const1865 Color FrameView::baseBackgroundColor() const
1866 {
1867     return m_baseBackgroundColor;
1868 }
1869 
setBaseBackgroundColor(const Color & backgroundColor)1870 void FrameView::setBaseBackgroundColor(const Color& backgroundColor)
1871 {
1872     m_baseBackgroundColor = backgroundColor;
1873 
1874     if (renderView() && renderView()->layer()->hasCompositedLayerMapping()) {
1875         CompositedLayerMapping* compositedLayerMapping = renderView()->layer()->compositedLayerMapping();
1876         compositedLayerMapping->updateContentsOpaque();
1877         if (compositedLayerMapping->mainGraphicsLayer())
1878             compositedLayerMapping->mainGraphicsLayer()->setNeedsDisplay();
1879     }
1880     recalculateScrollbarOverlayStyle();
1881 }
1882 
updateBackgroundRecursively(const Color & backgroundColor,bool transparent)1883 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
1884 {
1885     for (Frame* frame = m_frame.get(); frame; frame = frame->tree().traverseNext(m_frame.get())) {
1886         if (!frame->isLocalFrame())
1887             continue;
1888         if (FrameView* view = toLocalFrame(frame)->view()) {
1889             view->setTransparent(transparent);
1890             view->setBaseBackgroundColor(backgroundColor);
1891         }
1892     }
1893 }
1894 
scrollToAnchor()1895 void FrameView::scrollToAnchor()
1896 {
1897     RefPtrWillBeRawPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
1898     if (!anchorNode)
1899         return;
1900 
1901     if (!anchorNode->renderer())
1902         return;
1903 
1904     LayoutRect rect;
1905     if (anchorNode != m_frame->document())
1906         rect = anchorNode->boundingBox();
1907 
1908     RefPtrWillBeRawPtr<LocalFrame> boundaryFrame = m_frame->document()->findUnsafeParentScrollPropagationBoundary();
1909 
1910     if (boundaryFrame)
1911         boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
1912 
1913     // Scroll nested layers and frames to reveal the anchor.
1914     // Align to the top and to the closest side (this matches other browsers).
1915     anchorNode->renderer()->scrollRectToVisible(rect, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1916 
1917     if (boundaryFrame)
1918         boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
1919 
1920     if (AXObjectCache* cache = m_frame->document()->existingAXObjectCache())
1921         cache->handleScrolledToAnchor(anchorNode.get());
1922 
1923     // scrollRectToVisible can call into setScrollPosition(), which resets m_maintainScrollPositionAnchor.
1924     m_maintainScrollPositionAnchor = anchorNode;
1925 }
1926 
updateWidgets()1927 bool FrameView::updateWidgets()
1928 {
1929     // This is always called from updateWidgetsTimerFired.
1930     // m_updateWidgetsTimer should only be scheduled if we have widgets to update.
1931     // Thus I believe we can stop checking isEmpty here, and just ASSERT isEmpty:
1932     ASSERT(!m_widgetUpdateSet.isEmpty());
1933     if (m_nestedLayoutCount > 1 || m_widgetUpdateSet.isEmpty())
1934         return true;
1935 
1936     // Need to swap because script will run inside the below loop and invalidate the iterator.
1937     EmbeddedObjectSet objects;
1938     objects.swap(m_widgetUpdateSet);
1939 
1940     for (EmbeddedObjectSet::iterator it = objects.begin(); it != objects.end(); ++it) {
1941         RenderEmbeddedObject& object = **it;
1942         HTMLPlugInElement* element = toHTMLPlugInElement(object.node());
1943 
1944         // The object may have already been destroyed (thus node cleared),
1945         // but FrameView holds a manual ref, so it won't have been deleted.
1946         if (!element)
1947             continue;
1948 
1949         // No need to update if it's already crashed or known to be missing.
1950         if (object.showsUnavailablePluginIndicator())
1951             continue;
1952 
1953         if (element->needsWidgetUpdate())
1954             element->updateWidget();
1955         object.updateWidgetPosition();
1956 
1957         // Prevent plugins from causing infinite updates of themselves.
1958         // FIXME: Do we really need to prevent this?
1959         m_widgetUpdateSet.remove(&object);
1960     }
1961 
1962     return m_widgetUpdateSet.isEmpty();
1963 }
1964 
updateWidgetsTimerFired(Timer<FrameView> *)1965 void FrameView::updateWidgetsTimerFired(Timer<FrameView>*)
1966 {
1967     ASSERT(!isInPerformLayout());
1968     RefPtr<FrameView> protect(this);
1969     m_updateWidgetsTimer.stop();
1970     for (unsigned i = 0; i < maxUpdateWidgetsIterations; ++i) {
1971         if (updateWidgets())
1972             return;
1973     }
1974 }
1975 
flushAnyPendingPostLayoutTasks()1976 void FrameView::flushAnyPendingPostLayoutTasks()
1977 {
1978     ASSERT(!isInPerformLayout());
1979     if (m_postLayoutTasksTimer.isActive())
1980         performPostLayoutTasks();
1981     if (m_updateWidgetsTimer.isActive())
1982         updateWidgetsTimerFired(0);
1983 }
1984 
scheduleUpdateWidgetsIfNecessary()1985 void FrameView::scheduleUpdateWidgetsIfNecessary()
1986 {
1987     ASSERT(!isInPerformLayout());
1988     if (m_updateWidgetsTimer.isActive() || m_widgetUpdateSet.isEmpty())
1989         return;
1990     m_updateWidgetsTimer.startOneShot(0, FROM_HERE);
1991 }
1992 
performPostLayoutTasks()1993 void FrameView::performPostLayoutTasks()
1994 {
1995     // FIXME: We can reach here, even when the page is not active!
1996     // http/tests/inspector/elements/html-link-import.html and many other
1997     // tests hit that case.
1998     // We should ASSERT(isActive()); or at least return early if we can!
1999     ASSERT(!isInPerformLayout()); // Always before or after performLayout(), part of the highest-level layout() call.
2000     TRACE_EVENT0("blink", "FrameView::performPostLayoutTasks");
2001     RefPtr<FrameView> protect(this);
2002 
2003     m_postLayoutTasksTimer.stop();
2004 
2005     m_frame->selection().setCaretRectNeedsUpdate();
2006 
2007     {
2008         // Hits in compositing/overflow/do-not-repaint-if-scrolling-composited-layers.html
2009         DisableCompositingQueryAsserts disabler;
2010         m_frame->selection().updateAppearance();
2011     }
2012 
2013     ASSERT(m_frame->document());
2014     if (m_nestedLayoutCount <= 1) {
2015         if (m_firstLayoutCallbackPending)
2016             m_firstLayoutCallbackPending = false;
2017 
2018         // Ensure that we always send this eventually.
2019         if (!m_frame->document()->parsing() && m_frame->loader().stateMachine()->committedFirstRealDocumentLoad())
2020             m_isVisuallyNonEmpty = true;
2021 
2022         // If the layout was done with pending sheets, we are not in fact visually non-empty yet.
2023         if (m_isVisuallyNonEmpty && !m_frame->document()->didLayoutWithPendingStylesheets() && m_firstVisuallyNonEmptyLayoutCallbackPending) {
2024             m_firstVisuallyNonEmptyLayoutCallbackPending = false;
2025             // FIXME: This callback is probably not needed, but is currently used
2026             // by android for setting the background color.
2027             m_frame->loader().client()->dispatchDidFirstVisuallyNonEmptyLayout();
2028         }
2029     }
2030 
2031     FontFaceSet::didLayout(*m_frame->document());
2032 
2033     updateWidgetPositions();
2034 
2035     // Plugins could have torn down the page inside updateWidgetPositions().
2036     if (!renderView())
2037         return;
2038 
2039     scheduleUpdateWidgetsIfNecessary();
2040 
2041     if (Page* page = m_frame->page()) {
2042         if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
2043             scrollingCoordinator->notifyLayoutUpdated();
2044     }
2045 
2046     scrollToAnchor();
2047 
2048     sendResizeEventIfNeeded();
2049 }
2050 
wasViewportResized()2051 bool FrameView::wasViewportResized()
2052 {
2053     ASSERT(m_frame);
2054     RenderView* renderView = this->renderView();
2055     if (!renderView)
2056         return false;
2057     return (layoutSize(IncludeScrollbars) != m_lastViewportSize || renderView->style()->zoom() != m_lastZoomFactor);
2058 }
2059 
sendResizeEventIfNeeded()2060 void FrameView::sendResizeEventIfNeeded()
2061 {
2062     ASSERT(m_frame);
2063 
2064     RenderView* renderView = this->renderView();
2065     if (!renderView || renderView->document().printing())
2066         return;
2067 
2068     if (!wasViewportResized())
2069         return;
2070 
2071     m_lastViewportSize = layoutSize(IncludeScrollbars);
2072     m_lastZoomFactor = renderView->style()->zoom();
2073 
2074     m_frame->document()->enqueueResizeEvent();
2075 
2076     if (m_frame->isMainFrame())
2077         InspectorInstrumentation::didResizeMainFrame(m_frame->page());
2078 }
2079 
postLayoutTimerFired(Timer<FrameView> *)2080 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
2081 {
2082     performPostLayoutTasks();
2083 }
2084 
updateCounters()2085 void FrameView::updateCounters()
2086 {
2087     RenderView* view = renderView();
2088     if (!view->hasRenderCounters())
2089         return;
2090 
2091     for (RenderObject* renderer = view; renderer; renderer = renderer->nextInPreOrder()) {
2092         if (!renderer->isCounter())
2093             continue;
2094 
2095         toRenderCounter(renderer)->updateCounter();
2096     }
2097 }
2098 
updateOverflowStatus(bool horizontalOverflow,bool verticalOverflow)2099 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2100 {
2101     if (!m_viewportRenderer)
2102         return;
2103 
2104     if (m_overflowStatusDirty) {
2105         m_horizontalOverflow = horizontalOverflow;
2106         m_verticalOverflow = verticalOverflow;
2107         m_overflowStatusDirty = false;
2108         return;
2109     }
2110 
2111     bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2112     bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2113 
2114     if (horizontalOverflowChanged || verticalOverflowChanged) {
2115         m_horizontalOverflow = horizontalOverflow;
2116         m_verticalOverflow = verticalOverflow;
2117 
2118         RefPtrWillBeRawPtr<OverflowEvent> event = OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow);
2119         event->setTarget(m_viewportRenderer->node());
2120         m_frame->document()->enqueueAnimationFrameEvent(event.release());
2121     }
2122 
2123 }
2124 
windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const2125 IntRect FrameView::windowClipRect(IncludeScrollbarsInRect scrollbarInclusion) const
2126 {
2127     ASSERT(m_frame->view() == this);
2128 
2129     // Set our clip rect to be our contents.
2130     IntRect clipRect = contentsToWindow(visibleContentRect(scrollbarInclusion));
2131     if (!m_frame->deprecatedLocalOwner())
2132         return clipRect;
2133 
2134     // Take our owner element and get its clip rect.
2135     // FIXME: Do we need to do this for remote frames?
2136     HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
2137     FrameView* parentView = ownerElement->document().view();
2138     if (parentView)
2139         clipRect.intersect(parentView->windowClipRectForFrameOwner(ownerElement));
2140     return clipRect;
2141 }
2142 
windowClipRectForFrameOwner(const HTMLFrameOwnerElement * ownerElement) const2143 IntRect FrameView::windowClipRectForFrameOwner(const HTMLFrameOwnerElement* ownerElement) const
2144 {
2145     // The renderer can sometimes be null when style="display:none" interacts
2146     // with external content and plugins.
2147     if (!ownerElement->renderer())
2148         return windowClipRect();
2149 
2150     // If we have no layer, just return our window clip rect.
2151     const RenderLayer* enclosingLayer = ownerElement->renderer()->enclosingLayer();
2152     if (!enclosingLayer)
2153         return windowClipRect();
2154 
2155     // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date.
2156     // https://code.google.com/p/chromium/issues/detail?id=343769
2157     DisableCompositingQueryAsserts disabler;
2158 
2159     // Apply the clip from the layer.
2160     IntRect clipRect = contentsToWindow(pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect()));
2161     return intersection(clipRect, windowClipRect());
2162 }
2163 
isActive() const2164 bool FrameView::isActive() const
2165 {
2166     Page* page = frame().page();
2167     return page && page->focusController().isActive();
2168 }
2169 
scrollTo(const IntSize & newOffset)2170 void FrameView::scrollTo(const IntSize& newOffset)
2171 {
2172     LayoutSize offset = scrollOffset();
2173     ScrollView::scrollTo(newOffset);
2174     if (offset != scrollOffset()) {
2175         updateLayersAndCompositingAfterScrollIfNeeded();
2176         scrollPositionChanged();
2177     }
2178     frame().loader().client()->didChangeScrollOffset();
2179 }
2180 
invalidateScrollbarRect(Scrollbar * scrollbar,const IntRect & rect)2181 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
2182 {
2183     // Add in our offset within the FrameView.
2184     IntRect dirtyRect = rect;
2185     dirtyRect.moveBy(scrollbar->location());
2186 
2187     if (isInPerformLayout())
2188         addScrollbarDamage(scrollbar, rect);
2189     else
2190         invalidateRect(dirtyRect);
2191 }
2192 
getTickmarks(Vector<IntRect> & tickmarks) const2193 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
2194 {
2195     if (!m_tickmarks.isEmpty())
2196         tickmarks = m_tickmarks;
2197     else
2198         tickmarks = frame().document()->markers().renderedRectsForMarkers(DocumentMarker::TextMatch);
2199 }
2200 
windowResizerRect() const2201 IntRect FrameView::windowResizerRect() const
2202 {
2203     Page* page = frame().page();
2204     if (!page)
2205         return IntRect();
2206     return page->chrome().windowResizerRect();
2207 }
2208 
setVisibleContentScaleFactor(float visibleContentScaleFactor)2209 void FrameView::setVisibleContentScaleFactor(float visibleContentScaleFactor)
2210 {
2211     if (m_visibleContentScaleFactor == visibleContentScaleFactor)
2212         return;
2213 
2214     m_visibleContentScaleFactor = visibleContentScaleFactor;
2215     updateScrollbars(scrollOffset());
2216 }
2217 
setInputEventsTransformForEmulation(const IntSize & offset,float contentScaleFactor)2218 void FrameView::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor)
2219 {
2220     m_inputEventsOffsetForEmulation = offset;
2221     m_inputEventsScaleFactorForEmulation = contentScaleFactor;
2222 }
2223 
inputEventsOffsetForEmulation() const2224 IntSize FrameView::inputEventsOffsetForEmulation() const
2225 {
2226     return m_inputEventsOffsetForEmulation;
2227 }
2228 
inputEventsScaleFactor() const2229 float FrameView::inputEventsScaleFactor() const
2230 {
2231     float pageScale = m_frame->settings()->pinchVirtualViewportEnabled()
2232         ? m_frame->page()->frameHost().pinchViewport().scale()
2233         : visibleContentScaleFactor();
2234     return pageScale * m_inputEventsScaleFactorForEmulation;
2235 }
2236 
scrollbarsCanBeActive() const2237 bool FrameView::scrollbarsCanBeActive() const
2238 {
2239     if (m_frame->view() != this)
2240         return false;
2241 
2242     return !!m_frame->document();
2243 }
2244 
scrollableAreaBoundingBox() const2245 IntRect FrameView::scrollableAreaBoundingBox() const
2246 {
2247     RenderPart* ownerRenderer = frame().ownerRenderer();
2248     if (!ownerRenderer)
2249         return frameRect();
2250 
2251     return ownerRenderer->absoluteContentQuad().enclosingBoundingBox();
2252 }
2253 
2254 
isScrollable()2255 bool FrameView::isScrollable()
2256 {
2257     return scrollingReasons() == Scrollable;
2258 }
2259 
scrollingReasons()2260 FrameView::ScrollingReasons FrameView::scrollingReasons()
2261 {
2262     // Check for:
2263     // 1) If there an actual overflow.
2264     // 2) display:none or visibility:hidden set to self or inherited.
2265     // 3) overflow{-x,-y}: hidden;
2266     // 4) scrolling: no;
2267 
2268     // Covers #1
2269     IntSize contentsSize = this->contentsSize();
2270     IntSize visibleContentSize = visibleContentRect().size();
2271     if ((contentsSize.height() <= visibleContentSize.height() && contentsSize.width() <= visibleContentSize.width()))
2272         return NotScrollableNoOverflow;
2273 
2274     // Covers #2.
2275     // FIXME: Do we need to fix this for OOPI?
2276     HTMLFrameOwnerElement* owner = m_frame->deprecatedLocalOwner();
2277     if (owner && (!owner->renderer() || !owner->renderer()->visibleToHitTesting()))
2278         return NotScrollableNotVisible;
2279 
2280     // Cover #3 and #4.
2281     ScrollbarMode horizontalMode;
2282     ScrollbarMode verticalMode;
2283     calculateScrollbarModesForLayoutAndSetViewportRenderer(horizontalMode, verticalMode, RulesFromWebContentOnly);
2284     if (horizontalMode == ScrollbarAlwaysOff && verticalMode == ScrollbarAlwaysOff)
2285         return NotScrollableExplicitlyDisabled;
2286 
2287     return Scrollable;
2288 }
2289 
updateScrollableAreaSet()2290 void FrameView::updateScrollableAreaSet()
2291 {
2292     // That ensures that only inner frames are cached.
2293     FrameView* parentFrameView = this->parentFrameView();
2294     if (!parentFrameView)
2295         return;
2296 
2297     if (!isScrollable()) {
2298         parentFrameView->removeScrollableArea(this);
2299         return;
2300     }
2301 
2302     parentFrameView->addScrollableArea(this);
2303 }
2304 
shouldSuspendScrollAnimations() const2305 bool FrameView::shouldSuspendScrollAnimations() const
2306 {
2307     return m_frame->loader().state() != FrameStateComplete;
2308 }
2309 
scrollbarStyleChanged()2310 void FrameView::scrollbarStyleChanged()
2311 {
2312     // FIXME: Why does this only apply to the main frame?
2313     if (!m_frame->isMainFrame())
2314         return;
2315     ScrollView::scrollbarStyleChanged();
2316 }
2317 
notifyPageThatContentAreaWillPaint() const2318 void FrameView::notifyPageThatContentAreaWillPaint() const
2319 {
2320     Page* page = m_frame->page();
2321     if (!page)
2322         return;
2323 
2324     contentAreaWillPaint();
2325 
2326     if (!m_scrollableAreas)
2327         return;
2328 
2329     for (HashSet<ScrollableArea*>::const_iterator it = m_scrollableAreas->begin(), end = m_scrollableAreas->end(); it != end; ++it) {
2330         ScrollableArea* scrollableArea = *it;
2331 
2332         if (!scrollableArea->scrollbarsCanBeActive())
2333             continue;
2334 
2335         scrollableArea->contentAreaWillPaint();
2336     }
2337 }
2338 
scrollAnimatorEnabled() const2339 bool FrameView::scrollAnimatorEnabled() const
2340 {
2341     return m_frame->settings() && m_frame->settings()->scrollAnimatorEnabled();
2342 }
2343 
updateAnnotatedRegions()2344 void FrameView::updateAnnotatedRegions()
2345 {
2346     Document* document = m_frame->document();
2347     if (!document->hasAnnotatedRegions())
2348         return;
2349     Vector<AnnotatedRegionValue> newRegions;
2350     document->renderBox()->collectAnnotatedRegions(newRegions);
2351     if (newRegions == document->annotatedRegions())
2352         return;
2353     document->setAnnotatedRegions(newRegions);
2354     if (Page* page = m_frame->page())
2355         page->chrome().client().annotatedRegionsChanged();
2356 }
2357 
updateScrollCorner()2358 void FrameView::updateScrollCorner()
2359 {
2360     RefPtr<RenderStyle> cornerStyle;
2361     IntRect cornerRect = scrollCornerRect();
2362     Document* doc = m_frame->document();
2363 
2364     if (doc && !cornerRect.isEmpty()) {
2365         // Try the <body> element first as a scroll corner source.
2366         if (Element* body = doc->body()) {
2367             if (RenderObject* renderer = body->renderer())
2368                 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2369         }
2370 
2371         if (!cornerStyle) {
2372             // If the <body> didn't have a custom style, then the root element might.
2373             if (Element* docElement = doc->documentElement()) {
2374                 if (RenderObject* renderer = docElement->renderer())
2375                     cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2376             }
2377         }
2378 
2379         if (!cornerStyle) {
2380             // If we have an owning ipage/LocalFrame element, then it can set the custom scrollbar also.
2381             if (RenderPart* renderer = m_frame->ownerRenderer())
2382                 cornerStyle = renderer->getUncachedPseudoStyle(PseudoStyleRequest(SCROLLBAR_CORNER), renderer->style());
2383         }
2384     }
2385 
2386     if (cornerStyle) {
2387         if (!m_scrollCorner)
2388             m_scrollCorner = RenderScrollbarPart::createAnonymous(doc);
2389         m_scrollCorner->setStyle(cornerStyle.release());
2390         invalidateScrollCorner(cornerRect);
2391     } else if (m_scrollCorner) {
2392         m_scrollCorner->destroy();
2393         m_scrollCorner = nullptr;
2394     }
2395 
2396     ScrollView::updateScrollCorner();
2397 }
2398 
paintScrollCorner(GraphicsContext * context,const IntRect & cornerRect)2399 void FrameView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
2400 {
2401     if (m_scrollCorner) {
2402         bool needsBackgorund = m_frame->isMainFrame();
2403         if (needsBackgorund)
2404             context->fillRect(cornerRect, baseBackgroundColor());
2405         m_scrollCorner->paintIntoRect(context, cornerRect.location(), cornerRect);
2406         return;
2407     }
2408 
2409     ScrollView::paintScrollCorner(context, cornerRect);
2410 }
2411 
paintScrollbar(GraphicsContext * context,Scrollbar * bar,const IntRect & rect)2412 void FrameView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const IntRect& rect)
2413 {
2414     bool needsBackgorund = bar->isCustomScrollbar() && m_frame->isMainFrame();
2415     if (needsBackgorund) {
2416         IntRect toFill = bar->frameRect();
2417         toFill.intersect(rect);
2418         context->fillRect(toFill, baseBackgroundColor());
2419     }
2420 
2421     ScrollView::paintScrollbar(context, bar, rect);
2422 }
2423 
documentBackgroundColor() const2424 Color FrameView::documentBackgroundColor() const
2425 {
2426     // <https://bugs.webkit.org/show_bug.cgi?id=59540> We blend the background color of
2427     // the document and the body against the base background color of the frame view.
2428     // Background images are unfortunately impractical to include.
2429 
2430     Color result = baseBackgroundColor();
2431     if (!frame().document())
2432         return result;
2433 
2434     Element* htmlElement = frame().document()->documentElement();
2435     Element* bodyElement = frame().document()->body();
2436 
2437     // We take the aggregate of the base background color
2438     // the <html> background color, and the <body>
2439     // background color to find the document color. The
2440     // addition of the base background color is not
2441     // technically part of the document background, but it
2442     // otherwise poses problems when the aggregate is not
2443     // fully opaque.
2444     if (htmlElement && htmlElement->renderer())
2445         result = result.blend(htmlElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2446     if (bodyElement && bodyElement->renderer())
2447         result = result.blend(bodyElement->renderer()->style()->visitedDependentColor(CSSPropertyBackgroundColor));
2448 
2449     return result;
2450 }
2451 
hasCustomScrollbars() const2452 bool FrameView::hasCustomScrollbars() const
2453 {
2454     const HashSet<RefPtr<Widget> >* viewChildren = children();
2455     HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
2456     for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
2457         Widget* widget = current->get();
2458         if (widget->isFrameView()) {
2459             if (toFrameView(widget)->hasCustomScrollbars())
2460                 return true;
2461         } else if (widget->isScrollbar()) {
2462             Scrollbar* scrollbar = static_cast<Scrollbar*>(widget);
2463             if (scrollbar->isCustomScrollbar())
2464                 return true;
2465         }
2466     }
2467 
2468     return false;
2469 }
2470 
parentFrameView() const2471 FrameView* FrameView::parentFrameView() const
2472 {
2473     if (!parent())
2474         return 0;
2475 
2476     Frame* parentFrame = m_frame->tree().parent();
2477     if (parentFrame && parentFrame->isLocalFrame())
2478         return toLocalFrame(parentFrame)->view();
2479 
2480     return 0;
2481 }
2482 
wasScrolledByUser() const2483 bool FrameView::wasScrolledByUser() const
2484 {
2485     return m_wasScrolledByUser;
2486 }
2487 
setWasScrolledByUser(bool wasScrolledByUser)2488 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
2489 {
2490     if (m_inProgrammaticScroll)
2491         return;
2492     m_maintainScrollPositionAnchor = nullptr;
2493     m_wasScrolledByUser = wasScrolledByUser;
2494 }
2495 
paintContents(GraphicsContext * p,const IntRect & rect)2496 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
2497 {
2498     Document* document = m_frame->document();
2499 
2500 #ifndef NDEBUG
2501     bool fillWithRed;
2502     if (document->printing())
2503         fillWithRed = false; // Printing, don't fill with red (can't remember why).
2504     else if (m_frame->owner())
2505         fillWithRed = false; // Subframe, don't fill with red.
2506     else if (isTransparent())
2507         fillWithRed = false; // Transparent, don't fill with red.
2508     else if (m_paintBehavior & PaintBehaviorSelectionOnly)
2509         fillWithRed = false; // Selections are transparent, don't fill with red.
2510     else if (m_nodeToDraw)
2511         fillWithRed = false; // Element images are transparent, don't fill with red.
2512     else
2513         fillWithRed = true;
2514 
2515     if (fillWithRed)
2516         p->fillRect(rect, Color(0xFF, 0, 0));
2517 #endif
2518 
2519     RenderView* renderView = this->renderView();
2520     if (!renderView) {
2521         WTF_LOG_ERROR("called FrameView::paint with nil renderer");
2522         return;
2523     }
2524 
2525     RELEASE_ASSERT(!needsLayout());
2526     ASSERT(document->lifecycle().state() >= DocumentLifecycle::CompositingClean);
2527 
2528     TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Paint", "data", InspectorPaintEvent::data(renderView, rect, 0));
2529     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
2530     // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
2531     InspectorInstrumentation::willPaint(renderView, 0);
2532 
2533     bool isTopLevelPainter = !s_inPaintContents;
2534     s_inPaintContents = true;
2535 
2536     FontCachePurgePreventer fontCachePurgePreventer;
2537 
2538     PaintBehavior oldPaintBehavior = m_paintBehavior;
2539 
2540     if (FrameView* parentView = parentFrameView()) {
2541         if (parentView->paintBehavior() & PaintBehaviorFlattenCompositingLayers)
2542             m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
2543     }
2544 
2545     if (m_paintBehavior == PaintBehaviorNormal)
2546         document->markers().invalidateRenderedRectsForMarkersInRect(rect);
2547 
2548     if (document->printing())
2549         m_paintBehavior |= PaintBehaviorFlattenCompositingLayers;
2550 
2551     ASSERT(!m_isPainting);
2552     m_isPainting = true;
2553 
2554     // m_nodeToDraw is used to draw only one element (and its descendants)
2555     RenderObject* renderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
2556     RenderLayer* rootLayer = renderView->layer();
2557 
2558 #if ENABLE(ASSERT)
2559     renderView->assertSubtreeIsLaidOut();
2560     RenderObject::SetLayoutNeededForbiddenScope forbidSetNeedsLayout(*rootLayer->renderer());
2561 #endif
2562 
2563     rootLayer->paint(p, rect, m_paintBehavior, renderer);
2564 
2565     if (rootLayer->containsDirtyOverlayScrollbars())
2566         rootLayer->paintOverlayScrollbars(p, rect, m_paintBehavior, renderer);
2567 
2568     m_isPainting = false;
2569 
2570     m_paintBehavior = oldPaintBehavior;
2571     m_lastPaintTime = currentTime();
2572 
2573     // Regions may have changed as a result of the visibility/z-index of element changing.
2574     if (document->annotatedRegionsDirty())
2575         updateAnnotatedRegions();
2576 
2577     if (isTopLevelPainter) {
2578         // Everything that happens after paintContents completions is considered
2579         // to be part of the next frame.
2580         s_currentFrameTimeStamp = currentTime();
2581         s_inPaintContents = false;
2582     }
2583 
2584     InspectorInstrumentation::didPaint(renderView, 0, p, rect);
2585 }
2586 
setPaintBehavior(PaintBehavior behavior)2587 void FrameView::setPaintBehavior(PaintBehavior behavior)
2588 {
2589     m_paintBehavior = behavior;
2590 }
2591 
paintBehavior() const2592 PaintBehavior FrameView::paintBehavior() const
2593 {
2594     return m_paintBehavior;
2595 }
2596 
isPainting() const2597 bool FrameView::isPainting() const
2598 {
2599     return m_isPainting;
2600 }
2601 
setNodeToDraw(Node * node)2602 void FrameView::setNodeToDraw(Node* node)
2603 {
2604     m_nodeToDraw = node;
2605 }
2606 
paintOverhangAreas(GraphicsContext * context,const IntRect & horizontalOverhangArea,const IntRect & verticalOverhangArea,const IntRect & dirtyRect)2607 void FrameView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangArea, const IntRect& verticalOverhangArea, const IntRect& dirtyRect)
2608 {
2609     if (m_frame->document()->printing())
2610         return;
2611 
2612     if (m_frame->isMainFrame()) {
2613         if (m_frame->page()->chrome().client().paintCustomOverhangArea(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect))
2614             return;
2615     }
2616 
2617     ScrollView::paintOverhangAreas(context, horizontalOverhangArea, verticalOverhangArea, dirtyRect);
2618 }
2619 
updateWidgetPositionsIfNeeded()2620 void FrameView::updateWidgetPositionsIfNeeded()
2621 {
2622     if (!m_needsUpdateWidgetPositions)
2623         return;
2624 
2625     m_needsUpdateWidgetPositions = false;
2626 
2627     updateWidgetPositions();
2628 }
2629 
updateLayoutAndStyleForPainting()2630 void FrameView::updateLayoutAndStyleForPainting()
2631 {
2632     // Updating layout can run script, which can tear down the FrameView.
2633     RefPtr<FrameView> protector(this);
2634 
2635     updateLayoutAndStyleIfNeededRecursive();
2636 
2637     updateWidgetPositionsIfNeeded();
2638 
2639     if (RenderView* view = renderView()) {
2640         TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateLayerTree", "frame", m_frame.get());
2641         // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
2642         InspectorInstrumentation::willUpdateLayerTree(m_frame.get());
2643 
2644         view->compositor()->updateIfNeededRecursive();
2645 
2646         if (view->compositor()->inCompositingMode() && m_frame->isLocalRoot())
2647             m_frame->page()->scrollingCoordinator()->updateAfterCompositingChangeIfNeeded();
2648 
2649         updateCompositedSelectionBoundsIfNeeded();
2650 
2651         InspectorInstrumentation::didUpdateLayerTree(m_frame.get());
2652 
2653         invalidateTreeIfNeededRecursive();
2654     }
2655 
2656     scrollContentsIfNeededRecursive();
2657     ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean);
2658 }
2659 
updateLayoutAndStyleIfNeededRecursive()2660 void FrameView::updateLayoutAndStyleIfNeededRecursive()
2661 {
2662     // We have to crawl our entire tree looking for any FrameViews that need
2663     // layout and make sure they are up to date.
2664     // Mac actually tests for intersection with the dirty region and tries not to
2665     // update layout for frames that are outside the dirty region.  Not only does this seem
2666     // pointless (since those frames will have set a zero timer to layout anyway), but
2667     // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
2668     // region but then become included later by the second frame adding rects to the dirty region
2669     // when it lays out.
2670 
2671     m_frame->document()->updateRenderTreeIfNeeded();
2672 
2673     if (needsLayout())
2674         layout();
2675 
2676     // FIXME: Calling layout() shouldn't trigger scripe execution or have any
2677     // observable effects on the frame tree but we're not quite there yet.
2678     Vector<RefPtr<FrameView> > frameViews;
2679     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2680         if (!child->isLocalFrame())
2681             continue;
2682         if (FrameView* view = toLocalFrame(child)->view())
2683             frameViews.append(view);
2684     }
2685 
2686     const Vector<RefPtr<FrameView> >::iterator end = frameViews.end();
2687     for (Vector<RefPtr<FrameView> >::iterator it = frameViews.begin(); it != end; ++it)
2688         (*it)->updateLayoutAndStyleIfNeededRecursive();
2689 
2690     // When an <iframe> gets composited, it triggers an extra style recalc in its containing FrameView.
2691     // To avoid pushing an invalid tree for display, we have to check for this case and do another
2692     // style recalc. The extra style recalc needs to happen after our child <iframes> were updated.
2693     // FIXME: We shouldn't be triggering an extra style recalc in the first place.
2694     if (m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate()) {
2695         m_frame->document()->updateRenderTreeIfNeeded();
2696 
2697         if (needsLayout())
2698             layout();
2699     }
2700 
2701     // These asserts ensure that parent frames are clean, when child frames finished updating layout and style.
2702     ASSERT(!needsLayout());
2703     ASSERT(!m_frame->document()->hasSVGFilterElementsRequiringLayerUpdate());
2704 #if ENABLE(ASSERT)
2705     m_frame->document()->renderView()->assertRendererLaidOut();
2706 #endif
2707 
2708 }
2709 
invalidateTreeIfNeededRecursive()2710 void FrameView::invalidateTreeIfNeededRecursive()
2711 {
2712     // FIXME: We should be more aggressive at cutting tree traversals.
2713     lifecycle().advanceTo(DocumentLifecycle::InPaintInvalidation);
2714     invalidateTreeIfNeeded();
2715     lifecycle().advanceTo(DocumentLifecycle::PaintInvalidationClean);
2716 
2717     for (Frame* child = m_frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
2718         if (!child->isLocalFrame())
2719             continue;
2720 
2721         toLocalFrame(child)->view()->invalidateTreeIfNeededRecursive();
2722     }
2723 
2724     m_doFullPaintInvalidation = false;
2725 }
2726 
enableAutoSizeMode(const IntSize & minSize,const IntSize & maxSize)2727 void FrameView::enableAutoSizeMode(const IntSize& minSize, const IntSize& maxSize)
2728 {
2729     if (!m_autoSizeInfo)
2730         m_autoSizeInfo = adoptPtr(new FrameViewAutoSizeInfo(this));
2731 
2732     m_autoSizeInfo->configureAutoSizeMode(minSize, maxSize);
2733 }
2734 
forceLayout(bool allowSubtree)2735 void FrameView::forceLayout(bool allowSubtree)
2736 {
2737     layout(allowSubtree);
2738 }
2739 
forceLayoutForPagination(const FloatSize & pageSize,const FloatSize & originalPageSize,float maximumShrinkFactor)2740 void FrameView::forceLayoutForPagination(const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkFactor)
2741 {
2742     // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
2743     // the state of things before and after the layout
2744     if (RenderView* renderView = this->renderView()) {
2745         float pageLogicalWidth = renderView->style()->isHorizontalWritingMode() ? pageSize.width() : pageSize.height();
2746         float pageLogicalHeight = renderView->style()->isHorizontalWritingMode() ? pageSize.height() : pageSize.width();
2747 
2748         LayoutUnit flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2749         LayoutUnit flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2750         renderView->setLogicalWidth(flooredPageLogicalWidth);
2751         renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2752         renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
2753         forceLayout();
2754 
2755         // If we don't fit in the given page width, we'll lay out again. If we don't fit in the
2756         // page width when shrunk, we will lay out at maximum shrink and clip extra content.
2757         // FIXME: We are assuming a shrink-to-fit printing implementation.  A cropping
2758         // implementation should not do this!
2759         bool horizontalWritingMode = renderView->style()->isHorizontalWritingMode();
2760         const LayoutRect& documentRect = renderView->documentRect();
2761         LayoutUnit docLogicalWidth = horizontalWritingMode ? documentRect.width() : documentRect.height();
2762         if (docLogicalWidth > pageLogicalWidth) {
2763             FloatSize expectedPageSize(std::min<float>(documentRect.width().toFloat(), pageSize.width() * maximumShrinkFactor), std::min<float>(documentRect.height().toFloat(), pageSize.height() * maximumShrinkFactor));
2764             FloatSize maxPageSize = m_frame->resizePageRectsKeepingRatio(FloatSize(originalPageSize.width(), originalPageSize.height()), expectedPageSize);
2765             pageLogicalWidth = horizontalWritingMode ? maxPageSize.width() : maxPageSize.height();
2766             pageLogicalHeight = horizontalWritingMode ? maxPageSize.height() : maxPageSize.width();
2767 
2768             flooredPageLogicalWidth = static_cast<LayoutUnit>(pageLogicalWidth);
2769             flooredPageLogicalHeight = static_cast<LayoutUnit>(pageLogicalHeight);
2770             renderView->setLogicalWidth(flooredPageLogicalWidth);
2771             renderView->setPageLogicalHeight(flooredPageLogicalHeight);
2772             renderView->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
2773             forceLayout();
2774 
2775             const LayoutRect& updatedDocumentRect = renderView->documentRect();
2776             LayoutUnit docLogicalHeight = horizontalWritingMode ? updatedDocumentRect.height() : updatedDocumentRect.width();
2777             LayoutUnit docLogicalTop = horizontalWritingMode ? updatedDocumentRect.y() : updatedDocumentRect.x();
2778             LayoutUnit docLogicalRight = horizontalWritingMode ? updatedDocumentRect.maxX() : updatedDocumentRect.maxY();
2779             LayoutUnit clippedLogicalLeft = 0;
2780             if (!renderView->style()->isLeftToRightDirection())
2781                 clippedLogicalLeft = docLogicalRight - pageLogicalWidth;
2782             LayoutRect overflow(clippedLogicalLeft, docLogicalTop, pageLogicalWidth, docLogicalHeight);
2783 
2784             if (!horizontalWritingMode)
2785                 overflow = overflow.transposedRect();
2786             renderView->clearLayoutOverflow();
2787             renderView->addLayoutOverflow(overflow); // This is how we clip in case we overflow again.
2788         }
2789     }
2790 
2791     adjustViewSize();
2792 }
2793 
convertFromRenderer(const RenderObject & renderer,const IntRect & rendererRect) const2794 IntRect FrameView::convertFromRenderer(const RenderObject& renderer, const IntRect& rendererRect) const
2795 {
2796     IntRect rect = pixelSnappedIntRect(enclosingLayoutRect(renderer.localToAbsoluteQuad(FloatRect(rendererRect)).boundingBox()));
2797 
2798     // Convert from page ("absolute") to FrameView coordinates.
2799     rect.moveBy(-scrollPosition());
2800 
2801     return rect;
2802 }
2803 
convertToRenderer(const RenderObject & renderer,const IntRect & viewRect) const2804 IntRect FrameView::convertToRenderer(const RenderObject& renderer, const IntRect& viewRect) const
2805 {
2806     IntRect rect = viewRect;
2807 
2808     // Convert from FrameView coords into page ("absolute") coordinates.
2809     rect.moveBy(scrollPosition());
2810 
2811     // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
2812     // move the rect for now.
2813     rect.setLocation(roundedIntPoint(renderer.absoluteToLocal(rect.location(), UseTransforms)));
2814     return rect;
2815 }
2816 
convertFromRenderer(const RenderObject & renderer,const IntPoint & rendererPoint) const2817 IntPoint FrameView::convertFromRenderer(const RenderObject& renderer, const IntPoint& rendererPoint) const
2818 {
2819     IntPoint point = roundedIntPoint(renderer.localToAbsolute(rendererPoint, UseTransforms));
2820 
2821     // Convert from page ("absolute") to FrameView coordinates.
2822     point.moveBy(-scrollPosition());
2823     return point;
2824 }
2825 
convertToRenderer(const RenderObject & renderer,const IntPoint & viewPoint) const2826 IntPoint FrameView::convertToRenderer(const RenderObject& renderer, const IntPoint& viewPoint) const
2827 {
2828     IntPoint point = viewPoint;
2829 
2830     // Convert from FrameView coords into page ("absolute") coordinates.
2831     point += IntSize(scrollX(), scrollY());
2832 
2833     return roundedIntPoint(renderer.absoluteToLocal(point, UseTransforms));
2834 }
2835 
convertToContainingView(const IntRect & localRect) const2836 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
2837 {
2838     if (const ScrollView* parentScrollView = toScrollView(parent())) {
2839         if (parentScrollView->isFrameView()) {
2840             const FrameView* parentView = toFrameView(parentScrollView);
2841             // Get our renderer in the parent view
2842             RenderPart* renderer = m_frame->ownerRenderer();
2843             if (!renderer)
2844                 return localRect;
2845 
2846             IntRect rect(localRect);
2847             // Add borders and padding??
2848             rect.move(renderer->borderLeft() + renderer->paddingLeft(),
2849                 renderer->borderTop() + renderer->paddingTop());
2850             return parentView->convertFromRenderer(*renderer, rect);
2851         }
2852 
2853         return Widget::convertToContainingView(localRect);
2854     }
2855 
2856     return localRect;
2857 }
2858 
convertFromContainingView(const IntRect & parentRect) const2859 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
2860 {
2861     if (const ScrollView* parentScrollView = toScrollView(parent())) {
2862         if (parentScrollView->isFrameView()) {
2863             const FrameView* parentView = toFrameView(parentScrollView);
2864 
2865             // Get our renderer in the parent view
2866             RenderPart* renderer = m_frame->ownerRenderer();
2867             if (!renderer)
2868                 return parentRect;
2869 
2870             IntRect rect = parentView->convertToRenderer(*renderer, parentRect);
2871             // Subtract borders and padding
2872             rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
2873                       -renderer->borderTop() - renderer->paddingTop());
2874             return rect;
2875         }
2876 
2877         return Widget::convertFromContainingView(parentRect);
2878     }
2879 
2880     return parentRect;
2881 }
2882 
convertToContainingView(const IntPoint & localPoint) const2883 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
2884 {
2885     if (const ScrollView* parentScrollView = toScrollView(parent())) {
2886         if (parentScrollView->isFrameView()) {
2887             const FrameView* parentView = toFrameView(parentScrollView);
2888 
2889             // Get our renderer in the parent view
2890             RenderPart* renderer = m_frame->ownerRenderer();
2891             if (!renderer)
2892                 return localPoint;
2893 
2894             IntPoint point(localPoint);
2895 
2896             // Add borders and padding
2897             point.move(renderer->borderLeft() + renderer->paddingLeft(),
2898                        renderer->borderTop() + renderer->paddingTop());
2899             return parentView->convertFromRenderer(*renderer, point);
2900         }
2901 
2902         return Widget::convertToContainingView(localPoint);
2903     }
2904 
2905     return localPoint;
2906 }
2907 
convertFromContainingView(const IntPoint & parentPoint) const2908 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
2909 {
2910     if (const ScrollView* parentScrollView = toScrollView(parent())) {
2911         if (parentScrollView->isFrameView()) {
2912             const FrameView* parentView = toFrameView(parentScrollView);
2913 
2914             // Get our renderer in the parent view
2915             RenderPart* renderer = m_frame->ownerRenderer();
2916             if (!renderer)
2917                 return parentPoint;
2918 
2919             IntPoint point = parentView->convertToRenderer(*renderer, parentPoint);
2920             // Subtract borders and padding
2921             point.move(-renderer->borderLeft() - renderer->paddingLeft(),
2922                        -renderer->borderTop() - renderer->paddingTop());
2923             return point;
2924         }
2925 
2926         return Widget::convertFromContainingView(parentPoint);
2927     }
2928 
2929     return parentPoint;
2930 }
2931 
setTracksPaintInvalidations(bool trackPaintInvalidations)2932 void FrameView::setTracksPaintInvalidations(bool trackPaintInvalidations)
2933 {
2934     if (trackPaintInvalidations == m_isTrackingPaintInvalidations)
2935         return;
2936 
2937     for (Frame* frame = m_frame->tree().top(); frame; frame = frame->tree().traverseNext()) {
2938         if (!frame->isLocalFrame())
2939             continue;
2940         if (RenderView* renderView = toLocalFrame(frame)->contentRenderer())
2941             renderView->compositor()->setTracksPaintInvalidations(trackPaintInvalidations);
2942     }
2943 
2944     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"),
2945         "FrameView::setTracksPaintInvalidations", "enabled", trackPaintInvalidations);
2946 
2947     resetTrackedPaintInvalidations();
2948     m_isTrackingPaintInvalidations = trackPaintInvalidations;
2949 }
2950 
resetTrackedPaintInvalidations()2951 void FrameView::resetTrackedPaintInvalidations()
2952 {
2953     m_trackedPaintInvalidationRects.clear();
2954     if (RenderView* renderView = this->renderView())
2955         renderView->compositor()->resetTrackedPaintInvalidationRects();
2956 }
2957 
trackedPaintInvalidationRectsAsText() const2958 String FrameView::trackedPaintInvalidationRectsAsText() const
2959 {
2960     TextStream ts;
2961     if (!m_trackedPaintInvalidationRects.isEmpty()) {
2962         ts << "(repaint rects\n";
2963         for (size_t i = 0; i < m_trackedPaintInvalidationRects.size(); ++i)
2964             ts << "  (rect " << m_trackedPaintInvalidationRects[i].x() << " " << m_trackedPaintInvalidationRects[i].y() << " " << m_trackedPaintInvalidationRects[i].width() << " " << m_trackedPaintInvalidationRects[i].height() << ")\n";
2965         ts << ")\n";
2966     }
2967     return ts.release();
2968 }
2969 
addResizerArea(RenderBox & resizerBox)2970 void FrameView::addResizerArea(RenderBox& resizerBox)
2971 {
2972     if (!m_resizerAreas)
2973         m_resizerAreas = adoptPtr(new ResizerAreaSet);
2974     m_resizerAreas->add(&resizerBox);
2975 }
2976 
removeResizerArea(RenderBox & resizerBox)2977 void FrameView::removeResizerArea(RenderBox& resizerBox)
2978 {
2979     if (!m_resizerAreas)
2980         return;
2981 
2982     ResizerAreaSet::iterator it = m_resizerAreas->find(&resizerBox);
2983     if (it != m_resizerAreas->end())
2984         m_resizerAreas->remove(it);
2985 }
2986 
addScrollableArea(ScrollableArea * scrollableArea)2987 void FrameView::addScrollableArea(ScrollableArea* scrollableArea)
2988 {
2989     ASSERT(scrollableArea);
2990     if (!m_scrollableAreas)
2991         m_scrollableAreas = adoptPtr(new ScrollableAreaSet);
2992     m_scrollableAreas->add(scrollableArea);
2993 }
2994 
removeScrollableArea(ScrollableArea * scrollableArea)2995 void FrameView::removeScrollableArea(ScrollableArea* scrollableArea)
2996 {
2997     if (!m_scrollableAreas)
2998         return;
2999     m_scrollableAreas->remove(scrollableArea);
3000 }
3001 
setParent(Widget * widget)3002 void FrameView::setParent(Widget* widget)
3003 {
3004     ScrollView::setParent(widget);
3005     updateScrollableAreaSet();
3006 }
3007 
removeChild(Widget * widget)3008 void FrameView::removeChild(Widget* widget)
3009 {
3010     if (widget->isFrameView())
3011         removeScrollableArea(toFrameView(widget));
3012 
3013     ScrollView::removeChild(widget);
3014 }
3015 
wheelEvent(const PlatformWheelEvent & wheelEvent)3016 bool FrameView::wheelEvent(const PlatformWheelEvent& wheelEvent)
3017 {
3018     bool allowScrolling = userInputScrollable(HorizontalScrollbar) || userInputScrollable(VerticalScrollbar);
3019 
3020     // Note that to allow for rubber-band over-scroll behavior, even non-scrollable views
3021     // should handle wheel events.
3022 #if !USE(RUBBER_BANDING)
3023     if (!isScrollable())
3024         allowScrolling = false;
3025 #endif
3026 
3027     if (allowScrolling && ScrollableArea::handleWheelEvent(wheelEvent))
3028         return true;
3029 
3030     // If the frame didn't handle the event, give the pinch-zoom viewport a chance to
3031     // process the scroll event.
3032     if (m_frame->settings()->pinchVirtualViewportEnabled() && m_frame->isMainFrame())
3033         return page()->frameHost().pinchViewport().handleWheelEvent(wheelEvent);
3034 
3035     return false;
3036 }
3037 
isVerticalDocument() const3038 bool FrameView::isVerticalDocument() const
3039 {
3040     RenderView* renderView = this->renderView();
3041     if (!renderView)
3042         return true;
3043 
3044     return renderView->style()->isHorizontalWritingMode();
3045 }
3046 
isFlippedDocument() const3047 bool FrameView::isFlippedDocument() const
3048 {
3049     RenderView* renderView = this->renderView();
3050     if (!renderView)
3051         return false;
3052 
3053     return renderView->style()->isFlippedBlocksWritingMode();
3054 }
3055 
scrollbarsDisabled() const3056 bool FrameView::scrollbarsDisabled() const
3057 {
3058     if (!m_frame->settings() || !m_frame->settings()->pinchVirtualViewportEnabled())
3059         return false;
3060 
3061     return m_frame->isMainFrame() && ScrollbarTheme::theme()->usesOverlayScrollbars();
3062 }
3063 
axObjectCache() const3064 AXObjectCache* FrameView::axObjectCache() const
3065 {
3066     if (frame().document())
3067         return frame().document()->existingAXObjectCache();
3068     return 0;
3069 }
3070 
setCursor(const Cursor & cursor)3071 void FrameView::setCursor(const Cursor& cursor)
3072 {
3073     Page* page = frame().page();
3074     if (!page || !page->settings().deviceSupportsMouse())
3075         return;
3076     page->chrome().setCursor(cursor);
3077 }
3078 
frameRectsChanged()3079 void FrameView::frameRectsChanged()
3080 {
3081     if (layoutSizeFixedToFrameSize())
3082         setLayoutSizeInternal(frameRect().size());
3083 
3084     ScrollView::frameRectsChanged();
3085 }
3086 
setLayoutSizeInternal(const IntSize & size)3087 void FrameView::setLayoutSizeInternal(const IntSize& size)
3088 {
3089     if (m_layoutSize == size)
3090         return;
3091 
3092     m_layoutSize = size;
3093     contentsResized();
3094 }
3095 
didAddScrollbar(Scrollbar * scrollbar,ScrollbarOrientation orientation)3096 void FrameView::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3097 {
3098     ScrollableArea::didAddScrollbar(scrollbar, orientation);
3099     if (AXObjectCache* cache = axObjectCache())
3100         cache->handleScrollbarUpdate(this);
3101 }
3102 
willRemoveScrollbar(Scrollbar * scrollbar,ScrollbarOrientation orientation)3103 void FrameView::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientation orientation)
3104 {
3105     ScrollableArea::willRemoveScrollbar(scrollbar, orientation);
3106     if (AXObjectCache* cache = axObjectCache()) {
3107         cache->remove(scrollbar);
3108         cache->handleScrollbarUpdate(this);
3109     }
3110 }
3111 
setTopControlsViewportAdjustment(float adjustment)3112 void FrameView::setTopControlsViewportAdjustment(float adjustment)
3113 {
3114     m_topControlsViewportAdjustment = adjustment;
3115 }
3116 
maximumScrollPosition() const3117 IntPoint FrameView::maximumScrollPosition() const
3118 {
3119     FloatSize visibleContentSizeF = unscaledVisibleContentSize(ExcludeScrollbars);
3120     visibleContentSizeF.expand(0, -m_topControlsViewportAdjustment);
3121     visibleContentSizeF.scale(1 / visibleContentScaleFactor());
3122     IntSize visibleSize = expandedIntSize(visibleContentSizeF);
3123 
3124     IntPoint maximumOffset(
3125         contentsWidth() - visibleSize.width() - scrollOrigin().x(),
3126         contentsHeight() - visibleSize.height() - scrollOrigin().y());
3127     maximumOffset.clampNegativeToZero();
3128     return maximumOffset;
3129 }
3130 
3131 } // namespace blink
3132