1 /* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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 "Page.h" 22 23 #include "BackForwardController.h" 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 "DeviceMotionController.h" 33 #include "DeviceOrientationController.h" 34 #include "DocumentMarkerController.h" 35 #include "DragController.h" 36 #include "EditorClient.h" 37 #include "Event.h" 38 #include "EventNames.h" 39 #include "ExceptionCode.h" 40 #include "FileSystem.h" 41 #include "FocusController.h" 42 #include "Frame.h" 43 #include "FrameLoader.h" 44 #include "FrameLoaderClient.h" 45 #include "FrameTree.h" 46 #include "FrameView.h" 47 #include "HTMLElement.h" 48 #include "HistoryItem.h" 49 #include "InspectorController.h" 50 #include "InspectorInstrumentation.h" 51 #include "Logging.h" 52 #include "MediaCanStartListener.h" 53 #include "Navigator.h" 54 #include "NetworkStateNotifier.h" 55 #include "PageGroup.h" 56 #include "PluginData.h" 57 #include "PluginHalter.h" 58 #include "PluginView.h" 59 #include "PluginViewBase.h" 60 #include "ProgressTracker.h" 61 #include "RenderTheme.h" 62 #include "RenderWidget.h" 63 #include "RuntimeEnabledFeatures.h" 64 #include "ScriptController.h" 65 #include "SelectionController.h" 66 #include "Settings.h" 67 #include "SharedBuffer.h" 68 #include "SpeechInput.h" 69 #include "SpeechInputClient.h" 70 #include "TextResourceDecoder.h" 71 #include "Widget.h" 72 #include <wtf/HashMap.h> 73 #include <wtf/RefCountedLeakCounter.h> 74 #include <wtf/StdLibExtras.h> 75 #include <wtf/text/StringHash.h> 76 77 #if ENABLE(ACCELERATED_2D_CANVAS) 78 #include "SharedGraphicsContext3D.h" 79 #endif 80 81 #if ENABLE(DOM_STORAGE) 82 #include "StorageArea.h" 83 #include "StorageNamespace.h" 84 #endif 85 86 #if ENABLE(WML) 87 #include "WMLPageState.h" 88 #endif 89 90 #if ENABLE(CLIENT_BASED_GEOLOCATION) 91 #include "GeolocationController.h" 92 #endif 93 94 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) 95 #include "PackageNotifier.h" 96 #endif 97 98 namespace WebCore { 99 100 static HashSet<Page*>* allPages; 101 102 #ifndef NDEBUG 103 static WTF::RefCountedLeakCounter pageCounter("Page"); 104 #endif 105 106 static void networkStateChanged() 107 { 108 Vector<RefPtr<Frame> > frames; 109 110 // Get all the frames of all the pages in all the page groups 111 HashSet<Page*>::iterator end = allPages->end(); 112 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) { 113 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 114 frames.append(frame); 115 InspectorInstrumentation::networkStateChanged(*it); 116 } 117 118 AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent; 119 for (unsigned i = 0; i < frames.size(); i++) 120 frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false)); 121 } 122 123 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) 124 static void onPackageResultAvailable() 125 { 126 HashSet<Page*>::iterator end = allPages->end(); 127 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) { 128 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 129 frame->domWindow()->navigator()->onPackageResult(); 130 } 131 } 132 #endif 133 134 Page::Page(const PageClients& pageClients) 135 : m_chrome(adoptPtr(new Chrome(this, pageClients.chromeClient))) 136 , m_dragCaretController(adoptPtr(new SelectionController(0, true))) 137 #if ENABLE(DRAG_SUPPORT) 138 , m_dragController(adoptPtr(new DragController(this, pageClients.dragClient))) 139 #endif 140 , m_focusController(adoptPtr(new FocusController(this))) 141 #if ENABLE(CONTEXT_MENUS) 142 , m_contextMenuController(adoptPtr(new ContextMenuController(this, pageClients.contextMenuClient))) 143 #endif 144 #if ENABLE(INSPECTOR) 145 , m_inspectorController(adoptPtr(new InspectorController(this, pageClients.inspectorClient))) 146 #endif 147 #if ENABLE(CLIENT_BASED_GEOLOCATION) 148 , m_geolocationController(adoptPtr(new GeolocationController(this, pageClients.geolocationClient))) 149 #endif 150 #if ENABLE(DEVICE_ORIENTATION) 151 , m_deviceMotionController(RuntimeEnabledFeatures::deviceMotionEnabled() ? new DeviceMotionController(pageClients.deviceMotionClient) : 0) 152 , m_deviceOrientationController(RuntimeEnabledFeatures::deviceOrientationEnabled() ? new DeviceOrientationController(this, pageClients.deviceOrientationClient) : 0) 153 #endif 154 #if ENABLE(INPUT_SPEECH) 155 , m_speechInputClient(pageClients.speechInputClient) 156 #endif 157 , m_settings(adoptPtr(new Settings(this))) 158 , m_progress(adoptPtr(new ProgressTracker)) 159 , m_backForwardController(adoptPtr(new BackForwardController(this, pageClients.backForwardClient))) 160 , m_theme(RenderTheme::themeForPage(this)) 161 , m_editorClient(pageClients.editorClient) 162 , m_frameCount(0) 163 , m_openedByDOM(false) 164 , m_tabKeyCyclesThroughElements(true) 165 , m_defersLoading(false) 166 , m_inLowQualityInterpolationMode(false) 167 , m_cookieEnabled(true) 168 , m_areMemoryCacheClientCallsEnabled(true) 169 , m_mediaVolume(1) 170 , m_javaScriptURLsAreAllowed(true) 171 , m_didLoadUserStyleSheet(false) 172 , m_userStyleSheetModificationTime(0) 173 , m_group(0) 174 , m_debugger(0) 175 , m_customHTMLTokenizerTimeDelay(-1) 176 , m_customHTMLTokenizerChunkSize(-1) 177 , m_canStartMedia(true) 178 , m_viewMode(ViewModeWindowed) 179 , m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval()) 180 , m_isEditable(false) 181 { 182 if (!allPages) { 183 allPages = new HashSet<Page*>; 184 185 networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged); 186 #if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED) 187 packageNotifier().setOnResultAvailable(onPackageResultAvailable); 188 #endif 189 } 190 191 ASSERT(!allPages->contains(this)); 192 allPages->add(this); 193 194 if (pageClients.pluginHalterClient) { 195 m_pluginHalter.set(new PluginHalter(pageClients.pluginHalterClient)); 196 m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime()); 197 } 198 199 #ifndef NDEBUG 200 pageCounter.increment(); 201 #endif 202 } 203 204 Page::~Page() 205 { 206 m_mainFrame->setView(0); 207 setGroupName(String()); 208 allPages->remove(this); 209 210 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 211 frame->pageDestroyed(); 212 213 if (m_scrollableAreaSet) { 214 ScrollableAreaSet::const_iterator end = m_scrollableAreaSet->end(); 215 for (ScrollableAreaSet::const_iterator it = m_scrollableAreaSet->begin(); it != end; ++it) 216 (*it)->disconnectFromPage(); 217 } 218 219 m_editorClient->pageDestroyed(); 220 221 InspectorInstrumentation::inspectedPageDestroyed(this); 222 223 backForward()->close(); 224 225 #ifndef NDEBUG 226 pageCounter.decrement(); 227 228 // Cancel keepAlive timers, to ensure we release all Frames before exiting. 229 // It's safe to do this because we prohibit closing a Page while JavaScript 230 // is executing. 231 Frame::cancelAllKeepAlive(); 232 #endif 233 } 234 235 struct ViewModeInfo { 236 const char* name; 237 Page::ViewMode type; 238 }; 239 static const int viewModeMapSize = 5; 240 static ViewModeInfo viewModeMap[viewModeMapSize] = { 241 {"windowed", Page::ViewModeWindowed}, 242 {"floating", Page::ViewModeFloating}, 243 {"fullscreen", Page::ViewModeFullscreen}, 244 {"maximized", Page::ViewModeMaximized}, 245 {"minimized", Page::ViewModeMinimized} 246 }; 247 248 Page::ViewMode Page::stringToViewMode(const String& text) 249 { 250 for (int i = 0; i < viewModeMapSize; ++i) { 251 if (text == viewModeMap[i].name) 252 return viewModeMap[i].type; 253 } 254 return Page::ViewModeInvalid; 255 } 256 257 void Page::setViewMode(ViewMode viewMode) 258 { 259 if (viewMode == m_viewMode || viewMode == ViewModeInvalid) 260 return; 261 262 m_viewMode = viewMode; 263 264 if (!m_mainFrame) 265 return; 266 267 if (m_mainFrame->view()) 268 m_mainFrame->view()->forceLayout(); 269 270 if (m_mainFrame->document()) 271 m_mainFrame->document()->styleSelectorChanged(RecalcStyleImmediately); 272 } 273 274 void Page::setMainFrame(PassRefPtr<Frame> mainFrame) 275 { 276 ASSERT(!m_mainFrame); // Should only be called during initialization 277 m_mainFrame = mainFrame; 278 } 279 280 bool Page::openedByDOM() const 281 { 282 return m_openedByDOM; 283 } 284 285 void Page::setOpenedByDOM() 286 { 287 m_openedByDOM = true; 288 } 289 290 BackForwardList* Page::backForwardList() const 291 { 292 return m_backForwardController->client(); 293 } 294 295 bool Page::goBack() 296 { 297 HistoryItem* item = backForward()->backItem(); 298 299 if (item) { 300 goToItem(item, FrameLoadTypeBack); 301 return true; 302 } 303 return false; 304 } 305 306 bool Page::goForward() 307 { 308 HistoryItem* item = backForward()->forwardItem(); 309 310 if (item) { 311 goToItem(item, FrameLoadTypeForward); 312 return true; 313 } 314 return false; 315 } 316 317 bool Page::canGoBackOrForward(int distance) const 318 { 319 if (distance == 0) 320 return true; 321 if (distance > 0 && distance <= backForward()->forwardCount()) 322 return true; 323 if (distance < 0 && -distance <= backForward()->backCount()) 324 return true; 325 return false; 326 } 327 328 void Page::goBackOrForward(int distance) 329 { 330 if (distance == 0) 331 return; 332 333 HistoryItem* item = backForward()->itemAtIndex(distance); 334 if (!item) { 335 if (distance > 0) { 336 if (int forwardCount = backForward()->forwardCount()) 337 item = backForward()->itemAtIndex(forwardCount); 338 } else { 339 if (int backCount = backForward()->backCount()) 340 item = backForward()->itemAtIndex(-backCount); 341 } 342 } 343 344 ASSERT(item); 345 if (!item) 346 return; 347 348 goToItem(item, FrameLoadTypeIndexedBackForward); 349 } 350 351 void Page::goToItem(HistoryItem* item, FrameLoadType type) 352 { 353 if (defersLoading()) 354 return; 355 356 // stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem 357 // being deref()-ed. Make sure we can still use it with HistoryController::goToItem later. 358 RefPtr<HistoryItem> protector(item); 359 360 if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item)) 361 m_mainFrame->loader()->stopAllLoaders(); 362 363 m_mainFrame->loader()->history()->goToItem(item, type); 364 } 365 366 int Page::getHistoryLength() 367 { 368 return backForward()->backCount() + 1 + backForward()->forwardCount(); 369 } 370 371 void Page::setGroupName(const String& name) 372 { 373 if (m_group && !m_group->name().isEmpty()) { 374 ASSERT(m_group != m_singlePageGroup.get()); 375 ASSERT(!m_singlePageGroup); 376 m_group->removePage(this); 377 } 378 379 if (name.isEmpty()) 380 m_group = m_singlePageGroup.get(); 381 else { 382 m_singlePageGroup.clear(); 383 m_group = PageGroup::pageGroup(name); 384 m_group->addPage(this); 385 } 386 } 387 388 const String& Page::groupName() const 389 { 390 DEFINE_STATIC_LOCAL(String, nullString, ()); 391 return m_group ? m_group->name() : nullString; 392 } 393 394 void Page::initGroup() 395 { 396 ASSERT(!m_singlePageGroup); 397 ASSERT(!m_group); 398 m_singlePageGroup.set(new PageGroup(this)); 399 m_group = m_singlePageGroup.get(); 400 } 401 402 void Page::scheduleForcedStyleRecalcForAllPages() 403 { 404 if (!allPages) 405 return; 406 HashSet<Page*>::iterator end = allPages->end(); 407 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) 408 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) 409 frame->document()->scheduleForcedStyleRecalc(); 410 } 411 412 void Page::setNeedsRecalcStyleInAllFrames() 413 { 414 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 415 frame->document()->styleSelectorChanged(DeferRecalcStyle); 416 } 417 418 void Page::updateViewportArguments() 419 { 420 if (!mainFrame() || !mainFrame()->document() || mainFrame()->document()->viewportArguments() == m_viewportArguments) 421 return; 422 423 m_viewportArguments = mainFrame()->document()->viewportArguments(); 424 chrome()->dispatchViewportDataDidChange(m_viewportArguments); 425 } 426 427 void Page::refreshPlugins(bool reload) 428 { 429 if (!allPages) 430 return; 431 432 PluginData::refresh(); 433 434 Vector<RefPtr<Frame> > framesNeedingReload; 435 436 HashSet<Page*>::iterator end = allPages->end(); 437 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) { 438 Page* page = *it; 439 440 // Clear out the page's plug-in data. 441 if (page->m_pluginData) 442 page->m_pluginData = 0; 443 444 if (!reload) 445 continue; 446 447 for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) { 448 if (frame->loader()->subframeLoader()->containsPlugins()) 449 framesNeedingReload.append(frame); 450 } 451 } 452 453 for (size_t i = 0; i < framesNeedingReload.size(); ++i) 454 framesNeedingReload[i]->loader()->reload(); 455 } 456 457 PluginData* Page::pluginData() const 458 { 459 if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin)) 460 return 0; 461 if (!m_pluginData) 462 m_pluginData = PluginData::create(this); 463 return m_pluginData.get(); 464 } 465 466 inline MediaCanStartListener* Page::takeAnyMediaCanStartListener() 467 { 468 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 469 if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener()) 470 return listener; 471 } 472 return 0; 473 } 474 475 void Page::setCanStartMedia(bool canStartMedia) 476 { 477 if (m_canStartMedia == canStartMedia) 478 return; 479 480 m_canStartMedia = canStartMedia; 481 482 while (m_canStartMedia) { 483 MediaCanStartListener* listener = takeAnyMediaCanStartListener(); 484 if (!listener) 485 break; 486 listener->mediaCanStart(); 487 } 488 } 489 490 static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag) 491 { 492 return forward 493 ? curr->tree()->traverseNextWithWrap(wrapFlag) 494 : curr->tree()->traversePreviousWithWrap(wrapFlag); 495 } 496 497 bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap) 498 { 499 return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0)); 500 } 501 502 bool Page::findString(const String& target, FindOptions options) 503 { 504 if (target.isEmpty() || !mainFrame()) 505 return false; 506 507 bool shouldWrap = options & WrapAround; 508 Frame* frame = focusController()->focusedOrMainFrame(); 509 Frame* startFrame = frame; 510 do { 511 if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) { 512 if (frame != startFrame) 513 startFrame->selection()->clear(); 514 focusController()->setFocusedFrame(frame); 515 return true; 516 } 517 frame = incrementFrame(frame, !(options & Backwards), shouldWrap); 518 } while (frame && frame != startFrame); 519 520 // Search contents of startFrame, on the other side of the selection that we did earlier. 521 // We cheat a bit and just research with wrap on 522 if (shouldWrap && !startFrame->selection()->isNone()) { 523 bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection); 524 focusController()->setFocusedFrame(frame); 525 return found; 526 } 527 528 return false; 529 } 530 531 unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit) 532 { 533 return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit); 534 } 535 536 unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit) 537 { 538 if (target.isEmpty() || !mainFrame()) 539 return 0; 540 541 unsigned matches = 0; 542 543 Frame* frame = mainFrame(); 544 do { 545 frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight); 546 matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true); 547 frame = incrementFrame(frame, true, false); 548 } while (frame); 549 550 return matches; 551 } 552 553 void Page::unmarkAllTextMatches() 554 { 555 if (!mainFrame()) 556 return; 557 558 Frame* frame = mainFrame(); 559 do { 560 frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch); 561 frame = incrementFrame(frame, true, false); 562 } while (frame); 563 } 564 565 const VisibleSelection& Page::selection() const 566 { 567 return focusController()->focusedOrMainFrame()->selection()->selection(); 568 } 569 570 void Page::setDefersLoading(bool defers) 571 { 572 if (!m_settings->loadDeferringEnabled()) 573 return; 574 575 if (defers == m_defersLoading) 576 return; 577 578 m_defersLoading = defers; 579 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 580 frame->loader()->setDefersLoading(defers); 581 } 582 583 void Page::clearUndoRedoOperations() 584 { 585 m_editorClient->clearUndoRedoOperations(); 586 } 587 588 bool Page::inLowQualityImageInterpolationMode() const 589 { 590 return m_inLowQualityInterpolationMode; 591 } 592 593 void Page::setInLowQualityImageInterpolationMode(bool mode) 594 { 595 m_inLowQualityInterpolationMode = mode; 596 } 597 598 void Page::setMediaVolume(float volume) 599 { 600 if (volume < 0 || volume > 1) 601 return; 602 603 if (m_mediaVolume == volume) 604 return; 605 606 m_mediaVolume = volume; 607 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 608 frame->document()->mediaVolumeDidChange(); 609 } 610 } 611 612 void Page::didMoveOnscreen() 613 { 614 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 615 if (frame->view()) 616 frame->view()->didMoveOnscreen(); 617 } 618 } 619 620 void Page::willMoveOffscreen() 621 { 622 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 623 if (frame->view()) 624 frame->view()->willMoveOffscreen(); 625 } 626 } 627 628 void Page::userStyleSheetLocationChanged() 629 { 630 // FIXME: Eventually we will move to a model of just being handed the sheet 631 // text instead of loading the URL ourselves. 632 KURL url = m_settings->userStyleSheetLocation(); 633 if (url.isLocalFile()) 634 m_userStyleSheetPath = url.fileSystemPath(); 635 else 636 m_userStyleSheetPath = String(); 637 638 m_didLoadUserStyleSheet = false; 639 m_userStyleSheet = String(); 640 m_userStyleSheetModificationTime = 0; 641 642 // Data URLs with base64-encoded UTF-8 style sheets are common. We can process them 643 // synchronously and avoid using a loader. 644 if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) { 645 m_didLoadUserStyleSheet = true; 646 647 Vector<char> styleSheetAsUTF8; 648 if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, IgnoreWhitespace)) 649 m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size()); 650 } 651 652 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 653 if (frame->document()) 654 frame->document()->updatePageUserSheet(); 655 } 656 } 657 658 const String& Page::userStyleSheet() const 659 { 660 if (m_userStyleSheetPath.isEmpty()) 661 return m_userStyleSheet; 662 663 time_t modTime; 664 if (!getFileModificationTime(m_userStyleSheetPath, modTime)) { 665 // The stylesheet either doesn't exist, was just deleted, or is 666 // otherwise unreadable. If we've read the stylesheet before, we should 667 // throw away that data now as it no longer represents what's on disk. 668 m_userStyleSheet = String(); 669 return m_userStyleSheet; 670 } 671 672 // If the stylesheet hasn't changed since the last time we read it, we can 673 // just return the old data. 674 if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime) 675 return m_userStyleSheet; 676 677 m_didLoadUserStyleSheet = true; 678 m_userStyleSheet = String(); 679 m_userStyleSheetModificationTime = modTime; 680 681 // FIXME: It would be better to load this asynchronously to avoid blocking 682 // the process, but we will first need to create an asynchronous loading 683 // mechanism that is not tied to a particular Frame. We will also have to 684 // determine what our behavior should be before the stylesheet is loaded 685 // and what should happen when it finishes loading, especially with respect 686 // to when the load event fires, when Document::close is called, and when 687 // layout/paint are allowed to happen. 688 RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath); 689 if (!data) 690 return m_userStyleSheet; 691 692 RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css"); 693 m_userStyleSheet = decoder->decode(data->data(), data->size()); 694 m_userStyleSheet += decoder->flush(); 695 696 return m_userStyleSheet; 697 } 698 699 void Page::removeAllVisitedLinks() 700 { 701 if (!allPages) 702 return; 703 HashSet<PageGroup*> groups; 704 HashSet<Page*>::iterator pagesEnd = allPages->end(); 705 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 706 if (PageGroup* group = (*it)->groupPtr()) 707 groups.add(group); 708 } 709 HashSet<PageGroup*>::iterator groupsEnd = groups.end(); 710 for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it) 711 (*it)->removeVisitedLinks(); 712 } 713 714 void Page::allVisitedStateChanged(PageGroup* group) 715 { 716 ASSERT(group); 717 if (!allPages) 718 return; 719 720 HashSet<Page*>::iterator pagesEnd = allPages->end(); 721 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 722 Page* page = *it; 723 if (page->m_group != group) 724 continue; 725 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { 726 if (CSSStyleSelector* styleSelector = frame->document()->styleSelector()) 727 styleSelector->allVisitedStateChanged(); 728 } 729 } 730 } 731 732 void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash) 733 { 734 ASSERT(group); 735 if (!allPages) 736 return; 737 738 HashSet<Page*>::iterator pagesEnd = allPages->end(); 739 for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) { 740 Page* page = *it; 741 if (page->m_group != group) 742 continue; 743 for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) { 744 if (CSSStyleSelector* styleSelector = frame->document()->styleSelector()) 745 styleSelector->visitedStateChanged(visitedLinkHash); 746 } 747 } 748 } 749 750 void Page::setDebuggerForAllPages(JSC::Debugger* debugger) 751 { 752 ASSERT(allPages); 753 754 HashSet<Page*>::iterator end = allPages->end(); 755 for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) 756 (*it)->setDebugger(debugger); 757 } 758 759 void Page::setDebugger(JSC::Debugger* debugger) 760 { 761 if (m_debugger == debugger) 762 return; 763 764 m_debugger = debugger; 765 766 for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) 767 frame->script()->attachDebugger(m_debugger); 768 } 769 770 SharedGraphicsContext3D* Page::sharedGraphicsContext3D() 771 { 772 #if ENABLE(ACCELERATED_2D_CANVAS) 773 if (!m_sharedGraphicsContext3D) 774 m_sharedGraphicsContext3D = SharedGraphicsContext3D::create(chrome()); 775 776 return m_sharedGraphicsContext3D.get(); 777 #else 778 return 0; 779 #endif 780 } 781 782 #if ENABLE(DOM_STORAGE) 783 StorageNamespace* Page::sessionStorage(bool optionalCreate) 784 { 785 if (!m_sessionStorage && optionalCreate) 786 m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota()); 787 788 return m_sessionStorage.get(); 789 } 790 791 void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage) 792 { 793 m_sessionStorage = newStorage; 794 } 795 #endif 796 797 #if ENABLE(WML) 798 WMLPageState* Page::wmlPageState() 799 { 800 if (!m_wmlPageState) 801 m_wmlPageState.set(new WMLPageState(this)); 802 return m_wmlPageState.get(); 803 } 804 #endif 805 806 void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay) 807 { 808 if (customHTMLTokenizerTimeDelay < 0) { 809 m_customHTMLTokenizerTimeDelay = -1; 810 return; 811 } 812 m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay; 813 } 814 815 void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize) 816 { 817 if (customHTMLTokenizerChunkSize < 0) { 818 m_customHTMLTokenizerChunkSize = -1; 819 return; 820 } 821 m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize; 822 } 823 824 void Page::setMemoryCacheClientCallsEnabled(bool enabled) 825 { 826 if (m_areMemoryCacheClientCallsEnabled == enabled) 827 return; 828 829 m_areMemoryCacheClientCallsEnabled = enabled; 830 if (!enabled) 831 return; 832 833 for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 834 frame->loader()->tellClientAboutPastMemoryCacheLoads(); 835 } 836 837 void Page::setJavaScriptURLsAreAllowed(bool areAllowed) 838 { 839 m_javaScriptURLsAreAllowed = areAllowed; 840 } 841 842 bool Page::javaScriptURLsAreAllowed() const 843 { 844 return m_javaScriptURLsAreAllowed; 845 } 846 847 void Page::setMinimumTimerInterval(double minimumTimerInterval) 848 { 849 double oldTimerInterval = m_minimumTimerInterval; 850 m_minimumTimerInterval = minimumTimerInterval; 851 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNextWithWrap(false)) { 852 if (frame->document()) 853 frame->document()->adjustMinimumTimerInterval(oldTimerInterval); 854 } 855 } 856 857 double Page::minimumTimerInterval() const 858 { 859 return m_minimumTimerInterval; 860 } 861 862 #if ENABLE(INPUT_SPEECH) 863 SpeechInput* Page::speechInput() 864 { 865 ASSERT(m_speechInputClient); 866 if (!m_speechInput.get()) 867 m_speechInput.set(new SpeechInput(m_speechInputClient)); 868 return m_speechInput.get(); 869 } 870 #endif 871 872 void Page::dnsPrefetchingStateChanged() 873 { 874 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 875 frame->document()->initDNSPrefetch(); 876 } 877 878 void Page::privateBrowsingStateChanged() 879 { 880 bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled(); 881 882 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 883 frame->document()->privateBrowsingStateDidChange(); 884 885 // Collect the PluginViews in to a vector to ensure that action the plug-in takes 886 // from below privateBrowsingStateChanged does not affect their lifetime. 887 Vector<RefPtr<PluginViewBase>, 32> pluginViewBases; 888 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) { 889 FrameView* view = frame->view(); 890 if (!view) 891 return; 892 893 const HashSet<RefPtr<Widget> >* children = view->children(); 894 ASSERT(children); 895 896 HashSet<RefPtr<Widget> >::const_iterator end = children->end(); 897 for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) { 898 Widget* widget = (*it).get(); 899 if (widget->isPluginViewBase()) 900 pluginViewBases.append(static_cast<PluginViewBase*>(widget)); 901 } 902 } 903 904 for (size_t i = 0; i < pluginViewBases.size(); ++i) 905 pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled); 906 } 907 908 void Page::pluginAllowedRunTimeChanged() 909 { 910 if (m_pluginHalter) 911 m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime()); 912 } 913 914 void Page::didStartPlugin(HaltablePlugin* obj) 915 { 916 if (m_pluginHalter) 917 m_pluginHalter->didStartPlugin(obj); 918 } 919 920 void Page::didStopPlugin(HaltablePlugin* obj) 921 { 922 if (m_pluginHalter) 923 m_pluginHalter->didStopPlugin(obj); 924 } 925 926 void Page::addScrollableArea(ScrollableArea* scrollableArea) 927 { 928 if (!m_scrollableAreaSet) 929 m_scrollableAreaSet = adoptPtr(new ScrollableAreaSet); 930 m_scrollableAreaSet->add(scrollableArea); 931 } 932 933 void Page::removeScrollableArea(ScrollableArea* scrollableArea) 934 { 935 if (!m_scrollableAreaSet) 936 return; 937 m_scrollableAreaSet->remove(scrollableArea); 938 } 939 940 bool Page::containsScrollableArea(ScrollableArea* scrollableArea) const 941 { 942 if (!m_scrollableAreaSet) 943 return false; 944 return m_scrollableAreaSet->contains(scrollableArea); 945 } 946 947 #if !ASSERT_DISABLED 948 void Page::checkFrameCountConsistency() const 949 { 950 ASSERT(m_frameCount >= 0); 951 952 int frameCount = 0; 953 for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) 954 ++frameCount; 955 956 ASSERT(m_frameCount + 1 == frameCount); 957 } 958 #endif 959 960 Page::PageClients::PageClients() 961 : chromeClient(0) 962 , contextMenuClient(0) 963 , editorClient(0) 964 , dragClient(0) 965 , inspectorClient(0) 966 , pluginHalterClient(0) 967 , geolocationClient(0) 968 , deviceMotionClient(0) 969 , deviceOrientationClient(0) 970 , speechInputClient(0) 971 { 972 } 973 974 Page::PageClients::~PageClients() 975 { 976 } 977 978 } // namespace WebCore 979