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 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 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 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 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 168 ViewportDescription Page::viewportDescription() const 169 { 170 return mainFrame() && mainFrame()->document() ? mainFrame()->document()->viewportDescription() : ViewportDescription(); 171 } 172 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 181 String Page::mainThreadScrollingReasonsAsText() 182 { 183 if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) 184 return scrollingCoordinator->mainThreadScrollingReasonsAsText(); 185 186 return String(); 187 } 188 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 204 void Page::setMainFrame(PassRefPtr<Frame> mainFrame) 205 { 206 ASSERT(!m_mainFrame); // Should only be called during initialization 207 m_mainFrame = mainFrame; 208 } 209 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 220 bool Page::openedByDOM() const 221 { 222 return m_openedByDOM; 223 } 224 225 void Page::setOpenedByDOM() 226 { 227 m_openedByDOM = true; 228 } 229 230 void Page::clearPageGroup() 231 { 232 if (!m_group) 233 return; 234 m_group->removePage(this); 235 m_group = 0; 236 } 237 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 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 264 void Page::setNeedsRecalcStyleInAllFrames() 265 { 266 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext()) 267 frame->document()->styleResolverChanged(RecalcStyleDeferred); 268 } 269 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 300 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 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 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 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 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 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 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 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 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 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 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 435 double Page::timerAlignmentInterval() const 436 { 437 return m_timerAlignmentInterval; 438 } 439 440 #if !ASSERT_DISABLED 441 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 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 471 PageVisibilityState Page::visibilityState() const 472 { 473 return m_visibilityState; 474 } 475 476 void Page::addMultisamplingChangedObserver(MultisamplingChangedObserver* observer) 477 { 478 m_multisamplingChangedObservers.add(observer); 479 } 480 481 void Page::removeMultisamplingChangedObserver(MultisamplingChangedObserver* observer) 482 { 483 m_multisamplingChangedObservers.remove(observer); 484 } 485 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 528 void Page::didCommitLoad(Frame* frame) 529 { 530 lifecycleNotifier().notifyDidCommitLoad(frame); 531 if (m_mainFrame == frame) 532 useCounter().didCommitLoad(); 533 } 534 535 PageLifecycleNotifier& Page::lifecycleNotifier() 536 { 537 return static_cast<PageLifecycleNotifier&>(LifecycleContext<Page>::lifecycleNotifier()); 538 } 539 540 PassOwnPtr<LifecycleNotifier<Page> > Page::createLifecycleNotifier() 541 { 542 return PageLifecycleNotifier::create(this); 543 } 544 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 556 Page::PageClients::~PageClients() 557 { 558 } 559 560 } // namespace WebCore 561