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 "core/testing/InternalSettings.h" 29 30#include "bindings/core/v8/ExceptionState.h" 31#include "core/css/PointerProperties.h" 32#include "core/dom/ExceptionCode.h" 33#include "core/frame/Settings.h" 34#include "core/inspector/InspectorController.h" 35#include "core/page/Page.h" 36#include "platform/RuntimeEnabledFeatures.h" 37#include "platform/Supplementable.h" 38#include "platform/text/LocaleToScriptMapping.h" 39 40#define InternalSettingsGuardForSettingsReturn(returnValue) \ 41 if (!settings()) { \ 42 exceptionState.throwDOMException(InvalidAccessError, "The settings object cannot be obtained."); \ 43 return returnValue; \ 44 } 45 46#define InternalSettingsGuardForSettings() \ 47 if (!settings()) { \ 48 exceptionState.throwDOMException(InvalidAccessError, "The settings object cannot be obtained."); \ 49 return; \ 50 } 51 52#define InternalSettingsGuardForPage() \ 53 if (!page()) { \ 54 exceptionState.throwDOMException(InvalidAccessError, "The page object cannot be obtained."); \ 55 return; \ 56 } 57 58namespace blink { 59 60InternalSettings::Backup::Backup(Settings* settings) 61 : m_originalAuthorShadowDOMForAnyElementEnabled(RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled()) 62 , m_originalCSP(RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnabled()) 63 , m_originalLaxMixedContentCheckingEnabled(RuntimeEnabledFeatures::laxMixedContentCheckingEnabled()) 64 , m_originalOverlayScrollbarsEnabled(RuntimeEnabledFeatures::overlayScrollbarsEnabled()) 65 , m_originalEditingBehavior(settings->editingBehaviorType()) 66 , m_originalTextAutosizingEnabled(settings->textAutosizingEnabled()) 67 , m_originalTextAutosizingWindowSizeOverride(settings->textAutosizingWindowSizeOverride()) 68 , m_originalAccessibilityFontScaleFactor(settings->accessibilityFontScaleFactor()) 69 , m_originalMediaTypeOverride(settings->mediaTypeOverride()) 70 , m_originalMockScrollbarsEnabled(settings->mockScrollbarsEnabled()) 71 , m_originalMockGestureTapHighlightsEnabled(settings->mockGestureTapHighlightsEnabled()) 72 , m_langAttributeAwareFormControlUIEnabled(RuntimeEnabledFeatures::langAttributeAwareFormControlUIEnabled()) 73 , m_imagesEnabled(settings->imagesEnabled()) 74 , m_defaultVideoPosterURL(settings->defaultVideoPosterURL()) 75 , m_originalLayerSquashingEnabled(settings->layerSquashingEnabled()) 76 , m_originalPseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled(RuntimeEnabledFeatures::pseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled()) 77{ 78} 79 80void InternalSettings::Backup::restoreTo(Settings* settings) 81{ 82 RuntimeEnabledFeatures::setAuthorShadowDOMForAnyElementEnabled(m_originalAuthorShadowDOMForAnyElementEnabled); 83 RuntimeEnabledFeatures::setExperimentalContentSecurityPolicyFeaturesEnabled(m_originalCSP); 84 RuntimeEnabledFeatures::setLaxMixedContentCheckingEnabled(m_originalLaxMixedContentCheckingEnabled); 85 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(m_originalOverlayScrollbarsEnabled); 86 settings->setEditingBehaviorType(m_originalEditingBehavior); 87 settings->setTextAutosizingEnabled(m_originalTextAutosizingEnabled); 88 settings->setTextAutosizingWindowSizeOverride(m_originalTextAutosizingWindowSizeOverride); 89 settings->setAccessibilityFontScaleFactor(m_originalAccessibilityFontScaleFactor); 90 settings->setMediaTypeOverride(m_originalMediaTypeOverride); 91 settings->setMockScrollbarsEnabled(m_originalMockScrollbarsEnabled); 92 settings->setMockGestureTapHighlightsEnabled(m_originalMockGestureTapHighlightsEnabled); 93 RuntimeEnabledFeatures::setLangAttributeAwareFormControlUIEnabled(m_langAttributeAwareFormControlUIEnabled); 94 settings->setImagesEnabled(m_imagesEnabled); 95 settings->setDefaultVideoPosterURL(m_defaultVideoPosterURL); 96 settings->setLayerSquashingEnabled(m_originalLayerSquashingEnabled); 97 settings->genericFontFamilySettings().reset(); 98 RuntimeEnabledFeatures::setPseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled(m_originalPseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled); 99} 100 101#if ENABLE(OILPAN) 102InternalSettings* InternalSettings::from(Page& page) 103{ 104 if (!HeapSupplement<Page>::from(page, supplementName())) 105 HeapSupplement<Page>::provideTo(page, supplementName(), new InternalSettings(page)); 106 return static_cast<InternalSettings*>(HeapSupplement<Page>::from(page, supplementName())); 107} 108#else 109// We can't use RefCountedSupplement because that would try to make InternalSettings RefCounted 110// and InternalSettings is already RefCounted via its base class, InternalSettingsGenerated. 111// Instead, we manually make InternalSettings supplement Page. 112class InternalSettingsWrapper : public Supplement<Page> { 113public: 114 explicit InternalSettingsWrapper(Page& page) 115 : m_internalSettings(InternalSettings::create(page)) { } 116 virtual ~InternalSettingsWrapper() { m_internalSettings->hostDestroyed(); } 117#if ENABLE(ASSERT) 118 virtual bool isRefCountedWrapper() const OVERRIDE { return true; } 119#endif 120 InternalSettings* internalSettings() const { return m_internalSettings.get(); } 121 122private: 123 RefPtr<InternalSettings> m_internalSettings; 124}; 125 126InternalSettings* InternalSettings::from(Page& page) 127{ 128 if (!Supplement<Page>::from(page, supplementName())) 129 Supplement<Page>::provideTo(page, supplementName(), adoptPtr(new InternalSettingsWrapper(page))); 130 return static_cast<InternalSettingsWrapper*>(Supplement<Page>::from(page, supplementName()))->internalSettings(); 131} 132#endif 133 134const char* InternalSettings::supplementName() 135{ 136 return "InternalSettings"; 137} 138 139InternalSettings::~InternalSettings() 140{ 141} 142 143InternalSettings::InternalSettings(Page& page) 144 : InternalSettingsGenerated(&page) 145 , m_page(&page) 146 , m_backup(&page.settings()) 147{ 148} 149 150void InternalSettings::resetToConsistentState() 151{ 152 page()->setPageScaleFactor(1, IntPoint(0, 0)); 153 154 m_backup.restoreTo(settings()); 155 m_backup = Backup(settings()); 156 m_backup.m_originalTextAutosizingEnabled = settings()->textAutosizingEnabled(); 157 158 InternalSettingsGenerated::resetToConsistentState(); 159} 160 161Settings* InternalSettings::settings() const 162{ 163 if (!page()) 164 return 0; 165 return &page()->settings(); 166} 167 168void InternalSettings::setMockScrollbarsEnabled(bool enabled, ExceptionState& exceptionState) 169{ 170 InternalSettingsGuardForSettings(); 171 settings()->setMockScrollbarsEnabled(enabled); 172} 173 174void InternalSettings::setMockGestureTapHighlightsEnabled(bool enabled, ExceptionState& exceptionState) 175{ 176 InternalSettingsGuardForSettings(); 177 settings()->setMockGestureTapHighlightsEnabled(enabled); 178} 179 180void InternalSettings::setAuthorShadowDOMForAnyElementEnabled(bool isEnabled) 181{ 182 RuntimeEnabledFeatures::setAuthorShadowDOMForAnyElementEnabled(isEnabled); 183} 184 185void InternalSettings::setExperimentalContentSecurityPolicyFeaturesEnabled(bool enabled) 186{ 187 RuntimeEnabledFeatures::setExperimentalContentSecurityPolicyFeaturesEnabled(enabled); 188} 189 190void InternalSettings::setLaxMixedContentCheckingEnabled(bool enabled) 191{ 192 RuntimeEnabledFeatures::setLaxMixedContentCheckingEnabled(enabled); 193} 194 195void InternalSettings::setPseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled(bool enabled) 196{ 197 RuntimeEnabledFeatures::setPseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled(enabled); 198} 199 200void InternalSettings::setOverlayScrollbarsEnabled(bool enabled) 201{ 202 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(enabled); 203} 204 205void InternalSettings::setViewportEnabled(bool enabled, ExceptionState& exceptionState) 206{ 207 InternalSettingsGuardForSettings(); 208 settings()->setViewportEnabled(enabled); 209} 210 211// FIXME: This is a temporary flag and should be removed once squashing is 212// ready (crbug.com/261605). 213void InternalSettings::setLayerSquashingEnabled(bool enabled, ExceptionState& exceptionState) 214{ 215 InternalSettingsGuardForSettings(); 216 settings()->setLayerSquashingEnabled(enabled); 217} 218 219void InternalSettings::setStandardFontFamily(const AtomicString& family, const String& script, ExceptionState& exceptionState) 220{ 221 InternalSettingsGuardForSettings(); 222 UScriptCode code = scriptNameToCode(script); 223 if (code == USCRIPT_INVALID_CODE) 224 return; 225 if (settings()->genericFontFamilySettings().updateStandard(family, code)) 226 settings()->notifyGenericFontFamilyChange(); 227} 228 229void InternalSettings::setSerifFontFamily(const AtomicString& family, const String& script, ExceptionState& exceptionState) 230{ 231 InternalSettingsGuardForSettings(); 232 UScriptCode code = scriptNameToCode(script); 233 if (code == USCRIPT_INVALID_CODE) 234 return; 235 if (settings()->genericFontFamilySettings().updateSerif(family, code)) 236 settings()->notifyGenericFontFamilyChange(); 237} 238 239void InternalSettings::setSansSerifFontFamily(const AtomicString& family, const String& script, ExceptionState& exceptionState) 240{ 241 InternalSettingsGuardForSettings(); 242 UScriptCode code = scriptNameToCode(script); 243 if (code == USCRIPT_INVALID_CODE) 244 return; 245 if (settings()->genericFontFamilySettings().updateSansSerif(family, code)) 246 settings()->notifyGenericFontFamilyChange(); 247} 248 249void InternalSettings::setFixedFontFamily(const AtomicString& family, const String& script, ExceptionState& exceptionState) 250{ 251 InternalSettingsGuardForSettings(); 252 UScriptCode code = scriptNameToCode(script); 253 if (code == USCRIPT_INVALID_CODE) 254 return; 255 if (settings()->genericFontFamilySettings().updateFixed(family, code)) 256 settings()->notifyGenericFontFamilyChange(); 257} 258 259void InternalSettings::setCursiveFontFamily(const AtomicString& family, const String& script, ExceptionState& exceptionState) 260{ 261 InternalSettingsGuardForSettings(); 262 UScriptCode code = scriptNameToCode(script); 263 if (code == USCRIPT_INVALID_CODE) 264 return; 265 if (settings()->genericFontFamilySettings().updateCursive(family, code)) 266 settings()->notifyGenericFontFamilyChange(); 267} 268 269void InternalSettings::setFantasyFontFamily(const AtomicString& family, const String& script, ExceptionState& exceptionState) 270{ 271 InternalSettingsGuardForSettings(); 272 UScriptCode code = scriptNameToCode(script); 273 if (code == USCRIPT_INVALID_CODE) 274 return; 275 if (settings()->genericFontFamilySettings().updateFantasy(family, code)) 276 settings()->notifyGenericFontFamilyChange(); 277} 278 279void InternalSettings::setPictographFontFamily(const AtomicString& family, const String& script, ExceptionState& exceptionState) 280{ 281 InternalSettingsGuardForSettings(); 282 UScriptCode code = scriptNameToCode(script); 283 if (code == USCRIPT_INVALID_CODE) 284 return; 285 if (settings()->genericFontFamilySettings().updatePictograph(family, code)) 286 settings()->notifyGenericFontFamilyChange(); 287} 288 289void InternalSettings::setTextAutosizingEnabled(bool enabled, ExceptionState& exceptionState) 290{ 291 InternalSettingsGuardForSettings(); 292 settings()->setTextAutosizingEnabled(enabled); 293 m_page->inspectorController().setTextAutosizingEnabled(enabled); 294} 295 296void InternalSettings::setTextAutosizingWindowSizeOverride(int width, int height, ExceptionState& exceptionState) 297{ 298 InternalSettingsGuardForSettings(); 299 settings()->setTextAutosizingWindowSizeOverride(IntSize(width, height)); 300} 301 302void InternalSettings::setMediaTypeOverride(const String& mediaType, ExceptionState& exceptionState) 303{ 304 InternalSettingsGuardForSettings(); 305 settings()->setMediaTypeOverride(mediaType); 306} 307 308void InternalSettings::setAccessibilityFontScaleFactor(float fontScaleFactor, ExceptionState& exceptionState) 309{ 310 InternalSettingsGuardForSettings(); 311 settings()->setAccessibilityFontScaleFactor(fontScaleFactor); 312} 313 314void InternalSettings::setEditingBehavior(const String& editingBehavior, ExceptionState& exceptionState) 315{ 316 InternalSettingsGuardForSettings(); 317 if (equalIgnoringCase(editingBehavior, "win")) 318 settings()->setEditingBehaviorType(EditingWindowsBehavior); 319 else if (equalIgnoringCase(editingBehavior, "mac")) 320 settings()->setEditingBehaviorType(EditingMacBehavior); 321 else if (equalIgnoringCase(editingBehavior, "unix")) 322 settings()->setEditingBehaviorType(EditingUnixBehavior); 323 else if (equalIgnoringCase(editingBehavior, "android")) 324 settings()->setEditingBehaviorType(EditingAndroidBehavior); 325 else 326 exceptionState.throwDOMException(SyntaxError, "The editing behavior type provided ('" + editingBehavior + "') is invalid."); 327} 328 329void InternalSettings::setLangAttributeAwareFormControlUIEnabled(bool enabled) 330{ 331 RuntimeEnabledFeatures::setLangAttributeAwareFormControlUIEnabled(enabled); 332} 333 334void InternalSettings::setImagesEnabled(bool enabled, ExceptionState& exceptionState) 335{ 336 InternalSettingsGuardForSettings(); 337 settings()->setImagesEnabled(enabled); 338} 339 340void InternalSettings::setDefaultVideoPosterURL(const String& url, ExceptionState& exceptionState) 341{ 342 InternalSettingsGuardForSettings(); 343 settings()->setDefaultVideoPosterURL(url); 344} 345 346void InternalSettings::trace(Visitor* visitor) 347{ 348 visitor->trace(m_page); 349 InternalSettingsGenerated::trace(visitor); 350#if ENABLE(OILPAN) 351 HeapSupplement<Page>::trace(visitor); 352#endif 353} 354 355void InternalSettings::setAvailablePointerTypes(const String& pointers, ExceptionState& exceptionState) 356{ 357 InternalSettingsGuardForSettings(); 358 359 // Allow setting multiple pointer types by passing comma seperated list 360 // ("coarse,fine"). 361 Vector<String> tokens; 362 pointers.split(",", false, tokens); 363 364 int pointerTypes = 0; 365 for (size_t i = 0; i < tokens.size(); ++i) { 366 String token = tokens[i].stripWhiteSpace(); 367 368 if (token == "coarse") 369 pointerTypes |= PointerTypeCoarse; 370 else if (token == "fine") 371 pointerTypes |= PointerTypeFine; 372 else if (token == "none") 373 pointerTypes |= PointerTypeNone; 374 else 375 exceptionState.throwDOMException(SyntaxError, "The pointer type token ('" + token + ")' is invalid."); 376 } 377 378 settings()->setAvailablePointerTypes(pointerTypes); 379} 380 381void InternalSettings::setPrimaryPointerType(const String& pointer, ExceptionState& exceptionState) 382{ 383 InternalSettingsGuardForSettings(); 384 String token = pointer.stripWhiteSpace(); 385 386 PointerType type = PointerTypeNone; 387 if (token == "coarse") 388 type = PointerTypeCoarse; 389 else if (token == "fine") 390 type = PointerTypeFine; 391 else if (token == "none") 392 type = PointerTypeNone; 393 else 394 exceptionState.throwDOMException(SyntaxError, "The pointer type token ('" + token + ")' is invalid."); 395 396 settings()->setPrimaryPointerType(type); 397} 398 399void InternalSettings::setAvailableHoverTypes(const String& types, ExceptionState& exceptionState) 400{ 401 InternalSettingsGuardForSettings(); 402 403 // Allow setting multiple hover types by passing comma seperated list 404 // ("on-demand,none"). 405 Vector<String> tokens; 406 types.split(",", false, tokens); 407 408 int hoverTypes = 0; 409 for (size_t i = 0; i < tokens.size(); ++i) { 410 String token = tokens[i].stripWhiteSpace(); 411 412 if (token == "none") 413 hoverTypes |= HoverTypeNone; 414 else if (token == "on-demand") 415 hoverTypes |= HoverTypeOnDemand; 416 else if (token == "hover") 417 hoverTypes |= HoverTypeHover; 418 else 419 exceptionState.throwDOMException(SyntaxError, "The hover type token ('" + token + ")' is invalid."); 420 } 421 422 settings()->setAvailableHoverTypes(hoverTypes); 423} 424 425void InternalSettings::setPrimaryHoverType(const String& type, ExceptionState& exceptionState) 426{ 427 InternalSettingsGuardForSettings(); 428 String token = type.stripWhiteSpace(); 429 430 HoverType hoverType = HoverTypeNone; 431 if (token == "none") 432 hoverType = HoverTypeNone; 433 else if (token == "on-demand") 434 hoverType = HoverTypeOnDemand; 435 else if (token == "hover") 436 hoverType = HoverTypeHover; 437 else 438 exceptionState.throwDOMException(SyntaxError, "The hover type token ('" + token + ")' is invalid."); 439 440 settings()->setPrimaryHoverType(hoverType); 441} 442 443} 444