1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1.  Redistributions of source code must retain the above copyright
10 *     notice, this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "InternalSettings.h"
29
30#include "CaptionUserPreferences.h"
31#include "Document.h"
32#include "ExceptionCode.h"
33#include "Frame.h"
34#include "FrameView.h"
35#include "Language.h"
36#include "LocaleToScriptMapping.h"
37#include "Page.h"
38#include "PageGroup.h"
39#include "RuntimeEnabledFeatures.h"
40#include "Settings.h"
41#include "Supplementable.h"
42#include "TextRun.h"
43
44#if ENABLE(INPUT_TYPE_COLOR)
45#include "ColorChooser.h"
46#endif
47
48#define InternalSettingsGuardForSettingsReturn(returnValue) \
49    if (!settings()) { \
50        ec = INVALID_ACCESS_ERR; \
51        return returnValue; \
52    }
53
54#define InternalSettingsGuardForSettings()  \
55    if (!settings()) { \
56        ec = INVALID_ACCESS_ERR; \
57        return; \
58    }
59
60#define InternalSettingsGuardForPage() \
61    if (!page()) { \
62        ec = INVALID_ACCESS_ERR; \
63        return; \
64    }
65
66namespace WebCore {
67
68InternalSettings::Backup::Backup(Settings* settings)
69    : m_originalCSSExclusionsEnabled(RuntimeEnabledFeatures::cssExclusionsEnabled())
70    , m_originalCSSShapesEnabled(RuntimeEnabledFeatures::cssShapesEnabled())
71    , m_originalCSSVariablesEnabled(settings->cssVariablesEnabled())
72#if ENABLE(SHADOW_DOM)
73    , m_originalShadowDOMEnabled(RuntimeEnabledFeatures::shadowDOMEnabled())
74    , m_originalAuthorShadowDOMForAnyElementEnabled(RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
75#endif
76#if ENABLE(STYLE_SCOPED)
77    , m_originalStyleScoped(RuntimeEnabledFeatures::styleScopedEnabled())
78#endif
79    , m_originalEditingBehavior(settings->editingBehaviorType())
80#if ENABLE(TEXT_AUTOSIZING)
81    , m_originalTextAutosizingEnabled(settings->textAutosizingEnabled())
82    , m_originalTextAutosizingWindowSizeOverride(settings->textAutosizingWindowSizeOverride())
83    , m_originalTextAutosizingFontScaleFactor(settings->textAutosizingFontScaleFactor())
84#endif
85    , m_originalMediaTypeOverride(settings->mediaTypeOverride())
86#if ENABLE(DIALOG_ELEMENT)
87    , m_originalDialogElementEnabled(RuntimeEnabledFeatures::dialogElementEnabled())
88#endif
89    , m_originalCanvasUsesAcceleratedDrawing(settings->canvasUsesAcceleratedDrawing())
90    , m_originalMockScrollbarsEnabled(settings->mockScrollbarsEnabled())
91    , m_langAttributeAwareFormControlUIEnabled(RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled())
92    , m_imagesEnabled(settings->areImagesEnabled())
93    , m_minimumTimerInterval(settings->minDOMTimerInterval())
94#if ENABLE(VIDEO_TRACK)
95    , m_shouldDisplaySubtitles(settings->shouldDisplaySubtitles())
96    , m_shouldDisplayCaptions(settings->shouldDisplayCaptions())
97    , m_shouldDisplayTextDescriptions(settings->shouldDisplayTextDescriptions())
98#endif
99    , m_defaultVideoPosterURL(settings->defaultVideoPosterURL())
100    , m_originalTimeWithoutMouseMovementBeforeHidingControls(settings->timeWithoutMouseMovementBeforeHidingControls())
101    , m_useLegacyBackgroundSizeShorthandBehavior(settings->useLegacyBackgroundSizeShorthandBehavior())
102{
103}
104
105void InternalSettings::Backup::restoreTo(Settings* settings)
106{
107    RuntimeEnabledFeatures::setCSSExclusionsEnabled(m_originalCSSExclusionsEnabled);
108    RuntimeEnabledFeatures::setCSSShapesEnabled(m_originalCSSShapesEnabled);
109    settings->setCSSVariablesEnabled(m_originalCSSVariablesEnabled);
110#if ENABLE(SHADOW_DOM)
111    RuntimeEnabledFeatures::setShadowDOMEnabled(m_originalShadowDOMEnabled);
112    RuntimeEnabledFeatures::setAuthorShadowDOMForAnyElementEnabled(m_originalAuthorShadowDOMForAnyElementEnabled);
113#endif
114#if ENABLE(STYLE_SCOPED)
115    RuntimeEnabledFeatures::setStyleScopedEnabled(m_originalStyleScoped);
116#endif
117    settings->setEditingBehaviorType(m_originalEditingBehavior);
118#if ENABLE(TEXT_AUTOSIZING)
119    settings->setTextAutosizingEnabled(m_originalTextAutosizingEnabled);
120    settings->setTextAutosizingWindowSizeOverride(m_originalTextAutosizingWindowSizeOverride);
121    settings->setTextAutosizingFontScaleFactor(m_originalTextAutosizingFontScaleFactor);
122#endif
123    settings->setMediaTypeOverride(m_originalMediaTypeOverride);
124#if ENABLE(DIALOG_ELEMENT)
125    RuntimeEnabledFeatures::setDialogElementEnabled(m_originalDialogElementEnabled);
126#endif
127    settings->setCanvasUsesAcceleratedDrawing(m_originalCanvasUsesAcceleratedDrawing);
128    settings->setMockScrollbarsEnabled(m_originalMockScrollbarsEnabled);
129    RuntimeEnabledFeatures::setLangAttributeAwareFormControlUIEnabled(m_langAttributeAwareFormControlUIEnabled);
130    settings->setImagesEnabled(m_imagesEnabled);
131    settings->setMinDOMTimerInterval(m_minimumTimerInterval);
132#if ENABLE(VIDEO_TRACK)
133    settings->setShouldDisplaySubtitles(m_shouldDisplaySubtitles);
134    settings->setShouldDisplayCaptions(m_shouldDisplayCaptions);
135    settings->setShouldDisplayTextDescriptions(m_shouldDisplayTextDescriptions);
136#endif
137    settings->setDefaultVideoPosterURL(m_defaultVideoPosterURL);
138    settings->setTimeWithoutMouseMovementBeforeHidingControls(m_originalTimeWithoutMouseMovementBeforeHidingControls);
139    settings->setUseLegacyBackgroundSizeShorthandBehavior(m_useLegacyBackgroundSizeShorthandBehavior);
140}
141
142// We can't use RefCountedSupplement because that would try to make InternalSettings RefCounted
143// and InternalSettings is already RefCounted via its base class, InternalSettingsGenerated.
144// Instead, we manually make InternalSettings supplement Page.
145class InternalSettingsWrapper : public Supplement<Page> {
146public:
147    explicit InternalSettingsWrapper(Page* page)
148        : m_internalSettings(InternalSettings::create(page)) { }
149    virtual ~InternalSettingsWrapper() { m_internalSettings->hostDestroyed(); }
150#if !ASSERT_DISABLED
151    virtual bool isRefCountedWrapper() const OVERRIDE { return true; }
152#endif
153    InternalSettings* internalSettings() const { return m_internalSettings.get(); }
154
155private:
156    RefPtr<InternalSettings> m_internalSettings;
157};
158
159const char* InternalSettings::supplementName()
160{
161    return "InternalSettings";
162}
163
164InternalSettings* InternalSettings::from(Page* page)
165{
166    if (!Supplement<Page>::from(page, supplementName()))
167        Supplement<Page>::provideTo(page, supplementName(), adoptPtr(new InternalSettingsWrapper(page)));
168    return static_cast<InternalSettingsWrapper*>(Supplement<Page>::from(page, supplementName()))->internalSettings();
169}
170
171InternalSettings::~InternalSettings()
172{
173}
174
175InternalSettings::InternalSettings(Page* page)
176    : InternalSettingsGenerated(page)
177    , m_page(page)
178    , m_backup(page->settings())
179{
180}
181
182void InternalSettings::resetToConsistentState()
183{
184    page()->setPageScaleFactor(1, IntPoint(0, 0));
185    page()->setCanStartMedia(true);
186
187    m_backup.restoreTo(settings());
188    m_backup = Backup(settings());
189
190    InternalSettingsGenerated::resetToConsistentState();
191}
192
193Settings* InternalSettings::settings() const
194{
195    if (!page())
196        return 0;
197    return page()->settings();
198}
199
200void InternalSettings::setMockScrollbarsEnabled(bool enabled, ExceptionCode& ec)
201{
202    InternalSettingsGuardForSettings();
203    settings()->setMockScrollbarsEnabled(enabled);
204}
205
206static bool urlIsWhitelistedForSetShadowDOMEnabled(const String& url)
207{
208    // This check is just for preventing fuzzers from crashing because of unintended API calls.
209    // You can list your test if needed.
210    return notFound != url.find("fast/dom/shadow/content-shadow-unknown.html")
211        || notFound != url.find("fast/dom/shadow/insertion-points-with-shadow-disabled.html");
212}
213
214void InternalSettings::setShadowDOMEnabled(bool enabled, ExceptionCode& ec)
215{
216    if (!urlIsWhitelistedForSetShadowDOMEnabled(page()->mainFrame()->document()->url().string())) {
217        ec = INVALID_ACCESS_ERR;
218        return;
219    }
220
221#if ENABLE(SHADOW_DOM)
222    RuntimeEnabledFeatures::setShadowDOMEnabled(enabled);
223#else
224    // Even SHADOW_DOM is off, InternalSettings allows setShadowDOMEnabled(false) to
225    // have broader test coverage. But it cannot be setShadowDOMEnabled(true).
226    if (enabled)
227        ec = INVALID_ACCESS_ERR;
228#endif
229}
230
231void InternalSettings::setAuthorShadowDOMForAnyElementEnabled(bool isEnabled)
232{
233#if ENABLE(SHADOW_DOM)
234    RuntimeEnabledFeatures::setAuthorShadowDOMForAnyElementEnabled(isEnabled);
235#else
236    UNUSED_PARAM(isEnabled);
237#endif
238}
239
240void InternalSettings::setStyleScopedEnabled(bool enabled)
241{
242#if ENABLE(STYLE_SCOPED)
243    RuntimeEnabledFeatures::setStyleScopedEnabled(enabled);
244#else
245    UNUSED_PARAM(enabled);
246#endif
247}
248
249void InternalSettings::setTouchEventEmulationEnabled(bool enabled, ExceptionCode& ec)
250{
251#if ENABLE(TOUCH_EVENTS)
252    InternalSettingsGuardForSettings();
253    settings()->setTouchEventEmulationEnabled(enabled);
254#else
255    UNUSED_PARAM(enabled);
256    UNUSED_PARAM(ec);
257#endif
258}
259
260typedef void (Settings::*SetFontFamilyFunction)(const AtomicString&, UScriptCode);
261static void setFontFamily(Settings* settings, const String& family, const String& script, SetFontFamilyFunction setter)
262{
263    UScriptCode code = scriptNameToCode(script);
264    if (code != USCRIPT_INVALID_CODE)
265        (settings->*setter)(family, code);
266}
267
268void InternalSettings::setStandardFontFamily(const String& family, const String& script, ExceptionCode& ec)
269{
270    InternalSettingsGuardForSettings();
271    setFontFamily(settings(), family, script, &Settings::setStandardFontFamily);
272}
273
274void InternalSettings::setSerifFontFamily(const String& family, const String& script, ExceptionCode& ec)
275{
276    InternalSettingsGuardForSettings();
277    setFontFamily(settings(), family, script, &Settings::setSerifFontFamily);
278}
279
280void InternalSettings::setSansSerifFontFamily(const String& family, const String& script, ExceptionCode& ec)
281{
282    InternalSettingsGuardForSettings();
283    setFontFamily(settings(), family, script, &Settings::setSansSerifFontFamily);
284}
285
286void InternalSettings::setFixedFontFamily(const String& family, const String& script, ExceptionCode& ec)
287{
288    InternalSettingsGuardForSettings();
289    setFontFamily(settings(), family, script, &Settings::setFixedFontFamily);
290}
291
292void InternalSettings::setCursiveFontFamily(const String& family, const String& script, ExceptionCode& ec)
293{
294    InternalSettingsGuardForSettings();
295    setFontFamily(settings(), family, script, &Settings::setCursiveFontFamily);
296}
297
298void InternalSettings::setFantasyFontFamily(const String& family, const String& script, ExceptionCode& ec)
299{
300    InternalSettingsGuardForSettings();
301    setFontFamily(settings(), family, script, &Settings::setFantasyFontFamily);
302}
303
304void InternalSettings::setPictographFontFamily(const String& family, const String& script, ExceptionCode& ec)
305{
306    InternalSettingsGuardForSettings();
307    setFontFamily(settings(), family, script, &Settings::setPictographFontFamily);
308}
309
310void InternalSettings::setTextAutosizingEnabled(bool enabled, ExceptionCode& ec)
311{
312#if ENABLE(TEXT_AUTOSIZING)
313    InternalSettingsGuardForSettings();
314    settings()->setTextAutosizingEnabled(enabled);
315#else
316    UNUSED_PARAM(enabled);
317    UNUSED_PARAM(ec);
318#endif
319}
320
321void InternalSettings::setTextAutosizingWindowSizeOverride(int width, int height, ExceptionCode& ec)
322{
323#if ENABLE(TEXT_AUTOSIZING)
324    InternalSettingsGuardForSettings();
325    settings()->setTextAutosizingWindowSizeOverride(IntSize(width, height));
326#else
327    UNUSED_PARAM(width);
328    UNUSED_PARAM(height);
329    UNUSED_PARAM(ec);
330#endif
331}
332
333void InternalSettings::setMediaTypeOverride(const String& mediaType, ExceptionCode& ec)
334{
335    InternalSettingsGuardForSettings();
336    settings()->setMediaTypeOverride(mediaType);
337}
338
339void InternalSettings::setTextAutosizingFontScaleFactor(float fontScaleFactor, ExceptionCode& ec)
340{
341#if ENABLE(TEXT_AUTOSIZING)
342    InternalSettingsGuardForSettings();
343    settings()->setTextAutosizingFontScaleFactor(fontScaleFactor);
344#else
345    UNUSED_PARAM(fontScaleFactor);
346    UNUSED_PARAM(ec);
347#endif
348}
349
350void InternalSettings::setCSSExclusionsEnabled(bool enabled, ExceptionCode& ec)
351{
352    UNUSED_PARAM(ec);
353    RuntimeEnabledFeatures::setCSSExclusionsEnabled(enabled);
354}
355
356void InternalSettings::setCSSShapesEnabled(bool enabled, ExceptionCode& ec)
357{
358    UNUSED_PARAM(ec);
359    RuntimeEnabledFeatures::setCSSShapesEnabled(enabled);
360}
361
362void InternalSettings::setCSSVariablesEnabled(bool enabled, ExceptionCode& ec)
363{
364    InternalSettingsGuardForSettings();
365    settings()->setCSSVariablesEnabled(enabled);
366}
367
368bool InternalSettings::cssVariablesEnabled(ExceptionCode& ec)
369{
370    InternalSettingsGuardForSettingsReturn(false);
371    return settings()->cssVariablesEnabled();
372}
373
374void InternalSettings::setCanStartMedia(bool enabled, ExceptionCode& ec)
375{
376    InternalSettingsGuardForSettings();
377    m_page->setCanStartMedia(enabled);
378}
379
380void InternalSettings::setEditingBehavior(const String& editingBehavior, ExceptionCode& ec)
381{
382    InternalSettingsGuardForSettings();
383    if (equalIgnoringCase(editingBehavior, "win"))
384        settings()->setEditingBehaviorType(EditingWindowsBehavior);
385    else if (equalIgnoringCase(editingBehavior, "mac"))
386        settings()->setEditingBehaviorType(EditingMacBehavior);
387    else if (equalIgnoringCase(editingBehavior, "unix"))
388        settings()->setEditingBehaviorType(EditingUnixBehavior);
389    else
390        ec = SYNTAX_ERR;
391}
392
393void InternalSettings::setDialogElementEnabled(bool enabled, ExceptionCode& ec)
394{
395    UNUSED_PARAM(ec);
396#if ENABLE(DIALOG_ELEMENT)
397    RuntimeEnabledFeatures::setDialogElementEnabled(enabled);
398#else
399    UNUSED_PARAM(enabled);
400#endif
401}
402
403void InternalSettings::setShouldDisplayTrackKind(const String& kind, bool enabled, ExceptionCode& ec)
404{
405    InternalSettingsGuardForSettings();
406
407#if ENABLE(VIDEO_TRACK)
408    if (!page())
409        return;
410    CaptionUserPreferences* captionPreferences = page()->group().captionPreferences();
411
412    if (equalIgnoringCase(kind, "Subtitles"))
413        captionPreferences->setUserPrefersSubtitles(enabled);
414    else if (equalIgnoringCase(kind, "Captions"))
415        captionPreferences->setUserPrefersCaptions(enabled);
416    else if (equalIgnoringCase(kind, "TextDescriptions"))
417        captionPreferences->setUserPrefersTextDescriptions(enabled);
418    else
419        ec = SYNTAX_ERR;
420#else
421    UNUSED_PARAM(kind);
422    UNUSED_PARAM(enabled);
423#endif
424}
425
426bool InternalSettings::shouldDisplayTrackKind(const String& kind, ExceptionCode& ec)
427{
428    InternalSettingsGuardForSettingsReturn(false);
429
430#if ENABLE(VIDEO_TRACK)
431    if (!page())
432        return false;
433    CaptionUserPreferences* captionPreferences = page()->group().captionPreferences();
434
435    if (equalIgnoringCase(kind, "Subtitles"))
436        return captionPreferences->userPrefersSubtitles();
437    if (equalIgnoringCase(kind, "Captions"))
438        return captionPreferences->userPrefersCaptions();
439    if (equalIgnoringCase(kind, "TextDescriptions"))
440        return captionPreferences->userPrefersTextDescriptions();
441
442    ec = SYNTAX_ERR;
443    return false;
444#else
445    UNUSED_PARAM(kind);
446    return false;
447#endif
448}
449
450void InternalSettings::setStorageBlockingPolicy(const String& mode, ExceptionCode& ec)
451{
452    InternalSettingsGuardForSettings();
453
454    if (mode == "AllowAll")
455        settings()->setStorageBlockingPolicy(SecurityOrigin::AllowAllStorage);
456    else if (mode == "BlockThirdParty")
457        settings()->setStorageBlockingPolicy(SecurityOrigin::BlockThirdPartyStorage);
458    else if (mode == "BlockAll")
459        settings()->setStorageBlockingPolicy(SecurityOrigin::BlockAllStorage);
460    else
461        ec = SYNTAX_ERR;
462}
463
464void InternalSettings::setLangAttributeAwareFormControlUIEnabled(bool enabled)
465{
466    RuntimeEnabledFeatures::setLangAttributeAwareFormControlUIEnabled(enabled);
467}
468
469void InternalSettings::setImagesEnabled(bool enabled, ExceptionCode& ec)
470{
471    InternalSettingsGuardForSettings();
472    settings()->setImagesEnabled(enabled);
473}
474
475void InternalSettings::setMinimumTimerInterval(double intervalInSeconds, ExceptionCode& ec)
476{
477    InternalSettingsGuardForSettings();
478    settings()->setMinDOMTimerInterval(intervalInSeconds);
479}
480
481void InternalSettings::setDefaultVideoPosterURL(const String& url, ExceptionCode& ec)
482{
483    InternalSettingsGuardForSettings();
484    settings()->setDefaultVideoPosterURL(url);
485}
486
487void InternalSettings::setTimeWithoutMouseMovementBeforeHidingControls(double time, ExceptionCode& ec)
488{
489    InternalSettingsGuardForSettings();
490    settings()->setTimeWithoutMouseMovementBeforeHidingControls(time);
491}
492
493void InternalSettings::setUseLegacyBackgroundSizeShorthandBehavior(bool enabled, ExceptionCode& ec)
494{
495    InternalSettingsGuardForSettings();
496    settings()->setUseLegacyBackgroundSizeShorthandBehavior(enabled);
497}
498
499}
500