1/*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "core/page/Settings.h"
28
29#include <limits>
30#include "core/dom/Document.h"
31#include "core/inspector/InspectorInstrumentation.h"
32#include "core/loader/cache/ResourceFetcher.h"
33#include "core/page/Chrome.h"
34#include "core/page/Frame.h"
35#include "core/page/FrameTree.h"
36#include "core/page/FrameView.h"
37#include "core/page/Page.h"
38#include "core/rendering/TextAutosizer.h"
39
40using namespace std;
41
42namespace WebCore {
43
44static void setImageLoadingSettings(Page* page)
45{
46    for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
47        frame->document()->fetcher()->setImagesEnabled(page->settings()->areImagesEnabled());
48        frame->document()->fetcher()->setAutoLoadImages(page->settings()->loadsImagesAutomatically());
49    }
50}
51
52// Sets the entry in the font map for the given script. If family is the empty string, removes the entry instead.
53static inline void setGenericFontFamilyMap(ScriptFontFamilyMap& fontMap, const AtomicString& family, UScriptCode script, Page* page)
54{
55    ScriptFontFamilyMap::iterator it = fontMap.find(static_cast<int>(script));
56    if (family.isEmpty()) {
57        if (it == fontMap.end())
58            return;
59        fontMap.remove(it);
60    } else if (it != fontMap.end() && it->value == family)
61        return;
62    else
63        fontMap.set(static_cast<int>(script), family);
64
65    if (page)
66        page->setNeedsRecalcStyleInAllFrames();
67}
68
69static inline const AtomicString& getGenericFontFamilyForScript(const ScriptFontFamilyMap& fontMap, UScriptCode script)
70{
71    ScriptFontFamilyMap::const_iterator it = fontMap.find(static_cast<int>(script));
72    if (it != fontMap.end())
73        return it->value;
74    if (script != USCRIPT_COMMON)
75        return getGenericFontFamilyForScript(fontMap, USCRIPT_COMMON);
76    return emptyAtom;
77}
78
79bool Settings::gMockScrollbarsEnabled = false;
80bool Settings::gUsesOverlayScrollbars = false;
81
82// NOTEs
83//  1) EditingMacBehavior comprises builds on Mac;
84//  2) EditingWindowsBehavior comprises builds on Windows;
85//  3) EditingUnixBehavior comprises all unix-based systems, but Darwin/MacOS/Android (and then abusing the terminology);
86//  4) EditingAndroidBehavior comprises Android builds.
87// 99) MacEditingBehavior is used a fallback.
88static EditingBehaviorType editingBehaviorTypeForPlatform()
89{
90    return
91#if OS(DARWIN)
92    EditingMacBehavior
93#elif OS(WINDOWS)
94    EditingWindowsBehavior
95#elif OS(ANDROID)
96    EditingAndroidBehavior
97#elif OS(UNIX)
98    EditingUnixBehavior
99#else
100    // Fallback
101    EditingMacBehavior
102#endif
103    ;
104}
105
106static const bool defaultUnifiedTextCheckerEnabled = false;
107#if OS(DARWIN)
108static const bool defaultSmartInsertDeleteEnabled = true;
109#else
110static const bool defaultSmartInsertDeleteEnabled = false;
111#endif
112#if OS(WINDOWS)
113static const bool defaultSelectTrailingWhitespaceEnabled = true;
114#else
115static const bool defaultSelectTrailingWhitespaceEnabled = false;
116#endif
117
118Settings::Settings(Page* page)
119    : m_page(0)
120    , m_mediaTypeOverride("screen")
121    , m_textAutosizingFontScaleFactor(1)
122#if HACK_FORCE_TEXT_AUTOSIZING_ON_DESKTOP
123    , m_textAutosizingWindowSizeOverride(320, 480)
124    , m_textAutosizingEnabled(true)
125#else
126    , m_textAutosizingEnabled(false)
127#endif
128    , m_useWideViewport(true)
129    , m_loadWithOverviewMode(true)
130    SETTINGS_INITIALIZER_LIST
131    , m_isJavaEnabled(false)
132    , m_loadsImagesAutomatically(false)
133    , m_areImagesEnabled(true)
134    , m_arePluginsEnabled(false)
135    , m_isScriptEnabled(false)
136    , m_isCSSCustomFilterEnabled(false)
137    , m_cssStickyPositionEnabled(true)
138    , m_dnsPrefetchingEnabled(false)
139    , m_touchEventEmulationEnabled(false)
140    , m_setImageLoadingSettingsTimer(this, &Settings::imageLoadingSettingsTimerFired)
141{
142    m_page = page; // Page is not yet fully initialized wen constructing Settings, so keeping m_page null over initializeDefaultFontFamilies() call.
143}
144
145PassOwnPtr<Settings> Settings::create(Page* page)
146{
147    return adoptPtr(new Settings(page));
148}
149
150SETTINGS_SETTER_BODIES
151
152const AtomicString& Settings::standardFontFamily(UScriptCode script) const
153{
154    return getGenericFontFamilyForScript(m_standardFontFamilyMap, script);
155}
156
157void Settings::setStandardFontFamily(const AtomicString& family, UScriptCode script)
158{
159    setGenericFontFamilyMap(m_standardFontFamilyMap, family, script, m_page);
160}
161
162const AtomicString& Settings::fixedFontFamily(UScriptCode script) const
163{
164    return getGenericFontFamilyForScript(m_fixedFontFamilyMap, script);
165}
166
167void Settings::setFixedFontFamily(const AtomicString& family, UScriptCode script)
168{
169    setGenericFontFamilyMap(m_fixedFontFamilyMap, family, script, m_page);
170}
171
172const AtomicString& Settings::serifFontFamily(UScriptCode script) const
173{
174    return getGenericFontFamilyForScript(m_serifFontFamilyMap, script);
175}
176
177void Settings::setSerifFontFamily(const AtomicString& family, UScriptCode script)
178{
179     setGenericFontFamilyMap(m_serifFontFamilyMap, family, script, m_page);
180}
181
182const AtomicString& Settings::sansSerifFontFamily(UScriptCode script) const
183{
184    return getGenericFontFamilyForScript(m_sansSerifFontFamilyMap, script);
185}
186
187void Settings::setSansSerifFontFamily(const AtomicString& family, UScriptCode script)
188{
189    setGenericFontFamilyMap(m_sansSerifFontFamilyMap, family, script, m_page);
190}
191
192const AtomicString& Settings::cursiveFontFamily(UScriptCode script) const
193{
194    return getGenericFontFamilyForScript(m_cursiveFontFamilyMap, script);
195}
196
197void Settings::setCursiveFontFamily(const AtomicString& family, UScriptCode script)
198{
199    setGenericFontFamilyMap(m_cursiveFontFamilyMap, family, script, m_page);
200}
201
202const AtomicString& Settings::fantasyFontFamily(UScriptCode script) const
203{
204    return getGenericFontFamilyForScript(m_fantasyFontFamilyMap, script);
205}
206
207void Settings::setFantasyFontFamily(const AtomicString& family, UScriptCode script)
208{
209    setGenericFontFamilyMap(m_fantasyFontFamilyMap, family, script, m_page);
210}
211
212const AtomicString& Settings::pictographFontFamily(UScriptCode script) const
213{
214    return getGenericFontFamilyForScript(m_pictographFontFamilyMap, script);
215}
216
217void Settings::setPictographFontFamily(const AtomicString& family, UScriptCode script)
218{
219    setGenericFontFamilyMap(m_pictographFontFamilyMap, family, script, m_page);
220}
221
222void Settings::setTextAutosizingEnabled(bool textAutosizingEnabled)
223{
224    if (m_textAutosizingEnabled == textAutosizingEnabled)
225        return;
226
227    m_textAutosizingEnabled = textAutosizingEnabled;
228    m_page->setNeedsRecalcStyleInAllFrames();
229}
230
231void Settings::setTextAutosizingWindowSizeOverride(const IntSize& textAutosizingWindowSizeOverride)
232{
233    if (m_textAutosizingWindowSizeOverride == textAutosizingWindowSizeOverride)
234        return;
235
236    m_textAutosizingWindowSizeOverride = textAutosizingWindowSizeOverride;
237    m_page->setNeedsRecalcStyleInAllFrames();
238}
239
240void Settings::setUseWideViewport(bool useWideViewport)
241{
242    if (m_useWideViewport == useWideViewport)
243        return;
244
245    m_useWideViewport = useWideViewport;
246    if (m_page->mainFrame())
247        m_page->chrome().dispatchViewportPropertiesDidChange(m_page->mainFrame()->document()->viewportArguments());
248}
249
250void Settings::setLoadWithOverviewMode(bool loadWithOverviewMode)
251{
252    if (m_loadWithOverviewMode == loadWithOverviewMode)
253        return;
254
255    m_loadWithOverviewMode = loadWithOverviewMode;
256    if (m_page->mainFrame())
257        m_page->chrome().dispatchViewportPropertiesDidChange(m_page->mainFrame()->document()->viewportArguments());
258}
259
260void Settings::setTextAutosizingFontScaleFactor(float fontScaleFactor)
261{
262    m_textAutosizingFontScaleFactor = fontScaleFactor;
263
264    // FIXME: I wonder if this needs to traverse frames like in WebViewImpl::resize, or whether there is only one document per Settings instance?
265    for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext())
266        frame->document()->textAutosizer()->recalculateMultipliers();
267
268    m_page->setNeedsRecalcStyleInAllFrames();
269}
270
271void Settings::setMediaTypeOverride(const String& mediaTypeOverride)
272{
273    if (m_mediaTypeOverride == mediaTypeOverride)
274        return;
275
276    m_mediaTypeOverride = mediaTypeOverride;
277
278    Frame* mainFrame = m_page->mainFrame();
279    ASSERT(mainFrame);
280    FrameView* view = mainFrame->view();
281    ASSERT(view);
282
283    view->setMediaType(mediaTypeOverride);
284    m_page->setNeedsRecalcStyleInAllFrames();
285}
286
287void Settings::setLoadsImagesAutomatically(bool loadsImagesAutomatically)
288{
289    m_loadsImagesAutomatically = loadsImagesAutomatically;
290
291    // Changing this setting to true might immediately start new loads for images that had previously had loading disabled.
292    // If this happens while a WebView is being dealloc'ed, and we don't know the WebView is being dealloc'ed, these new loads
293    // can cause crashes downstream when the WebView memory has actually been free'd.
294    // One example where this can happen is in Mac apps that subclass WebView then do work in their overridden dealloc methods.
295    // Starting these loads synchronously is not important.  By putting it on a 0-delay, properly closing the Page cancels them
296    // before they have a chance to really start.
297    // See http://webkit.org/b/60572 for more discussion.
298    m_setImageLoadingSettingsTimer.startOneShot(0);
299}
300
301void Settings::imageLoadingSettingsTimerFired(Timer<Settings>*)
302{
303    setImageLoadingSettings(m_page);
304}
305
306void Settings::setScriptEnabled(bool isScriptEnabled)
307{
308    m_isScriptEnabled = isScriptEnabled;
309    InspectorInstrumentation::scriptsEnabled(m_page, m_isScriptEnabled);
310}
311
312void Settings::setJavaEnabled(bool isJavaEnabled)
313{
314    m_isJavaEnabled = isJavaEnabled;
315}
316
317void Settings::setImagesEnabled(bool areImagesEnabled)
318{
319    m_areImagesEnabled = areImagesEnabled;
320
321    // See comment in setLoadsImagesAutomatically.
322    m_setImageLoadingSettingsTimer.startOneShot(0);
323}
324
325void Settings::setPluginsEnabled(bool arePluginsEnabled)
326{
327    m_arePluginsEnabled = arePluginsEnabled;
328}
329
330void Settings::setUserStyleSheetLocation(const KURL& userStyleSheetLocation)
331{
332    if (m_userStyleSheetLocation == userStyleSheetLocation)
333        return;
334
335    m_userStyleSheetLocation = userStyleSheetLocation;
336
337    m_page->userStyleSheetLocationChanged();
338}
339
340void Settings::setDNSPrefetchingEnabled(bool dnsPrefetchingEnabled)
341{
342    if (m_dnsPrefetchingEnabled == dnsPrefetchingEnabled)
343        return;
344
345    m_dnsPrefetchingEnabled = dnsPrefetchingEnabled;
346    m_page->dnsPrefetchingStateChanged();
347}
348
349void Settings::setMockScrollbarsEnabled(bool flag)
350{
351    gMockScrollbarsEnabled = flag;
352}
353
354bool Settings::mockScrollbarsEnabled()
355{
356    return gMockScrollbarsEnabled;
357}
358
359void Settings::setUsesOverlayScrollbars(bool flag)
360{
361    gUsesOverlayScrollbars = flag;
362}
363
364bool Settings::usesOverlayScrollbars()
365{
366    return gUsesOverlayScrollbars;
367}
368
369void Settings::setOpenGLMultisamplingEnabled(bool flag)
370{
371    if (m_openGLMultisamplingEnabled == flag)
372        return;
373
374    m_openGLMultisamplingEnabled = flag;
375    m_page->multisamplingChanged();
376}
377
378bool Settings::openGLMultisamplingEnabled()
379{
380    return m_openGLMultisamplingEnabled;
381}
382
383} // namespace WebCore
384