1 /* 2 * Copyright (C) 2006, 2007, 2008 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 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Library General Public License for more details. 14 * 15 * You should have received a copy of the GNU Library General Public License 16 * along with this library; see the file COPYING.LIB. If not, write to 17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21 #include "config.h" 22 #include "Page.h" 23 24 #include "BackForwardList.h" 25 #include "Base64.h" 26 #include "CSSStyleSelector.h" 27 #include "Chrome.h" 28 #include "ChromeClient.h" 29 #include "ContextMenuClient.h" 30 #include "ContextMenuController.h" 31 #include "DOMWindow.h" 32 #include "DragController.h" 33 #include "ExceptionCode.h" 34 #include "EditorClient.h" 35 #include "EventNames.h" 36 #include "Event.h" 37 #include "FileSystem.h" 38 #include "FocusController.h" 39 #include "Frame.h" 40 #include "FrameLoader.h" 41 #include "FrameLoaderClient.h" 42 #include "FrameTree.h" 43 #include "FrameView.h" 44 #include "HTMLElement.h" 45 #include "HistoryItem.h" 46 #include "InspectorController.h" 47 #include "InspectorTimelineAgent.h" 48 #include "Logging.h" 49 #include "Navigator.h" 50 #include "NetworkStateNotifier.h" 51 #include "PageGroup.h" 52 #include "PluginData.h" 53 #include "PluginHalter.h" 54 #include "ProgressTracker.h" 55 #include "RenderWidget.h" 56 #include "RenderTheme.h" 57 #include "ScriptController.h" 58 #include "SelectionController.h" 59 #include "Settings.h" 60 #include "StringHash.h" 61 #include "TextResourceDecoder.h" 62 #include "Widget.h" 63 #include <wtf/HashMap.h> 64 #include <wtf/RefCountedLeakCounter.h> 65 #include <wtf/StdLibExtras.h> 66 67 #if ENABLE(DOM_STORAGE) 68 #include "StorageArea.h" 69 #include "StorageNamespace.h" 70 #endif 71 72 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) 73 #include "JavaScriptDebugServer.h" 74 #endif 75 76 #if ENABLE(WML) 77 #include "WMLPageState.h" 78 #endif 79 80 #if ENABLE(CLIENT_BASED_GEOLOCATION) 81 #include "GeolocationController.h" 82 #endif 83 84 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) 85 #include "PackageNotifier.h" 86 #endif 87 88 namespace WebCore { 89 90 static HashSet<Page*>* allPages; 91 92 #ifndef NDEBUG 93 static WTF::RefCountedLeakCounter pageCounter("Page"); 94 #endif 95 96 static void networkStateChanged() 97 { 98 Vector<RefPtr<Frame> > frames; 99 100 // Get all the frames of all the pages in all the page groups 101 HashSet<Page*>::iterator end = allPages->end(); 102 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) { 103 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 104 frames.append(frame); 105 } 106 107 AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent; 108 for (unsigned i = 0; i < frames.size(); i++) 109 frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false)); 110 } 111 112 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) 113 static void onPackageResultAvailable() 114 { 115 HashSet<Page*>::iterator end = allPages->end(); 116 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) { 117 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 118 frame->domWindow()->navigator()->onPackageResult(); 119 } 120 } 121 #endif 122 123 Page::Page(ChromeClient* chromeClient, ContextMenuClient* contextMenuClient, EditorClient* editorClient, DragClient* dragClient, InspectorClient* inspectorClient, PluginHalterClient* pluginHalterClient, GeolocationControllerClient* geolocationControllerClient) 124 : m_chrome(new Chrome(this, chromeClient)) 125 , m_dragCaretController(new SelectionController(0, true)) 126 #if ENABLE(DRAG_SUPPORT) 127 , m_dragController(new DragController(this, dragClient)) 128 #endif 129 , m_focusController(new FocusController(this)) 130 #if ENABLE(CONTEXT_MENUS) 131 , m_contextMenuController(new ContextMenuController(this, contextMenuClient)) 132 #endif 133 #if ENABLE(INSPECTOR) 134 , m_inspectorController(new InspectorController(this, inspectorClient)) 135 #endif 136 #if ENABLE(CLIENT_BASED_GEOLOCATION) 137 , m_geolocationController(new GeolocationController(this, geolocationControllerClient)) 138 #endif 139 , m_settings(new Settings(this)) 140 , m_progress(new ProgressTracker) 141 , m_backForwardList(BackForwardList::create(this)) 142 , m_theme(RenderTheme::themeForPage(this)) 143 , m_editorClient(editorClient) 144 , m_frameCount(0) 145 , m_openedByDOM(false) 146 , m_tabKeyCyclesThroughElements(true) 147 , m_defersLoading(false) 148 , m_inLowQualityInterpolationMode(false) 149 , m_cookieEnabled(true) 150 , m_areMemoryCacheClientCallsEnabled(true) 151 , m_mediaVolume(1) 152 , m_javaScriptURLsAreAllowed(true) 153 #if ENABLE(INSPECTOR) 154 , m_parentInspectorController(0) 155 #endif 156 , m_didLoadUserStyleSheet(false) 157 , m_userStyleSheetModificationTime(0) 158 , m_group(0) 159 , m_debugger(0) 160 , m_customHTMLTokenizerTimeDelay(-1) 161 , m_customHTMLTokenizerChunkSize(-1) 162 , m_canStartPlugins(true) 163 { 164 #if !ENABLE(CONTEXT_MENUS) 165 UNUSED_PARAM(contextMenuClient); 166 #endif 167 #if !ENABLE(DRAG_SUPPORT) 168 UNUSED_PARAM(dragClient); 169 #endif 170 #if !ENABLE(INSPECTOR) 171 UNUSED_PARAM(inspectorClient); 172 #endif 173 #if !ENABLE(CLIENT_BASED_GEOLOCATION) 174 UNUSED_PARAM(geolocationControllerClient); 175 #endif 176 177 if (!allPages) { 178 allPages = new HashSet<Page*>; 179 180 networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged); 181 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) 182 packageNotifier().setOnResultAvailable(onPackageResultAvailable); 183 #endif 184 } 185 186 ASSERT(!allPages->contains(this)); 187 allPages->add(this); 188 189 if (pluginHalterClient) { 190 m_pluginHalter.set(new PluginHalter(pluginHalterClient)); 191 m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime()); 192 } 193 194 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC) 195 JavaScriptDebugServer::shared().pageCreated(this); 196 #endif 197 198 #ifndef NDEBUG 199 pageCounter.increment(); 200 #endif 201 } 202 203 Page::~Page() 204 { 205 m_mainFrame->setView(0); 206 setGroupName(String()); 207 allPages->remove(this); 208 209 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 210 frame->pageDestroyed(); 211 212 m_editorClient->pageDestroyed(); 213 if (m_pluginData) 214 m_pluginData->disconnectPage(); 215 216 #if ENABLE(INSPECTOR) 217 if (m_parentInspectorController) 218 m_parentInspectorController->pageDestroyed(); 219 m_inspectorController->inspectedPageDestroyed(); 220 #endif 221 222 m_backForwardList->close(); 223 224 #ifndef NDEBUG 225 pageCounter.decrement(); 226 227 // Cancel keepAlive timers, to ensure we release all Frames before exiting. 228 // It's safe to do this because we prohibit closing a Page while JavaScript 229 // is executing. 230 Frame::cancelAllKeepAlive(); 231 #endif 232 } 233 234 void Page::setMainFrame(PassRefPtr<Frame> mainFrame) 235 { 236 ASSERT(!m_mainFrame); // Should only be called during initialization 237 m_mainFrame = mainFrame; 238 } 239 240 bool Page::openedByDOM() const 241 { 242 return m_openedByDOM; 243 } 244 245 void Page::setOpenedByDOM() 246 { 247 m_openedByDOM = true; 248 } 249 250 BackForwardList* Page::backForwardList() 251 { 252 return m_backForwardList.get(); 253 } 254 255 bool Page::goBack() 256 { 257 HistoryItem* item = m_backForwardList->backItem(); 258 259 if (item) { 260 goToItem(item, FrameLoadTypeBack); 261 return true; 262 } 263 return false; 264 } 265 266 bool Page::goForward() 267 { 268 HistoryItem* item = m_backForwardList->forwardItem(); 269 270 if (item) { 271 goToItem(item, FrameLoadTypeForward); 272 return true; 273 } 274 return false; 275 } 276 277 bool Page::canGoBackOrForward(int distance) const 278 { 279 if (distance == 0) 280 return true; 281 if (distance > 0 && distance <= m_backForwardList->forwardListCount()) 282 return true; 283 if (distance < 0 && -distance <= m_backForwardList->backListCount()) 284 return true; 285 return false; 286 } 287 288 void Page::goBackOrForward(int distance) 289 { 290 if (distance == 0) 291 return; 292 293 HistoryItem* item = m_backForwardList->itemAtIndex(distance); 294 if (!item) { 295 if (distance > 0) { 296 int forwardListCount = m_backForwardList->forwardListCount(); 297 if (forwardListCount > 0) 298 item = m_backForwardList->itemAtIndex(forwardListCount); 299 } else { 300 int backListCount = m_backForwardList->backListCount(); 301 if (backListCount > 0) 302 item = m_backForwardList->itemAtIndex(-backListCount); 303 } 304 } 305 306 ASSERT(item); // we should not reach this line with an empty back/forward list 307 if (item) 308 goToItem(item, FrameLoadTypeIndexedBackForward); 309 } 310 311 void Page::goToItem(HistoryItem* item, FrameLoadType type) 312 { 313 // Abort any current load unless we're navigating the current document to a new state object 314 HistoryItem* currentItem = m_mainFrame->loader()->history()->currentItem(); 315 if (!item->stateObject() || !currentItem || item->documentSequenceNumber() != currentItem->documentSequenceNumber()) { 316 // Define what to do with any open database connections. By default we stop them and terminate the database thread. 317 DatabasePolicy databasePolicy = DatabasePolicyStop; 318 319 #if ENABLE(DATABASE) 320 // If we're navigating the history via a fragment on the same document, then we do not want to stop databases. 321 const KURL& currentURL = m_mainFrame->loader()->url(); 322 const KURL& newURL = item->url(); 323 324 if (newURL.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(currentURL, newURL)) 325 databasePolicy = DatabasePolicyContinue; 326 #endif 327 328 m_mainFrame->loader()->stopAllLoaders(databasePolicy); 329 } 330 331 m_mainFrame->loader()->history()->goToItem(item, type); 332 } 333 334 int Page::getHistoryLength() 335 { 336 return m_backForwardList->backListCount() + 1 + m_backForwardList->forwardListCount(); 337 } 338 339 void Page::setGlobalHistoryItem(HistoryItem* item) 340 { 341 m_globalHistoryItem = item; 342 } 343 344 void Page::setGroupName(const String& name) 345 { 346 if (m_group && !m_group->name().isEmpty()) { 347 ASSERT(m_group != m_singlePageGroup.get()); 348 ASSERT(!m_singlePageGroup); 349 m_group->removePage(this); 350 } 351 352 if (name.isEmpty()) 353 m_group = m_singlePageGroup.get(); 354 else { 355 m_singlePageGroup.clear(); 356 m_group = PageGroup::pageGroup(name); 357 m_group->addPage(this); 358 } 359 } 360 361 const String& Page::groupName() const 362 { 363 DEFINE_STATIC_LOCAL(String, nullString, ()); 364 return m_group ? m_group->name() : nullString; 365 } 366 367 void Page::initGroup() 368 { 369 ASSERT(!m_singlePageGroup); 370 ASSERT(!m_group); 371 m_singlePageGroup.set(new PageGroup(this)); 372 m_group = m_singlePageGroup.get(); 373 } 374 375 void Page::setNeedsReapplyStyles() 376 { 377 if (!allPages) 378 return; 379 HashSet<Page*>::iterator end = allPages->end(); 380 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) 381 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 382 frame->setNeedsReapplyStyles(); 383 } 384 385 void Page::refreshPlugins(bool reload) 386 { 387 if (!allPages) 388 return; 389 390 PluginData::refresh(); 391 392 Vector<RefPtr<Frame> > framesNeedingReload; 393 394 HashSet<Page*>::iterator end = allPages->end(); 395 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) { 396 Page* page = *it; 397 398 // Clear out the page's plug-in data. 399 if (page->m_pluginData) { 400 page->m_pluginData->disconnectPage(); 401 page->m_pluginData = 0; 402 } 403 404 if (reload) { 405 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) { 406 if (frame->loader()->containsPlugins()) 407 framesNeedingReload.append(frame); 408 } 409 } 410 } 411 412 for (size_t i = 0; i < framesNeedingReload.size(); ++i) 413 framesNeedingReload[i]->loader()->reload(); 414 } 415 416 PluginData* Page::pluginData() const 417 { 418 if (!settings()->arePluginsEnabled()) 419 return 0; 420 if (!m_pluginData) 421 m_pluginData = PluginData::create(this); 422 return m_pluginData.get(); 423 } 424 425 void Page::addUnstartedPlugin(PluginView* view) 426 { 427 ASSERT(!m_canStartPlugins); 428 m_unstartedPlugins.add(view); 429 } 430 431 void Page::removeUnstartedPlugin(PluginView* view) 432 { 433 ASSERT(!m_canStartPlugins); 434 ASSERT(m_unstartedPlugins.contains(view)); 435 m_unstartedPlugins.remove(view); 436 } 437 438 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag) 439 { 440 return forward 441 ? curr->tree()->traverseNextWithWrap(wrapFlag) 442 : curr->tree()->traversePreviousWithWrap(wrapFlag); 443 } 444 445 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap) 446 { 447 if (target.isEmpty() || !mainFrame()) 448 return false; 449 450 Frame* frame = focusController()->focusedOrMainFrame(); 451 Frame* startFrame = frame; 452 do { 453 if (frame->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, false, true)) { 454 if (frame != startFrame) 455 startFrame->selection()->clear(); 456 focusController()->setFocusedFrame(frame); 457 return true; 458 } 459 frame = incrementFrame(frame, direction == FindDirectionForward, shouldWrap); 460 } while (frame && frame != startFrame); 461 462 // Search contents of startFrame, on the other side of the selection that we did earlier. 463 // We cheat a bit and just research with wrap on 464 if (shouldWrap && !startFrame->selection()->isNone()) { 465 bool found = startFrame->findString(target, direction == FindDirectionForward, caseSensitivity == TextCaseSensitive, true, true); 466 focusController()->setFocusedFrame(frame); 467 return found; 468 } 469 470 return false; 471 } 472 473 unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit) 474 { 475 if (target.isEmpty() || !mainFrame()) 476 return 0; 477 478 unsigned matches = 0; 479 480 Frame* frame = mainFrame(); 481 do { 482 frame->setMarkedTextMatchesAreHighlighted(shouldHighlight); 483 matches += frame->markAllMatchesForText(target, caseSensitivity == TextCaseSensitive, (limit == 0) ? 0 : (limit - matches)); 484 frame = incrementFrame(frame, true, false); 485 } while (frame); 486 487 return matches; 488 } 489 490 void Page::unmarkAllTextMatches() 491 { 492 if (!mainFrame()) 493 return; 494 495 Frame* frame = mainFrame(); 496 do { 497 frame->document()->removeMarkers(DocumentMarker::TextMatch); 498 frame = incrementFrame(frame, true, false); 499 } while (frame); 500 } 501 502 const VisibleSelection& Page::selection() const 503 { 504 return focusController()->focusedOrMainFrame()->selection()->selection(); 505 } 506 507 void Page::setDefersLoading(bool defers) 508 { 509 if (!m_settings->loadDeferringEnabled()) 510 return; 511 512 if (defers == m_defersLoading) 513 return; 514 515 m_defersLoading = defers; 516 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 517 frame->loader()->setDefersLoading(defers); 518 } 519 520 void Page::clearUndoRedoOperations() 521 { 522 m_editorClient->clearUndoRedoOperations(); 523 } 524 525 bool Page::inLowQualityImageInterpolationMode() const 526 { 527 return m_inLowQualityInterpolationMode; 528 } 529 530 void Page::setInLowQualityImageInterpolationMode(bool mode) 531 { 532 m_inLowQualityInterpolationMode = mode; 533 } 534 535 void Page::setMediaVolume(float volume) 536 { 537 if (volume < 0 || volume > 1) 538 return; 539 540 if (m_mediaVolume == volume) 541 return; 542 543 m_mediaVolume = volume; 544 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 545 frame->document()->mediaVolumeDidChange(); 546 } 547 } 548 549 void Page::didMoveOnscreen() 550 { 551 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 552 if (frame->view()) 553 frame->view()->didMoveOnscreen(); 554 } 555 } 556 557 void Page::willMoveOffscreen() 558 { 559 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 560 if (frame->view()) 561 frame->view()->willMoveOffscreen(); 562 } 563 } 564 565 void Page::userStyleSheetLocationChanged() 566 { 567 // FIXME: Eventually we will move to a model of just being handed the sheet 568 // text instead of loading the URL ourselves. 569 KURL url = m_settings->userStyleSheetLocation(); 570 if (url.isLocalFile()) 571 m_userStyleSheetPath = url.fileSystemPath(); 572 else 573 m_userStyleSheetPath = String(); 574 575 m_didLoadUserStyleSheet = false; 576 m_userStyleSheet = String(); 577 m_userStyleSheetModificationTime = 0; 578 579 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them 580 // synchronously and avoid using a loader. 581 if (url.protocolIs("data") && url.string().startsWith("data:text/css;charset=utf-8;base64,")) { 582 m_didLoadUserStyleSheet = true; 583 584 const unsigned prefixLength = 35; 585 Vector<char> encodedData(url.string().length() - prefixLength); 586 for (unsigned i = prefixLength; i < url.string().length(); ++i) 587 encodedData[i - prefixLength] = static_cast<char>(url.string()[i]); 588 589 Vector<char> styleSheetAsUTF8; 590 if (base64Decode(encodedData, styleSheetAsUTF8)) 591 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size()); 592 } 593 594 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 595 if (frame->document()) 596 frame->document()->clearPageUserSheet(); 597 } 598 } 599 600 const String& Page::userStyleSheet() const 601 { 602 if (m_userStyleSheetPath.isEmpty()) 603 return m_userStyleSheet; 604 605 time_t modTime; 606 if (!getFileModificationTime(m_userStyleSheetPath, modTime)) { 607 // The stylesheet either doesn't exist, was just deleted, or is 608 // otherwise unreadable. If we've read the stylesheet before, we should 609 // throw away that data now as it no longer represents what's on disk. 610 m_userStyleSheet = String(); 611 return m_userStyleSheet; 612 } 613 614 // If the stylesheet hasn't changed since the last time we read it, we can 615 // just return the old data. 616 if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime) 617 return m_userStyleSheet; 618 619 m_didLoadUserStyleSheet = true; 620 m_userStyleSheet = String(); 621 m_userStyleSheetModificationTime = modTime; 622 623 // FIXME: It would be better to load this asynchronously to avoid blocking 624 // the process, but we will first need to create an asynchronous loading 625 // mechanism that is not tied to a particular Frame. We will also have to 626 // determine what our behavior should be before the stylesheet is loaded 627 // and what should happen when it finishes loading, especially with respect 628 // to when the load event fires, when Document::close is called, and when 629 // layout/paint are allowed to happen. 630 RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath); 631 if (!data) 632 return m_userStyleSheet; 633 634 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css"); 635 m_userStyleSheet = decoder->decode(data->data(), data->size()); 636 m_userStyleSheet += decoder->flush(); 637 638 return m_userStyleSheet; 639 } 640 641 void Page::removeAllVisitedLinks() 642 { 643 if (!allPages) 644 return; 645 HashSet<PageGroup*> groups; 646 HashSet<Page*>::iterator pagesEnd = allPages->end(); 647 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 648 if (PageGroup* group = (*it)->groupPtr()) 649 groups.add(group); 650 } 651 HashSet<PageGroup*>::iterator groupsEnd = groups.end(); 652 for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it) 653 (*it)->removeVisitedLinks(); 654 } 655 656 void Page::allVisitedStateChanged(PageGroup* group) 657 { 658 ASSERT(group); 659 if (!allPages) 660 return; 661 662 HashSet<Page*>::iterator pagesEnd = allPages->end(); 663 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 664 Page* page = *it; 665 if (page->m_group != group) 666 continue; 667 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { 668 if (CSSStyleSelector* styleSelector = frame->document()->styleSelector()) 669 styleSelector->allVisitedStateChanged(); 670 } 671 } 672 } 673 674 void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash) 675 { 676 ASSERT(group); 677 if (!allPages) 678 return; 679 680 HashSet<Page*>::iterator pagesEnd = allPages->end(); 681 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 682 Page* page = *it; 683 if (page->m_group != group) 684 continue; 685 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { 686 if (CSSStyleSelector* styleSelector = frame->document()->styleSelector()) 687 styleSelector->visitedStateChanged(visitedLinkHash); 688 } 689 } 690 } 691 692 void Page::setDebuggerForAllPages(JSC::Debugger* debugger) 693 { 694 ASSERT(allPages); 695 696 HashSet<Page*>::iterator end = allPages->end(); 697 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) 698 (*it)->setDebugger(debugger); 699 } 700 701 void Page::setDebugger(JSC::Debugger* debugger) 702 { 703 if (m_debugger == debugger) 704 return; 705 706 m_debugger = debugger; 707 708 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) 709 frame->script()->attachDebugger(m_debugger); 710 } 711 712 #if ENABLE(DOM_STORAGE) 713 StorageNamespace* Page::sessionStorage(bool optionalCreate) 714 { 715 if (!m_sessionStorage && optionalCreate) 716 m_sessionStorage = StorageNamespace::sessionStorageNamespace(this); 717 718 return m_sessionStorage.get(); 719 } 720 721 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage) 722 { 723 m_sessionStorage = newStorage; 724 } 725 #endif 726 727 #if ENABLE(WML) 728 WMLPageState* Page::wmlPageState() 729 { 730 if (!m_wmlPageState) 731 m_wmlPageState.set(new WMLPageState(this)); 732 return m_wmlPageState.get(); 733 } 734 #endif 735 736 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay) 737 { 738 if (customHTMLTokenizerTimeDelay < 0) { 739 m_customHTMLTokenizerTimeDelay = -1; 740 return; 741 } 742 m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay; 743 } 744 745 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize) 746 { 747 if (customHTMLTokenizerChunkSize < 0) { 748 m_customHTMLTokenizerChunkSize = -1; 749 return; 750 } 751 m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize; 752 } 753 754 void Page::setMemoryCacheClientCallsEnabled(bool enabled) 755 { 756 if (m_areMemoryCacheClientCallsEnabled == enabled) 757 return; 758 759 m_areMemoryCacheClientCallsEnabled = enabled; 760 if (!enabled) 761 return; 762 763 for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 764 frame->loader()->tellClientAboutPastMemoryCacheLoads(); 765 } 766 767 void Page::setJavaScriptURLsAreAllowed(bool areAllowed) 768 { 769 m_javaScriptURLsAreAllowed = areAllowed; 770 } 771 772 bool Page::javaScriptURLsAreAllowed() const 773 { 774 return m_javaScriptURLsAreAllowed; 775 } 776 777 #if ENABLE(INSPECTOR) 778 InspectorTimelineAgent* Page::inspectorTimelineAgent() const 779 { 780 return m_inspectorController->timelineAgent(); 781 } 782 #endif 783 784 void Page::pluginAllowedRunTimeChanged() 785 { 786 if (m_pluginHalter) 787 m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime()); 788 } 789 790 void Page::didStartPlugin(HaltablePlugin* obj) 791 { 792 if (m_pluginHalter) 793 m_pluginHalter->didStartPlugin(obj); 794 } 795 796 void Page::didStopPlugin(HaltablePlugin* obj) 797 { 798 if (m_pluginHalter) 799 m_pluginHalter->didStopPlugin(obj); 800 } 801 802 #if !ASSERT_DISABLED 803 void Page::checkFrameCountConsistency() const 804 { 805 ASSERT(m_frameCount >= 0); 806 807 int frameCount = 0; 808 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 809 ++frameCount; 810 811 ASSERT(m_frameCount + 1 == frameCount); 812 } 813 #endif 814 } // namespace WebCore 815