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