/* * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "Settings.h" #include "AudioSession.h" #include "BackForwardController.h" #include "CachedResourceLoader.h" #include "CookieStorage.h" #include "DOMTimer.h" #include "Database.h" #include "Document.h" #include "FontCascade.h" #include "FontGenericFamilies.h" #include "FrameTree.h" #include "FrameView.h" #include "HTMLMediaElement.h" #include "HistoryItem.h" #include "InspectorInstrumentation.h" #include "MainFrame.h" #include "Page.h" #include "PageCache.h" #include "StorageMap.h" #include "TextAutosizer.h" #include #include #include #if ENABLE(MEDIA_STREAM) #include "MockRealtimeMediaSourceCenter.h" #endif namespace WebCore { static void setImageLoadingSettings(Page* page) { if (!page) return; for (Frame* frame = &page->mainFrame(); frame; frame = frame->tree().traverseNext()) { if (!frame->document()) continue; frame->document()->cachedResourceLoader().setImagesEnabled(page->settings().areImagesEnabled()); frame->document()->cachedResourceLoader().setAutoLoadImages(page->settings().loadsImagesAutomatically()); } } static void invalidateAfterGenericFamilyChange(Page* page) { invalidateFontCascadeCache(); if (page) page->setNeedsRecalcStyleInAllFrames(); } #if USE(AVFOUNDATION) bool Settings::gAVFoundationEnabled = true; bool Settings::gAVFoundationNSURLSessionEnabled = false; #endif #if PLATFORM(COCOA) bool Settings::gQTKitEnabled = false; #endif bool Settings::gMockScrollbarsEnabled = false; bool Settings::gUsesOverlayScrollbars = false; bool Settings::gMockScrollAnimatorEnabled = false; #if ENABLE(MEDIA_STREAM) bool Settings::gMockCaptureDevicesEnabled = false; #endif #if PLATFORM(WIN) bool Settings::gShouldUseHighResolutionTimers = true; #endif bool Settings::gShouldRewriteConstAsVar = false; bool Settings::gShouldRespectPriorityInCSSAttributeSetters = false; bool Settings::gLowPowerVideoAudioBufferSizeEnabled = false; bool Settings::gResourceLoadStatisticsEnabledEnabled = false; #if PLATFORM(IOS) bool Settings::gNetworkDataUsageTrackingEnabled = false; bool Settings::gAVKitEnabled = false; bool Settings::gShouldOptOutOfNetworkStateObservation = false; bool Settings::gManageAudioSession = false; #endif // NOTEs // 1) EditingMacBehavior comprises Tiger, Leopard, SnowLeopard and iOS builds, as well as QtWebKit when built on Mac; // 2) EditingWindowsBehavior comprises Win32 build; // 3) EditingUnixBehavior comprises all unix-based systems, but Darwin/MacOS (and then abusing the terminology); // 99) MacEditingBehavior is used as a fallback. static EditingBehaviorType editingBehaviorTypeForPlatform() { return #if PLATFORM(IOS) EditingIOSBehavior #elif OS(DARWIN) EditingMacBehavior #elif OS(WINDOWS) EditingWindowsBehavior #elif OS(UNIX) EditingUnixBehavior #else // Fallback EditingMacBehavior #endif ; } #if PLATFORM(IOS) static const bool defaultFixedPositionCreatesStackingContext = true; static const bool defaultFixedBackgroundsPaintRelativeToDocument = true; static const bool defaultAcceleratedCompositingForFixedPositionEnabled = true; static const bool defaultAllowsInlineMediaPlayback = false; static const bool defaultInlineMediaPlaybackRequiresPlaysInlineAttribute = true; static const bool defaultRequiresUserGestureForMediaPlayback = true; static const bool defaultAudioPlaybackRequiresUserGesture = true; static const bool defaultMediaDataLoadsAutomatically = false; static const bool defaultShouldRespectImageOrientation = true; static const bool defaultImageSubsamplingEnabled = true; static const bool defaultScrollingTreeIncludesFrames = true; static const bool defaultMediaControlsScaleWithPageZoom = true; #else static const bool defaultFixedPositionCreatesStackingContext = false; static const bool defaultFixedBackgroundsPaintRelativeToDocument = false; static const bool defaultAcceleratedCompositingForFixedPositionEnabled = false; static const bool defaultAllowsInlineMediaPlayback = true; static const bool defaultInlineMediaPlaybackRequiresPlaysInlineAttribute = false; static const bool defaultRequiresUserGestureForMediaPlayback = false; static const bool defaultAudioPlaybackRequiresUserGesture = false; static const bool defaultMediaDataLoadsAutomatically = true; static const bool defaultShouldRespectImageOrientation = false; static const bool defaultImageSubsamplingEnabled = false; static const bool defaultScrollingTreeIncludesFrames = false; static const bool defaultMediaControlsScaleWithPageZoom = true; #endif static const bool defaultAllowsPictureInPictureMediaPlayback = true; static const double defaultIncrementalRenderingSuppressionTimeoutInSeconds = 5; #if USE(UNIFIED_TEXT_CHECKING) static const bool defaultUnifiedTextCheckerEnabled = true; #else static const bool defaultUnifiedTextCheckerEnabled = false; #endif static const bool defaultSmartInsertDeleteEnabled = true; static const bool defaultSelectTrailingWhitespaceEnabled = false; // This amount of time must have elapsed before we will even consider scheduling a layout without a delay. // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high // for dual G5s. :) static const auto layoutScheduleThreshold = std::chrono::milliseconds(250); Settings::Settings(Page* page) : m_page(nullptr) , m_mediaTypeOverride("screen") , m_fontGenericFamilies(std::make_unique()) , m_storageBlockingPolicy(SecurityOrigin::AllowAllStorage) , m_layoutInterval(layoutScheduleThreshold) , m_minimumDOMTimerInterval(DOMTimer::defaultMinimumInterval()) #if ENABLE(TEXT_AUTOSIZING) , m_textAutosizingFontScaleFactor(1) #if HACK_FORCE_TEXT_AUTOSIZING_ON_DESKTOP , m_textAutosizingWindowSizeOverride(320, 480) , m_textAutosizingEnabled(true) #else , m_textAutosizingEnabled(false) #endif #endif SETTINGS_INITIALIZER_LIST , m_isJavaEnabled(false) , m_isJavaEnabledForLocalFiles(true) , m_loadsImagesAutomatically(false) , m_areImagesEnabled(true) , m_arePluginsEnabled(false) , m_isScriptEnabled(false) , m_needsAdobeFrameReloadingQuirk(false) , m_usesPageCache(false) , m_fontRenderingMode(0) , m_antialiasedFontDilationEnabled(false) , m_showTiledScrollingIndicator(false) , m_backgroundShouldExtendBeyondPage(false) , m_dnsPrefetchingEnabled(false) #if ENABLE(TOUCH_EVENTS) , m_touchEventEmulationEnabled(false) #endif , m_scrollingPerformanceLoggingEnabled(false) , m_timeWithoutMouseMovementBeforeHidingControls(3) , m_setImageLoadingSettingsTimer(*this, &Settings::imageLoadingSettingsTimerFired) #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) , m_hiddenPageDOMTimerThrottlingEnabled(false) #endif , m_hiddenPageCSSAnimationSuspensionEnabled(false) , m_fontFallbackPrefersPictographs(false) , m_forcePendingWebGLPolicy(false) { // A Frame may not have been created yet, so we initialize the AtomicString // hash before trying to use it. AtomicString::init(); initializeDefaultFontFamilies(); m_page = page; // Page is not yet fully initialized when constructing Settings, so keeping m_page null over initializeDefaultFontFamilies() call. } Settings::~Settings() { } Ref Settings::create(Page* page) { return adoptRef(*new Settings(page)); } SETTINGS_SETTER_BODIES #if !PLATFORM(COCOA) void Settings::initializeDefaultFontFamilies() { // Other platforms can set up fonts from a client, but on Mac, we want it in WebCore to share code between WebKit1 and WebKit2. } #endif const AtomicString& Settings::standardFontFamily(UScriptCode script) const { return m_fontGenericFamilies->standardFontFamily(script); } void Settings::setStandardFontFamily(const AtomicString& family, UScriptCode script) { bool changes = m_fontGenericFamilies->setStandardFontFamily(family, script); if (changes) invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::fixedFontFamily(UScriptCode script) const { return m_fontGenericFamilies->fixedFontFamily(script); } void Settings::setFixedFontFamily(const AtomicString& family, UScriptCode script) { bool changes = m_fontGenericFamilies->setFixedFontFamily(family, script); if (changes) invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::serifFontFamily(UScriptCode script) const { return m_fontGenericFamilies->serifFontFamily(script); } void Settings::setSerifFontFamily(const AtomicString& family, UScriptCode script) { bool changes = m_fontGenericFamilies->setSerifFontFamily(family, script); if (changes) invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::sansSerifFontFamily(UScriptCode script) const { return m_fontGenericFamilies->sansSerifFontFamily(script); } void Settings::setSansSerifFontFamily(const AtomicString& family, UScriptCode script) { bool changes = m_fontGenericFamilies->setSansSerifFontFamily(family, script); if (changes) invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::cursiveFontFamily(UScriptCode script) const { return m_fontGenericFamilies->cursiveFontFamily(script); } void Settings::setCursiveFontFamily(const AtomicString& family, UScriptCode script) { bool changes = m_fontGenericFamilies->setCursiveFontFamily(family, script); if (changes) invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::fantasyFontFamily(UScriptCode script) const { return m_fontGenericFamilies->fantasyFontFamily(script); } void Settings::setFantasyFontFamily(const AtomicString& family, UScriptCode script) { bool changes = m_fontGenericFamilies->setFantasyFontFamily(family, script); if (changes) invalidateAfterGenericFamilyChange(m_page); } const AtomicString& Settings::pictographFontFamily(UScriptCode script) const { return m_fontGenericFamilies->pictographFontFamily(script); } void Settings::setPictographFontFamily(const AtomicString& family, UScriptCode script) { bool changes = m_fontGenericFamilies->setPictographFontFamily(family, script); if (changes) invalidateAfterGenericFamilyChange(m_page); } #if ENABLE(TEXT_AUTOSIZING) void Settings::setTextAutosizingEnabled(bool textAutosizingEnabled) { if (m_textAutosizingEnabled == textAutosizingEnabled) return; m_textAutosizingEnabled = textAutosizingEnabled; if (m_page) m_page->setNeedsRecalcStyleInAllFrames(); } void Settings::setTextAutosizingWindowSizeOverride(const IntSize& textAutosizingWindowSizeOverride) { if (m_textAutosizingWindowSizeOverride == textAutosizingWindowSizeOverride) return; m_textAutosizingWindowSizeOverride = textAutosizingWindowSizeOverride; if (m_page) m_page->setNeedsRecalcStyleInAllFrames(); } void Settings::setTextAutosizingFontScaleFactor(float fontScaleFactor) { m_textAutosizingFontScaleFactor = fontScaleFactor; if (!m_page) return; // FIXME: I wonder if this needs to traverse frames like in WebViewImpl::resize, or whether there is only one document per Settings instance? for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) frame->document()->textAutosizer()->recalculateMultipliers(); m_page->setNeedsRecalcStyleInAllFrames(); } #endif void Settings::setAntialiasedFontDilationEnabled(bool enabled) { // FIXME: It's wrong for a setting to toggle a global, but this code is temporary. FontCascade::setAntialiasedFontDilationEnabled(enabled); } void Settings::setMediaTypeOverride(const String& mediaTypeOverride) { if (m_mediaTypeOverride == mediaTypeOverride) return; m_mediaTypeOverride = mediaTypeOverride; if (!m_page) return; FrameView* view = m_page->mainFrame().view(); ASSERT(view); view->setMediaType(mediaTypeOverride); m_page->setNeedsRecalcStyleInAllFrames(); } void Settings::setLoadsImagesAutomatically(bool loadsImagesAutomatically) { m_loadsImagesAutomatically = loadsImagesAutomatically; // Changing this setting to true might immediately start new loads for images that had previously had loading disabled. // If this happens while a WebView is being dealloc'ed, and we don't know the WebView is being dealloc'ed, these new loads // can cause crashes downstream when the WebView memory has actually been free'd. // One example where this can happen is in Mac apps that subclass WebView then do work in their overridden dealloc methods. // Starting these loads synchronously is not important. By putting it on a 0-delay, properly closing the Page cancels them // before they have a chance to really start. // See http://webkit.org/b/60572 for more discussion. m_setImageLoadingSettingsTimer.startOneShot(0); } void Settings::imageLoadingSettingsTimerFired() { setImageLoadingSettings(m_page); } void Settings::setScriptEnabled(bool isScriptEnabled) { if (m_isScriptEnabled == isScriptEnabled) return; m_isScriptEnabled = isScriptEnabled; if (!m_page) return; #if PLATFORM(IOS) m_page->setNeedsRecalcStyleInAllFrames(); #endif InspectorInstrumentation::scriptsEnabled(*m_page, m_isScriptEnabled); } void Settings::setJavaEnabled(bool isJavaEnabled) { m_isJavaEnabled = isJavaEnabled; } void Settings::setJavaEnabledForLocalFiles(bool isJavaEnabledForLocalFiles) { m_isJavaEnabledForLocalFiles = isJavaEnabledForLocalFiles; } void Settings::setImagesEnabled(bool areImagesEnabled) { m_areImagesEnabled = areImagesEnabled; // See comment in setLoadsImagesAutomatically. m_setImageLoadingSettingsTimer.startOneShot(0); } void Settings::setForcePendingWebGLPolicy(bool forced) { m_forcePendingWebGLPolicy = forced; } void Settings::setPluginsEnabled(bool arePluginsEnabled) { if (m_arePluginsEnabled == arePluginsEnabled) return; m_arePluginsEnabled = arePluginsEnabled; Page::refreshPlugins(false); } void Settings::setUserStyleSheetLocation(const URL& userStyleSheetLocation) { if (m_userStyleSheetLocation == userStyleSheetLocation) return; m_userStyleSheetLocation = userStyleSheetLocation; if (m_page) m_page->userStyleSheetLocationChanged(); } // FIXME: This quirk is needed because of Radar 4674537 and 5211271. We need to phase it out once Adobe // can fix the bug from their end. void Settings::setNeedsAdobeFrameReloadingQuirk(bool shouldNotReloadIFramesForUnchangedSRC) { m_needsAdobeFrameReloadingQuirk = shouldNotReloadIFramesForUnchangedSRC; } void Settings::setMinimumDOMTimerInterval(double interval) { double oldTimerInterval = m_minimumDOMTimerInterval; m_minimumDOMTimerInterval = interval; if (!m_page) return; for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) { if (frame->document()) frame->document()->adjustMinimumTimerInterval(oldTimerInterval); } } void Settings::setLayoutInterval(std::chrono::milliseconds layoutInterval) { // FIXME: It seems weird that this function may disregard the specified layout interval. // We should either expose layoutScheduleThreshold or better communicate this invariant. m_layoutInterval = std::max(layoutInterval, layoutScheduleThreshold); } void Settings::setUsesPageCache(bool usesPageCache) { if (m_usesPageCache == usesPageCache) return; m_usesPageCache = usesPageCache; if (!m_page) return; if (!m_usesPageCache) PageCache::singleton().pruneToSizeNow(0, PruningReason::None); } void Settings::setFontRenderingMode(FontRenderingMode mode) { if (fontRenderingMode() == mode) return; m_fontRenderingMode = static_cast(mode); if (m_page) m_page->setNeedsRecalcStyleInAllFrames(); } FontRenderingMode Settings::fontRenderingMode() const { return static_cast(m_fontRenderingMode); } void Settings::setDNSPrefetchingEnabled(bool dnsPrefetchingEnabled) { if (m_dnsPrefetchingEnabled == dnsPrefetchingEnabled) return; m_dnsPrefetchingEnabled = dnsPrefetchingEnabled; if (m_page) m_page->dnsPrefetchingStateChanged(); } void Settings::setShowTiledScrollingIndicator(bool enabled) { if (m_showTiledScrollingIndicator == enabled) return; m_showTiledScrollingIndicator = enabled; } #if ENABLE(RESOURCE_USAGE) void Settings::setResourceUsageOverlayVisible(bool visible) { if (m_resourceUsageOverlayVisible == visible) return; m_resourceUsageOverlayVisible = visible; if (m_page) m_page->setResourceUsageOverlayVisible(visible); } #endif #if PLATFORM(WIN) void Settings::setShouldUseHighResolutionTimers(bool shouldUseHighResolutionTimers) { gShouldUseHighResolutionTimers = shouldUseHighResolutionTimers; } #endif void Settings::setStorageBlockingPolicy(SecurityOrigin::StorageBlockingPolicy enabled) { if (m_storageBlockingPolicy == enabled) return; m_storageBlockingPolicy = enabled; if (m_page) m_page->storageBlockingStateChanged(); } void Settings::setBackgroundShouldExtendBeyondPage(bool shouldExtend) { if (m_backgroundShouldExtendBeyondPage == shouldExtend) return; m_backgroundShouldExtendBeyondPage = shouldExtend; if (m_page) m_page->mainFrame().view()->updateExtendBackgroundIfNecessary(); } #if USE(AVFOUNDATION) void Settings::setAVFoundationEnabled(bool enabled) { if (gAVFoundationEnabled == enabled) return; gAVFoundationEnabled = enabled; HTMLMediaElement::resetMediaEngines(); } void Settings::setAVFoundationNSURLSessionEnabled(bool enabled) { if (gAVFoundationNSURLSessionEnabled == enabled) return; gAVFoundationNSURLSessionEnabled = enabled; } #endif #if PLATFORM(COCOA) void Settings::setQTKitEnabled(bool enabled) { if (gQTKitEnabled == enabled) return; gQTKitEnabled = enabled; HTMLMediaElement::resetMediaEngines(); } #endif #if ENABLE(MEDIA_STREAM) bool Settings::mockCaptureDevicesEnabled() { return gMockCaptureDevicesEnabled; } void Settings::setMockCaptureDevicesEnabled(bool enabled) { gMockCaptureDevicesEnabled = enabled; MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(enabled); } #endif void Settings::setScrollingPerformanceLoggingEnabled(bool enabled) { m_scrollingPerformanceLoggingEnabled = enabled; if (m_page && m_page->mainFrame().view()) m_page->mainFrame().view()->setScrollingPerformanceLoggingEnabled(enabled); } void Settings::setMockScrollbarsEnabled(bool flag) { gMockScrollbarsEnabled = flag; // FIXME: This should update scroll bars in existing pages. } bool Settings::mockScrollbarsEnabled() { return gMockScrollbarsEnabled; } void Settings::setUsesOverlayScrollbars(bool flag) { gUsesOverlayScrollbars = flag; // FIXME: This should update scroll bars in existing pages. } bool Settings::usesOverlayScrollbars() { return gUsesOverlayScrollbars; } void Settings::setUsesMockScrollAnimator(bool flag) { gMockScrollAnimatorEnabled = flag; } bool Settings::usesMockScrollAnimator() { return gMockScrollAnimatorEnabled; } void Settings::setShouldRespectPriorityInCSSAttributeSetters(bool flag) { gShouldRespectPriorityInCSSAttributeSetters = flag; } bool Settings::shouldRespectPriorityInCSSAttributeSetters() { return gShouldRespectPriorityInCSSAttributeSetters; } #if ENABLE(HIDDEN_PAGE_DOM_TIMER_THROTTLING) void Settings::setHiddenPageDOMTimerThrottlingEnabled(bool flag) { if (m_hiddenPageDOMTimerThrottlingEnabled == flag) return; m_hiddenPageDOMTimerThrottlingEnabled = flag; if (m_page) m_page->hiddenPageDOMTimerThrottlingStateChanged(); } #endif void Settings::setHiddenPageCSSAnimationSuspensionEnabled(bool flag) { if (m_hiddenPageCSSAnimationSuspensionEnabled == flag) return; m_hiddenPageCSSAnimationSuspensionEnabled = flag; if (m_page) m_page->hiddenPageCSSAnimationSuspensionStateChanged(); } void Settings::setFontFallbackPrefersPictographs(bool preferPictographs) { if (m_fontFallbackPrefersPictographs == preferPictographs) return; m_fontFallbackPrefersPictographs = preferPictographs; if (m_page) m_page->setNeedsRecalcStyleInAllFrames(); } void Settings::setLowPowerVideoAudioBufferSizeEnabled(bool flag) { gLowPowerVideoAudioBufferSizeEnabled = flag; } void Settings::setResourceLoadStatisticsEnabled(bool flag) { gResourceLoadStatisticsEnabledEnabled = flag; } #if PLATFORM(IOS) void Settings::setAudioSessionCategoryOverride(unsigned sessionCategory) { AudioSession::sharedSession().setCategoryOverride(static_cast(sessionCategory)); } unsigned Settings::audioSessionCategoryOverride() { return AudioSession::sharedSession().categoryOverride(); } void Settings::setNetworkDataUsageTrackingEnabled(bool trackingEnabled) { gNetworkDataUsageTrackingEnabled = trackingEnabled; } bool Settings::networkDataUsageTrackingEnabled() { return gNetworkDataUsageTrackingEnabled; } static String& sharedNetworkInterfaceNameGlobal() { static NeverDestroyed networkInterfaceName; return networkInterfaceName; } void Settings::setNetworkInterfaceName(const String& networkInterfaceName) { sharedNetworkInterfaceNameGlobal() = networkInterfaceName; } const String& Settings::networkInterfaceName() { return sharedNetworkInterfaceNameGlobal(); } #endif } // namespace WebCore