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 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25 #include "config.h"
26 #include "FrameView.h"
27
28 #include "AXObjectCache.h"
29 #include "CSSStyleSelector.h"
30 #include "ChromeClient.h"
31 #include "EventHandler.h"
32 #include "FloatRect.h"
33 #include "FocusController.h"
34 #include "Frame.h"
35 #include "FrameLoader.h"
36 #include "FrameLoaderClient.h"
37 #include "FrameTree.h"
38 #include "GraphicsContext.h"
39 #include "HTMLDocument.h"
40 #include "HTMLFrameElement.h"
41 #include "HTMLFrameSetElement.h"
42 #include "HTMLNames.h"
43 #include "OverflowEvent.h"
44 #include "Page.h"
45 #include "RenderPart.h"
46 #include "RenderPartObject.h"
47 #include "RenderScrollbar.h"
48 #include "RenderTheme.h"
49 #include "RenderView.h"
50 #include "Settings.h"
51 #include <wtf/CurrentTime.h>
52
53 #ifdef ANDROID_INSTRUMENT
54 #include "FrameTree.h"
55 #include "TimeCounter.h"
56 #endif
57
58 namespace WebCore {
59
60 using namespace HTMLNames;
61
62 double FrameView::sCurrentPaintTimeStamp = 0.0;
63
64 struct ScheduledEvent {
65 RefPtr<Event> m_event;
66 RefPtr<EventTargetNode> m_eventTarget;
67 };
68
FrameView(Frame * frame)69 FrameView::FrameView(Frame* frame)
70 : m_refCount(1)
71 , m_frame(frame)
72 , m_vmode(ScrollbarAuto)
73 , m_hmode(ScrollbarAuto)
74 , m_slowRepaintObjectCount(0)
75 , m_layoutTimer(this, &FrameView::layoutTimerFired)
76 , m_layoutRoot(0)
77 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
78 , m_needToInitScrollbars(true)
79 , m_isTransparent(false)
80 , m_baseBackgroundColor(Color::white)
81 , m_mediaType("screen")
82 , m_enqueueEvents(0)
83 , m_overflowStatusDirty(true)
84 , m_viewportRenderer(0)
85 , m_wasScrolledByUser(false)
86 , m_inProgrammaticScroll(false)
87 , m_shouldUpdateWhileOffscreen(true)
88 {
89 init();
90 show();
91 }
92
FrameView(Frame * frame,const IntSize & initialSize)93 FrameView::FrameView(Frame* frame, const IntSize& initialSize)
94 : m_refCount(1)
95 , m_frame(frame)
96 , m_vmode(ScrollbarAuto)
97 , m_hmode(ScrollbarAuto)
98 , m_slowRepaintObjectCount(0)
99 , m_layoutTimer(this, &FrameView::layoutTimerFired)
100 , m_layoutRoot(0)
101 , m_postLayoutTasksTimer(this, &FrameView::postLayoutTimerFired)
102 , m_needToInitScrollbars(true)
103 , m_isTransparent(false)
104 , m_baseBackgroundColor(Color::white)
105 , m_mediaType("screen")
106 , m_enqueueEvents(0)
107 , m_overflowStatusDirty(true)
108 , m_viewportRenderer(0)
109 , m_wasScrolledByUser(false)
110 , m_inProgrammaticScroll(false)
111 , m_shouldUpdateWhileOffscreen(true)
112 {
113 init();
114 Widget::setFrameRect(IntRect(x(), y(), initialSize.width(), initialSize.height()));
115 show();
116 }
117
~FrameView()118 FrameView::~FrameView()
119 {
120 if (m_postLayoutTasksTimer.isActive()) {
121 m_postLayoutTasksTimer.stop();
122 m_scheduledEvents.clear();
123 m_enqueueEvents = 0;
124 }
125
126 resetScrollbars();
127 setHasHorizontalScrollbar(false); // Remove native scrollbars now before we lose the connection to the HostWindow.
128 setHasVerticalScrollbar(false);
129
130 ASSERT(m_refCount == 0);
131 ASSERT(m_scheduledEvents.isEmpty());
132 ASSERT(!m_enqueueEvents);
133
134 if (m_frame) {
135 ASSERT(m_frame->view() != this || !m_frame->document() || !m_frame->contentRenderer());
136 RenderPart* renderer = m_frame->ownerRenderer();
137 if (renderer && renderer->widget() == this)
138 renderer->setWidget(0);
139 }
140 }
141
reset()142 void FrameView::reset()
143 {
144 m_useSlowRepaints = false;
145 m_borderX = 30;
146 m_borderY = 30;
147 m_layoutTimer.stop();
148 m_layoutRoot = 0;
149 m_delayedLayout = false;
150 m_doFullRepaint = true;
151 m_layoutSchedulingEnabled = true;
152 m_midLayout = false;
153 m_layoutCount = 0;
154 m_nestedLayoutCount = 0;
155 m_postLayoutTasksTimer.stop();
156 m_firstLayout = true;
157 m_firstLayoutCallbackPending = false;
158 m_wasScrolledByUser = false;
159 m_lastLayoutSize = IntSize();
160 m_lastZoomFactor = 1.0f;
161 m_deferringRepaints = 0;
162 m_repaintCount = 0;
163 m_repaintRect = IntRect();
164 m_repaintRects.clear();
165 m_paintRestriction = PaintRestrictionNone;
166 m_isPainting = false;
167 m_isVisuallyNonEmpty = false;
168 m_firstVisuallyNonEmptyLayoutCallbackPending = true;
169 }
170
isFrameView() const171 bool FrameView::isFrameView() const
172 {
173 return true;
174 }
175
clearFrame()176 void FrameView::clearFrame()
177 {
178 m_frame = 0;
179 }
180
resetScrollbars()181 void FrameView::resetScrollbars()
182 {
183 // Reset the document's scrollbars back to our defaults before we yield the floor.
184 m_firstLayout = true;
185 setScrollbarsSuppressed(true);
186 setScrollbarModes(m_hmode, m_vmode);
187 setScrollbarsSuppressed(false);
188 }
189
init()190 void FrameView::init()
191 {
192 reset();
193
194 m_margins = IntSize(-1, -1); // undefined
195 m_size = IntSize();
196
197 // Propagate the marginwidth/height and scrolling modes to the view.
198 Element* ownerElement = m_frame && m_frame->document() ? m_frame->document()->ownerElement() : 0;
199 if (ownerElement && (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag))) {
200 HTMLFrameElement* frameElt = static_cast<HTMLFrameElement*>(ownerElement);
201 if (frameElt->scrollingMode() == ScrollbarAlwaysOff)
202 setCanHaveScrollbars(false);
203 int marginWidth = frameElt->getMarginWidth();
204 int marginHeight = frameElt->getMarginHeight();
205 if (marginWidth != -1)
206 setMarginWidth(marginWidth);
207 if (marginHeight != -1)
208 setMarginHeight(marginHeight);
209 }
210 }
211
clear()212 void FrameView::clear()
213 {
214 setCanBlitOnScroll(true);
215
216 reset();
217
218 if (m_frame) {
219 if (RenderPart* renderer = m_frame->ownerRenderer())
220 renderer->viewCleared();
221 }
222
223 setScrollbarsSuppressed(true);
224 }
225
didFirstLayout() const226 bool FrameView::didFirstLayout() const
227 {
228 return !m_firstLayout;
229 }
230
initScrollbars()231 void FrameView::initScrollbars()
232 {
233 if (!m_needToInitScrollbars)
234 return;
235 m_needToInitScrollbars = false;
236 updateDefaultScrollbarState();
237 }
238
updateDefaultScrollbarState()239 void FrameView::updateDefaultScrollbarState()
240 {
241 m_hmode = horizontalScrollbarMode();
242 m_vmode = verticalScrollbarMode();
243 setScrollbarModes(m_hmode, m_vmode);
244 }
245
invalidateRect(const IntRect & rect)246 void FrameView::invalidateRect(const IntRect& rect)
247 {
248 if (!parent()) {
249 if (hostWindow())
250 hostWindow()->repaint(rect, true);
251 return;
252 }
253
254 if (!m_frame)
255 return;
256
257 RenderPart* renderer = m_frame->ownerRenderer();
258 if (!renderer)
259 return;
260
261 IntRect repaintRect = rect;
262 repaintRect.move(renderer->borderLeft() + renderer->paddingLeft(),
263 renderer->borderTop() + renderer->paddingTop());
264 renderer->repaintRectangle(repaintRect);
265 }
266
setMarginWidth(int w)267 void FrameView::setMarginWidth(int w)
268 {
269 // make it update the rendering area when set
270 m_margins.setWidth(w);
271 }
272
setMarginHeight(int h)273 void FrameView::setMarginHeight(int h)
274 {
275 // make it update the rendering area when set
276 m_margins.setHeight(h);
277 }
278
setCanHaveScrollbars(bool canScroll)279 void FrameView::setCanHaveScrollbars(bool canScroll)
280 {
281 ScrollView::setCanHaveScrollbars(canScroll);
282 scrollbarModes(m_hmode, m_vmode);
283 }
284
createScrollbar(ScrollbarOrientation orientation)285 PassRefPtr<Scrollbar> FrameView::createScrollbar(ScrollbarOrientation orientation)
286 {
287 // FIXME: We need to update the scrollbar dynamically as documents change (or as doc elements and bodies get discovered that have custom styles).
288 Document* doc = m_frame->document();
289 if (!doc)
290 return ScrollView::createScrollbar(orientation);
291
292 // Try the <body> element first as a scrollbar source.
293 Element* body = doc->body();
294 if (body && body->renderer() && body->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
295 return RenderScrollbar::createCustomScrollbar(this, orientation, body->renderBox());
296
297 // If the <body> didn't have a custom style, then the root element might.
298 Element* docElement = doc->documentElement();
299 if (docElement && docElement->renderer() && docElement->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
300 return RenderScrollbar::createCustomScrollbar(this, orientation, docElement->renderBox());
301
302 // If we have an owning iframe/frame element, then it can set the custom scrollbar also.
303 RenderPart* frameRenderer = m_frame->ownerRenderer();
304 if (frameRenderer && frameRenderer->style()->hasPseudoStyle(RenderStyle::SCROLLBAR))
305 return RenderScrollbar::createCustomScrollbar(this, orientation, frameRenderer);
306
307 // Nobody set a custom style, so we just use a native scrollbar.
308 return ScrollView::createScrollbar(orientation);
309 }
310
setContentsSize(const IntSize & size)311 void FrameView::setContentsSize(const IntSize& size)
312 {
313 ScrollView::setContentsSize(size);
314
315 Page* page = frame() ? frame()->page() : 0;
316 if (!page)
317 return;
318
319 page->chrome()->contentsSizeChanged(frame(), size); //notify only
320 }
321
adjustViewSize()322 void FrameView::adjustViewSize()
323 {
324 ASSERT(m_frame->view() == this);
325 RenderView* root = m_frame->contentRenderer();
326 if (!root)
327 return;
328 setContentsSize(IntSize(root->overflowWidth(), root->overflowHeight()));
329 }
330
applyOverflowToViewport(RenderObject * o,ScrollbarMode & hMode,ScrollbarMode & vMode)331 void FrameView::applyOverflowToViewport(RenderObject* o, ScrollbarMode& hMode, ScrollbarMode& vMode)
332 {
333 // Handle the overflow:hidden/scroll case for the body/html elements. WinIE treats
334 // overflow:hidden and overflow:scroll on <body> as applying to the document's
335 // scrollbars. The CSS2.1 draft states that HTML UAs should use the <html> or <body> element and XML/XHTML UAs should
336 // use the root element.
337 switch (o->style()->overflowX()) {
338 case OHIDDEN:
339 hMode = ScrollbarAlwaysOff;
340 break;
341 case OSCROLL:
342 hMode = ScrollbarAlwaysOn;
343 break;
344 case OAUTO:
345 hMode = ScrollbarAuto;
346 break;
347 default:
348 // Don't set it at all.
349 ;
350 }
351
352 switch (o->style()->overflowY()) {
353 case OHIDDEN:
354 vMode = ScrollbarAlwaysOff;
355 break;
356 case OSCROLL:
357 vMode = ScrollbarAlwaysOn;
358 break;
359 case OAUTO:
360 vMode = ScrollbarAuto;
361 break;
362 default:
363 // Don't set it at all.
364 ;
365 }
366
367 m_viewportRenderer = o;
368 }
369
layoutRoot(bool onlyDuringLayout) const370 RenderObject* FrameView::layoutRoot(bool onlyDuringLayout) const
371 {
372 return onlyDuringLayout && layoutPending() ? 0 : m_layoutRoot;
373 }
374
layout(bool allowSubtree)375 void FrameView::layout(bool allowSubtree)
376 {
377 if (m_midLayout)
378 return;
379
380 m_layoutTimer.stop();
381 m_delayedLayout = false;
382
383 // Protect the view from being deleted during layout (in recalcStyle)
384 RefPtr<FrameView> protector(this);
385
386 if (!m_frame) {
387 // FIXME: Do we need to set m_size.width here?
388 // FIXME: Should we set m_size.height here too?
389 m_size.setWidth(layoutWidth());
390 return;
391 }
392
393 // we shouldn't enter layout() while painting
394 ASSERT(!isPainting());
395 if (isPainting())
396 return;
397
398 if (!allowSubtree && m_layoutRoot) {
399 m_layoutRoot->markContainingBlocksForLayout(false);
400 m_layoutRoot = 0;
401 }
402
403 ASSERT(m_frame->view() == this);
404 // This early return should be removed when rdar://5598072 is resolved. In the meantime, there is a
405 // gigantic CrashTracer because of this issue, and the early return will hopefully cause graceful
406 // failure instead.
407 if (m_frame->view() != this)
408 return;
409
410 Document* document = m_frame->document();
411 if (!document) {
412 // FIXME: Should we set m_size.height here too?
413 m_size.setWidth(layoutWidth());
414 return;
415 }
416
417 m_layoutSchedulingEnabled = false;
418
419 if (!m_nestedLayoutCount && m_postLayoutTasksTimer.isActive()) {
420 // This is a new top-level layout. If there are any remaining tasks from the previous
421 // layout, finish them now.
422 m_postLayoutTasksTimer.stop();
423 performPostLayoutTasks();
424 }
425
426 // Viewport-dependent media queries may cause us to need completely different style information.
427 // Check that here.
428 if (document->styleSelector()->affectedByViewportChange())
429 document->updateStyleSelector();
430
431 // Always ensure our style info is up-to-date. This can happen in situations where
432 // the layout beats any sort of style recalc update that needs to occur.
433 if (m_frame->needsReapplyStyles())
434 m_frame->reapplyStyles();
435 else if (document->hasChangedChild())
436 document->recalcStyle();
437
438 bool subtree = m_layoutRoot;
439
440 // If there is only one ref to this view left, then its going to be destroyed as soon as we exit,
441 // so there's no point to continuing to layout
442 if (protector->hasOneRef())
443 return;
444
445 RenderObject* root = subtree ? m_layoutRoot : document->renderer();
446 if (!root) {
447 // FIXME: Do we need to set m_size here?
448 m_layoutSchedulingEnabled = true;
449 return;
450 }
451
452 #ifdef ANDROID_INSTRUMENT
453 if (!m_frame->tree() || !m_frame->tree()->parent())
454 android::TimeCounter::start(android::TimeCounter::LayoutTimeCounter);
455 #endif
456
457 m_nestedLayoutCount++;
458
459 ScrollbarMode hMode = m_hmode;
460 ScrollbarMode vMode = m_vmode;
461
462 if (!subtree) {
463 RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
464 Node* body = document->body();
465 if (body && body->renderer()) {
466 if (body->hasTagName(framesetTag)) {
467 body->renderer()->setChildNeedsLayout(true);
468 vMode = ScrollbarAlwaysOff;
469 hMode = ScrollbarAlwaysOff;
470 } else if (body->hasTagName(bodyTag)) {
471 if (!m_firstLayout && m_size.height() != layoutHeight()
472 && toRenderBox(body->renderer())->stretchesToViewHeight())
473 body->renderer()->setChildNeedsLayout(true);
474 // It's sufficient to just check the X overflow,
475 // since it's illegal to have visible in only one direction.
476 RenderObject* o = rootRenderer->style()->overflowX() == OVISIBLE && document->documentElement()->hasTagName(htmlTag) ? body->renderer() : rootRenderer;
477 applyOverflowToViewport(o, hMode, vMode);
478 }
479 } else if (rootRenderer)
480 applyOverflowToViewport(rootRenderer, hMode, vMode);
481 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
482 if (m_firstLayout && !document->ownerElement())
483 printf("Elapsed time before first layout: %d\n", document->elapsedTime());
484 #endif
485 }
486
487 m_doFullRepaint = !subtree && (m_firstLayout || static_cast<RenderView*>(root)->printing());
488
489 if (!subtree) {
490 // Now set our scrollbar state for the layout.
491 ScrollbarMode currentHMode = horizontalScrollbarMode();
492 ScrollbarMode currentVMode = verticalScrollbarMode();
493
494 if (m_firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
495 setScrollbarsSuppressed(true);
496 if (m_firstLayout) {
497 m_firstLayout = false;
498 m_firstLayoutCallbackPending = true;
499 m_lastLayoutSize = IntSize(width(), height());
500 m_lastZoomFactor = root->style()->zoom();
501
502 // Set the initial vMode to AlwaysOn if we're auto.
503 if (vMode == ScrollbarAuto)
504 setVerticalScrollbarMode(ScrollbarAlwaysOn); // This causes a vertical scrollbar to appear.
505 // Set the initial hMode to AlwaysOff if we're auto.
506 if (hMode == ScrollbarAuto)
507 setHorizontalScrollbarMode(ScrollbarAlwaysOff); // This causes a horizontal scrollbar to disappear.
508 }
509 setScrollbarModes(hMode, vMode);
510 setScrollbarsSuppressed(false, true);
511 }
512
513 IntSize oldSize = m_size;
514
515 m_size = IntSize(layoutWidth(), layoutHeight());
516
517 if (oldSize != m_size)
518 m_doFullRepaint = true;
519 }
520
521 RenderLayer* layer = root->enclosingLayer();
522
523 pauseScheduledEvents();
524
525 if (subtree)
526 root->view()->pushLayoutState(root);
527
528 m_midLayout = true;
529 beginDeferredRepaints();
530 root->layout();
531 endDeferredRepaints();
532 m_midLayout = false;
533
534 if (subtree)
535 root->view()->popLayoutState();
536 m_layoutRoot = 0;
537
538 m_frame->invalidateSelection();
539
540 m_layoutSchedulingEnabled = true;
541
542 if (!subtree && !static_cast<RenderView*>(root)->printing())
543 adjustViewSize();
544
545 // Now update the positions of all layers.
546 beginDeferredRepaints();
547 layer->updateLayerPositions(m_doFullRepaint);
548 endDeferredRepaints();
549
550 m_layoutCount++;
551
552 #if PLATFORM(MAC)
553 if (AXObjectCache::accessibilityEnabled())
554 root->document()->axObjectCache()->postNotificationToElement(root, "AXLayoutComplete");
555 #endif
556 #if ENABLE(DASHBOARD_SUPPORT)
557 updateDashboardRegions();
558 #endif
559
560 #ifdef ANDROID_INSTRUMENT
561 if (!m_frame->tree()->parent())
562 android::TimeCounter::record(android::TimeCounter::LayoutTimeCounter, __FUNCTION__);
563 #endif
564 ASSERT(!root->needsLayout());
565
566 setCanBlitOnScroll(!useSlowRepaints());
567
568 if (document->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
569 updateOverflowStatus(layoutWidth() < contentsWidth(),
570 layoutHeight() < contentsHeight());
571
572 if (!m_postLayoutTasksTimer.isActive()) {
573 // Calls resumeScheduledEvents()
574 performPostLayoutTasks();
575
576 if (needsLayout()) {
577 // Post-layout widget updates or an event handler made us need layout again.
578 // Lay out again, but this time defer widget updates and event dispatch until after
579 // we return.
580 m_postLayoutTasksTimer.startOneShot(0);
581 pauseScheduledEvents();
582 layout();
583 }
584 } else {
585 resumeScheduledEvents();
586 ASSERT(m_enqueueEvents);
587 }
588
589 m_nestedLayoutCount--;
590 }
591
addWidgetToUpdate(RenderPartObject * object)592 void FrameView::addWidgetToUpdate(RenderPartObject* object)
593 {
594 if (!m_widgetUpdateSet)
595 m_widgetUpdateSet.set(new HashSet<RenderPartObject*>);
596
597 m_widgetUpdateSet->add(object);
598 }
599
removeWidgetToUpdate(RenderPartObject * object)600 void FrameView::removeWidgetToUpdate(RenderPartObject* object)
601 {
602 if (!m_widgetUpdateSet)
603 return;
604
605 m_widgetUpdateSet->remove(object);
606 }
607
setMediaType(const String & mediaType)608 void FrameView::setMediaType(const String& mediaType)
609 {
610 m_mediaType = mediaType;
611 }
612
mediaType() const613 String FrameView::mediaType() const
614 {
615 // See if we have an override type.
616 String overrideType = m_frame->loader()->client()->overrideMediaType();
617 if (!overrideType.isNull())
618 return overrideType;
619 return m_mediaType;
620 }
621
useSlowRepaints() const622 bool FrameView::useSlowRepaints() const
623 {
624 return m_useSlowRepaints || m_slowRepaintObjectCount > 0;
625 }
626
setUseSlowRepaints()627 void FrameView::setUseSlowRepaints()
628 {
629 m_useSlowRepaints = true;
630 setCanBlitOnScroll(false);
631 }
632
addSlowRepaintObject()633 void FrameView::addSlowRepaintObject()
634 {
635 if (!m_slowRepaintObjectCount)
636 setCanBlitOnScroll(false);
637 m_slowRepaintObjectCount++;
638 }
639
removeSlowRepaintObject()640 void FrameView::removeSlowRepaintObject()
641 {
642 ASSERT(m_slowRepaintObjectCount > 0);
643 m_slowRepaintObjectCount--;
644 if (!m_slowRepaintObjectCount)
645 setCanBlitOnScroll(!m_useSlowRepaints);
646 }
647
restoreScrollbar()648 void FrameView::restoreScrollbar()
649 {
650 setScrollbarsSuppressed(false);
651 }
652
scrollRectIntoViewRecursively(const IntRect & r)653 void FrameView::scrollRectIntoViewRecursively(const IntRect& r)
654 {
655 bool wasInProgrammaticScroll = m_inProgrammaticScroll;
656 m_inProgrammaticScroll = true;
657 ScrollView::scrollRectIntoViewRecursively(r);
658 m_inProgrammaticScroll = wasInProgrammaticScroll;
659 }
660
setScrollPosition(const IntPoint & scrollPoint)661 void FrameView::setScrollPosition(const IntPoint& scrollPoint)
662 {
663 bool wasInProgrammaticScroll = m_inProgrammaticScroll;
664 m_inProgrammaticScroll = true;
665 ScrollView::setScrollPosition(scrollPoint);
666 m_inProgrammaticScroll = wasInProgrammaticScroll;
667 }
668
hostWindow() const669 HostWindow* FrameView::hostWindow() const
670 {
671 Page* page = frame() ? frame()->page() : 0;
672 if (!page)
673 return 0;
674 return page->chrome();
675 }
676
677 const unsigned cRepaintRectUnionThreshold = 25;
678
repaintContentRectangle(const IntRect & r,bool immediate)679 void FrameView::repaintContentRectangle(const IntRect& r, bool immediate)
680 {
681 ASSERT(!m_frame->document()->ownerElement());
682
683 if (m_deferringRepaints && !immediate) {
684 IntRect visibleContent = visibleContentRect();
685 visibleContent.intersect(r);
686 if (!visibleContent.isEmpty()) {
687 m_repaintCount++;
688 m_repaintRect.unite(r);
689 if (m_repaintCount == cRepaintRectUnionThreshold)
690 m_repaintRects.clear();
691 else if (m_repaintCount < cRepaintRectUnionThreshold)
692 m_repaintRects.append(r);
693 }
694 #ifdef ANDROID_CAPTURE_OFFSCREEN_PAINTS
695 else
696 ScrollView::platformOffscreenContentRectangle(r);
697 #endif
698 return;
699 }
700
701 if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen())
702 return;
703
704 ScrollView::repaintContentRectangle(r, immediate);
705 }
706
beginDeferredRepaints()707 void FrameView::beginDeferredRepaints()
708 {
709 Page* page = m_frame->page();
710 if (page->mainFrame() != m_frame)
711 return page->mainFrame()->view()->beginDeferredRepaints();
712
713 m_deferringRepaints++;
714 #ifdef ANDROID_FIX // This allows sub frames to accumulate deferred repaints
715 if (m_deferringRepaints == 1) {
716 #endif
717 m_repaintCount = 0;
718 m_repaintRect = IntRect();
719 m_repaintRects.clear();
720 #ifdef ANDROID_FIX
721 }
722 #endif
723 }
724
725
endDeferredRepaints()726 void FrameView::endDeferredRepaints()
727 {
728 Page* page = m_frame->page();
729 if (page->mainFrame() != m_frame)
730 return page->mainFrame()->view()->endDeferredRepaints();
731
732 ASSERT(m_deferringRepaints > 0);
733 if (--m_deferringRepaints == 0) {
734 if (m_repaintCount >= cRepaintRectUnionThreshold)
735 repaintContentRectangle(m_repaintRect, false);
736 else {
737 unsigned size = m_repaintRects.size();
738 for (unsigned i = 0; i < size; i++)
739 repaintContentRectangle(m_repaintRects[i], false);
740 m_repaintRects.clear();
741 }
742 }
743 }
744
layoutTimerFired(Timer<FrameView> *)745 void FrameView::layoutTimerFired(Timer<FrameView>*)
746 {
747 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
748 if (m_frame->document() && !m_frame->document()->ownerElement())
749 printf("Layout timer fired at %d\n", m_frame->document()->elapsedTime());
750 #endif
751 layout();
752 }
753
scheduleRelayout()754 void FrameView::scheduleRelayout()
755 {
756 ASSERT(!m_frame->document() || !m_frame->document()->inPageCache());
757 ASSERT(m_frame->view() == this);
758
759 if (m_layoutRoot) {
760 m_layoutRoot->markContainingBlocksForLayout(false);
761 m_layoutRoot = 0;
762 }
763 if (!m_layoutSchedulingEnabled)
764 return;
765 if (!needsLayout())
766 return;
767 if (!m_frame->document() || !m_frame->document()->shouldScheduleLayout())
768 return;
769
770 #if defined(FLATTEN_IFRAME) || defined(FLATTEN_FRAMESET)
771 if (m_frame->ownerRenderer())
772 m_frame->ownerRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
773 #endif
774
775 #ifdef ANDROID_MOBILE
776 int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay();
777 #else
778 int delay = m_frame->document()->minimumLayoutDelay();
779 #endif
780 if (m_layoutTimer.isActive() && m_delayedLayout && !delay)
781 unscheduleRelayout();
782 if (m_layoutTimer.isActive())
783 return;
784
785 m_delayedLayout = delay != 0;
786
787 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
788 if (!m_frame->document()->ownerElement())
789 printf("Scheduling layout for %d\n", delay);
790 #endif
791
792 m_layoutTimer.startOneShot(delay * 0.001);
793 }
794
isObjectAncestorContainerOf(RenderObject * ancestor,RenderObject * descendant)795 static bool isObjectAncestorContainerOf(RenderObject* ancestor, RenderObject* descendant)
796 {
797 for (RenderObject* r = descendant; r; r = r->container()) {
798 if (r == ancestor)
799 return true;
800 }
801 return false;
802 }
803
scheduleRelayoutOfSubtree(RenderObject * relayoutRoot)804 void FrameView::scheduleRelayoutOfSubtree(RenderObject* relayoutRoot)
805 {
806 ASSERT(m_frame->view() == this);
807
808 if (!m_layoutSchedulingEnabled || (m_frame->contentRenderer()
809 && m_frame->contentRenderer()->needsLayout())) {
810 if (relayoutRoot)
811 relayoutRoot->markContainingBlocksForLayout(false);
812 return;
813 }
814
815 if (layoutPending()) {
816 if (m_layoutRoot != relayoutRoot) {
817 if (isObjectAncestorContainerOf(m_layoutRoot, relayoutRoot)) {
818 // Keep the current root
819 relayoutRoot->markContainingBlocksForLayout(false, m_layoutRoot);
820 } else if (m_layoutRoot && isObjectAncestorContainerOf(relayoutRoot, m_layoutRoot)) {
821 // Re-root at relayoutRoot
822 m_layoutRoot->markContainingBlocksForLayout(false, relayoutRoot);
823 m_layoutRoot = relayoutRoot;
824 } else {
825 // Just do a full relayout
826 if (m_layoutRoot)
827 m_layoutRoot->markContainingBlocksForLayout(false);
828 m_layoutRoot = 0;
829 relayoutRoot->markContainingBlocksForLayout(false);
830 }
831 }
832 } else {
833 #ifdef ANDROID_MOBILE
834 int delay = m_frame->document()->minimumLayoutDelay() + m_frame->document()->extraLayoutDelay();
835 #else
836 int delay = m_frame->document()->minimumLayoutDelay();
837 #endif
838 m_layoutRoot = relayoutRoot;
839 m_delayedLayout = delay != 0;
840 m_layoutTimer.startOneShot(delay * 0.001);
841 }
842 }
843
layoutPending() const844 bool FrameView::layoutPending() const
845 {
846 return m_layoutTimer.isActive();
847 }
848
needsLayout() const849 bool FrameView::needsLayout() const
850 {
851 // This can return true in cases where the document does not have a body yet.
852 // Document::shouldScheduleLayout takes care of preventing us from scheduling
853 // layout in that case.
854 if (!m_frame)
855 return false;
856 RenderView* root = m_frame->contentRenderer();
857 Document* document = m_frame->document();
858 return layoutPending()
859 || (root && root->needsLayout())
860 || m_layoutRoot
861 || (document && document->hasChangedChild()) // can occur when using WebKit ObjC interface
862 || m_frame->needsReapplyStyles();
863 }
864
setNeedsLayout()865 void FrameView::setNeedsLayout()
866 {
867 RenderView* root = m_frame->contentRenderer();
868 if (root)
869 root->setNeedsLayout(true);
870 }
871
unscheduleRelayout()872 void FrameView::unscheduleRelayout()
873 {
874 if (!m_layoutTimer.isActive())
875 return;
876
877 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
878 if (m_frame->document() && !m_frame->document()->ownerElement())
879 printf("Layout timer unscheduled at %d\n", m_frame->document()->elapsedTime());
880 #endif
881
882 m_layoutTimer.stop();
883 m_delayedLayout = false;
884 }
885
isTransparent() const886 bool FrameView::isTransparent() const
887 {
888 return m_isTransparent;
889 }
890
setTransparent(bool isTransparent)891 void FrameView::setTransparent(bool isTransparent)
892 {
893 m_isTransparent = isTransparent;
894 }
895
baseBackgroundColor() const896 Color FrameView::baseBackgroundColor() const
897 {
898 return m_baseBackgroundColor;
899 }
900
setBaseBackgroundColor(Color bc)901 void FrameView::setBaseBackgroundColor(Color bc)
902 {
903 if (!bc.isValid())
904 bc = Color::white;
905 m_baseBackgroundColor = bc;
906 }
907
updateBackgroundRecursively(const Color & backgroundColor,bool transparent)908 void FrameView::updateBackgroundRecursively(const Color& backgroundColor, bool transparent)
909 {
910 for (Frame* frame = m_frame.get(); frame; frame = frame->tree()->traverseNext(m_frame.get())) {
911 FrameView* view = frame->view();
912 if (!view)
913 continue;
914
915 view->setTransparent(transparent);
916 view->setBaseBackgroundColor(backgroundColor);
917 }
918 }
919
shouldUpdateWhileOffscreen() const920 bool FrameView::shouldUpdateWhileOffscreen() const
921 {
922 return m_shouldUpdateWhileOffscreen;
923 }
924
setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)925 void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
926 {
927 m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
928 }
929
scheduleEvent(PassRefPtr<Event> event,PassRefPtr<EventTargetNode> eventTarget)930 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<EventTargetNode> eventTarget)
931 {
932 if (!m_enqueueEvents) {
933 ExceptionCode ec = 0;
934 eventTarget->dispatchEvent(event, ec);
935 return;
936 }
937
938 ScheduledEvent* scheduledEvent = new ScheduledEvent;
939 scheduledEvent->m_event = event;
940 scheduledEvent->m_eventTarget = eventTarget;
941 m_scheduledEvents.append(scheduledEvent);
942 }
943
pauseScheduledEvents()944 void FrameView::pauseScheduledEvents()
945 {
946 ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents);
947 m_enqueueEvents++;
948 }
949
resumeScheduledEvents()950 void FrameView::resumeScheduledEvents()
951 {
952 m_enqueueEvents--;
953 if (!m_enqueueEvents)
954 dispatchScheduledEvents();
955 ASSERT(m_scheduledEvents.isEmpty() || m_enqueueEvents);
956 }
957
performPostLayoutTasks()958 void FrameView::performPostLayoutTasks()
959 {
960 if (m_firstLayoutCallbackPending) {
961 m_firstLayoutCallbackPending = false;
962 m_frame->loader()->didFirstLayout();
963 }
964
965 if (m_isVisuallyNonEmpty && m_firstVisuallyNonEmptyLayoutCallbackPending) {
966 m_firstVisuallyNonEmptyLayoutCallbackPending = false;
967 m_frame->loader()->didFirstVisuallyNonEmptyLayout();
968 }
969
970 RenderView* root = m_frame->contentRenderer();
971
972 root->updateWidgetPositions();
973 if (m_widgetUpdateSet && m_nestedLayoutCount <= 1) {
974 Vector<RenderPartObject*> objectVector;
975 copyToVector(*m_widgetUpdateSet, objectVector);
976 size_t size = objectVector.size();
977 for (size_t i = 0; i < size; ++i) {
978 RenderPartObject* object = objectVector[i];
979 object->updateWidget(false);
980
981 // updateWidget() can destroy the RenderPartObject, so we need to make sure it's
982 // alive by checking if it's still in m_widgetUpdateSet.
983 if (m_widgetUpdateSet->contains(object))
984 object->updateWidgetPosition();
985 }
986 m_widgetUpdateSet->clear();
987 }
988
989 resumeScheduledEvents();
990
991 if (!root->printing()) {
992 IntSize currentSize = IntSize(width(), height());
993 float currentZoomFactor = root->style()->zoom();
994 bool resized = !m_firstLayout && (currentSize != m_lastLayoutSize || currentZoomFactor != m_lastZoomFactor);
995 m_lastLayoutSize = currentSize;
996 m_lastZoomFactor = currentZoomFactor;
997 if (resized)
998 m_frame->sendResizeEvent();
999 }
1000 }
1001
postLayoutTimerFired(Timer<FrameView> *)1002 void FrameView::postLayoutTimerFired(Timer<FrameView>*)
1003 {
1004 performPostLayoutTasks();
1005 }
1006
updateOverflowStatus(bool horizontalOverflow,bool verticalOverflow)1007 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
1008 {
1009 if (!m_viewportRenderer)
1010 return;
1011
1012 if (m_overflowStatusDirty) {
1013 m_horizontalOverflow = horizontalOverflow;
1014 m_verticalOverflow = verticalOverflow;
1015 m_overflowStatusDirty = false;
1016 return;
1017 }
1018
1019 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
1020 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
1021
1022 if (horizontalOverflowChanged || verticalOverflowChanged) {
1023 m_horizontalOverflow = horizontalOverflow;
1024 m_verticalOverflow = verticalOverflow;
1025
1026 scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow,
1027 verticalOverflowChanged, verticalOverflow),
1028 EventTargetNodeCast(m_viewportRenderer->element()));
1029 }
1030
1031 }
1032
dispatchScheduledEvents()1033 void FrameView::dispatchScheduledEvents()
1034 {
1035 if (m_scheduledEvents.isEmpty())
1036 return;
1037
1038 Vector<ScheduledEvent*> scheduledEventsCopy = m_scheduledEvents;
1039 m_scheduledEvents.clear();
1040
1041 Vector<ScheduledEvent*>::iterator end = scheduledEventsCopy.end();
1042 for (Vector<ScheduledEvent*>::iterator it = scheduledEventsCopy.begin(); it != end; ++it) {
1043 ScheduledEvent* scheduledEvent = *it;
1044
1045 ExceptionCode ec = 0;
1046
1047 // Only dispatch events to nodes that are in the document
1048 if (scheduledEvent->m_eventTarget->inDocument())
1049 scheduledEvent->m_eventTarget->dispatchEvent(scheduledEvent->m_event, ec);
1050
1051 delete scheduledEvent;
1052 }
1053 }
1054
windowClipRect(bool clipToContents) const1055 IntRect FrameView::windowClipRect(bool clipToContents) const
1056 {
1057 ASSERT(m_frame->view() == this);
1058
1059 // Set our clip rect to be our contents.
1060 IntRect clipRect = contentsToWindow(visibleContentRect(!clipToContents));
1061 if (!m_frame || !m_frame->document() || !m_frame->document()->ownerElement())
1062 return clipRect;
1063
1064 // Take our owner element and get the clip rect from the enclosing layer.
1065 Element* elt = m_frame->document()->ownerElement();
1066 RenderLayer* layer = elt->renderer()->enclosingLayer();
1067 // FIXME: layer should never be null, but sometimes seems to be anyway.
1068 if (!layer)
1069 return clipRect;
1070 FrameView* parentView = elt->document()->view();
1071 clipRect.intersect(parentView->windowClipRectForLayer(layer, true));
1072 return clipRect;
1073 }
1074
windowClipRectForLayer(const RenderLayer * layer,bool clipToLayerContents) const1075 IntRect FrameView::windowClipRectForLayer(const RenderLayer* layer, bool clipToLayerContents) const
1076 {
1077 // If we have no layer, just return our window clip rect.
1078 if (!layer)
1079 return windowClipRect();
1080
1081 // Apply the clip from the layer.
1082 IntRect clipRect;
1083 if (clipToLayerContents)
1084 clipRect = layer->childrenClipRect();
1085 else
1086 clipRect = layer->selfClipRect();
1087 clipRect = contentsToWindow(clipRect);
1088 return intersection(clipRect, windowClipRect());
1089 }
1090
isActive() const1091 bool FrameView::isActive() const
1092 {
1093 Page* page = frame()->page();
1094 return page && page->focusController()->isActive();
1095 }
1096
valueChanged(Scrollbar * bar)1097 void FrameView::valueChanged(Scrollbar* bar)
1098 {
1099 // Figure out if we really moved.
1100 IntSize offset = scrollOffset();
1101 ScrollView::valueChanged(bar);
1102 if (offset != scrollOffset())
1103 frame()->sendScrollEvent();
1104 }
1105
invalidateScrollbarRect(Scrollbar * scrollbar,const IntRect & rect)1106 void FrameView::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
1107 {
1108 // Add in our offset within the FrameView.
1109 IntRect dirtyRect = rect;
1110 dirtyRect.move(scrollbar->x(), scrollbar->y());
1111 invalidateRect(dirtyRect);
1112 }
1113
getTickmarks(Vector<IntRect> & tickmarks) const1114 void FrameView::getTickmarks(Vector<IntRect>& tickmarks) const
1115 {
1116 tickmarks = frame()->document()->renderedRectsForMarkers(DocumentMarker::TextMatch);
1117 }
1118
windowResizerRect() const1119 IntRect FrameView::windowResizerRect() const
1120 {
1121 Page* page = frame() ? frame()->page() : 0;
1122 if (!page)
1123 return IntRect();
1124 return page->chrome()->windowResizerRect();
1125 }
1126
1127 #if ENABLE(DASHBOARD_SUPPORT)
updateDashboardRegions()1128 void FrameView::updateDashboardRegions()
1129 {
1130 Document* document = m_frame->document();
1131 if (!document->hasDashboardRegions())
1132 return;
1133 Vector<DashboardRegionValue> newRegions;
1134 document->renderBox()->collectDashboardRegions(newRegions);
1135 if (newRegions == document->dashboardRegions())
1136 return;
1137 document->setDashboardRegions(newRegions);
1138 Page* page = m_frame->page();
1139 if (!page)
1140 return;
1141 page->chrome()->client()->dashboardRegionsChanged();
1142 }
1143 #endif
1144
updateControlTints()1145 void FrameView::updateControlTints()
1146 {
1147 // This is called when control tints are changed from aqua/graphite to clear and vice versa.
1148 // We do a "fake" paint, and when the theme gets a paint call, it can then do an invalidate.
1149 // This is only done if the theme supports control tinting. It's up to the theme and platform
1150 // to define when controls get the tint and to call this function when that changes.
1151
1152 // Optimize the common case where we bring a window to the front while it's still empty.
1153 if (!m_frame || m_frame->loader()->url().isEmpty())
1154 return;
1155
1156 if (theme()->supportsControlTints() && m_frame->contentRenderer()) {
1157 if (needsLayout())
1158 layout();
1159 PlatformGraphicsContext* const noContext = 0;
1160 GraphicsContext context(noContext);
1161 context.setUpdatingControlTints(true);
1162 if (platformWidget())
1163 paintContents(&context, visibleContentRect());
1164 else
1165 paint(&context, frameRect());
1166 }
1167 }
1168
wasScrolledByUser() const1169 bool FrameView::wasScrolledByUser() const
1170 {
1171 return m_wasScrolledByUser;
1172 }
1173
setWasScrolledByUser(bool wasScrolledByUser)1174 void FrameView::setWasScrolledByUser(bool wasScrolledByUser)
1175 {
1176 if (m_inProgrammaticScroll)
1177 return;
1178 m_wasScrolledByUser = wasScrolledByUser;
1179 }
1180
paintContents(GraphicsContext * p,const IntRect & rect)1181 void FrameView::paintContents(GraphicsContext* p, const IntRect& rect)
1182 {
1183 if (!frame())
1184 return;
1185
1186 Document* document = frame()->document();
1187 if (!document)
1188 return;
1189
1190 #ifndef NDEBUG
1191 bool fillWithRed;
1192 if (document || document->printing())
1193 fillWithRed = false; // Printing, don't fill with red (can't remember why).
1194 else if (document->ownerElement())
1195 fillWithRed = false; // Subframe, don't fill with red.
1196 else if (isTransparent())
1197 fillWithRed = false; // Transparent, don't fill with red.
1198 else if (m_paintRestriction == PaintRestrictionSelectionOnly || m_paintRestriction == PaintRestrictionSelectionOnlyBlackText)
1199 fillWithRed = false; // Selections are transparent, don't fill with red.
1200 else if (m_nodeToDraw)
1201 fillWithRed = false; // Element images are transparent, don't fill with red.
1202 else
1203 fillWithRed = true;
1204
1205 if (fillWithRed)
1206 p->fillRect(rect, Color(0xFF, 0, 0));
1207 #endif
1208
1209 bool isTopLevelPainter = !sCurrentPaintTimeStamp;
1210 if (isTopLevelPainter)
1211 sCurrentPaintTimeStamp = currentTime();
1212
1213 RenderView* contentRenderer = frame()->contentRenderer();
1214 if (!contentRenderer) {
1215 LOG_ERROR("called Frame::paint with nil renderer");
1216 return;
1217 }
1218
1219 ASSERT(!needsLayout());
1220 ASSERT(!m_isPainting);
1221
1222 m_isPainting = true;
1223
1224 // m_nodeToDraw is used to draw only one element (and its descendants)
1225 RenderObject* eltRenderer = m_nodeToDraw ? m_nodeToDraw->renderer() : 0;
1226 if (m_paintRestriction == PaintRestrictionNone)
1227 document->invalidateRenderedRectsForMarkersInRect(rect);
1228 contentRenderer->layer()->paint(p, rect, m_paintRestriction, eltRenderer);
1229
1230 m_isPainting = false;
1231
1232 #if ENABLE(DASHBOARD_SUPPORT)
1233 // Regions may have changed as a result of the visibility/z-index of element changing.
1234 if (document->dashboardRegionsDirty())
1235 updateDashboardRegions();
1236 #endif
1237
1238 if (isTopLevelPainter)
1239 sCurrentPaintTimeStamp = 0;
1240 }
1241
setPaintRestriction(PaintRestriction pr)1242 void FrameView::setPaintRestriction(PaintRestriction pr)
1243 {
1244 m_paintRestriction = pr;
1245 }
1246
isPainting() const1247 bool FrameView::isPainting() const
1248 {
1249 return m_isPainting;
1250 }
1251
setNodeToDraw(Node * node)1252 void FrameView::setNodeToDraw(Node* node)
1253 {
1254 m_nodeToDraw = node;
1255 }
1256
layoutIfNeededRecursive()1257 void FrameView::layoutIfNeededRecursive()
1258 {
1259 // We have to crawl our entire tree looking for any FrameViews that need
1260 // layout and make sure they are up to date.
1261 // Mac actually tests for intersection with the dirty region and tries not to
1262 // update layout for frames that are outside the dirty region. Not only does this seem
1263 // pointless (since those frames will have set a zero timer to layout anyway), but
1264 // it is also incorrect, since if two frames overlap, the first could be excluded from the dirty
1265 // region but then become included later by the second frame adding rects to the dirty region
1266 // when it lays out.
1267
1268 if (needsLayout())
1269 layout();
1270
1271 const HashSet<Widget*>* viewChildren = children();
1272 HashSet<Widget*>::const_iterator end = viewChildren->end();
1273 for (HashSet<Widget*>::const_iterator current = viewChildren->begin(); current != end; ++current)
1274 if ((*current)->isFrameView())
1275 static_cast<FrameView*>(*current)->layoutIfNeededRecursive();
1276 }
1277
1278 } // namespace WebCore
1279