2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 #include "core/page/Page.h"
23 #include "core/dom/ClientRectList.h"
24 #include "core/dom/DocumentMarkerController.h"
25 #include "core/dom/StyleEngine.h"
26 #include "core/dom/VisitedLinkState.h"
27 #include "core/editing/Caret.h"
28 #include "core/editing/UndoStack.h"
29 #include "core/events/Event.h"
30 #include "core/fetch/ResourceFetcher.h"
31 #include "core/frame/DOMTimer.h"
32 #include "core/frame/LocalDOMWindow.h"
33 #include "core/frame/EventHandlerRegistry.h"
34 #include "core/frame/FrameHost.h"
35 #include "core/frame/FrameView.h"
36 #include "core/frame/LocalFrame.h"
37 #include "core/frame/RemoteFrame.h"
38 #include "core/frame/RemoteFrameView.h"
39 #include "core/frame/Settings.h"
40 #include "core/inspector/InspectorController.h"
41 #include "core/inspector/InspectorInstrumentation.h"
42 #include "core/loader/FrameLoader.h"
43 #include "core/loader/HistoryItem.h"
44 #include "core/page/AutoscrollController.h"
45 #include "core/page/Chrome.h"
46 #include "core/page/ChromeClient.h"
47 #include "core/page/ContextMenuController.h"
48 #include "core/page/DragController.h"
49 #include "core/page/FocusController.h"
50 #include "core/page/FrameTree.h"
51 #include "core/page/PageLifecycleNotifier.h"
52 #include "core/page/PointerLockController.h"
53 #include "core/page/StorageClient.h"
54 #include "core/page/ValidationMessageClient.h"
55 #include "core/page/scrolling/ScrollingCoordinator.h"
56 #include "core/rendering/FastTextAutosizer.h"
57 #include "core/rendering/RenderView.h"
58 #include "core/rendering/TextAutosizer.h"
59 #include "core/storage/StorageNamespace.h"
60 #include "platform/plugins/PluginData.h"
61 #include "wtf/HashMap.h"
62 #include "wtf/RefCountedLeakCounter.h"
63 #include "wtf/StdLibExtras.h"
64 #include "wtf/text/Base64.h"
68 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
71 HashSet<Page*>& Page::allPages()
73 DEFINE_STATIC_LOCAL(HashSet<Page*>, allPages, ());
78 HashSet<Page*>& Page::ordinaryPages()
80 DEFINE_STATIC_LOCAL(HashSet<Page*>, ordinaryPages, ());
85 void Page::networkStateChanged(bool online)
87 Vector<RefPtr<LocalFrame> > frames;
89 // Get all the frames of all the pages in all the page groups
90 HashSet<Page*>::iterator end = allPages().end();
91 for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it) {
92 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
93 // FIXME: There is currently no way to dispatch events to out-of-process frames.
94 if (frame->isLocalFrame())
95 frames.append(toLocalFrame(frame));
97 InspectorInstrumentation::networkStateChanged(*it, online);
100 AtomicString eventName = online ? EventTypeNames::online : EventTypeNames::offline;
101 for (unsigned i = 0; i < frames.size(); i++)
102 frames[i]->domWindow()->dispatchEvent(Event::create(eventName));
105 float deviceScaleFactor(LocalFrame* frame)
109 Page* page = frame->page();
112 return page->deviceScaleFactor();
115 Page::Page(PageClients& pageClients)
116 : SettingsDelegate(Settings::create())
118 , m_autoscrollController(AutoscrollController::create(*this))
119 , m_chrome(Chrome::create(this, pageClients.chromeClient))
120 , m_dragCaretController(DragCaretController::create())
121 , m_dragController(DragController::create(this, pageClients.dragClient))
122 , m_focusController(FocusController::create(this))
123 , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
124 , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
125 , m_pointerLockController(PointerLockController::create(this))
126 , m_undoStack(UndoStack::create())
128 , m_backForwardClient(pageClients.backForwardClient)
129 , m_editorClient(pageClients.editorClient)
130 , m_spellCheckerClient(pageClients.spellCheckerClient)
131 , m_storageClient(pageClients.storageClient)
133 , m_openedByDOM(false)
134 , m_tabKeyCyclesThroughElements(true)
135 , m_defersLoading(false)
136 , m_deviceScaleFactor(1)
137 , m_timerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval())
138 , m_visibilityState(PageVisibilityStateVisible)
139 , m_isCursorVisible(true)
141 , m_isPainting(false)
143 , m_frameHost(FrameHost::create(*this))
145 ASSERT(m_editorClient);
147 ASSERT(!allPages().contains(this));
148 allPages().add(this);
151 pageCounter.increment();
157 // willBeDestroyed() must be called before Page destruction.
158 ASSERT(!m_mainFrame);
161 void Page::makeOrdinary()
163 ASSERT(!ordinaryPages().contains(this));
164 ordinaryPages().add(this);
167 ViewportDescription Page::viewportDescription() const
169 return mainFrame() && mainFrame()->isLocalFrame() && deprecatedLocalMainFrame()->document() ? deprecatedLocalMainFrame()->document()->viewportDescription() : ViewportDescription();
172 ScrollingCoordinator* Page::scrollingCoordinator()
174 if (!m_scrollingCoordinator && m_settings->acceleratedCompositingEnabled())
175 m_scrollingCoordinator = ScrollingCoordinator::create(this);
177 return m_scrollingCoordinator.get();
180 String Page::mainThreadScrollingReasonsAsText()
182 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
183 return scrollingCoordinator->mainThreadScrollingReasonsAsText();
188 PassRefPtrWillBeRawPtr<ClientRectList> Page::nonFastScrollableRects(const LocalFrame* frame)
190 if (m_mainFrame->isLocalFrame() && deprecatedLocalMainFrame()->document())
191 deprecatedLocalMainFrame()->document()->updateLayout();
193 Vector<IntRect> rects;
194 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
195 rects = scrollingCoordinator->computeShouldHandleScrollGestureOnMainThreadRegion(frame, IntPoint()).rects();
197 Vector<FloatQuad> quads(rects.size());
198 for (size_t i = 0; i < rects.size(); ++i)
199 quads[i] = FloatRect(rects[i]);
200 return ClientRectList::create(quads);
203 void Page::setMainFrame(Frame* mainFrame)
205 ASSERT(!m_mainFrame); // Should only be called during initialization
206 m_mainFrame = mainFrame;
209 void Page::documentDetached(Document* document)
211 m_multisamplingChangedObservers.clear();
212 m_pointerLockController->documentDetached(document);
213 m_contextMenuController->documentDetached(document);
214 if (m_validationMessageClient)
215 m_validationMessageClient->documentDetached(*document);
216 m_frameHost->eventHandlerRegistry().documentDetached(*document);
219 bool Page::openedByDOM() const
221 return m_openedByDOM;
224 void Page::setOpenedByDOM()
226 m_openedByDOM = true;
229 void Page::scheduleForcedStyleRecalcForAllPages()
231 HashSet<Page*>::iterator end = allPages().end();
232 for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it)
233 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
234 if (frame->isLocalFrame())
235 toLocalFrame(frame)->document()->setNeedsStyleRecalc(SubtreeStyleChange);
239 void Page::setNeedsRecalcStyleInAllFrames()
241 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
242 if (frame->isLocalFrame())
243 toLocalFrame(frame)->document()->styleResolverChanged();
247 void Page::setNeedsLayoutInAllFrames()
249 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
250 if (!frame->isLocalFrame())
252 if (FrameView* view = toLocalFrame(frame)->view()) {
253 view->setNeedsLayout();
254 view->scheduleRelayout();
259 void Page::refreshPlugins(bool reload)
261 if (allPages().isEmpty())
264 PluginData::refresh();
266 Vector<RefPtr<LocalFrame> > framesNeedingReload;
268 HashSet<Page*>::iterator end = allPages().end();
269 for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it) {
272 // Clear out the page's plug-in data.
273 if (page->m_pluginData)
274 page->m_pluginData = nullptr;
279 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
280 if (frame->isLocalFrame() && toLocalFrame(frame)->document()->containsPlugins())
281 framesNeedingReload.append(toLocalFrame(frame));
285 for (size_t i = 0; i < framesNeedingReload.size(); ++i)
286 framesNeedingReload[i]->loader().reload();
289 PluginData* Page::pluginData() const
291 if (!deprecatedLocalMainFrame()->loader().allowPlugins(NotAboutToInstantiatePlugin))
294 m_pluginData = PluginData::create(this);
295 return m_pluginData.get();
298 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
301 ? curr->tree().traverseNextWithWrap(wrapFlag)
302 : curr->tree().traversePreviousWithWrap(wrapFlag);
305 void Page::unmarkAllTextMatches()
310 Frame* frame = mainFrame();
312 if (frame->isLocalFrame())
313 toLocalFrame(frame)->document()->markers().removeMarkers(DocumentMarker::TextMatch);
314 frame = incrementFrame(frame, true, false);
318 void Page::setValidationMessageClient(PassOwnPtrWillBeRawPtr<ValidationMessageClient> client)
320 m_validationMessageClient = client;
323 void Page::setDefersLoading(bool defers)
325 if (defers == m_defersLoading)
328 m_defersLoading = defers;
329 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
330 if (frame->isLocalFrame())
331 toLocalFrame(frame)->loader().setDefersLoading(defers);
335 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
337 if (!mainFrame()->isLocalFrame())
340 FrameView* view = deprecatedLocalMainFrame()->view();
341 PinchViewport& viewport = frameHost().pinchViewport();
343 if (scale != viewport.scale()) {
344 viewport.setScale(scale);
346 if (view && !settings().pinchVirtualViewportEnabled())
347 view->setVisibleContentScaleFactor(scale);
349 deprecatedLocalMainFrame()->deviceOrPageScaleFactorChanged();
350 m_chrome->client().deviceOrPageScaleFactorChanged();
352 // FIXME: In virtual-viewport pinch mode, scale doesn't change the fixed-pos viewport;
353 // remove once it's the only pinch mode in town.
355 view->viewportConstrainedVisibleContentSizeChanged(true, true);
357 deprecatedLocalMainFrame()->loader().saveScrollState();
360 if (view && view->scrollPosition() != origin)
361 view->notifyScrollPositionChanged(origin);
364 float Page::pageScaleFactor() const
366 return frameHost().pinchViewport().scale();
369 void Page::setDeviceScaleFactor(float scaleFactor)
371 if (m_deviceScaleFactor == scaleFactor)
374 m_deviceScaleFactor = scaleFactor;
375 setNeedsRecalcStyleInAllFrames();
377 if (mainFrame() && mainFrame()->isLocalFrame()) {
378 deprecatedLocalMainFrame()->deviceOrPageScaleFactorChanged();
379 m_chrome->client().deviceOrPageScaleFactorChanged();
383 void Page::allVisitedStateChanged()
385 HashSet<Page*>::iterator pagesEnd = ordinaryPages().end();
386 for (HashSet<Page*>::iterator it = ordinaryPages().begin(); it != pagesEnd; ++it) {
388 for (Frame* frame = page->m_mainFrame; frame; frame = frame->tree().traverseNext()) {
389 if (frame->isLocalFrame())
390 toLocalFrame(frame)->document()->visitedLinkState().invalidateStyleForAllLinks();
395 void Page::visitedStateChanged(LinkHash linkHash)
397 HashSet<Page*>::iterator pagesEnd = ordinaryPages().end();
398 for (HashSet<Page*>::iterator it = ordinaryPages().begin(); it != pagesEnd; ++it) {
400 for (Frame* frame = page->m_mainFrame; frame; frame = frame->tree().traverseNext()) {
401 if (frame->isLocalFrame())
402 toLocalFrame(frame)->document()->visitedLinkState().invalidateStyleForLink(linkHash);
407 StorageNamespace* Page::sessionStorage(bool optionalCreate)
409 if (!m_sessionStorage && optionalCreate)
410 m_sessionStorage = m_storageClient->createSessionStorageNamespace();
411 return m_sessionStorage.get();
414 void Page::setTimerAlignmentInterval(double interval)
416 if (interval == m_timerAlignmentInterval)
419 m_timerAlignmentInterval = interval;
420 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
421 if (frame->isLocalFrame() && toLocalFrame(frame)->document())
422 toLocalFrame(frame)->document()->didChangeTimerAlignmentInterval();
426 double Page::timerAlignmentInterval() const
428 return m_timerAlignmentInterval;
432 void Page::checkSubframeCountConsistency() const
434 ASSERT(m_subframeCount >= 0);
436 int subframeCount = 0;
437 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
440 ASSERT(m_subframeCount + 1 == subframeCount);
444 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
446 if (m_visibilityState == visibilityState)
448 m_visibilityState = visibilityState;
450 if (visibilityState == WebCore::PageVisibilityStateHidden)
451 setTimerAlignmentInterval(DOMTimer::hiddenPageAlignmentInterval());
453 setTimerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval());
456 lifecycleNotifier().notifyPageVisibilityChanged();
458 if (!isInitialState && m_mainFrame && m_mainFrame->isLocalFrame())
459 deprecatedLocalMainFrame()->didChangeVisibilityState();
462 PageVisibilityState Page::visibilityState() const
464 return m_visibilityState;
467 bool Page::isCursorVisible() const
469 return m_isCursorVisible && settings().deviceSupportsMouse();
472 void Page::addMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
474 m_multisamplingChangedObservers.add(observer);
477 void Page::removeMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
479 m_multisamplingChangedObservers.remove(observer);
482 void Page::settingsChanged(SettingsDelegate::ChangeType changeType)
484 switch (changeType) {
485 case SettingsDelegate::StyleChange:
486 setNeedsRecalcStyleInAllFrames();
488 case SettingsDelegate::ViewportDescriptionChange:
489 if (mainFrame() && mainFrame()->isLocalFrame())
490 deprecatedLocalMainFrame()->document()->updateViewportDescription();
492 case SettingsDelegate::MediaTypeChange:
493 if (m_mainFrame->isLocalFrame()) {
494 deprecatedLocalMainFrame()->view()->setMediaType(AtomicString(settings().mediaTypeOverride()));
495 setNeedsRecalcStyleInAllFrames();
498 case SettingsDelegate::DNSPrefetchingChange:
499 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
500 if (frame->isLocalFrame())
501 toLocalFrame(frame)->document()->initDNSPrefetch();
504 case SettingsDelegate::MultisamplingChange: {
505 WillBeHeapHashSet<RawPtrWillBeWeakMember<MultisamplingChangedObserver> >::iterator stop = m_multisamplingChangedObservers.end();
506 for (WillBeHeapHashSet<RawPtrWillBeWeakMember<MultisamplingChangedObserver> >::iterator it = m_multisamplingChangedObservers.begin(); it != stop; ++it)
507 (*it)->multisamplingChanged(m_settings->openGLMultisamplingEnabled());
510 case SettingsDelegate::ImageLoadingChange:
511 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
512 if (frame->isLocalFrame()) {
513 toLocalFrame(frame)->document()->fetcher()->setImagesEnabled(settings().imagesEnabled());
514 toLocalFrame(frame)->document()->fetcher()->setAutoLoadImages(settings().loadsImagesAutomatically());
518 case SettingsDelegate::TextAutosizingChange:
519 if (!mainFrame() || !mainFrame()->isLocalFrame())
521 if (FastTextAutosizer* textAutosizer = deprecatedLocalMainFrame()->document()->fastTextAutosizer()) {
522 textAutosizer->updatePageInfoInAllFrames();
524 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
525 if (!frame->isLocalFrame())
527 if (TextAutosizer* textAutosizer = toLocalFrame(frame)->document()->textAutosizer())
528 textAutosizer->recalculateMultipliers();
530 // TextAutosizing updates RenderStyle during layout phase (via TextAutosizer::processSubtree).
531 // We should invoke setNeedsLayout here.
532 setNeedsLayoutInAllFrames();
535 case SettingsDelegate::ScriptEnableChange:
536 m_inspectorController->scriptsEnabled(settings().scriptEnabled());
538 case SettingsDelegate::FontFamilyChange:
539 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
540 if (frame->isLocalFrame())
541 toLocalFrame(frame)->document()->styleEngine()->updateGenericFontFamilySettings();
543 setNeedsRecalcStyleInAllFrames();
545 case SettingsDelegate::AcceleratedCompositingChange:
546 updateAcceleratedCompositingSettings();
551 void Page::updateAcceleratedCompositingSettings()
553 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
554 if (!frame->isLocalFrame())
556 if (FrameView* view = toLocalFrame(frame)->view())
557 view->updateAcceleratedCompositingSettings();
561 void Page::didCommitLoad(LocalFrame* frame)
563 lifecycleNotifier().notifyDidCommitLoad(frame);
564 if (m_mainFrame == frame) {
565 useCounter().didCommitLoad();
566 m_inspectorController->didCommitLoadForMainFrame();
570 void Page::acceptLanguagesChanged()
572 Vector< RefPtr<LocalFrame> > frames;
574 // Even though we don't fire an event from here, the LocalDOMWindow's will fire
575 // an event so we keep the frames alive until we are done.
576 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
577 if (frame->isLocalFrame())
578 frames.append(toLocalFrame(frame));
581 for (unsigned i = 0; i < frames.size(); ++i)
582 frames[i]->domWindow()->acceptLanguagesChanged();
585 PageLifecycleNotifier& Page::lifecycleNotifier()
587 return static_cast<PageLifecycleNotifier&>(LifecycleContext<Page>::lifecycleNotifier());
590 PassOwnPtr<LifecycleNotifier<Page> > Page::createLifecycleNotifier()
592 return PageLifecycleNotifier::create(this);
595 void Page::trace(Visitor* visitor)
597 visitor->trace(m_dragCaretController);
598 visitor->trace(m_dragController);
599 visitor->trace(m_contextMenuController);
600 visitor->trace(m_pointerLockController);
601 visitor->trace(m_undoStack);
602 visitor->trace(m_validationMessageClient);
603 visitor->trace(m_multisamplingChangedObservers);
604 visitor->trace(m_frameHost);
605 WillBeHeapSupplementable<Page>::trace(visitor);
608 void Page::willBeDestroyed()
610 RefPtr<Frame> mainFrame = m_mainFrame;
612 if (mainFrame->isLocalFrame())
613 toLocalFrame(mainFrame.get())->loader().frameDetached();
615 // Disable all agents prior to resetting the frame view.
616 m_inspectorController->willBeDestroyed();
618 if (mainFrame->isLocalFrame()) {
619 toLocalFrame(mainFrame.get())->setView(nullptr);
621 ASSERT(m_mainFrame->isRemoteFrame());
622 toRemoteFrame(mainFrame.get())->setView(nullptr);
625 allPages().remove(this);
626 if (ordinaryPages().contains(this))
627 ordinaryPages().remove(this);
629 if (m_scrollingCoordinator)
630 m_scrollingCoordinator->willBeDestroyed();
633 pageCounter.decrement();
636 m_chrome->willBeDestroyed();
638 if (m_validationMessageClient)
639 m_validationMessageClient->willBeDestroyed();
640 WillBeHeapSupplementable<Page>::willBeDestroyed();
643 Page::PageClients::PageClients()
645 , contextMenuClient(0)
649 , backForwardClient(0)
650 , spellCheckerClient(0)
655 Page::PageClients::~PageClients()
659 } // namespace WebCore