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 58 namespace blink { 59 60 InternalSettings::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 80 void 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) 102 InternalSettings* 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. 112 class InternalSettingsWrapper : public Supplement<Page> { 113 public: 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 122 private: 123 RefPtr<InternalSettings> m_internalSettings; 124 }; 125 126 InternalSettings* 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 134 const char* InternalSettings::supplementName() 135 { 136 return "InternalSettings"; 137 } 138 139 InternalSettings::~InternalSettings() 140 { 141 } 142 143 InternalSettings::InternalSettings(Page& page) 144 : InternalSettingsGenerated(&page) 145 , m_page(&page) 146 , m_backup(&page.settings()) 147 { 148 } 149 150 void 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 161 Settings* InternalSettings::settings() const 162 { 163 if (!page()) 164 return 0; 165 return &page()->settings(); 166 } 167 168 void InternalSettings::setMockScrollbarsEnabled(bool enabled, ExceptionState& exceptionState) 169 { 170 InternalSettingsGuardForSettings(); 171 settings()->setMockScrollbarsEnabled(enabled); 172 } 173 174 void InternalSettings::setMockGestureTapHighlightsEnabled(bool enabled, ExceptionState& exceptionState) 175 { 176 InternalSettingsGuardForSettings(); 177 settings()->setMockGestureTapHighlightsEnabled(enabled); 178 } 179 180 void InternalSettings::setAuthorShadowDOMForAnyElementEnabled(bool isEnabled) 181 { 182 RuntimeEnabledFeatures::setAuthorShadowDOMForAnyElementEnabled(isEnabled); 183 } 184 185 void InternalSettings::setExperimentalContentSecurityPolicyFeaturesEnabled(bool enabled) 186 { 187 RuntimeEnabledFeatures::setExperimentalContentSecurityPolicyFeaturesEnabled(enabled); 188 } 189 190 void InternalSettings::setLaxMixedContentCheckingEnabled(bool enabled) 191 { 192 RuntimeEnabledFeatures::setLaxMixedContentCheckingEnabled(enabled); 193 } 194 195 void InternalSettings::setPseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled(bool enabled) 196 { 197 RuntimeEnabledFeatures::setPseudoClassesInMatchingCriteriaInAuthorShadowTreesEnabled(enabled); 198 } 199 200 void InternalSettings::setOverlayScrollbarsEnabled(bool enabled) 201 { 202 RuntimeEnabledFeatures::setOverlayScrollbarsEnabled(enabled); 203 } 204 205 void 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). 213 void InternalSettings::setLayerSquashingEnabled(bool enabled, ExceptionState& exceptionState) 214 { 215 InternalSettingsGuardForSettings(); 216 settings()->setLayerSquashingEnabled(enabled); 217 } 218 219 void 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 229 void 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 239 void 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 249 void 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 259 void 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 269 void 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 279 void 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 289 void InternalSettings::setTextAutosizingEnabled(bool enabled, ExceptionState& exceptionState) 290 { 291 InternalSettingsGuardForSettings(); 292 settings()->setTextAutosizingEnabled(enabled); 293 m_page->inspectorController().setTextAutosizingEnabled(enabled); 294 } 295 296 void InternalSettings::setTextAutosizingWindowSizeOverride(int width, int height, ExceptionState& exceptionState) 297 { 298 InternalSettingsGuardForSettings(); 299 settings()->setTextAutosizingWindowSizeOverride(IntSize(width, height)); 300 } 301 302 void InternalSettings::setMediaTypeOverride(const String& mediaType, ExceptionState& exceptionState) 303 { 304 InternalSettingsGuardForSettings(); 305 settings()->setMediaTypeOverride(mediaType); 306 } 307 308 void InternalSettings::setAccessibilityFontScaleFactor(float fontScaleFactor, ExceptionState& exceptionState) 309 { 310 InternalSettingsGuardForSettings(); 311 settings()->setAccessibilityFontScaleFactor(fontScaleFactor); 312 } 313 314 void 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 329 void InternalSettings::setLangAttributeAwareFormControlUIEnabled(bool enabled) 330 { 331 RuntimeEnabledFeatures::setLangAttributeAwareFormControlUIEnabled(enabled); 332 } 333 334 void InternalSettings::setImagesEnabled(bool enabled, ExceptionState& exceptionState) 335 { 336 InternalSettingsGuardForSettings(); 337 settings()->setImagesEnabled(enabled); 338 } 339 340 void InternalSettings::setDefaultVideoPosterURL(const String& url, ExceptionState& exceptionState) 341 { 342 InternalSettingsGuardForSettings(); 343 settings()->setDefaultVideoPosterURL(url); 344 } 345 346 void 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 355 void 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 381 void 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 399 void 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 425 void 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