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 #include "config.h"
27 #include "FrameView.h"
28
29 #include "AXObjectCache.h"
30 #include "CSSStyleSelector.h"
31 #include "ChromeClient.h"
32 #include "DocLoader.h"
33 #include "EventHandler.h"
34 #include "FloatRect.h"
35 #include "FocusController.h"
36 #include "Frame.h"
37 #include "FrameLoader.h"
38 #include "FrameLoaderClient.h"
39 #include "FrameTree.h"
40 #include "GraphicsContext.h"
41 #include "HTMLDocument.h"
42 #include "HTMLFrameElement.h"
43 #include "HTMLFrameSetElement.h"
44 #include "HTMLNames.h"
45 #include "OverflowEvent.h"
46 #include "Page.h"
47 #include "RenderPart.h"
48 #include "RenderPartObject.h"
49 #include "RenderScrollbar.h"
50 #include "RenderTheme.h"
51 #include "RenderView.h"
52 #include "Settings.h"
53 #include <wtf/CurrentTime.h>
54
55 #ifdef ANDROID_INSTRUMENT
56 #include "FrameTree.h"
57 #include "TimeCounter.h"
58 #endif
59
60 #if USE(ACCELERATED_COMPOSITING)
61 #include "RenderLayerCompositor.h"
62 #endif
63
64 namespace WebCore {
65
66 using namespace HTMLNames;
67
68 double FrameView::sCurrentPaintTimeStamp = 0.0;
69
70 #if ENABLE(REPAINT_THROTTLING)
71 // Normal delay
72 static const double deferredRepaintDelay = 0.025;
73 // Negative value would mean that first few repaints happen without a delay
74 static const double initialDeferredRepaintDelayDuringLoading = 0;
75 // The delay grows on each repaint to this maximum value
76 static const double maxDeferredRepaintDelayDuringLoading = 2.5;
77 // On each repaint the delay increses by this amount
78 static const double deferredRepaintDelayIncrementDuringLoading = 0.5;
79 #else
80 // FIXME: Repaint throttling could be good to have on all platform.
81 // The balance between CPU use and repaint frequency will need some tuning for desktop.
82 // More hooks may be needed to reset the delay on things like GIF and CSS animations.
83 static const double deferredRepaintDelay = 0;
84 static const double initialDeferredRepaintDelayDuringLoading = 0;
85 static const double maxDeferredRepaintDelayDuringLoading = 0;
86 static const double deferredRepaintDelayIncrementDuringLoading = 0;
87 #endif
88
89 // The maximum number of updateWidgets iterations that should be done before returning.
90 static const unsigned maxUpdateWidgetsIterations = 2;
91
92 struct ScheduledEvent {
93 RefPtr<Event> m_event;
94 RefPtr<Node> m_eventTarget;
95 };
96
FrameView(Frame * frame)97 FrameView::FrameView(Frame* frame)
98 : m_frame(frame)
99 , m_vmode(ScrollbarAuto)
100 , m_hmode(ScrollbarAuto)
101 , m_slowRepaintObjectCount(0)
102 , m_layoutTimer(this, &FrameView::layoutTimerFired)
103 , m_layoutRoot(0)
104 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
105 , m_needToInitScrollbars(true)
106 , m_isTransparent(false)
107 , m_baseBackgroundColor(Color::white)
108 , m_mediaType("screen")
109 , m_enqueueEvents(0)
110 , m_overflowStatusDirty(true)
111 , m_viewportRenderer(0)
112 , m_wasScrolledByUser(false)
113 , m_inProgrammaticScroll(false)
114 , m_deferredRepaintTimer(this, &FrameView::deferredRepaintTimerFired)
115 , m_shouldUpdateWhileOffscreen(true)
116 , m_deferSetNeedsLayouts(0)
117 , m_setNeedsLayoutWasDeferred(false)
118 {
119 init();
120 }
121
create(Frame * frame)122 PassRefPtr<FrameView> FrameView::create(Frame* frame)
123 {
124 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
125 view->show();
126 return view.release();
127 }
128
create(Frame * frame,const IntSize & initialSize)129 PassRefPtr<FrameView> FrameView::create(Frame* frame, const IntSize& initialSize)
130 {
131 RefPtr<FrameView> view = adoptRef(new FrameView(frame));
132 view->Widget::setFrameRect(IntRect(view->pos(), initialSize));
133 view->show();
134 return view.release();
135 }
136
~FrameView()137 FrameView::~FrameView()
138 {
139 if (m_postLayoutTasksTimer.isActive()) {
140 m_postLayoutTasksTimer.stop();
141 m_scheduledEvents.clear();
142 m_enqueueEvents = 0;
143 }
144
145 resetScrollbars();
146 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
147 setHasVerticalScrollbar(false);
148
149 ASSERT(m_scheduledEvents.isEmpty());
150 ASSERT(!m_enqueueEvents);
151
152 if (m_frame) {
153 ASSERT(m_frame->view() != this || !m_frame->contentRenderer());
154 RenderPart* renderer = m_frame->ownerRenderer();
155 if (renderer && renderer->widget() == this)
156 renderer->setWidget(0);
157 }
158 }
159
reset()160 void FrameView::reset()
161 {
162 m_useSlowRepaints = false;
163 m_isOverlapped = false;
164 m_contentIsOpaque = false;
165 m_borderX = 30;
166 m_borderY = 30;
167 m_layoutTimer.stop();
168 m_layoutRoot = 0;
169 m_delayedLayout = false;
170 m_doFullRepaint = true;
171 m_layoutSchedulingEnabled = true;
172 m_midLayout = false;
173 m_layoutCount = 0;
174 m_nestedLayoutCount = 0;
175 m_postLayoutTasksTimer.stop();
176 m_firstLayout = true;
177 m_firstLayoutCallbackPending = false;
178 m_wasScrolledByUser = false;
179 m_lastLayoutSize = IntSize();
180 m_lastZoomFactor = 1.0f;
181 m_deferringRepaints = 0;
182 m_repaintCount = 0;
183 m_repaintRects.clear();
184 m_deferredRepaintDelay = initialDeferredRepaintDelayDuringLoading;
185 m_deferredRepaintTimer.stop();
186 m_lastPaintTime = 0;
187 m_paintRestriction = PaintRestrictionNone;
188 m_isPainting = false;
189 m_isVisuallyNonEmpty = false;
190 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
191 m_maintainScrollPositionAnchor = 0;
192 }
193
isFrameView() const194 bool FrameView::isFrameView() const
195 {
196 return true;
197 }
198
clearFrame()199 void FrameView::clearFrame()
200 {
201 m_frame = 0;
202 }
203
resetScrollbars()204 void FrameView::resetScrollbars()
205 {
206 // Reset the document's scrollbars back to our defaults before we yield the floor.
207 m_firstLayout = true;
208 setScrollbarsSuppressed(true);
209 setScrollbarModes(m_hmode, m_vmode);
210 setScrollbarsSuppressed(false);
211 }
212
init()213 void FrameView::init()
214 {
215 reset();
216
217 m_margins = IntSize(-1, -1); // undefined
218 m_size = IntSize();
219
220 // Propagate the marginwidth/height and scrolling modes to the view.
221 Element* ownerElement = m_frame && m_frame->document() ? m_frame->document()->ownerElement() : 0;
222 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
223 HTMLFrameElement* frameElt = static_cast<HTMLFrameElement*>(ownerElement);
224 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
225 setCanHaveScrollbars(false);
226 int marginWidth = frameElt->getMarginWidth();
227 int marginHeight = frameElt->getMarginHeight();
228 if (marginWidth != -1)
229 setMarginWidth(marginWidth);
230 if (marginHeight != -1)
231 setMarginHeight(marginHeight);
232 }
233 }
234
detachCustomScrollbars()235 void FrameView::detachCustomScrollbars()
236 {
237 if (!m_frame)
238 return;
239
240 Document* document = m_frame->document();
241 if (!document)
242 return;
243
244 Element* body = document->body();
245 if (!body)
246 return;
247
248 RenderBox* renderBox = body->renderBox();
249
250 Scrollbar* horizontalBar = horizontalScrollbar();
251 if (horizontalBar && horizontalBar->isCustomScrollbar() && toRenderScrollbar(horizontalBar)->owningRenderer() == renderBox)
252 setHasHorizontalScrollbar(false);
253
254 Scrollbar* verticalBar = verticalScrollbar();
255 if (verticalBar && verticalBar->isCustomScrollbar() && toRenderScrollbar(verticalBar)->owningRenderer() == renderBox)
256 setHasVerticalScrollbar(false);
257 }
258
clear()259 void FrameView::clear()
260 {
261 setCanBlitOnScroll(true);
262
263 reset();
264
265 if (m_frame) {
266 if (RenderPart* renderer = m_frame->ownerRenderer())
267 renderer->viewCleared();
268 }
269
270 setScrollbarsSuppressed(true);
271 }
272
didFirstLayout() const273 bool FrameView::didFirstLayout() const
274 {
275 return !m_firstLayout;
276 }
277
initScrollbars()278 void FrameView::initScrollbars()
279 {
280 if (!m_needToInitScrollbars)
281 return;
282 m_needToInitScrollbars = false;
283 updateDefaultScrollbarState();
284 }
285
updateDefaultScrollbarState()286 void FrameView::updateDefaultScrollbarState()
287 {
288 m_hmode = horizontalScrollbarMode();
289 m_vmode = verticalScrollbarMode();
290 setScrollbarModes(m_hmode, m_vmode);
291 }
292
invalidateRect(const IntRect & rect)293 void FrameView::invalidateRect(const IntRect& rect)
294 {
295 if (!parent()) {
296 if (hostWindow())
297 hostWindow()->repaint(rect, true);
298 return;
299 }
300
301 if (!m_frame)
302 return;
303
304 RenderPart* renderer = m_frame->ownerRenderer();
305 if (!renderer)
306 return;
307
308 IntRect repaintRect = rect;
309 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
310 renderer->borderTop() + renderer->paddingTop());
311 renderer->repaintRectangle(repaintRect);
312 }
313
setMarginWidth(int w)314 void FrameView::setMarginWidth(int w)
315 {
316 // make it update the rendering area when set
317 m_margins.setWidth(w);
318 }
319
setMarginHeight(int h)320 void FrameView::setMarginHeight(int h)
321 {
322 // make it update the rendering area when set
323 m_margins.setHeight(h);
324 }
325
setCanHaveScrollbars(bool canScroll)326 void FrameView::setCanHaveScrollbars(bool canScroll)
327 {
328 ScrollView::setCanHaveScrollbars(canScroll);
329 scrollbarModes(m_hmode, m_vmode);
330 }
331
createScrollbar(ScrollbarOrientation orientation)332 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
333 {
334 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
335 Document* doc = m_frame->document();
336
337 // Try the <body> element first as a scrollbar source.
338 Element* body = doc ? doc->body() : 0;
339 if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(SCROLLBAR))
340 return RenderScrollbar::createCustomScrollbar(this, orientation, body->renderBox());
341
342 // If the <body> didn't have a custom style, then the root element might.
343 Element* docElement = doc ? doc->documentElement() : 0;
344 if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(SCROLLBAR))
345 return RenderScrollbar::createCustomScrollbar(this, orientation, docElement->renderBox());
346
347 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
348 RenderPart* frameRenderer = m_frame->ownerRenderer();
349 if (frameRenderer && frameRenderer->style()->hasPseudoStyle(SCROLLBAR))
350 return RenderScrollbar::createCustomScrollbar(this, orientation, frameRenderer);
351
352 // Nobody set a custom style, so we just use a native scrollbar.
353 return ScrollView::createScrollbar(orientation);
354 }
355
setContentsSize(const IntSize & size)356 void FrameView::setContentsSize(const IntSize& size)
357 {
358 m_deferSetNeedsLayouts++;
359
360 ScrollView::setContentsSize(size);
361
362 Page* page = frame() ? frame()->page() : 0;
363 if (!page)
364 return;
365
366 page->chrome()->contentsSizeChanged(frame(), size); //notify only
367
368 m_deferSetNeedsLayouts--;
369
370 if (!m_deferSetNeedsLayouts)
371 m_setNeedsLayoutWasDeferred = false; // FIXME: Find a way to make the deferred layout actually happen.
372 }
373
adjustViewSize()374 void FrameView::adjustViewSize()
375 {
376 ASSERT(m_frame->view() == this);
377 RenderView* root = m_frame->contentRenderer();
378 if (!root)
379 return;
380 setContentsSize(IntSize(root->overflowWidth(), root->overflowHeight()));
381 }
382
applyOverflowToViewport(RenderObject * o,ScrollbarMode & hMode,ScrollbarMode & vMode)383 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
384 {
385 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
386 // overflow:hidden and overflow:scroll on <body> as applying to the document's
387 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
388 // use the root element.
389 switch (o->style()->overflowX()) {
390 case OHIDDEN:
391 hMode = ScrollbarAlwaysOff;
392 break;
393 case OSCROLL:
394 hMode = ScrollbarAlwaysOn;
395 break;
396 case OAUTO:
397 hMode = ScrollbarAuto;
398 break;
399 default:
400 // Don't set it at all.
401 ;
402 }
403
404 switch (o->style()->overflowY()) {
405 case OHIDDEN:
406 vMode = ScrollbarAlwaysOff;
407 break;
408 case OSCROLL:
409 vMode = ScrollbarAlwaysOn;
410 break;
411 case OAUTO:
412 vMode = ScrollbarAuto;
413 break;
414 default:
415 // Don't set it at all.
416 ;
417 }
418
419 m_viewportRenderer = o;
420 }
421
422 #if USE(ACCELERATED_COMPOSITING)
updateCompositingLayers()423 void FrameView::updateCompositingLayers()
424 {
425 RenderView* view = m_frame->contentRenderer();
426 if (!view)
427 return;
428
429 // This call will make sure the cached hasAcceleratedCompositing is updated from the pref
430 view->compositor()->cacheAcceleratedCompositingEnabledFlag();
431
432 if (!view->usesCompositing())
433 return;
434
435 view->compositor()->updateCompositingLayers();
436 }
437
setNeedsOneShotDrawingSynchronization()438 void FrameView::setNeedsOneShotDrawingSynchronization()
439 {
440 Page* page = frame() ? frame()->page() : 0;
441 if (page)
442 page->chrome()->client()->setNeedsOneShotDrawingSynchronization();
443 }
444 #endif // USE(ACCELERATED_COMPOSITING)
445
syncCompositingStateRecursive()446 bool FrameView::syncCompositingStateRecursive()
447 {
448 #if USE(ACCELERATED_COMPOSITING)
449 ASSERT(m_frame->view() == this);
450 RenderView* contentRenderer = m_frame->contentRenderer();
451 if (!contentRenderer)
452 return true; // We don't want to keep trying to update layers if we have no renderer.
453
454 if (m_layoutTimer.isActive()) {
455 // Don't sync layers if there's a layout pending.
456 return false;
457 }
458
459 if (GraphicsLayer* rootLayer = contentRenderer->compositor()->rootPlatformLayer())
460 rootLayer->syncCompositingState();
461
462 bool allSubframesSynced = true;
463 const HashSet<RefPtr<Widget> >* viewChildren = children();
464 HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
465 for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
466 Widget* widget = (*current).get();
467 if (widget->isFrameView()) {
468 bool synced = static_cast<FrameView*>(widget)->syncCompositingStateRecursive();
469 allSubframesSynced &= synced;
470 }
471 }
472 return allSubframesSynced;
473 #endif // USE(ACCELERATED_COMPOSITING)
474 return true;
475 }
476
didMoveOnscreen()477 void FrameView::didMoveOnscreen()
478 {
479 RenderView* view = m_frame->contentRenderer();
480 if (view)
481 view->didMoveOnscreen();
482 }
483
willMoveOffscreen()484 void FrameView::willMoveOffscreen()
485 {
486 RenderView* view = m_frame->contentRenderer();
487 if (view)
488 view->willMoveOffscreen();
489 }
490
layoutRoot(bool onlyDuringLayout) const491 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
492 {
493 return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot;
494 }
495
layout(bool allowSubtree)496 void FrameView::layout(bool allowSubtree)
497 {
498 if (m_midLayout)
499 return;
500
501 m_layoutTimer.stop();
502 m_delayedLayout = false;
503 m_setNeedsLayoutWasDeferred = false;
504
505 // Protect the view from being deleted during layout (in recalcStyle)
506 RefPtr<FrameView> protector(this);
507
508 if (!m_frame) {
509 // FIXME: Do we need to set m_size.width here?
510 // FIXME: Should we set m_size.height here too?
511 m_size.setWidth(layoutWidth());
512 return;
513 }
514
515 // we shouldn't enter layout() while painting
516 ASSERT(!isPainting());
517 if (isPainting())
518 return;
519
520 if (!allowSubtree && m_layoutRoot) {
521 m_layoutRoot->markContainingBlocksForLayout(false);
522 m_layoutRoot = 0;
523 }
524
525 ASSERT(m_frame->view() == this);
526 // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a
527 // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful
528 // failure instead.
529 if (m_frame->view() != this)
530 return;
531
532 Document* document = m_frame->document();
533
534 m_layoutSchedulingEnabled = false;
535
536 if (!m_nestedLayoutCount && m_postLayoutTasksTimer.isActive()) {
537 // This is a new top-level layout. If there are any remaining tasks from the previous
538 // layout, finish them now.
539 m_postLayoutTasksTimer.stop();
540 performPostLayoutTasks();
541 }
542
543 // Viewport-dependent media queries may cause us to need completely different style information.
544 // Check that here.
545 if (document->styleSelector()->affectedByViewportChange())
546 document->updateStyleSelector();
547
548 // Always ensure our style info is up-to-date. This can happen in situations where
549 // the layout beats any sort of style recalc update that needs to occur.
550 if (m_frame->needsReapplyStyles())
551 m_frame->reapplyStyles();
552 else if (document->childNeedsStyleRecalc())
553 document->recalcStyle();
554
555 bool subtree = m_layoutRoot;
556
557 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
558 // so there's no point to continuing to layout
559 if (protector->hasOneRef())
560 return;
561
562 RenderObject* root = subtree ? m_layoutRoot : document->renderer();
563 if (!root) {
564 // FIXME: Do we need to set m_size here?
565 m_layoutSchedulingEnabled = true;
566 return;
567 }
568
569 #ifdef ANDROID_INSTRUMENT
570 if (!m_frame->tree() || !m_frame->tree()->parent())
571 android::TimeCounter::start(android::TimeCounter::LayoutTimeCounter);
572 #endif
573
574 m_nestedLayoutCount++;
575
576 ScrollbarMode hMode = m_hmode;
577 ScrollbarMode vMode = m_vmode;
578
579 if (!subtree) {
580 RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
581 Node* body = document->body();
582 if (body && body->renderer()) {
583 if (body->hasTagName(framesetTag)) {
584 body->renderer()->setChildNeedsLayout(true);
585 vMode = ScrollbarAlwaysOff;
586 hMode = ScrollbarAlwaysOff;
587 } else if (body->hasTagName(bodyTag)) {
588 if (!m_firstLayout && m_size.height() != layoutHeight()
589 && toRenderBox(body->renderer())->stretchesToViewHeight())
590 body->renderer()->setChildNeedsLayout(true);
591 // It's sufficient to just check the X overflow,
592 // since it's illegal to have visible in only one direction.
593 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
594 applyOverflowToViewport(o, hMode, vMode);
595 }
596 } else if (rootRenderer)
597 applyOverflowToViewport(rootRenderer, hMode, vMode);
598 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
599 if (m_firstLayout && !document->ownerElement())
600 printf("Elapsed time before first layout: %d\n", document->elapsedTime());
601 #endif
602 }
603
604 m_doFullRepaint = !subtree && (m_firstLayout || toRenderView(root)->printing());
605
606 if (!subtree) {
607 // Now set our scrollbar state for the layout.
608 ScrollbarMode currentHMode = horizontalScrollbarMode();
609 ScrollbarMode currentVMode = verticalScrollbarMode();
610
611 if (m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
612 setScrollbarsSuppressed(true);
613 if (m_firstLayout) {
614 m_firstLayout = false;
615 m_firstLayoutCallbackPending = true;
616 m_lastLayoutSize = IntSize(width(), height());
617 m_lastZoomFactor = root->style()->zoom();
618
619 // Set the initial vMode to AlwaysOn if we're auto.
620 if (vMode == ScrollbarAuto)
621 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
622 // Set the initial hMode to AlwaysOff if we're auto.
623 if (hMode == ScrollbarAuto)
624 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
625 }
626 setScrollbarModes(hMode, vMode);
627 setScrollbarsSuppressed(false, true);
628 }
629
630 IntSize oldSize = m_size;
631
632 m_size = IntSize(layoutWidth(), layoutHeight());
633
634 if (oldSize != m_size)
635 m_doFullRepaint = true;
636 }
637
638 RenderLayer* layer = root->enclosingLayer();
639
640 pauseScheduledEvents();
641
642 if (subtree)
643 root->view()->pushLayoutState(root);
644
645 m_midLayout = true;
646 beginDeferredRepaints();
647 root->layout();
648 endDeferredRepaints();
649 m_midLayout = false;
650
651 if (subtree)
652 root->view()->popLayoutState();
653 m_layoutRoot = 0;
654
655 m_frame->invalidateSelection();
656
657 m_layoutSchedulingEnabled = true;
658
659 if (!subtree && !toRenderView(root)->printing())
660 adjustViewSize();
661
662 // Now update the positions of all layers.
663 beginDeferredRepaints();
664 layer->updateLayerPositions((m_doFullRepaint ? RenderLayer::DoFullRepaint : 0)
665 | RenderLayer::CheckForRepaint
666 | RenderLayer::UpdateCompositingLayers);
667 endDeferredRepaints();
668
669 #if USE(ACCELERATED_COMPOSITING)
670 updateCompositingLayers();
671 #endif
672
673 m_layoutCount++;
674
675 #if PLATFORM(MAC)
676 if (AXObjectCache::accessibilityEnabled())
677 root->document()->axObjectCache()->postNotification(root, "AXLayoutComplete", true);
678 #endif
679 #if ENABLE(DASHBOARD_SUPPORT)
680 updateDashboardRegions();
681 #endif
682
683 #ifdef ANDROID_INSTRUMENT
684 if (!m_frame->tree()->parent())
685 android::TimeCounter::record(android::TimeCounter::LayoutTimeCounter, __FUNCTION__);
686 #endif
687 ASSERT(!root->needsLayout());
688
689 setCanBlitOnScroll(!useSlowRepaints());
690
691 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
692 updateOverflowStatus(layoutWidth() < contentsWidth(),
693 layoutHeight() < contentsHeight());
694
695 if (!m_postLayoutTasksTimer.isActive()) {
696 // Calls resumeScheduledEvents()
697 performPostLayoutTasks();
698
699 if (!m_postLayoutTasksTimer.isActive() && needsLayout()) {
700 // Post-layout widget updates or an event handler made us need layout again.
701 // Lay out again, but this time defer widget updates and event dispatch until after
702 // we return.
703 m_postLayoutTasksTimer.startOneShot(0);
704 pauseScheduledEvents();
705 layout();
706 }
707 } else {
708 resumeScheduledEvents();
709 ASSERT(m_enqueueEvents);
710 }
711
712 m_nestedLayoutCount--;
713 }
714
addWidgetToUpdate(RenderPartObject * object)715 void FrameView::addWidgetToUpdate(RenderPartObject* object)
716 {
717 if (!m_widgetUpdateSet)
718 m_widgetUpdateSet.set(new HashSet<RenderPartObject*>);
719
720 m_widgetUpdateSet->add(object);
721 }
722
removeWidgetToUpdate(RenderPartObject * object)723 void FrameView::removeWidgetToUpdate(RenderPartObject* object)
724 {
725 if (!m_widgetUpdateSet)
726 return;
727
728 m_widgetUpdateSet->remove(object);
729 }
730
setMediaType(const String & mediaType)731 void FrameView::setMediaType(const String& mediaType)
732 {
733 m_mediaType = mediaType;
734 }
735
mediaType() const736 String FrameView::mediaType() const
737 {
738 // See if we have an override type.
739 String overrideType = m_frame->loader()->client()->overrideMediaType();
740 if (!overrideType.isNull())
741 return overrideType;
742 return m_mediaType;
743 }
744
useSlowRepaints() const745 bool FrameView::useSlowRepaints() const
746 {
747 return m_useSlowRepaints || m_slowRepaintObjectCount > 0 || m_isOverlapped || !m_contentIsOpaque;
748 }
749
setUseSlowRepaints()750 void FrameView::setUseSlowRepaints()
751 {
752 m_useSlowRepaints = true;
753 setCanBlitOnScroll(false);
754 }
755
addSlowRepaintObject()756 void FrameView::addSlowRepaintObject()
757 {
758 if (!m_slowRepaintObjectCount)
759 setCanBlitOnScroll(false);
760 m_slowRepaintObjectCount++;
761 }
762
removeSlowRepaintObject()763 void FrameView::removeSlowRepaintObject()
764 {
765 ASSERT(m_slowRepaintObjectCount > 0);
766 m_slowRepaintObjectCount--;
767 if (!m_slowRepaintObjectCount)
768 setCanBlitOnScroll(!useSlowRepaints());
769 }
770
setIsOverlapped(bool isOverlapped)771 void FrameView::setIsOverlapped(bool isOverlapped)
772 {
773 if (isOverlapped == m_isOverlapped)
774 return;
775
776 m_isOverlapped = isOverlapped;
777 setCanBlitOnScroll(!useSlowRepaints());
778 }
779
setContentIsOpaque(bool contentIsOpaque)780 void FrameView::setContentIsOpaque(bool contentIsOpaque)
781 {
782 if (contentIsOpaque == m_contentIsOpaque)
783 return;
784
785 m_contentIsOpaque = contentIsOpaque;
786 setCanBlitOnScroll(!useSlowRepaints());
787 }
788
restoreScrollbar()789 void FrameView::restoreScrollbar()
790 {
791 setScrollbarsSuppressed(false);
792 }
793
maintainScrollPositionAtAnchor(Node * anchorNode)794 void FrameView::maintainScrollPositionAtAnchor(Node* anchorNode)
795 {
796 m_maintainScrollPositionAnchor = anchorNode;
797 if (!m_maintainScrollPositionAnchor)
798 return;
799
800 // We need to update the layout before scrolling, otherwise we could
801 // really mess things up if an anchor scroll comes at a bad moment.
802 m_frame->document()->updateStyleIfNeeded();
803 // Only do a layout if changes have occurred that make it necessary.
804 if (m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout())
805 layout();
806 else
807 scrollToAnchor();
808 }
809
scrollRectIntoViewRecursively(const IntRect & r)810 void FrameView::scrollRectIntoViewRecursively(const IntRect& r)
811 {
812 bool wasInProgrammaticScroll = m_inProgrammaticScroll;
813 m_inProgrammaticScroll = true;
814 m_maintainScrollPositionAnchor = 0;
815 ScrollView::scrollRectIntoViewRecursively(r);
816 m_inProgrammaticScroll = wasInProgrammaticScroll;
817 }
818
setScrollPosition(const IntPoint & scrollPoint)819 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
820 {
821 bool wasInProgrammaticScroll = m_inProgrammaticScroll;
822 m_inProgrammaticScroll = true;
823 m_maintainScrollPositionAnchor = 0;
824 ScrollView::setScrollPosition(scrollPoint);
825 m_inProgrammaticScroll = wasInProgrammaticScroll;
826 }
827
hostWindow() const828 HostWindow* FrameView::hostWindow() const
829 {
830 Page* page = frame() ? frame()->page() : 0;
831 if (!page)
832 return 0;
833 return page->chrome();
834 }
835
836 const unsigned cRepaintRectUnionThreshold = 25;
837
repaintContentRectangle(const IntRect & r,bool immediate)838 void FrameView::repaintContentRectangle(const IntRect& r, bool immediate)
839 {
840 ASSERT(!m_frame->document()->ownerElement());
841
842 double delay = adjustedDeferredRepaintDelay();
843 if ((m_deferringRepaints || m_deferredRepaintTimer.isActive() || delay) && !immediate) {
844 IntRect visibleContent = visibleContentRect();
845 visibleContent.intersect(r);
846 #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
847 if (visibleContent.isEmpty())
848 ScrollView::platformOffscreenContentRectangle(r);
849 #endif
850 if (visibleContent.isEmpty())
851 return;
852 if (m_repaintCount == cRepaintRectUnionThreshold) {
853 IntRect unionedRect;
854 for (unsigned i = 0; i < cRepaintRectUnionThreshold; ++i)
855 unionedRect.unite(m_repaintRects[i]);
856 m_repaintRects.clear();
857 m_repaintRects.append(unionedRect);
858 }
859 if (m_repaintCount < cRepaintRectUnionThreshold)
860 m_repaintRects.append(r);
861 else
862 m_repaintRects[0].unite(r);
863 m_repaintCount++;
864
865 if (!m_deferringRepaints && !m_deferredRepaintTimer.isActive())
866 m_deferredRepaintTimer.startOneShot(delay);
867 return;
868 }
869
870 if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen())
871 return;
872
873 ScrollView::repaintContentRectangle(r, immediate);
874 }
875
visibleContentsResized()876 void FrameView::visibleContentsResized()
877 {
878 // We check to make sure the view is attached to a frame() as this method can
879 // be triggered before the view is attached by Frame::createView(...) setting
880 // various values such as setScrollBarModes(...) for example. An ASSERT is
881 // triggered when a view is layout before being attached to a frame().
882 if (!frame()->view())
883 return;
884
885 if (needsLayout())
886 layout();
887 }
888
beginDeferredRepaints()889 void FrameView::beginDeferredRepaints()
890 {
891 Page* page = m_frame->page();
892 if (page->mainFrame() != m_frame)
893 return page->mainFrame()->view()->beginDeferredRepaints();
894
895 m_deferringRepaints++;
896 }
897
898
endDeferredRepaints()899 void FrameView::endDeferredRepaints()
900 {
901 Page* page = m_frame->page();
902 if (page->mainFrame() != m_frame)
903 return page->mainFrame()->view()->endDeferredRepaints();
904
905 ASSERT(m_deferringRepaints > 0);
906
907 if (--m_deferringRepaints)
908 return;
909
910 if (m_deferredRepaintTimer.isActive())
911 return;
912
913 if (double delay = adjustedDeferredRepaintDelay()) {
914 m_deferredRepaintTimer.startOneShot(delay);
915 return;
916 }
917
918 doDeferredRepaints();
919 }
920
checkStopDelayingDeferredRepaints()921 void FrameView::checkStopDelayingDeferredRepaints()
922 {
923 if (!m_deferredRepaintTimer.isActive())
924 return;
925
926 Document* document = m_frame->document();
927 if (document && (document->parsing() || document->docLoader()->requestCount()))
928 return;
929
930 m_deferredRepaintTimer.stop();
931
932 doDeferredRepaints();
933 }
934
doDeferredRepaints()935 void FrameView::doDeferredRepaints()
936 {
937 ASSERT(!m_deferringRepaints);
938 if (isOffscreen() && !shouldUpdateWhileOffscreen()) {
939 m_repaintRects.clear();
940 m_repaintCount = 0;
941 return;
942 }
943 unsigned size = m_repaintRects.size();
944 for (unsigned i = 0; i < size; i++)
945 ScrollView::repaintContentRectangle(m_repaintRects[i], false);
946 m_repaintRects.clear();
947 m_repaintCount = 0;
948
949 updateDeferredRepaintDelay();
950 }
951
updateDeferredRepaintDelay()952 void FrameView::updateDeferredRepaintDelay()
953 {
954 Document* document = m_frame->document();
955 if (!document || (!document->parsing() && !document->docLoader()->requestCount())) {
956 m_deferredRepaintDelay = deferredRepaintDelay;
957 return;
958 }
959 if (m_deferredRepaintDelay < maxDeferredRepaintDelayDuringLoading) {
960 m_deferredRepaintDelay += deferredRepaintDelayIncrementDuringLoading;
961 if (m_deferredRepaintDelay > maxDeferredRepaintDelayDuringLoading)
962 m_deferredRepaintDelay = maxDeferredRepaintDelayDuringLoading;
963 }
964 }
965
resetDeferredRepaintDelay()966 void FrameView::resetDeferredRepaintDelay()
967 {
968 m_deferredRepaintDelay = 0;
969 if (m_deferredRepaintTimer.isActive()) {
970 m_deferredRepaintTimer.stop();
971 if (!m_deferringRepaints)
972 doDeferredRepaints();
973 }
974 }
975
adjustedDeferredRepaintDelay() const976 double FrameView::adjustedDeferredRepaintDelay() const
977 {
978 if (!m_deferredRepaintDelay)
979 return 0;
980 double timeSinceLastPaint = currentTime() - m_lastPaintTime;
981 return max(0., m_deferredRepaintDelay - timeSinceLastPaint);
982 }
983
deferredRepaintTimerFired(Timer<FrameView> *)984 void FrameView::deferredRepaintTimerFired(Timer<FrameView>*)
985 {
986 doDeferredRepaints();
987 }
988
layoutTimerFired(Timer<FrameView> *)989 void FrameView::layoutTimerFired(Timer<FrameView>*)
990 {
991 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
992 if (!m_frame->document()->ownerElement())
993 printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
994 #endif
995 layout();
996 }
997
scheduleRelayout()998 void FrameView::scheduleRelayout()
999 {
1000 ASSERT(!m_frame->document()->inPageCache());
1001 ASSERT(m_frame->view() == this);
1002
1003 if (m_layoutRoot) {
1004 m_layoutRoot->markContainingBlocksForLayout(false);
1005 m_layoutRoot = 0;
1006 }
1007 if (!m_layoutSchedulingEnabled)
1008 return;
1009 if (!needsLayout())
1010 return;
1011 if (!m_frame->document()->shouldScheduleLayout())
1012 return;
1013
1014 #if defined(FLATTEN_IFRAME) || defined(FLATTEN_FRAMESET)
1015 if (m_frame->ownerRenderer())
1016 m_frame->ownerRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
1017 #endif
1018
1019 #ifdef ANDROID_MOBILE
1020 int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay();
1021 #else
1022 int delay = m_frame->document()->minimumLayoutDelay();
1023 #endif
1024 if (m_layoutTimer.isActive() && m_delayedLayout && !delay)
1025 unscheduleRelayout();
1026 if (m_layoutTimer.isActive())
1027 return;
1028
1029 m_delayedLayout = delay != 0;
1030
1031 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1032 if (!m_frame->document()->ownerElement())
1033 printf("Scheduling layout for %d\n", delay);
1034 #endif
1035
1036 m_layoutTimer.startOneShot(delay * 0.001);
1037 }
1038
isObjectAncestorContainerOf(RenderObject * ancestor,RenderObject * descendant)1039 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
1040 {
1041 for (RenderObject* r = descendant; r; r = r->container()) {
1042 if (r == ancestor)
1043 return true;
1044 }
1045 return false;
1046 }
1047
scheduleRelayoutOfSubtree(RenderObject * relayoutRoot)1048 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
1049 {
1050 ASSERT(m_frame->view() == this);
1051
1052 if (!m_layoutSchedulingEnabled || (m_frame->contentRenderer()
1053 && m_frame->contentRenderer()->needsLayout())) {
1054 if (relayoutRoot)
1055 relayoutRoot->markContainingBlocksForLayout(false);
1056 return;
1057 }
1058
1059 if (layoutPending()) {
1060 if (m_layoutRoot != relayoutRoot) {
1061 if (isObjectAncestorContainerOf(m_layoutRoot, relayoutRoot)) {
1062 // Keep the current root
1063 relayoutRoot->markContainingBlocksForLayout(false, m_layoutRoot);
1064 } else if (m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, m_layoutRoot)) {
1065 // Re-root at relayoutRoot
1066 m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot);
1067 m_layoutRoot = relayoutRoot;
1068 } else {
1069 // Just do a full relayout
1070 if (m_layoutRoot)
1071 m_layoutRoot->markContainingBlocksForLayout(false);
1072 m_layoutRoot = 0;
1073 relayoutRoot->markContainingBlocksForLayout(false);
1074 }
1075 }
1076 } else {
1077 #ifdef ANDROID_MOBILE
1078 int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay();
1079 #else
1080 int delay = m_frame->document()->minimumLayoutDelay();
1081 #endif
1082 m_layoutRoot = relayoutRoot;
1083 m_delayedLayout = delay != 0;
1084 m_layoutTimer.startOneShot(delay * 0.001);
1085 }
1086 }
1087
layoutPending() const1088 bool FrameView::layoutPending() const
1089 {
1090 return m_layoutTimer.isActive();
1091 }
1092
needsLayout() const1093 bool FrameView::needsLayout() const
1094 {
1095 // This can return true in cases where the document does not have a body yet.
1096 // Document::shouldScheduleLayout takes care of preventing us from scheduling
1097 // layout in that case.
1098 if (!m_frame)
1099 return false;
1100 RenderView* root = m_frame->contentRenderer();
1101 Document* document = m_frame->document();
1102 return layoutPending()
1103 || (root && root->needsLayout())
1104 || m_layoutRoot
1105 || (document && document->childNeedsStyleRecalc()) // can occur when using WebKit ObjC interface
1106 || m_frame->needsReapplyStyles()
1107 || (m_deferSetNeedsLayouts && m_setNeedsLayoutWasDeferred);
1108 }
1109
setNeedsLayout()1110 void FrameView::setNeedsLayout()
1111 {
1112 if (m_deferSetNeedsLayouts) {
1113 m_setNeedsLayoutWasDeferred = true;
1114 return;
1115 }
1116 RenderView* root = m_frame->contentRenderer();
1117 if (root)
1118 root->setNeedsLayout(true);
1119 }
1120
unscheduleRelayout()1121 void FrameView::unscheduleRelayout()
1122 {
1123 if (!m_layoutTimer.isActive())
1124 return;
1125
1126 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
1127 if (!m_frame->document()->ownerElement())
1128 printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
1129 #endif
1130
1131 m_layoutTimer.stop();
1132 m_delayedLayout = false;
1133 }
1134
isTransparent() const1135 bool FrameView::isTransparent() const
1136 {
1137 return m_isTransparent;
1138 }
1139
setTransparent(bool isTransparent)1140 void FrameView::setTransparent(bool isTransparent)
1141 {
1142 m_isTransparent = isTransparent;
1143 }
1144
baseBackgroundColor() const1145 Color FrameView::baseBackgroundColor() const
1146 {
1147 return m_baseBackgroundColor;
1148 }
1149
setBaseBackgroundColor(Color bc)1150 void FrameView::setBaseBackgroundColor(Color bc)
1151 {
1152 if (!bc.isValid())
1153 bc = Color::white;
1154 m_baseBackgroundColor = bc;
1155 }
1156
updateBackgroundRecursively(const Color & backgroundColor,bool transparent)1157 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
1158 {
1159 for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) {
1160 FrameView* view = frame->view();
1161 if (!view)
1162 continue;
1163
1164 view->setTransparent(transparent);
1165 view->setBaseBackgroundColor(backgroundColor);
1166 }
1167 }
1168
shouldUpdateWhileOffscreen() const1169 bool FrameView::shouldUpdateWhileOffscreen() const
1170 {
1171 return m_shouldUpdateWhileOffscreen;
1172 }
1173
setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)1174 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
1175 {
1176 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
1177 }
1178
scheduleEvent(PassRefPtr<Event> event,PassRefPtr<Node> eventTarget)1179 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<Node> eventTarget)
1180 {
1181 if (!m_enqueueEvents) {
1182 ExceptionCode ec = 0;
1183 eventTarget->dispatchEvent(event, ec);
1184 return;
1185 }
1186
1187 ScheduledEvent* scheduledEvent = new ScheduledEvent;
1188 scheduledEvent->m_event = event;
1189 scheduledEvent->m_eventTarget = eventTarget;
1190 m_scheduledEvents.append(scheduledEvent);
1191 }
1192
pauseScheduledEvents()1193 void FrameView::pauseScheduledEvents()
1194 {
1195 ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents);
1196 m_enqueueEvents++;
1197 }
1198
resumeScheduledEvents()1199 void FrameView::resumeScheduledEvents()
1200 {
1201 m_enqueueEvents--;
1202 if (!m_enqueueEvents)
1203 dispatchScheduledEvents();
1204 ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents);
1205 }
1206
scrollToAnchor()1207 void FrameView::scrollToAnchor()
1208 {
1209 RefPtr<Node> anchorNode = m_maintainScrollPositionAnchor;
1210 if (!anchorNode)
1211 return;
1212
1213 if (!anchorNode->renderer())
1214 return;
1215
1216 IntRect rect;
1217 if (anchorNode != m_frame->document())
1218 rect = anchorNode->getRect();
1219
1220 // Scroll nested layers and frames to reveal the anchor.
1221 // Align to the top and to the closest side (this matches other browsers).
1222 anchorNode->renderer()->enclosingLayer()->scrollRectToVisible(rect, true, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
1223
1224 // scrollRectToVisible can call into scrollRectIntoViewRecursively(), which resets m_maintainScrollPositionAnchor.
1225 m_maintainScrollPositionAnchor = anchorNode;
1226 }
1227
updateWidgets()1228 bool FrameView::updateWidgets()
1229 {
1230 if (m_nestedLayoutCount > 1 || !m_widgetUpdateSet || m_widgetUpdateSet->isEmpty())
1231 return true;
1232
1233 Vector<RenderPartObject*> objectVector;
1234 copyToVector(*m_widgetUpdateSet, objectVector);
1235 size_t size = objectVector.size();
1236 for (size_t i = 0; i < size; ++i) {
1237 RenderPartObject* object = objectVector[i];
1238 object->updateWidget(false);
1239
1240 // updateWidget() can destroy the RenderPartObject, so we need to make sure it's
1241 // alive by checking if it's still in m_widgetUpdateSet.
1242 if (m_widgetUpdateSet->contains(object)) {
1243 object->updateWidgetPosition();
1244 m_widgetUpdateSet->remove(object);
1245 }
1246 }
1247
1248 return m_widgetUpdateSet->isEmpty();
1249 }
1250
performPostLayoutTasks()1251 void FrameView::performPostLayoutTasks()
1252 {
1253 if (m_firstLayoutCallbackPending) {
1254 m_firstLayoutCallbackPending = false;
1255 m_frame->loader()->didFirstLayout();
1256 }
1257
1258 if (m_isVisuallyNonEmpty && m_firstVisuallyNonEmptyLayoutCallbackPending) {
1259 m_firstVisuallyNonEmptyLayoutCallbackPending = false;
1260 m_frame->loader()->didFirstVisuallyNonEmptyLayout();
1261 }
1262
1263 RenderView* root = m_frame->contentRenderer();
1264
1265 root->updateWidgetPositions();
1266
1267 for (unsigned i = 0; i < maxUpdateWidgetsIterations; i++) {
1268 if (updateWidgets())
1269 break;
1270 }
1271
1272 scrollToAnchor();
1273
1274 resumeScheduledEvents();
1275
1276 if (!root->printing()) {
1277 IntSize currentSize = IntSize(width(), height());
1278 float currentZoomFactor = root->style()->zoom();
1279 bool resized = !m_firstLayout && (currentSize != m_lastLayoutSize || currentZoomFactor != m_lastZoomFactor);
1280 m_lastLayoutSize = currentSize;
1281 m_lastZoomFactor = currentZoomFactor;
1282 if (resized)
1283 m_frame->eventHandler()->sendResizeEvent();
1284 }
1285 }
1286
postLayoutTimerFired(Timer<FrameView> *)1287 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
1288 {
1289 performPostLayoutTasks();
1290 }
1291
updateOverflowStatus(bool horizontalOverflow,bool verticalOverflow)1292 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
1293 {
1294 if (!m_viewportRenderer)
1295 return;
1296
1297 if (m_overflowStatusDirty) {
1298 m_horizontalOverflow = horizontalOverflow;
1299 m_verticalOverflow = verticalOverflow;
1300 m_overflowStatusDirty = false;
1301 return;
1302 }
1303
1304 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
1305 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
1306
1307 if (horizontalOverflowChanged || verticalOverflowChanged) {
1308 m_horizontalOverflow = horizontalOverflow;
1309 m_verticalOverflow = verticalOverflow;
1310
1311 scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
1312 verticalOverflowChanged, verticalOverflow),
1313 m_viewportRenderer->node());
1314 }
1315
1316 }
1317
dispatchScheduledEvents()1318 void FrameView::dispatchScheduledEvents()
1319 {
1320 if (m_scheduledEvents.isEmpty())
1321 return;
1322
1323 Vector<ScheduledEvent*> scheduledEventsCopy = m_scheduledEvents;
1324 m_scheduledEvents.clear();
1325
1326 Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end();
1327 for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) {
1328 ScheduledEvent* scheduledEvent = *it;
1329
1330 ExceptionCode ec = 0;
1331
1332 // Only dispatch events to nodes that are in the document
1333 if (scheduledEvent->m_eventTarget->inDocument())
1334 scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event, ec);
1335
1336 delete scheduledEvent;
1337 }
1338 }
1339
windowClipRect(bool clipToContents) const1340 IntRect FrameView::windowClipRect(bool clipToContents) const
1341 {
1342 ASSERT(m_frame->view() == this);
1343
1344 // Set our clip rect to be our contents.
1345 IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents));
1346 if (!m_frame || !m_frame->document()->ownerElement())
1347 return clipRect;
1348
1349 // Take our owner element and get the clip rect from the enclosing layer.
1350 Element* elt = m_frame->document()->ownerElement();
1351 RenderLayer* layer = elt->renderer()->enclosingLayer();
1352 // FIXME: layer should never be null, but sometimes seems to be anyway.
1353 if (!layer)
1354 return clipRect;
1355 FrameView* parentView = elt->document()->view();
1356 clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
1357 return clipRect;
1358 }
1359
windowClipRectForLayer(const RenderLayer * layer,bool clipToLayerContents) const1360 IntRect FrameView::windowClipRectForLayer(const RenderLayer* layer, bool clipToLayerContents) const
1361 {
1362 // If we have no layer, just return our window clip rect.
1363 if (!layer)
1364 return windowClipRect();
1365
1366 // Apply the clip from the layer.
1367 IntRect clipRect;
1368 if (clipToLayerContents)
1369 clipRect = layer->childrenClipRect();
1370 else
1371 clipRect = layer->selfClipRect();
1372 clipRect = contentsToWindow(clipRect);
1373 return intersection(clipRect, windowClipRect());
1374 }
1375
isActive() const1376 bool FrameView::isActive() const
1377 {
1378 Page* page = frame()->page();
1379 return page && page->focusController()->isActive();
1380 }
1381
valueChanged(Scrollbar * bar)1382 void FrameView::valueChanged(Scrollbar* bar)
1383 {
1384 // Figure out if we really moved.
1385 IntSize offset = scrollOffset();
1386 ScrollView::valueChanged(bar);
1387 if (offset != scrollOffset())
1388 frame()->eventHandler()->sendScrollEvent();
1389 }
1390
invalidateScrollbarRect(Scrollbar * scrollbar,const IntRect & rect)1391 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
1392 {
1393 // Add in our offset within the FrameView.
1394 IntRect dirtyRect = rect;
1395 dirtyRect.move(scrollbar->x(), scrollbar->y());
1396 invalidateRect(dirtyRect);
1397 }
1398
getTickmarks(Vector<IntRect> & tickmarks) const1399 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
1400 {
1401 tickmarks = frame()->document()->renderedRectsForMarkers(DocumentMarker::TextMatch);
1402 }
1403
windowResizerRect() const1404 IntRect FrameView::windowResizerRect() const
1405 {
1406 Page* page = frame() ? frame()->page() : 0;
1407 if (!page)
1408 return IntRect();
1409 return page->chrome()->windowResizerRect();
1410 }
1411
1412 #if ENABLE(DASHBOARD_SUPPORT)
updateDashboardRegions()1413 void FrameView::updateDashboardRegions()
1414 {
1415 Document* document = m_frame->document();
1416 if (!document->hasDashboardRegions())
1417 return;
1418 Vector<DashboardRegionValue> newRegions;
1419 document->renderBox()->collectDashboardRegions(newRegions);
1420 if (newRegions == document->dashboardRegions())
1421 return;
1422 document->setDashboardRegions(newRegions);
1423 Page* page = m_frame->page();
1424 if (!page)
1425 return;
1426 page->chrome()->client()->dashboardRegionsChanged();
1427 }
1428 #endif
1429
updateControlTints()1430 void FrameView::updateControlTints()
1431 {
1432 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
1433 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
1434 // This is only done if the theme supports control tinting. It's up to the theme and platform
1435 // to define when controls get the tint and to call this function when that changes.
1436
1437 // Optimize the common case where we bring a window to the front while it's still empty.
1438 if (!m_frame || m_frame->loader()->url().isEmpty())
1439 return;
1440
1441 if (m_frame->contentRenderer() && m_frame->contentRenderer()->theme()->supportsControlTints()) {
1442 if (needsLayout())
1443 layout();
1444 PlatformGraphicsContext* const noContext = 0;
1445 GraphicsContext context(noContext);
1446 context.setUpdatingControlTints(true);
1447 if (platformWidget())
1448 paintContents(&context, visibleContentRect());
1449 else
1450 paint(&context, frameRect());
1451 }
1452 }
1453
wasScrolledByUser() const1454 bool FrameView::wasScrolledByUser() const
1455 {
1456 return m_wasScrolledByUser;
1457 }
1458
setWasScrolledByUser(bool wasScrolledByUser)1459 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
1460 {
1461 if (m_inProgrammaticScroll)
1462 return;
1463 m_maintainScrollPositionAnchor = 0;
1464 m_wasScrolledByUser = wasScrolledByUser;
1465 }
1466
paintContents(GraphicsContext * p,const IntRect & rect)1467 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
1468 {
1469 if (!frame())
1470 return;
1471
1472 Document* document = frame()->document();
1473
1474 #ifndef NDEBUG
1475 bool fillWithRed;
1476 if (document->printing())
1477 fillWithRed = false; // Printing, don't fill with red (can't remember why).
1478 else if (document->ownerElement())
1479 fillWithRed = false; // Subframe, don't fill with red.
1480 else if (isTransparent())
1481 fillWithRed = false; // Transparent, don't fill with red.
1482 else if (m_paintRestriction == PaintRestrictionSelectionOnly || m_paintRestriction == PaintRestrictionSelectionOnlyBlackText)
1483 fillWithRed = false; // Selections are transparent, don't fill with red.
1484 else if (m_nodeToDraw)
1485 fillWithRed = false; // Element images are transparent, don't fill with red.
1486 else
1487 fillWithRed = true;
1488
1489 if (fillWithRed)
1490 p->fillRect(rect, Color(0xFF, 0, 0));
1491 #endif
1492
1493 bool isTopLevelPainter = !sCurrentPaintTimeStamp;
1494 if (isTopLevelPainter)
1495 sCurrentPaintTimeStamp = currentTime();
1496
1497 RenderView* contentRenderer = frame()->contentRenderer();
1498 if (!contentRenderer) {
1499 LOG_ERROR("called Frame::paint with nil renderer");
1500 return;
1501 }
1502
1503 ASSERT(!needsLayout());
1504 if (needsLayout())
1505 return;
1506
1507 #if USE(ACCELERATED_COMPOSITING)
1508 if (!p->paintingDisabled()) {
1509 if (GraphicsLayer* rootLayer = contentRenderer->compositor()->rootPlatformLayer())
1510 rootLayer->syncCompositingState();
1511 }
1512 #endif
1513
1514 ASSERT(!m_isPainting);
1515
1516 m_isPainting = true;
1517
1518 // m_nodeToDraw is used to draw only one element (and its descendants)
1519 RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
1520 if (m_paintRestriction == PaintRestrictionNone)
1521 document->invalidateRenderedRectsForMarkersInRect(rect);
1522 contentRenderer->layer()->paint(p, rect, m_paintRestriction, eltRenderer);
1523
1524 m_isPainting = false;
1525 m_lastPaintTime = currentTime();
1526
1527 #if ENABLE(DASHBOARD_SUPPORT)
1528 // Regions may have changed as a result of the visibility/z-index of element changing.
1529 if (document->dashboardRegionsDirty())
1530 updateDashboardRegions();
1531 #endif
1532
1533 if (isTopLevelPainter)
1534 sCurrentPaintTimeStamp = 0;
1535 }
1536
setPaintRestriction(PaintRestriction pr)1537 void FrameView::setPaintRestriction(PaintRestriction pr)
1538 {
1539 m_paintRestriction = pr;
1540 }
1541
isPainting() const1542 bool FrameView::isPainting() const
1543 {
1544 return m_isPainting;
1545 }
1546
setNodeToDraw(Node * node)1547 void FrameView::setNodeToDraw(Node* node)
1548 {
1549 m_nodeToDraw = node;
1550 }
1551
layoutIfNeededRecursive()1552 void FrameView::layoutIfNeededRecursive()
1553 {
1554 // We have to crawl our entire tree looking for any FrameViews that need
1555 // layout and make sure they are up to date.
1556 // Mac actually tests for intersection with the dirty region and tries not to
1557 // update layout for frames that are outside the dirty region. Not only does this seem
1558 // pointless (since those frames will have set a zero timer to layout anyway), but
1559 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
1560 // region but then become included later by the second frame adding rects to the dirty region
1561 // when it lays out.
1562
1563 if (needsLayout())
1564 layout();
1565
1566 const HashSet<RefPtr<Widget> >* viewChildren = children();
1567 HashSet<RefPtr<Widget> >::const_iterator end = viewChildren->end();
1568 for (HashSet<RefPtr<Widget> >::const_iterator current = viewChildren->begin(); current != end; ++current) {
1569 Widget* widget = (*current).get();
1570 if (widget->isFrameView())
1571 static_cast<FrameView*>(widget)->layoutIfNeededRecursive();
1572 }
1573
1574 // layoutIfNeededRecursive is called when we need to make sure layout is up-to-date before
1575 // painting, so we need to flush out any deferred repaints too.
1576 if (m_deferredRepaintTimer.isActive()) {
1577 m_deferredRepaintTimer.stop();
1578 doDeferredRepaints();
1579 }
1580 }
1581
forceLayout(bool allowSubtree)1582 void FrameView::forceLayout(bool allowSubtree)
1583 {
1584 layout(allowSubtree);
1585 // We cannot unschedule a pending relayout, since the force can be called with
1586 // a tiny rectangle from a drawRect update. By unscheduling we in effect
1587 // "validate" and stop the necessary full repaint from occurring. Basically any basic
1588 // append/remove DHTML is broken by this call. For now, I have removed the optimization
1589 // until we have a better invalidation stategy. -dwh
1590 //unscheduleRelayout();
1591 }
1592
forceLayoutWithPageWidthRange(float minPageWidth,float maxPageWidth,bool _adjustViewSize)1593 void FrameView::forceLayoutWithPageWidthRange(float minPageWidth, float maxPageWidth, bool _adjustViewSize)
1594 {
1595 // Dumping externalRepresentation(m_frame->renderer()).ascii() is a good trick to see
1596 // the state of things before and after the layout
1597 RenderView *root = toRenderView(m_frame->document()->renderer());
1598 if (root) {
1599 // This magic is basically copied from khtmlview::print
1600 int pageW = (int)ceilf(minPageWidth);
1601 root->setWidth(pageW);
1602 root->setNeedsLayoutAndPrefWidthsRecalc();
1603 forceLayout();
1604
1605 // If we don't fit in the minimum page width, we'll lay out again. If we don't fit in the
1606 // maximum page width, we will lay out to the maximum page width and clip extra content.
1607 // FIXME: We are assuming a shrink-to-fit printing implementation. A cropping
1608 // implementation should not do this!
1609 int rightmostPos = root->rightmostPosition();
1610 if (rightmostPos > minPageWidth) {
1611 pageW = std::min(rightmostPos, (int)ceilf(maxPageWidth));
1612 root->setWidth(pageW);
1613 root->setNeedsLayoutAndPrefWidthsRecalc();
1614 forceLayout();
1615 }
1616 }
1617
1618 if (_adjustViewSize)
1619 adjustViewSize();
1620 }
1621
adjustPageHeight(float * newBottom,float oldTop,float oldBottom,float)1622 void FrameView::adjustPageHeight(float *newBottom, float oldTop, float oldBottom, float /*bottomLimit*/)
1623 {
1624 RenderView* root = m_frame->contentRenderer();
1625 if (root) {
1626 // Use a context with painting disabled.
1627 GraphicsContext context((PlatformGraphicsContext*)0);
1628 root->setTruncatedAt((int)floorf(oldBottom));
1629 IntRect dirtyRect(0, (int)floorf(oldTop), root->overflowWidth(), (int)ceilf(oldBottom - oldTop));
1630 root->layer()->paint(&context, dirtyRect);
1631 *newBottom = root->bestTruncatedAt();
1632 if (*newBottom == 0)
1633 *newBottom = oldBottom;
1634 } else
1635 *newBottom = oldBottom;
1636 }
1637
convertFromRenderer(const RenderObject * renderer,const IntRect & rendererRect) const1638 IntRect FrameView::convertFromRenderer(const RenderObject* renderer, const IntRect& rendererRect) const
1639 {
1640 IntRect rect = renderer->localToAbsoluteQuad(FloatRect(rendererRect)).enclosingBoundingBox();
1641
1642 // Convert from page ("absolute") to FrameView coordinates.
1643 rect.move(-scrollX(), -scrollY());
1644
1645 return rect;
1646 }
1647
convertToRenderer(const RenderObject * renderer,const IntRect & viewRect) const1648 IntRect FrameView::convertToRenderer(const RenderObject* renderer, const IntRect& viewRect) const
1649 {
1650 IntRect rect = viewRect;
1651
1652 // Convert from FrameView coords into page ("absolute") coordinates.
1653 rect.move(scrollX(), scrollY());
1654
1655 // FIXME: we don't have a way to map an absolute rect down to a local quad, so just
1656 // move the rect for now.
1657 rect.setLocation(roundedIntPoint(renderer->absoluteToLocal(rect.location(), false, true /* use transforms */)));
1658 return rect;
1659 }
1660
convertFromRenderer(const RenderObject * renderer,const IntPoint & rendererPoint) const1661 IntPoint FrameView::convertFromRenderer(const RenderObject* renderer, const IntPoint& rendererPoint) const
1662 {
1663 IntPoint point = roundedIntPoint(renderer->localToAbsolute(rendererPoint, false, true /* use transforms */));
1664
1665 // Convert from page ("absolute") to FrameView coordinates.
1666 point.move(-scrollX(), -scrollY());
1667 return point;
1668 }
1669
convertToRenderer(const RenderObject * renderer,const IntPoint & viewPoint) const1670 IntPoint FrameView::convertToRenderer(const RenderObject* renderer, const IntPoint& viewPoint) const
1671 {
1672 IntPoint point = viewPoint;
1673
1674 // Convert from FrameView coords into page ("absolute") coordinates.
1675 point += IntSize(scrollX(), scrollY());
1676
1677 return roundedIntPoint(renderer->absoluteToLocal(point, false, true /* use transforms */));
1678 }
1679
convertToContainingView(const IntRect & localRect) const1680 IntRect FrameView::convertToContainingView(const IntRect& localRect) const
1681 {
1682 if (const ScrollView* parentScrollView = parent()) {
1683 if (parentScrollView->isFrameView()) {
1684 const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
1685 // Get our renderer in the parent view
1686 RenderPart* renderer = m_frame->ownerRenderer();
1687 if (!renderer)
1688 return localRect;
1689
1690 IntRect rect(localRect);
1691 // Add borders and padding??
1692 rect.move(renderer->borderLeft() + renderer->paddingLeft(),
1693 renderer->borderTop() + renderer->paddingTop());
1694 return parentView->convertFromRenderer(renderer, rect);
1695 }
1696
1697 return Widget::convertToContainingView(localRect);
1698 }
1699
1700 return localRect;
1701 }
1702
convertFromContainingView(const IntRect & parentRect) const1703 IntRect FrameView::convertFromContainingView(const IntRect& parentRect) const
1704 {
1705 if (const ScrollView* parentScrollView = parent()) {
1706 if (parentScrollView->isFrameView()) {
1707 const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
1708
1709 // Get our renderer in the parent view
1710 RenderPart* renderer = m_frame->ownerRenderer();
1711 if (!renderer)
1712 return parentRect;
1713
1714 IntRect rect = parentView->convertToRenderer(renderer, parentRect);
1715 // Subtract borders and padding
1716 rect.move(-renderer->borderLeft() - renderer->paddingLeft(),
1717 -renderer->borderTop() - renderer->paddingTop());
1718 return rect;
1719 }
1720
1721 return Widget::convertFromContainingView(parentRect);
1722 }
1723
1724 return parentRect;
1725 }
1726
convertToContainingView(const IntPoint & localPoint) const1727 IntPoint FrameView::convertToContainingView(const IntPoint& localPoint) const
1728 {
1729 if (const ScrollView* parentScrollView = parent()) {
1730 if (parentScrollView->isFrameView()) {
1731 const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
1732
1733 // Get our renderer in the parent view
1734 RenderPart* renderer = m_frame->ownerRenderer();
1735 if (!renderer)
1736 return localPoint;
1737
1738 IntPoint point(localPoint);
1739
1740 // Add borders and padding
1741 point.move(renderer->borderLeft() + renderer->paddingLeft(),
1742 renderer->borderTop() + renderer->paddingTop());
1743 return parentView->convertFromRenderer(renderer, point);
1744 }
1745
1746 return Widget::convertToContainingView(localPoint);
1747 }
1748
1749 return localPoint;
1750 }
1751
convertFromContainingView(const IntPoint & parentPoint) const1752 IntPoint FrameView::convertFromContainingView(const IntPoint& parentPoint) const
1753 {
1754 if (const ScrollView* parentScrollView = parent()) {
1755 if (parentScrollView->isFrameView()) {
1756 const FrameView* parentView = static_cast<const FrameView*>(parentScrollView);
1757
1758 // Get our renderer in the parent view
1759 RenderPart* renderer = m_frame->ownerRenderer();
1760 if (!renderer)
1761 return parentPoint;
1762
1763 IntPoint point = parentView->convertToRenderer(renderer, parentPoint);
1764 // Subtract borders and padding
1765 point.move(-renderer->borderLeft() - renderer->paddingLeft(),
1766 -renderer->borderTop() - renderer->paddingTop());
1767 return point;
1768 }
1769
1770 return Widget::convertFromContainingView(parentPoint);
1771 }
1772
1773 return parentPoint;
1774 }
1775
1776 } // namespace WebCore
1777