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