1 /*
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/)
4 *
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.
13 *
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.
18 */
19
20 #include "config.h"
21 #include "core/page/Page.h"
22
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/FrameView.h"
36 #include "core/history/HistoryItem.h"
37 #include "core/inspector/InspectorController.h"
38 #include "core/inspector/InspectorInstrumentation.h"
39 #include "core/loader/FrameLoader.h"
40 #include "core/loader/ProgressTracker.h"
41 #include "core/page/AutoscrollController.h"
42 #include "core/page/Chrome.h"
43 #include "core/page/ChromeClient.h"
44 #include "core/page/ContextMenuController.h"
45 #include "core/page/DragController.h"
46 #include "core/page/FocusController.h"
47 #include "core/page/FrameTree.h"
48 #include "core/page/PageConsole.h"
49 #include "core/page/PageGroup.h"
50 #include "core/page/PageLifecycleNotifier.h"
51 #include "core/page/PointerLockController.h"
52 #include "core/frame/Settings.h"
53 #include "core/page/ValidationMessageClient.h"
54 #include "core/page/scrolling/ScrollingCoordinator.h"
55 #include "core/rendering/RenderView.h"
56 #include "core/rendering/TextAutosizer.h"
57 #include "core/storage/StorageNamespace.h"
58 #include "core/workers/SharedWorkerRepositoryClient.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"
64
65 namespace WebCore {
66
67 static HashSet<Page*>* allPages;
68
69 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, pageCounter, ("Page"));
70
networkStateChanged(bool online)71 void Page::networkStateChanged(bool online)
72 {
73 if (!allPages)
74 return;
75
76 Vector<RefPtr<Frame> > frames;
77
78 // Get all the frames of all the pages in all the page groups
79 HashSet<Page*>::iterator end = allPages->end();
80 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
81 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext())
82 frames.append(frame);
83 InspectorInstrumentation::networkStateChanged(*it, online);
84 }
85
86 AtomicString eventName = online ? EventTypeNames::online : EventTypeNames::offline;
87 for (unsigned i = 0; i < frames.size(); i++)
88 frames[i]->domWindow()->dispatchEvent(Event::create(eventName));
89 }
90
deviceScaleFactor(Frame * frame)91 float deviceScaleFactor(Frame* frame)
92 {
93 if (!frame)
94 return 1;
95 Page* page = frame->page();
96 if (!page)
97 return 1;
98 return page->deviceScaleFactor();
99 }
100
Page(PageClients & pageClients)101 Page::Page(PageClients& pageClients)
102 : SettingsDelegate(Settings::create())
103 , m_autoscrollController(AutoscrollController::create(*this))
104 , m_chrome(Chrome::create(this, pageClients.chromeClient))
105 , m_dragCaretController(DragCaretController::create())
106 , m_dragController(DragController::create(this, pageClients.dragClient))
107 , m_focusController(FocusController::create(this))
108 , m_contextMenuController(ContextMenuController::create(this, pageClients.contextMenuClient))
109 , m_inspectorController(InspectorController::create(this, pageClients.inspectorClient))
110 , m_pointerLockController(PointerLockController::create(this))
111 , m_historyController(adoptPtr(new HistoryController(this)))
112 , m_progress(ProgressTracker::create())
113 , m_undoStack(UndoStack::create())
114 , m_backForwardClient(pageClients.backForwardClient)
115 , m_editorClient(pageClients.editorClient)
116 , m_validationMessageClient(0)
117 , m_sharedWorkerRepositoryClient(0)
118 , m_spellCheckerClient(pageClients.spellCheckerClient)
119 , m_subframeCount(0)
120 , m_openedByDOM(false)
121 , m_tabKeyCyclesThroughElements(true)
122 , m_defersLoading(false)
123 , m_pageScaleFactor(1)
124 , m_deviceScaleFactor(1)
125 , m_group(0)
126 , m_timerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval())
127 , m_visibilityState(PageVisibilityStateVisible)
128 , m_isCursorVisible(true)
129 #ifndef NDEBUG
130 , m_isPainting(false)
131 #endif
132 , m_console(PageConsole::create(this))
133 {
134 ASSERT(m_editorClient);
135
136 if (!allPages)
137 allPages = new HashSet<Page*>;
138
139 ASSERT(!allPages->contains(this));
140 allPages->add(this);
141
142 #ifndef NDEBUG
143 pageCounter.increment();
144 #endif
145 }
146
~Page()147 Page::~Page()
148 {
149 m_mainFrame->setView(0);
150 clearPageGroup();
151 allPages->remove(this);
152
153 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
154 frame->willDetachPage();
155 frame->detachFromPage();
156 }
157
158 m_inspectorController->inspectedPageDestroyed();
159
160 if (m_scrollingCoordinator)
161 m_scrollingCoordinator->pageDestroyed();
162
163 #ifndef NDEBUG
164 pageCounter.decrement();
165 #endif
166 }
167
viewportDescription() const168 ViewportDescription Page::viewportDescription() const
169 {
170 return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportDescription() : ViewportDescription();
171 }
172
scrollingCoordinator()173 ScrollingCoordinator* Page::scrollingCoordinator()
174 {
175 if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled())
176 m_scrollingCoordinator = ScrollingCoordinator::create(this);
177
178 return m_scrollingCoordinator.get();
179 }
180
mainThreadScrollingReasonsAsText()181 String Page::mainThreadScrollingReasonsAsText()
182 {
183 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
184 return scrollingCoordinator->mainThreadScrollingReasonsAsText();
185
186 return String();
187 }
188
nonFastScrollableRects(const Frame * frame)189 PassRefPtr<ClientRectList> Page::nonFastScrollableRects(const Frame* frame)
190 {
191 if (Document* document = m_mainFrame->document())
192 document->updateLayout();
193
194 Vector<IntRect> rects;
195 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator())
196 rects = scrollingCoordinator->computeShouldHandleScrollGestureOnMainThreadRegion(frame, IntPoint()).rects();
197
198 Vector<FloatQuad> quads(rects.size());
199 for (size_t i = 0; i < rects.size(); ++i)
200 quads[i] = FloatRect(rects[i]);
201 return ClientRectList::create(quads);
202 }
203
setMainFrame(PassRefPtr<Frame> mainFrame)204 void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
205 {
206 ASSERT(!m_mainFrame); // Should only be called during initialization
207 m_mainFrame = mainFrame;
208 }
209
documentDetached(Document * document)210 void Page::documentDetached(Document* document)
211 {
212 m_pointerLockController->documentDetached(document);
213 m_contextMenuController->documentDetached(document);
214 if (m_validationMessageClient)
215 m_validationMessageClient->documentDetached(*document);
216 if (m_sharedWorkerRepositoryClient)
217 m_sharedWorkerRepositoryClient->documentDetached(document);
218 }
219
openedByDOM() const220 bool Page::openedByDOM() const
221 {
222 return m_openedByDOM;
223 }
224
setOpenedByDOM()225 void Page::setOpenedByDOM()
226 {
227 m_openedByDOM = true;
228 }
229
clearPageGroup()230 void Page::clearPageGroup()
231 {
232 if (!m_group)
233 return;
234 m_group->removePage(this);
235 m_group = 0;
236 }
237
setGroupType(PageGroupType type)238 void Page::setGroupType(PageGroupType type)
239 {
240 clearPageGroup();
241
242 switch (type) {
243 case PrivatePageGroup:
244 m_group = PageGroup::create();
245 break;
246 case SharedPageGroup:
247 m_group = PageGroup::sharedGroup();
248 break;
249 }
250
251 m_group->addPage(this);
252 }
253
scheduleForcedStyleRecalcForAllPages()254 void Page::scheduleForcedStyleRecalcForAllPages()
255 {
256 if (!allPages)
257 return;
258 HashSet<Page*>::iterator end = allPages->end();
259 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
260 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext())
261 frame->document()->setNeedsStyleRecalc();
262 }
263
setNeedsRecalcStyleInAllFrames()264 void Page::setNeedsRecalcStyleInAllFrames()
265 {
266 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
267 frame->document()->styleResolverChanged(RecalcStyleDeferred);
268 }
269
refreshPlugins(bool reload)270 void Page::refreshPlugins(bool reload)
271 {
272 if (!allPages)
273 return;
274
275 PluginData::refresh();
276
277 Vector<RefPtr<Frame> > framesNeedingReload;
278
279 HashSet<Page*>::iterator end = allPages->end();
280 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
281 Page* page = *it;
282
283 // Clear out the page's plug-in data.
284 if (page->m_pluginData)
285 page->m_pluginData = 0;
286
287 if (!reload)
288 continue;
289
290 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree().traverseNext()) {
291 if (frame->document()->containsPlugins())
292 framesNeedingReload.append(frame);
293 }
294 }
295
296 for (size_t i = 0; i < framesNeedingReload.size(); ++i)
297 framesNeedingReload[i]->loader().reload();
298 }
299
pluginData() const300 PluginData* Page::pluginData() const
301 {
302 if (!mainFrame()->loader().allowPlugins(NotAboutToInstantiatePlugin))
303 return 0;
304 if (!m_pluginData)
305 m_pluginData = PluginData::create(this);
306 return m_pluginData.get();
307 }
308
incrementFrame(Frame * curr,bool forward,bool wrapFlag)309 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
310 {
311 return forward
312 ? curr->tree().traverseNextWithWrap(wrapFlag)
313 : curr->tree().traversePreviousWithWrap(wrapFlag);
314 }
315
unmarkAllTextMatches()316 void Page::unmarkAllTextMatches()
317 {
318 if (!mainFrame())
319 return;
320
321 Frame* frame = mainFrame();
322 do {
323 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
324 frame = incrementFrame(frame, true, false);
325 } while (frame);
326 }
327
setDefersLoading(bool defers)328 void Page::setDefersLoading(bool defers)
329 {
330 if (defers == m_defersLoading)
331 return;
332
333 m_defersLoading = defers;
334 m_historyController->setDefersLoading(defers);
335 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
336 frame->loader().setDefersLoading(defers);
337 }
338
setPageScaleFactor(float scale,const IntPoint & origin)339 void Page::setPageScaleFactor(float scale, const IntPoint& origin)
340 {
341 FrameView* view = mainFrame()->view();
342
343 if (scale != m_pageScaleFactor) {
344 m_pageScaleFactor = scale;
345
346 if (view)
347 view->setVisibleContentScaleFactor(scale);
348
349 mainFrame()->deviceOrPageScaleFactorChanged();
350 m_chrome->client().deviceOrPageScaleFactorChanged();
351
352 if (view)
353 view->setViewportConstrainedObjectsNeedLayout();
354 }
355
356 if (view && view->scrollPosition() != origin)
357 view->notifyScrollPositionChanged(origin);
358 }
359
setDeviceScaleFactor(float scaleFactor)360 void Page::setDeviceScaleFactor(float scaleFactor)
361 {
362 if (m_deviceScaleFactor == scaleFactor)
363 return;
364
365 m_deviceScaleFactor = scaleFactor;
366 setNeedsRecalcStyleInAllFrames();
367
368 if (mainFrame()) {
369 mainFrame()->deviceOrPageScaleFactorChanged();
370 m_chrome->client().deviceOrPageScaleFactorChanged();
371 }
372 }
373
setPagination(const Pagination & pagination)374 void Page::setPagination(const Pagination& pagination)
375 {
376 if (m_pagination == pagination)
377 return;
378
379 m_pagination = pagination;
380
381 setNeedsRecalcStyleInAllFrames();
382 }
383
allVisitedStateChanged(PageGroup * group)384 void Page::allVisitedStateChanged(PageGroup* group)
385 {
386 ASSERT(group);
387 if (!allPages)
388 return;
389
390 HashSet<Page*>::iterator pagesEnd = allPages->end();
391 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
392 Page* page = *it;
393 if (page->m_group != group)
394 continue;
395 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
396 frame->document()->visitedLinkState().invalidateStyleForAllLinks();
397 }
398 }
399
visitedStateChanged(PageGroup * group,LinkHash linkHash)400 void Page::visitedStateChanged(PageGroup* group, LinkHash linkHash)
401 {
402 ASSERT(group);
403 if (!allPages)
404 return;
405
406 HashSet<Page*>::iterator pagesEnd = allPages->end();
407 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
408 Page* page = *it;
409 if (page->m_group != group)
410 continue;
411 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree().traverseNext())
412 frame->document()->visitedLinkState().invalidateStyleForLink(linkHash);
413 }
414 }
415
sessionStorage(bool optionalCreate)416 StorageNamespace* Page::sessionStorage(bool optionalCreate)
417 {
418 if (!m_sessionStorage && optionalCreate)
419 m_sessionStorage = StorageNamespace::sessionStorageNamespace(this);
420 return m_sessionStorage.get();
421 }
422
setTimerAlignmentInterval(double interval)423 void Page::setTimerAlignmentInterval(double interval)
424 {
425 if (interval == m_timerAlignmentInterval)
426 return;
427
428 m_timerAlignmentInterval = interval;
429 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNextWithWrap(false)) {
430 if (frame->document())
431 frame->document()->didChangeTimerAlignmentInterval();
432 }
433 }
434
timerAlignmentInterval() const435 double Page::timerAlignmentInterval() const
436 {
437 return m_timerAlignmentInterval;
438 }
439
440 #if !ASSERT_DISABLED
checkSubframeCountConsistency() const441 void Page::checkSubframeCountConsistency() const
442 {
443 ASSERT(m_subframeCount >= 0);
444
445 int subframeCount = 0;
446 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
447 ++subframeCount;
448
449 ASSERT(m_subframeCount + 1 == subframeCount);
450 }
451 #endif
452
setVisibilityState(PageVisibilityState visibilityState,bool isInitialState)453 void Page::setVisibilityState(PageVisibilityState visibilityState, bool isInitialState)
454 {
455 if (m_visibilityState == visibilityState)
456 return;
457 m_visibilityState = visibilityState;
458
459 if (visibilityState == WebCore::PageVisibilityStateHidden)
460 setTimerAlignmentInterval(DOMTimer::hiddenPageAlignmentInterval());
461 else
462 setTimerAlignmentInterval(DOMTimer::visiblePageAlignmentInterval());
463
464 if (!isInitialState)
465 lifecycleNotifier().notifyPageVisibilityChanged();
466
467 if (!isInitialState && m_mainFrame)
468 m_mainFrame->dispatchVisibilityStateChangeEvent();
469 }
470
visibilityState() const471 PageVisibilityState Page::visibilityState() const
472 {
473 return m_visibilityState;
474 }
475
addMultisamplingChangedObserver(MultisamplingChangedObserver * observer)476 void Page::addMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
477 {
478 m_multisamplingChangedObservers.add(observer);
479 }
480
removeMultisamplingChangedObserver(MultisamplingChangedObserver * observer)481 void Page::removeMultisamplingChangedObserver(MultisamplingChangedObserver* observer)
482 {
483 m_multisamplingChangedObservers.remove(observer);
484 }
485
settingsChanged(SettingsDelegate::ChangeType changeType)486 void Page::settingsChanged(SettingsDelegate::ChangeType changeType)
487 {
488 switch (changeType) {
489 case SettingsDelegate::StyleChange:
490 setNeedsRecalcStyleInAllFrames();
491 break;
492 case SettingsDelegate::ViewportDescriptionChange:
493 if (mainFrame())
494 mainFrame()->document()->updateViewportDescription();
495 break;
496 case SettingsDelegate::MediaTypeChange:
497 m_mainFrame->view()->setMediaType(settings().mediaTypeOverride());
498 setNeedsRecalcStyleInAllFrames();
499 break;
500 case SettingsDelegate::DNSPrefetchingChange:
501 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext())
502 frame->document()->initDNSPrefetch();
503 break;
504 case SettingsDelegate::MultisamplingChange: {
505 HashSet<MultisamplingChangedObserver*>::iterator stop = m_multisamplingChangedObservers.end();
506 for (HashSet<MultisamplingChangedObserver*>::iterator it = m_multisamplingChangedObservers.begin(); it != stop; ++it)
507 (*it)->multisamplingChanged(m_settings->openGLMultisamplingEnabled());
508 break;
509 }
510 case SettingsDelegate::ImageLoadingChange:
511 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
512 frame->document()->fetcher()->setImagesEnabled(settings().imagesEnabled());
513 frame->document()->fetcher()->setAutoLoadImages(settings().loadsImagesAutomatically());
514 }
515 break;
516 case SettingsDelegate::TextAutosizingChange:
517 // FIXME: I wonder if this needs to traverse frames like in WebViewImpl::resize, or whether there is only one document per Settings instance?
518 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) {
519 TextAutosizer* textAutosizer = frame->document()->textAutosizer();
520 if (textAutosizer)
521 textAutosizer->recalculateMultipliers();
522 }
523 setNeedsRecalcStyleInAllFrames();
524 break;
525 }
526 }
527
didCommitLoad(Frame * frame)528 void Page::didCommitLoad(Frame* frame)
529 {
530 lifecycleNotifier().notifyDidCommitLoad(frame);
531 if (m_mainFrame == frame)
532 useCounter().didCommitLoad();
533 }
534
lifecycleNotifier()535 PageLifecycleNotifier& Page::lifecycleNotifier()
536 {
537 return static_cast<PageLifecycleNotifier&>(LifecycleContext<Page>::lifecycleNotifier());
538 }
539
createLifecycleNotifier()540 PassOwnPtr<LifecycleNotifier<Page> > Page::createLifecycleNotifier()
541 {
542 return PageLifecycleNotifier::create(this);
543 }
544
PageClients()545 Page::PageClients::PageClients()
546 : chromeClient(0)
547 , contextMenuClient(0)
548 , editorClient(0)
549 , dragClient(0)
550 , inspectorClient(0)
551 , backForwardClient(0)
552 , spellCheckerClient(0)
553 {
554 }
555
~PageClients()556 Page::PageClients::~PageClients()
557 {
558 }
559
560 } // namespace WebCore
561