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/events/ThreadLocalEventNames.h"
31 #include "core/fetch/ResourceFetcher.h"
32 #include "core/frame/DOMTimer.h"
33 #include "core/frame/DOMWindow.h"
34 #include "core/frame/Frame.h"
35 #include "core/frame/FrameHost.h"
36 #include "core/frame/FrameView.h"
37 #include "core/frame/Settings.h"
38 #include "core/inspector/InspectorController.h"
39 #include "core/inspector/InspectorInstrumentation.h"
40 #include "core/loader/FrameLoader.h"
41 #include "core/loader/HistoryItem.h"
42 #include "core/loader/ProgressTracker.h"
43 #include "core/page/AutoscrollController.h"
44 #include "core/page/Chrome.h"
45 #include "core/page/ChromeClient.h"
46 #include "core/page/ContextMenuController.h"
47 #include "core/page/DragController.h"
48 #include "core/page/FocusController.h"
49 #include "core/page/FrameTree.h"
50 #include "core/page/PageGroup.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/RenderView.h"
57 #include "core/rendering/TextAutosizer.h"
58 #include "core/storage/StorageNamespace.h"
59 #include "platform/plugins/PluginData.h"
60 #include "wtf/HashMap.h"
61 #include "wtf/RefCountedLeakCounter.h"
62 #include "wtf/StdLibExtras.h"
63 #include "wtf/text/Base64.h"
67 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
70 HashSet<Page*>& Page::allPages()
72 DEFINE_STATIC_LOCAL(HashSet<Page*>, allPages, ());
76 void Page::networkStateChanged(bool online)
78 Vector<RefPtr<Frame> > frames;
80 // Get all the frames of all the pages in all the page groups
81 HashSet<Page*>::iterator end = allPages().end();
82 for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it) {
83 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext())
85 InspectorInstrumentation::networkStateChanged(*it, online);
88 AtomicString eventName = online ? EventTypeNames::online : EventTypeNames::offline;
89 for (unsigned i = 0; i < frames.size(); i++)
90 frames[i]->domWindow()->dispatchEvent(Event::create(eventName));
93 float deviceScaleFactor(Frame* frame)
97 Page* page = frame->page();
100 return page->deviceScaleFactor();
103 Page::Page(PageClients& pageClients)
104 : SettingsDelegate(Settings::create())
105 , m_autoscrollController(AutoscrollController::create(*this))
106 , m_chrome(Chrome::create(this, pageClients.chromeClient))
107 , m_dragCaretController(DragCaretController::create())
108 , m_dragController(DragController::create(this, pageClients.dragClient))
109 , m_focusController(FocusController::create(this))
110 , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
111 , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
112 , m_pointerLockController(PointerLockController::create(this))
113 , m_historyController(adoptPtr(new HistoryController(this)))
114 , m_progress(ProgressTracker::create())
115 , m_undoStack(UndoStack::create())
116 , m_backForwardClient(pageClients.backForwardClient)
117 , m_editorClient(pageClients.editorClient)
118 , m_validationMessageClient(0)
119 , m_spellCheckerClient(pageClients.spellCheckerClient)
120 , m_storageClient(pageClients.storageClient)
122 , m_openedByDOM(false)
123 , m_tabKeyCyclesThroughElements(true)
124 , m_defersLoading(false)
125 , m_pageScaleFactor(1)
126 , m_deviceScaleFactor(1)
128 , m_timerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval())
129 , m_visibilityState(PageVisibilityStateVisible)
130 , m_isCursorVisible(true)
132 , m_isPainting(false)
134 , m_frameHost(FrameHost::create(*this))
136 ASSERT(m_editorClient);
138 ASSERT(!allPages().contains(this));
139 allPages().add(this);
142 pageCounter.increment();
148 m_mainFrame->setView(0);
150 allPages().remove(this);
152 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
153 frame->willDetachFrameHost();
154 frame->detachFromFrameHost();
157 m_inspectorController->inspectedPageDestroyed();
159 if (m_scrollingCoordinator)
160 m_scrollingCoordinator->pageDestroyed();
163 pageCounter.decrement();
167 ViewportDescription Page::viewportDescription() const
169 return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportDescription() : ViewportDescription();
172 ScrollingCoordinator* Page::scrollingCoordinator()
174 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
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 PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame)
190 if (Document* document = m_mainFrame->document())
191 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(PassRefPtr<Frame> mainFrame)
205 ASSERT(!m_mainFrame); // Should only be called during initialization
206 m_mainFrame = mainFrame;
209 void Page::documentDetached(Document* document)
211 m_pointerLockController->documentDetached(document);
212 m_contextMenuController->documentDetached(document);
213 if (m_validationMessageClient)
214 m_validationMessageClient->documentDetached(*document);
217 bool Page::openedByDOM() const
219 return m_openedByDOM;
222 void Page::setOpenedByDOM()
224 m_openedByDOM = true;
227 void Page::clearPageGroup()
231 m_group->removePage(this);
235 void Page::setGroupType(PageGroupType type)
240 case PrivatePageGroup:
241 m_group = PageGroup::create();
243 case SharedPageGroup:
244 m_group = PageGroup::sharedGroup();
248 m_group->addPage(this);
251 void Page::scheduleForcedStyleRecalcForAllPages()
253 HashSet<Page*>::iterator end = allPages().end();
254 for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it)
255 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext())
256 frame->document()->setNeedsStyleRecalc(SubtreeStyleChange);
259 void Page::setNeedsRecalcStyleInAllFrames()
261 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
262 frame->document()->styleResolverChanged(RecalcStyleDeferred);
265 void Page::setNeedsLayoutInAllFrames()
267 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
268 if (FrameView* view = frame->view()) {
269 view->setNeedsLayout();
270 view->scheduleRelayout();
275 void Page::refreshPlugins(bool reload)
277 if (allPages().isEmpty())
280 PluginData::refresh();
282 Vector<RefPtr<Frame> > framesNeedingReload;
284 HashSet<Page*>::iterator end = allPages().end();
285 for (HashSet<Page*>::iterator it = allPages().begin(); it != end; ++it) {
288 // Clear out the page's plug-in data.
289 if (page->m_pluginData)
290 page->m_pluginData = 0;
295 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
296 if (frame->document()->containsPlugins())
297 framesNeedingReload.append(frame);
301 for (size_t i = 0; i < framesNeedingReload.size(); ++i)
302 framesNeedingReload[i]->loader().reload();
305 PluginData* Page::pluginData() const
307 if (!mainFrame()->loader().allowPlugins(NotAboutToInstantiatePlugin))
310 m_pluginData = PluginData::create(this);
311 return m_pluginData.get();
314 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
317 ? curr->tree().traverseNextWithWrap(wrapFlag)
318 : curr->tree().traversePreviousWithWrap(wrapFlag);
321 void Page::unmarkAllTextMatches()
326 Frame* frame = mainFrame();
328 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
329 frame = incrementFrame(frame, true, false);
333 void Page::setDefersLoading(bool defers)
335 if (defers == m_defersLoading)
338 m_defersLoading = defers;
339 m_historyController->setDefersLoading(defers);
340 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
341 frame->loader().setDefersLoading(defers);
344 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
346 FrameView* view = mainFrame()->view();
348 if (scale != m_pageScaleFactor) {
349 m_pageScaleFactor = scale;
352 view->setVisibleContentScaleFactor(scale);
354 mainFrame()->deviceOrPageScaleFactorChanged();
355 m_chrome->client().deviceOrPageScaleFactorChanged();
358 view->viewportConstrainedVisibleContentSizeChanged(true, true);
361 if (view && view->scrollPosition() != origin)
362 view->notifyScrollPositionChanged(origin);
365 void Page::setDeviceScaleFactor(float scaleFactor)
367 if (m_deviceScaleFactor == scaleFactor)
370 m_deviceScaleFactor = scaleFactor;
371 setNeedsRecalcStyleInAllFrames();
374 mainFrame()->deviceOrPageScaleFactorChanged();
375 m_chrome->client().deviceOrPageScaleFactorChanged();
379 void Page::allVisitedStateChanged()
381 HashSet<Page*>::iterator pagesEnd = allPages().end();
382 for (HashSet<Page*>::iterator it = allPages().begin(); it != pagesEnd; ++it) {
384 if (page->m_group != PageGroup::sharedGroup())
386 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
387 frame->document()->visitedLinkState().invalidateStyleForAllLinks();
391 void Page::visitedStateChanged(LinkHash linkHash)
393 HashSet<Page*>::iterator pagesEnd = allPages().end();
394 for (HashSet<Page*>::iterator it = allPages().begin(); it != pagesEnd; ++it) {
396 if (page->m_group != PageGroup::sharedGroup())
398 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
399 frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
403 StorageNamespace* Page::sessionStorage(bool optionalCreate)
405 if (!m_sessionStorage && optionalCreate)
406 m_sessionStorage = m_storageClient->createSessionStorageNamespace();
407 return m_sessionStorage.get();
410 void Page::setTimerAlignmentInterval(double interval)
412 if (interval == m_timerAlignmentInterval)
415 m_timerAlignmentInterval = interval;
416 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
417 if (frame->document())
418 frame->document()->didChangeTimerAlignmentInterval();
422 double Page::timerAlignmentInterval() const
424 return m_timerAlignmentInterval;
428 void Page::checkSubframeCountConsistency() const
430 ASSERT(m_subframeCount >= 0);
432 int subframeCount = 0;
433 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
436 ASSERT(m_subframeCount + 1 == subframeCount);
440 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
442 if (m_visibilityState == visibilityState)
444 m_visibilityState = visibilityState;
446 if (visibilityState == WebCore::PageVisibilityStateHidden)
447 setTimerAlignmentInterval(DOMTimer::hiddenPageAlignmentInterval());
449 setTimerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval());
452 lifecycleNotifier().notifyPageVisibilityChanged();
454 if (!isInitialState && m_mainFrame)
455 m_mainFrame->didChangeVisibilityState();
458 PageVisibilityState Page::visibilityState() const
460 return m_visibilityState;
463 void Page::addMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
465 m_multisamplingChangedObservers.add(observer);
468 void Page::removeMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
470 m_multisamplingChangedObservers.remove(observer);
473 void Page::settingsChanged(SettingsDelegate::ChangeType changeType)
475 switch (changeType) {
476 case SettingsDelegate::StyleChange:
477 setNeedsRecalcStyleInAllFrames();
479 case SettingsDelegate::ViewportDescriptionChange:
481 mainFrame()->document()->updateViewportDescription();
483 case SettingsDelegate::MediaTypeChange:
484 m_mainFrame->view()->setMediaType(AtomicString(settings().mediaTypeOverride()));
485 setNeedsRecalcStyleInAllFrames();
487 case SettingsDelegate::DNSPrefetchingChange:
488 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
489 frame->document()->initDNSPrefetch();
491 case SettingsDelegate::MultisamplingChange: {
492 HashSet<MultisamplingChangedObserver*>::iterator stop = m_multisamplingChangedObservers.end();
493 for (HashSet<MultisamplingChangedObserver*>::iterator it = m_multisamplingChangedObservers.begin(); it != stop; ++it)
494 (*it)->multisamplingChanged(m_settings->openGLMultisamplingEnabled());
497 case SettingsDelegate::ImageLoadingChange:
498 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
499 frame->document()->fetcher()->setImagesEnabled(settings().imagesEnabled());
500 frame->document()->fetcher()->setAutoLoadImages(settings().loadsImagesAutomatically());
503 case SettingsDelegate::TextAutosizingChange:
504 // FTA needs both setNeedsRecalcStyle and setNeedsLayout after a setting change.
505 if (RuntimeEnabledFeatures::fastTextAutosizingEnabled()) {
506 setNeedsRecalcStyleInAllFrames();
508 // FIXME: I wonder if this needs to traverse frames like in WebViewImpl::resize, or whether there is only one document per Settings instance?
509 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
510 TextAutosizer* textAutosizer = frame->document()->textAutosizer();
512 textAutosizer->recalculateMultipliers();
515 // TextAutosizing updates RenderStyle during layout phase (via TextAutosizer::processSubtree).
516 // We should invoke setNeedsLayout here.
517 setNeedsLayoutInAllFrames();
519 case SettingsDelegate::ScriptEnableChange:
520 m_inspectorController->scriptsEnabled(settings().scriptEnabled());
522 case SettingsDelegate::FontFamilyChange:
523 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
524 frame->document()->styleEngine()->updateGenericFontFamilySettings();
525 setNeedsRecalcStyleInAllFrames();
530 void Page::didCommitLoad(Frame* frame)
532 lifecycleNotifier().notifyDidCommitLoad(frame);
533 if (m_mainFrame == frame) {
534 useCounter().didCommitLoad();
535 m_inspectorController->didCommitLoadForMainFrame();
539 PageLifecycleNotifier& Page::lifecycleNotifier()
541 return static_cast<PageLifecycleNotifier&>(LifecycleContext<Page>::lifecycleNotifier());
544 PassOwnPtr<LifecycleNotifier<Page> > Page::createLifecycleNotifier()
546 return PageLifecycleNotifier::create(this);
549 Page::PageClients::PageClients()
551 , contextMenuClient(0)
555 , backForwardClient(0)
556 , spellCheckerClient(0)
561 Page::PageClients::~PageClients()
565 } // namespace WebCore