/*
* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All Rights Reserved.
* Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "Page.h"
#include "BackForwardController.h"
#include "BackForwardList.h"
#include "Base64.h"
#include "CSSStyleSelector.h"
#include "Chrome.h"
#include "ChromeClient.h"
#include "ContextMenuClient.h"
#include "ContextMenuController.h"
#include "DOMWindow.h"
#include "DeviceMotionController.h"
#include "DeviceOrientationController.h"
#include "DocumentMarkerController.h"
#include "DragController.h"
#include "EditorClient.h"
#include "Event.h"
#include "EventNames.h"
#include "ExceptionCode.h"
#include "FileSystem.h"
#include "FocusController.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "HTMLElement.h"
#include "HistoryItem.h"
#include "InspectorController.h"
#include "InspectorInstrumentation.h"
#include "Logging.h"
#include "MediaCanStartListener.h"
#include "Navigator.h"
#include "NetworkStateNotifier.h"
#include "PageGroup.h"
#include "PluginData.h"
#include "PluginHalter.h"
#include "PluginView.h"
#include "PluginViewBase.h"
#include "ProgressTracker.h"
#include "RenderTheme.h"
#include "RenderWidget.h"
#include "RuntimeEnabledFeatures.h"
#include "ScriptController.h"
#include "SelectionController.h"
#include "Settings.h"
#include "SharedBuffer.h"
#include "SpeechInput.h"
#include "SpeechInputClient.h"
#include "TextResourceDecoder.h"
#include "Widget.h"
#include <wtf/HashMap.h>
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/StdLibExtras.h>
#include <wtf/text/StringHash.h>
#if ENABLE(ACCELERATED_2D_CANVAS)
#include "SharedGraphicsContext3D.h"
#endif
#if ENABLE(DOM_STORAGE)
#include "StorageArea.h"
#include "StorageNamespace.h"
#endif
#if ENABLE(WML)
#include "WMLPageState.h"
#endif
#if ENABLE(CLIENT_BASED_GEOLOCATION)
#include "GeolocationController.h"
#endif
#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
#include "PackageNotifier.h"
#endif
namespace WebCore {
static HashSet<Page*>* allPages;
#ifndef NDEBUG
static WTF::RefCountedLeakCounter pageCounter("Page");
#endif
static void networkStateChanged()
{
Vector<RefPtr<Frame> > frames;
// Get all the frames of all the pages in all the page groups
HashSet<Page*>::iterator end = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
frames.append(frame);
InspectorInstrumentation::networkStateChanged(*it);
}
AtomicString eventName = networkStateNotifier().onLine() ? eventNames().onlineEvent : eventNames().offlineEvent;
for (unsigned i = 0; i < frames.size(); i++)
frames[i]->document()->dispatchWindowEvent(Event::create(eventName, false, false));
}
#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
static void onPackageResultAvailable()
{
HashSet<Page*>::iterator end = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
frame->domWindow()->navigator()->onPackageResult();
}
}
#endif
Page::Page(const PageClients& pageClients)
: m_chrome(adoptPtr(new Chrome(this, pageClients.chromeClient)))
, m_dragCaretController(adoptPtr(new SelectionController(0, true)))
#if ENABLE(DRAG_SUPPORT)
, m_dragController(adoptPtr(new DragController(this, pageClients.dragClient)))
#endif
, m_focusController(adoptPtr(new FocusController(this)))
#if ENABLE(CONTEXT_MENUS)
, m_contextMenuController(adoptPtr(new ContextMenuController(this, pageClients.contextMenuClient)))
#endif
#if ENABLE(INSPECTOR)
, m_inspectorController(adoptPtr(new InspectorController(this, pageClients.inspectorClient)))
#endif
#if ENABLE(CLIENT_BASED_GEOLOCATION)
, m_geolocationController(adoptPtr(new GeolocationController(this, pageClients.geolocationClient)))
#endif
#if ENABLE(DEVICE_ORIENTATION)
, m_deviceMotionController(RuntimeEnabledFeatures::deviceMotionEnabled() ? new DeviceMotionController(pageClients.deviceMotionClient) : 0)
, m_deviceOrientationController(RuntimeEnabledFeatures::deviceOrientationEnabled() ? new DeviceOrientationController(this, pageClients.deviceOrientationClient) : 0)
#endif
#if ENABLE(INPUT_SPEECH)
, m_speechInputClient(pageClients.speechInputClient)
#endif
, m_settings(adoptPtr(new Settings(this)))
, m_progress(adoptPtr(new ProgressTracker))
, m_backForwardController(adoptPtr(new BackForwardController(this, pageClients.backForwardClient)))
, m_theme(RenderTheme::themeForPage(this))
, m_editorClient(pageClients.editorClient)
, m_frameCount(0)
, m_openedByDOM(false)
, m_tabKeyCyclesThroughElements(true)
, m_defersLoading(false)
, m_inLowQualityInterpolationMode(false)
, m_cookieEnabled(true)
, m_areMemoryCacheClientCallsEnabled(true)
, m_mediaVolume(1)
, m_javaScriptURLsAreAllowed(true)
, m_didLoadUserStyleSheet(false)
, m_userStyleSheetModificationTime(0)
, m_group(0)
, m_debugger(0)
, m_customHTMLTokenizerTimeDelay(-1)
, m_customHTMLTokenizerChunkSize(-1)
, m_canStartMedia(true)
, m_viewMode(ViewModeWindowed)
, m_minimumTimerInterval(Settings::defaultMinDOMTimerInterval())
, m_isEditable(false)
{
if (!allPages) {
allPages = new HashSet<Page*>;
networkStateNotifier().setNetworkStateChangedFunction(networkStateChanged);
#if PLATFORM(ANDROID) && ENABLE(APPLICATION_INSTALLED)
packageNotifier().setOnResultAvailable(onPackageResultAvailable);
#endif
}
ASSERT(!allPages->contains(this));
allPages->add(this);
if (pageClients.pluginHalterClient) {
m_pluginHalter.set(new PluginHalter(pageClients.pluginHalterClient));
m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime());
}
#ifndef NDEBUG
pageCounter.increment();
#endif
}
Page::~Page()
{
m_mainFrame->setView(0);
setGroupName(String());
allPages->remove(this);
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
frame->pageDestroyed();
if (m_scrollableAreaSet) {
ScrollableAreaSet::const_iterator end = m_scrollableAreaSet->end();
for (ScrollableAreaSet::const_iterator it = m_scrollableAreaSet->begin(); it != end; ++it)
(*it)->disconnectFromPage();
}
m_editorClient->pageDestroyed();
InspectorInstrumentation::inspectedPageDestroyed(this);
backForward()->close();
#ifndef NDEBUG
pageCounter.decrement();
// Cancel keepAlive timers, to ensure we release all Frames before exiting.
// It's safe to do this because we prohibit closing a Page while JavaScript
// is executing.
Frame::cancelAllKeepAlive();
#endif
}
struct ViewModeInfo {
const char* name;
Page::ViewMode type;
};
static const int viewModeMapSize = 5;
static ViewModeInfo viewModeMap[viewModeMapSize] = {
{"windowed", Page::ViewModeWindowed},
{"floating", Page::ViewModeFloating},
{"fullscreen", Page::ViewModeFullscreen},
{"maximized", Page::ViewModeMaximized},
{"minimized", Page::ViewModeMinimized}
};
Page::ViewMode Page::stringToViewMode(const String& text)
{
for (int i = 0; i < viewModeMapSize; ++i) {
if (text == viewModeMap[i].name)
return viewModeMap[i].type;
}
return Page::ViewModeInvalid;
}
void Page::setViewMode(ViewMode viewMode)
{
if (viewMode == m_viewMode || viewMode == ViewModeInvalid)
return;
m_viewMode = viewMode;
if (!m_mainFrame)
return;
if (m_mainFrame->view())
m_mainFrame->view()->forceLayout();
if (m_mainFrame->document())
m_mainFrame->document()->styleSelectorChanged(RecalcStyleImmediately);
}
void Page::setMainFrame(PassRefPtr<Frame> mainFrame)
{
ASSERT(!m_mainFrame); // Should only be called during initialization
m_mainFrame = mainFrame;
}
bool Page::openedByDOM() const
{
return m_openedByDOM;
}
void Page::setOpenedByDOM()
{
m_openedByDOM = true;
}
BackForwardList* Page::backForwardList() const
{
return m_backForwardController->client();
}
bool Page::goBack()
{
HistoryItem* item = backForward()->backItem();
if (item) {
goToItem(item, FrameLoadTypeBack);
return true;
}
return false;
}
bool Page::goForward()
{
HistoryItem* item = backForward()->forwardItem();
if (item) {
goToItem(item, FrameLoadTypeForward);
return true;
}
return false;
}
bool Page::canGoBackOrForward(int distance) const
{
if (distance == 0)
return true;
if (distance > 0 && distance <= backForward()->forwardCount())
return true;
if (distance < 0 && -distance <= backForward()->backCount())
return true;
return false;
}
void Page::goBackOrForward(int distance)
{
if (distance == 0)
return;
HistoryItem* item = backForward()->itemAtIndex(distance);
if (!item) {
if (distance > 0) {
if (int forwardCount = backForward()->forwardCount())
item = backForward()->itemAtIndex(forwardCount);
} else {
if (int backCount = backForward()->backCount())
item = backForward()->itemAtIndex(-backCount);
}
}
ASSERT(item);
if (!item)
return;
goToItem(item, FrameLoadTypeIndexedBackForward);
}
void Page::goToItem(HistoryItem* item, FrameLoadType type)
{
if (defersLoading())
return;
// stopAllLoaders may end up running onload handlers, which could cause further history traversals that may lead to the passed in HistoryItem
// being deref()-ed. Make sure we can still use it with HistoryController::goToItem later.
RefPtr<HistoryItem> protector(item);
if (m_mainFrame->loader()->history()->shouldStopLoadingForHistoryItem(item))
m_mainFrame->loader()->stopAllLoaders();
m_mainFrame->loader()->history()->goToItem(item, type);
}
int Page::getHistoryLength()
{
return backForward()->backCount() + 1 + backForward()->forwardCount();
}
void Page::setGroupName(const String& name)
{
if (m_group && !m_group->name().isEmpty()) {
ASSERT(m_group != m_singlePageGroup.get());
ASSERT(!m_singlePageGroup);
m_group->removePage(this);
}
if (name.isEmpty())
m_group = m_singlePageGroup.get();
else {
m_singlePageGroup.clear();
m_group = PageGroup::pageGroup(name);
m_group->addPage(this);
}
}
const String& Page::groupName() const
{
DEFINE_STATIC_LOCAL(String, nullString, ());
return m_group ? m_group->name() : nullString;
}
void Page::initGroup()
{
ASSERT(!m_singlePageGroup);
ASSERT(!m_group);
m_singlePageGroup.set(new PageGroup(this));
m_group = m_singlePageGroup.get();
}
void Page::scheduleForcedStyleRecalcForAllPages()
{
if (!allPages)
return;
HashSet<Page*>::iterator end = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext())
frame->document()->scheduleForcedStyleRecalc();
}
void Page::setNeedsRecalcStyleInAllFrames()
{
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
frame->document()->styleSelectorChanged(DeferRecalcStyle);
}
void Page::updateViewportArguments()
{
if (!mainFrame() || !mainFrame()->document() || mainFrame()->document()->viewportArguments() == m_viewportArguments)
return;
m_viewportArguments = mainFrame()->document()->viewportArguments();
chrome()->dispatchViewportDataDidChange(m_viewportArguments);
}
void Page::refreshPlugins(bool reload)
{
if (!allPages)
return;
PluginData::refresh();
Vector<RefPtr<Frame> > framesNeedingReload;
HashSet<Page*>::iterator end = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it) {
Page* page = *it;
// Clear out the page's plug-in data.
if (page->m_pluginData)
page->m_pluginData = 0;
if (!reload)
continue;
for (Frame* frame = (*it)->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (frame->loader()->subframeLoader()->containsPlugins())
framesNeedingReload.append(frame);
}
}
for (size_t i = 0; i < framesNeedingReload.size(); ++i)
framesNeedingReload[i]->loader()->reload();
}
PluginData* Page::pluginData() const
{
if (!mainFrame()->loader()->subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin))
return 0;
if (!m_pluginData)
m_pluginData = PluginData::create(this);
return m_pluginData.get();
}
inline MediaCanStartListener* Page::takeAnyMediaCanStartListener()
{
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (MediaCanStartListener* listener = frame->document()->takeAnyMediaCanStartListener())
return listener;
}
return 0;
}
void Page::setCanStartMedia(bool canStartMedia)
{
if (m_canStartMedia == canStartMedia)
return;
m_canStartMedia = canStartMedia;
while (m_canStartMedia) {
MediaCanStartListener* listener = takeAnyMediaCanStartListener();
if (!listener)
break;
listener->mediaCanStart();
}
}
static Frame* incrementFrame(Frame* curr, bool forward, bool wrapFlag)
{
return forward
? curr->tree()->traverseNextWithWrap(wrapFlag)
: curr->tree()->traversePreviousWithWrap(wrapFlag);
}
bool Page::findString(const String& target, TextCaseSensitivity caseSensitivity, FindDirection direction, bool shouldWrap)
{
return findString(target, (caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0) | (direction == FindDirectionBackward ? Backwards : 0) | (shouldWrap ? WrapAround : 0));
}
bool Page::findString(const String& target, FindOptions options)
{
if (target.isEmpty() || !mainFrame())
return false;
bool shouldWrap = options & WrapAround;
Frame* frame = focusController()->focusedOrMainFrame();
Frame* startFrame = frame;
do {
if (frame->editor()->findString(target, (options & ~WrapAround) | StartInSelection)) {
if (frame != startFrame)
startFrame->selection()->clear();
focusController()->setFocusedFrame(frame);
return true;
}
frame = incrementFrame(frame, !(options & Backwards), shouldWrap);
} while (frame && frame != startFrame);
// Search contents of startFrame, on the other side of the selection that we did earlier.
// We cheat a bit and just research with wrap on
if (shouldWrap && !startFrame->selection()->isNone()) {
bool found = startFrame->editor()->findString(target, options | WrapAround | StartInSelection);
focusController()->setFocusedFrame(frame);
return found;
}
return false;
}
unsigned int Page::markAllMatchesForText(const String& target, TextCaseSensitivity caseSensitivity, bool shouldHighlight, unsigned limit)
{
return markAllMatchesForText(target, caseSensitivity == TextCaseInsensitive ? CaseInsensitive : 0, shouldHighlight, limit);
}
unsigned int Page::markAllMatchesForText(const String& target, FindOptions options, bool shouldHighlight, unsigned limit)
{
if (target.isEmpty() || !mainFrame())
return 0;
unsigned matches = 0;
Frame* frame = mainFrame();
do {
frame->editor()->setMarkedTextMatchesAreHighlighted(shouldHighlight);
matches += frame->editor()->countMatchesForText(target, options, limit ? (limit - matches) : 0, true);
frame = incrementFrame(frame, true, false);
} while (frame);
return matches;
}
void Page::unmarkAllTextMatches()
{
if (!mainFrame())
return;
Frame* frame = mainFrame();
do {
frame->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
frame = incrementFrame(frame, true, false);
} while (frame);
}
const VisibleSelection& Page::selection() const
{
return focusController()->focusedOrMainFrame()->selection()->selection();
}
void Page::setDefersLoading(bool defers)
{
if (!m_settings->loadDeferringEnabled())
return;
if (defers == m_defersLoading)
return;
m_defersLoading = defers;
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
frame->loader()->setDefersLoading(defers);
}
void Page::clearUndoRedoOperations()
{
m_editorClient->clearUndoRedoOperations();
}
bool Page::inLowQualityImageInterpolationMode() const
{
return m_inLowQualityInterpolationMode;
}
void Page::setInLowQualityImageInterpolationMode(bool mode)
{
m_inLowQualityInterpolationMode = mode;
}
void Page::setMediaVolume(float volume)
{
if (volume < 0 || volume > 1)
return;
if (m_mediaVolume == volume)
return;
m_mediaVolume = volume;
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
frame->document()->mediaVolumeDidChange();
}
}
void Page::didMoveOnscreen()
{
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (frame->view())
frame->view()->didMoveOnscreen();
}
}
void Page::willMoveOffscreen()
{
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (frame->view())
frame->view()->willMoveOffscreen();
}
}
void Page::userStyleSheetLocationChanged()
{
// FIXME: Eventually we will move to a model of just being handed the sheet
// text instead of loading the URL ourselves.
KURL url = m_settings->userStyleSheetLocation();
if (url.isLocalFile())
m_userStyleSheetPath = url.fileSystemPath();
else
m_userStyleSheetPath = String();
m_didLoadUserStyleSheet = false;
m_userStyleSheet = String();
m_userStyleSheetModificationTime = 0;
// Data URLs with base64-encoded UTF-8 style sheets are common. We can process them
// synchronously and avoid using a loader.
if (url.protocolIsData() && url.string().startsWith("data:text/css;charset=utf-8;base64,")) {
m_didLoadUserStyleSheet = true;
Vector<char> styleSheetAsUTF8;
if (base64Decode(decodeURLEscapeSequences(url.string().substring(35)), styleSheetAsUTF8, IgnoreWhitespace))
m_userStyleSheet = String::fromUTF8(styleSheetAsUTF8.data(), styleSheetAsUTF8.size());
}
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
if (frame->document())
frame->document()->updatePageUserSheet();
}
}
const String& Page::userStyleSheet() const
{
if (m_userStyleSheetPath.isEmpty())
return m_userStyleSheet;
time_t modTime;
if (!getFileModificationTime(m_userStyleSheetPath, modTime)) {
// The stylesheet either doesn't exist, was just deleted, or is
// otherwise unreadable. If we've read the stylesheet before, we should
// throw away that data now as it no longer represents what's on disk.
m_userStyleSheet = String();
return m_userStyleSheet;
}
// If the stylesheet hasn't changed since the last time we read it, we can
// just return the old data.
if (m_didLoadUserStyleSheet && modTime <= m_userStyleSheetModificationTime)
return m_userStyleSheet;
m_didLoadUserStyleSheet = true;
m_userStyleSheet = String();
m_userStyleSheetModificationTime = modTime;
// FIXME: It would be better to load this asynchronously to avoid blocking
// the process, but we will first need to create an asynchronous loading
// mechanism that is not tied to a particular Frame. We will also have to
// determine what our behavior should be before the stylesheet is loaded
// and what should happen when it finishes loading, especially with respect
// to when the load event fires, when Document::close is called, and when
// layout/paint are allowed to happen.
RefPtr<SharedBuffer> data = SharedBuffer::createWithContentsOfFile(m_userStyleSheetPath);
if (!data)
return m_userStyleSheet;
RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("text/css");
m_userStyleSheet = decoder->decode(data->data(), data->size());
m_userStyleSheet += decoder->flush();
return m_userStyleSheet;
}
void Page::removeAllVisitedLinks()
{
if (!allPages)
return;
HashSet<PageGroup*> groups;
HashSet<Page*>::iterator pagesEnd = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
if (PageGroup* group = (*it)->groupPtr())
groups.add(group);
}
HashSet<PageGroup*>::iterator groupsEnd = groups.end();
for (HashSet<PageGroup*>::iterator it = groups.begin(); it != groupsEnd; ++it)
(*it)->removeVisitedLinks();
}
void Page::allVisitedStateChanged(PageGroup* group)
{
ASSERT(group);
if (!allPages)
return;
HashSet<Page*>::iterator pagesEnd = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
Page* page = *it;
if (page->m_group != group)
continue;
for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
styleSelector->allVisitedStateChanged();
}
}
}
void Page::visitedStateChanged(PageGroup* group, LinkHash visitedLinkHash)
{
ASSERT(group);
if (!allPages)
return;
HashSet<Page*>::iterator pagesEnd = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != pagesEnd; ++it) {
Page* page = *it;
if (page->m_group != group)
continue;
for (Frame* frame = page->m_mainFrame.get(); frame; frame = frame->tree()->traverseNext()) {
if (CSSStyleSelector* styleSelector = frame->document()->styleSelector())
styleSelector->visitedStateChanged(visitedLinkHash);
}
}
}
void Page::setDebuggerForAllPages(JSC::Debugger* debugger)
{
ASSERT(allPages);
HashSet<Page*>::iterator end = allPages->end();
for (HashSet<Page*>::iterator it = allPages->begin(); it != end; ++it)
(*it)->setDebugger(debugger);
}
void Page::setDebugger(JSC::Debugger* debugger)
{
if (m_debugger == debugger)
return;
m_debugger = debugger;
for (Frame* frame = m_mainFrame.get(); frame; frame = frame->tree()->traverseNext())
frame->script()->attachDebugger(m_debugger);
}
SharedGraphicsContext3D* Page::sharedGraphicsContext3D()
{
#if ENABLE(ACCELERATED_2D_CANVAS)
if (!m_sharedGraphicsContext3D)
m_sharedGraphicsContext3D = SharedGraphicsContext3D::create(chrome());
return m_sharedGraphicsContext3D.get();
#else
return 0;
#endif
}
#if ENABLE(DOM_STORAGE)
StorageNamespace* Page::sessionStorage(bool optionalCreate)
{
if (!m_sessionStorage && optionalCreate)
m_sessionStorage = StorageNamespace::sessionStorageNamespace(this, m_settings->sessionStorageQuota());
return m_sessionStorage.get();
}
void Page::setSessionStorage(PassRefPtr<StorageNamespace> newStorage)
{
m_sessionStorage = newStorage;
}
#endif
#if ENABLE(WML)
WMLPageState* Page::wmlPageState()
{
if (!m_wmlPageState)
m_wmlPageState.set(new WMLPageState(this));
return m_wmlPageState.get();
}
#endif
void Page::setCustomHTMLTokenizerTimeDelay(double customHTMLTokenizerTimeDelay)
{
if (customHTMLTokenizerTimeDelay < 0) {
m_customHTMLTokenizerTimeDelay = -1;
return;
}
m_customHTMLTokenizerTimeDelay = customHTMLTokenizerTimeDelay;
}
void Page::setCustomHTMLTokenizerChunkSize(int customHTMLTokenizerChunkSize)
{
if (customHTMLTokenizerChunkSize < 0) {
m_customHTMLTokenizerChunkSize = -1;
return;
}
m_customHTMLTokenizerChunkSize = customHTMLTokenizerChunkSize;
}
void Page::setMemoryCacheClientCallsEnabled(bool enabled)
{
if (m_areMemoryCacheClientCallsEnabled == enabled)
return;
m_areMemoryCacheClientCallsEnabled = enabled;
if (!enabled)
return;
for (RefPtr<Frame> frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
frame->loader()->tellClientAboutPastMemoryCacheLoads();
}
void Page::setJavaScriptURLsAreAllowed(bool areAllowed)
{
m_javaScriptURLsAreAllowed = areAllowed;
}
bool Page::javaScriptURLsAreAllowed() const
{
return m_javaScriptURLsAreAllowed;
}
void Page::setMinimumTimerInterval(double minimumTimerInterval)
{
double oldTimerInterval = m_minimumTimerInterval;
m_minimumTimerInterval = minimumTimerInterval;
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNextWithWrap(false)) {
if (frame->document())
frame->document()->adjustMinimumTimerInterval(oldTimerInterval);
}
}
double Page::minimumTimerInterval() const
{
return m_minimumTimerInterval;
}
#if ENABLE(INPUT_SPEECH)
SpeechInput* Page::speechInput()
{
ASSERT(m_speechInputClient);
if (!m_speechInput.get())
m_speechInput.set(new SpeechInput(m_speechInputClient));
return m_speechInput.get();
}
#endif
void Page::dnsPrefetchingStateChanged()
{
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
frame->document()->initDNSPrefetch();
}
void Page::privateBrowsingStateChanged()
{
bool privateBrowsingEnabled = m_settings->privateBrowsingEnabled();
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
frame->document()->privateBrowsingStateDidChange();
// Collect the PluginViews in to a vector to ensure that action the plug-in takes
// from below privateBrowsingStateChanged does not affect their lifetime.
Vector<RefPtr<PluginViewBase>, 32> pluginViewBases;
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext()) {
FrameView* view = frame->view();
if (!view)
return;
const HashSet<RefPtr<Widget> >* children = view->children();
ASSERT(children);
HashSet<RefPtr<Widget> >::const_iterator end = children->end();
for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(); it != end; ++it) {
Widget* widget = (*it).get();
if (widget->isPluginViewBase())
pluginViewBases.append(static_cast<PluginViewBase*>(widget));
}
}
for (size_t i = 0; i < pluginViewBases.size(); ++i)
pluginViewBases[i]->privateBrowsingStateChanged(privateBrowsingEnabled);
}
void Page::pluginAllowedRunTimeChanged()
{
if (m_pluginHalter)
m_pluginHalter->setPluginAllowedRunTime(m_settings->pluginAllowedRunTime());
}
void Page::didStartPlugin(HaltablePlugin* obj)
{
if (m_pluginHalter)
m_pluginHalter->didStartPlugin(obj);
}
void Page::didStopPlugin(HaltablePlugin* obj)
{
if (m_pluginHalter)
m_pluginHalter->didStopPlugin(obj);
}
void Page::addScrollableArea(ScrollableArea* scrollableArea)
{
if (!m_scrollableAreaSet)
m_scrollableAreaSet = adoptPtr(new ScrollableAreaSet);
m_scrollableAreaSet->add(scrollableArea);
}
void Page::removeScrollableArea(ScrollableArea* scrollableArea)
{
if (!m_scrollableAreaSet)
return;
m_scrollableAreaSet->remove(scrollableArea);
}
bool Page::containsScrollableArea(ScrollableArea* scrollableArea) const
{
if (!m_scrollableAreaSet)
return false;
return m_scrollableAreaSet->contains(scrollableArea);
}
#if !ASSERT_DISABLED
void Page::checkFrameCountConsistency() const
{
ASSERT(m_frameCount >= 0);
int frameCount = 0;
for (Frame* frame = mainFrame(); frame; frame = frame->tree()->traverseNext())
++frameCount;
ASSERT(m_frameCount + 1 == frameCount);
}
#endif
Page::PageClients::PageClients()
: chromeClient(0)
, contextMenuClient(0)
, editorClient(0)
, dragClient(0)
, inspectorClient(0)
, pluginHalterClient(0)
, geolocationClient(0)
, deviceMotionClient(0)
, deviceOrientationClient(0)
, speechInputClient(0)
{
}
Page::PageClients::~PageClients()
{
}
} // namespace WebCore