Home | History | Annotate | Download | only in page
      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