diff options
Diffstat (limited to 'Source/WebCore/testing')
43 files changed, 7251 insertions, 1727 deletions
diff --git a/Source/WebCore/testing/GCObservation.cpp b/Source/WebCore/testing/GCObservation.cpp new file mode 100644 index 000000000..03091921f --- /dev/null +++ b/Source/WebCore/testing/GCObservation.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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 "GCObservation.h" + +#include <heap/HeapInlines.h> +#include <heap/WeakInlines.h> + +namespace WebCore { + +GCObservation::GCObservation(JSC::JSObject* object) + : m_observedValue(object, nullptr, nullptr) +{ +} + +} // namespace WebCore diff --git a/Source/WebCore/testing/GCObservation.h b/Source/WebCore/testing/GCObservation.h new file mode 100644 index 000000000..116c54fe3 --- /dev/null +++ b/Source/WebCore/testing/GCObservation.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#include <heap/Weak.h> +#include <runtime/JSCJSValueInlines.h> +#include <runtime/JSObject.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + +class GCObservation final : public RefCounted<GCObservation> { +public: + template<typename... Args> static RefPtr<GCObservation> create(Args&&... args) + { + return adoptRef(new GCObservation(std::forward<Args>(args)...)); + } + + bool wasCollected() const { return !m_observedValue; } + +private: + explicit GCObservation(JSC::JSObject*); + + mutable JSC::Weak<JSC::JSObject> m_observedValue; +}; + +} // namespace WebCore diff --git a/Source/WebCore/testing/GCObservation.idl b/Source/WebCore/testing/GCObservation.idl new file mode 100644 index 000000000..b6cb37802 --- /dev/null +++ b/Source/WebCore/testing/GCObservation.idl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * Copyright (C) 2016 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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. + */ + +[ + NoInterfaceObject, + ImplementationLacksVTable, + ExportMacro=WEBCORE_TESTSUPPORT_EXPORT, +] interface GCObservation { + readonly attribute boolean wasCollected; +}; diff --git a/Source/WebCore/testing/InternalSettings.cpp b/Source/WebCore/testing/InternalSettings.cpp index dc7da1e92..fadddbf56 100644 --- a/Source/WebCore/testing/InternalSettings.cpp +++ b/Source/WebCore/testing/InternalSettings.cpp @@ -45,129 +45,160 @@ #include "ColorChooser.h" #endif -#define InternalSettingsGuardForSettingsReturn(returnValue) \ - if (!settings()) { \ - ec = INVALID_ACCESS_ERR; \ - return returnValue; \ - } - -#define InternalSettingsGuardForSettings() \ - if (!settings()) { \ - ec = INVALID_ACCESS_ERR; \ - return; \ - } - -#define InternalSettingsGuardForPage() \ - if (!page()) { \ - ec = INVALID_ACCESS_ERR; \ - return; \ - } +#if USE(SOUP) +#include "SoupNetworkSession.h" +#endif namespace WebCore { InternalSettings::Backup::Backup(Settings& settings) - : m_originalCSSExclusionsEnabled(RuntimeEnabledFeatures::sharedFeatures().cssExclusionsEnabled()) - , m_originalCSSShapesEnabled(RuntimeEnabledFeatures::sharedFeatures().cssShapesEnabled()) -#if ENABLE(SHADOW_DOM) - , m_originalShadowDOMEnabled(RuntimeEnabledFeatures::sharedFeatures().shadowDOMEnabled()) - , m_originalAuthorShadowDOMForAnyElementEnabled(RuntimeEnabledFeatures::sharedFeatures().authorShadowDOMForAnyElementEnabled()) -#endif - , m_originalEditingBehavior(settings.editingBehaviorType()) + : m_originalEditingBehavior(settings.editingBehaviorType()) #if ENABLE(TEXT_AUTOSIZING) , m_originalTextAutosizingEnabled(settings.textAutosizingEnabled()) , m_originalTextAutosizingWindowSizeOverride(settings.textAutosizingWindowSizeOverride()) - , m_originalTextAutosizingFontScaleFactor(settings.textAutosizingFontScaleFactor()) #endif , m_originalMediaTypeOverride(settings.mediaTypeOverride()) , m_originalCanvasUsesAcceleratedDrawing(settings.canvasUsesAcceleratedDrawing()) , m_originalMockScrollbarsEnabled(settings.mockScrollbarsEnabled()) - , m_langAttributeAwareFormControlUIEnabled(RuntimeEnabledFeatures::sharedFeatures().langAttributeAwareFormControlUIEnabled()) , m_imagesEnabled(settings.areImagesEnabled()) - , m_minimumTimerInterval(settings.minDOMTimerInterval()) + , m_preferMIMETypeForImages(settings.preferMIMETypeForImages()) + , m_minimumTimerInterval(settings.minimumDOMTimerInterval()) #if ENABLE(VIDEO_TRACK) , m_shouldDisplaySubtitles(settings.shouldDisplaySubtitles()) , m_shouldDisplayCaptions(settings.shouldDisplayCaptions()) , m_shouldDisplayTextDescriptions(settings.shouldDisplayTextDescriptions()) #endif , m_defaultVideoPosterURL(settings.defaultVideoPosterURL()) + , m_forcePendingWebGLPolicy(settings.isForcePendingWebGLPolicy()) , m_originalTimeWithoutMouseMovementBeforeHidingControls(settings.timeWithoutMouseMovementBeforeHidingControls()) , m_useLegacyBackgroundSizeShorthandBehavior(settings.useLegacyBackgroundSizeShorthandBehavior()) , m_autoscrollForDragAndDropEnabled(settings.autoscrollForDragAndDropEnabled()) - , m_pluginReplacementEnabled(RuntimeEnabledFeatures::sharedFeatures().pluginReplacementEnabled()) + , m_quickTimePluginReplacementEnabled(settings.quickTimePluginReplacementEnabled()) + , m_youTubeFlashPluginReplacementEnabled(settings.youTubeFlashPluginReplacementEnabled()) + , m_shouldConvertPositionStyleOnCopy(settings.shouldConvertPositionStyleOnCopy()) + , m_fontFallbackPrefersPictographs(settings.fontFallbackPrefersPictographs()) + , m_webFontsAlwaysFallBack(settings.webFontsAlwaysFallBack()) + , m_backgroundShouldExtendBeyondPage(settings.backgroundShouldExtendBeyondPage()) + , m_storageBlockingPolicy(settings.storageBlockingPolicy()) + , m_scrollingTreeIncludesFrames(settings.scrollingTreeIncludesFrames()) +#if ENABLE(TOUCH_EVENTS) + , m_touchEventEmulationEnabled(settings.isTouchEventEmulationEnabled()) +#endif +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + , m_allowsAirPlayForMediaPlayback(settings.allowsAirPlayForMediaPlayback()) +#endif + , m_allowsInlineMediaPlayback(settings.allowsInlineMediaPlayback()) + , m_allowsInlineMediaPlaybackAfterFullscreen(settings.allowsInlineMediaPlaybackAfterFullscreen()) + , m_inlineMediaPlaybackRequiresPlaysInlineAttribute(settings.inlineMediaPlaybackRequiresPlaysInlineAttribute()) + , m_deferredCSSParserEnabled(settings.deferredCSSParserEnabled()) + , m_inputEventsEnabled(settings.inputEventsEnabled()) + , m_userInterfaceDirectionPolicy(settings.userInterfaceDirectionPolicy()) + , m_systemLayoutDirection(settings.systemLayoutDirection()) + , m_pdfImageCachingPolicy(settings.pdfImageCachingPolicy()) + , m_forcedColorsAreInvertedAccessibilityValue(settings.forcedColorsAreInvertedAccessibilityValue()) + , m_forcedDisplayIsMonochromeAccessibilityValue(settings.forcedDisplayIsMonochromeAccessibilityValue()) + , m_forcedPrefersReducedMotionAccessibilityValue(settings.forcedPrefersReducedMotionAccessibilityValue()) +#if ENABLE(INDEXED_DATABASE_IN_WORKERS) + , m_indexedDBWorkersEnabled(RuntimeEnabledFeatures::sharedFeatures().indexedDBWorkersEnabled()) +#endif + , m_cssGridLayoutEnabled(RuntimeEnabledFeatures::sharedFeatures().isCSSGridLayoutEnabled()) +#if ENABLE(WEBGL2) + , m_webGL2Enabled(RuntimeEnabledFeatures::sharedFeatures().webGL2Enabled()) +#endif { } void InternalSettings::Backup::restoreTo(Settings& settings) { - RuntimeEnabledFeatures::sharedFeatures().setCSSExclusionsEnabled(m_originalCSSExclusionsEnabled); - RuntimeEnabledFeatures::sharedFeatures().setCSSShapesEnabled(m_originalCSSShapesEnabled); -#if ENABLE(SHADOW_DOM) - RuntimeEnabledFeatures::sharedFeatures().setShadowDOMEnabled(m_originalShadowDOMEnabled); - RuntimeEnabledFeatures::sharedFeatures().setAuthorShadowDOMForAnyElementEnabled(m_originalAuthorShadowDOMForAnyElementEnabled); -#endif settings.setEditingBehaviorType(m_originalEditingBehavior); - for (auto iter = m_standardFontFamilies.begin(); iter != m_standardFontFamilies.end(); ++iter) - settings.setStandardFontFamily(iter->value, static_cast<UScriptCode>(iter->key)); + for (const auto& standardFont : m_standardFontFamilies) + settings.setStandardFontFamily(standardFont.value, static_cast<UScriptCode>(standardFont.key)); m_standardFontFamilies.clear(); - for (auto iter = m_fixedFontFamilies.begin(); iter != m_fixedFontFamilies.end(); ++iter) - settings.setFixedFontFamily(iter->value, static_cast<UScriptCode>(iter->key)); + for (const auto& fixedFont : m_fixedFontFamilies) + settings.setFixedFontFamily(fixedFont.value, static_cast<UScriptCode>(fixedFont.key)); m_fixedFontFamilies.clear(); - for (auto iter = m_serifFontFamilies.begin(); iter != m_serifFontFamilies.end(); ++iter) - settings.setSerifFontFamily(iter->value, static_cast<UScriptCode>(iter->key)); + for (const auto& serifFont : m_serifFontFamilies) + settings.setSerifFontFamily(serifFont.value, static_cast<UScriptCode>(serifFont.key)); m_serifFontFamilies.clear(); - for (auto iter = m_sansSerifFontFamilies.begin(); iter != m_sansSerifFontFamilies.end(); ++iter) - settings.setSansSerifFontFamily(iter->value, static_cast<UScriptCode>(iter->key)); + for (const auto& sansSerifFont : m_sansSerifFontFamilies) + settings.setSansSerifFontFamily(sansSerifFont.value, static_cast<UScriptCode>(sansSerifFont.key)); m_sansSerifFontFamilies.clear(); - for (auto iter = m_cursiveFontFamilies.begin(); iter != m_cursiveFontFamilies.end(); ++iter) - settings.setCursiveFontFamily(iter->value, static_cast<UScriptCode>(iter->key)); + for (const auto& cursiveFont : m_cursiveFontFamilies) + settings.setCursiveFontFamily(cursiveFont.value, static_cast<UScriptCode>(cursiveFont.key)); m_cursiveFontFamilies.clear(); - for (auto iter = m_fantasyFontFamilies.begin(); iter != m_fantasyFontFamilies.end(); ++iter) - settings.setFantasyFontFamily(iter->value, static_cast<UScriptCode>(iter->key)); + for (const auto& fantasyFont : m_fantasyFontFamilies) + settings.setFantasyFontFamily(fantasyFont.value, static_cast<UScriptCode>(fantasyFont.key)); m_fantasyFontFamilies.clear(); - for (auto iter = m_pictographFontFamilies.begin(); iter != m_pictographFontFamilies.end(); ++iter) - settings.setPictographFontFamily(iter->value, static_cast<UScriptCode>(iter->key)); + for (const auto& pictographFont : m_pictographFontFamilies) + settings.setPictographFontFamily(pictographFont.value, static_cast<UScriptCode>(pictographFont.key)); m_pictographFontFamilies.clear(); #if ENABLE(TEXT_AUTOSIZING) settings.setTextAutosizingEnabled(m_originalTextAutosizingEnabled); settings.setTextAutosizingWindowSizeOverride(m_originalTextAutosizingWindowSizeOverride); - settings.setTextAutosizingFontScaleFactor(m_originalTextAutosizingFontScaleFactor); #endif settings.setMediaTypeOverride(m_originalMediaTypeOverride); settings.setCanvasUsesAcceleratedDrawing(m_originalCanvasUsesAcceleratedDrawing); - settings.setMockScrollbarsEnabled(m_originalMockScrollbarsEnabled); - RuntimeEnabledFeatures::sharedFeatures().setLangAttributeAwareFormControlUIEnabled(m_langAttributeAwareFormControlUIEnabled); settings.setImagesEnabled(m_imagesEnabled); - settings.setMinDOMTimerInterval(m_minimumTimerInterval); + settings.setPreferMIMETypeForImages(m_preferMIMETypeForImages); + settings.setMinimumDOMTimerInterval(m_minimumTimerInterval); #if ENABLE(VIDEO_TRACK) settings.setShouldDisplaySubtitles(m_shouldDisplaySubtitles); settings.setShouldDisplayCaptions(m_shouldDisplayCaptions); settings.setShouldDisplayTextDescriptions(m_shouldDisplayTextDescriptions); #endif settings.setDefaultVideoPosterURL(m_defaultVideoPosterURL); + settings.setForcePendingWebGLPolicy(m_forcePendingWebGLPolicy); settings.setTimeWithoutMouseMovementBeforeHidingControls(m_originalTimeWithoutMouseMovementBeforeHidingControls); settings.setUseLegacyBackgroundSizeShorthandBehavior(m_useLegacyBackgroundSizeShorthandBehavior); settings.setAutoscrollForDragAndDropEnabled(m_autoscrollForDragAndDropEnabled); - RuntimeEnabledFeatures::sharedFeatures().setPluginReplacementEnabled(m_pluginReplacementEnabled); + settings.setShouldConvertPositionStyleOnCopy(m_shouldConvertPositionStyleOnCopy); + settings.setFontFallbackPrefersPictographs(m_fontFallbackPrefersPictographs); + settings.setWebFontsAlwaysFallBack(m_webFontsAlwaysFallBack); + settings.setBackgroundShouldExtendBeyondPage(m_backgroundShouldExtendBeyondPage); + settings.setStorageBlockingPolicy(m_storageBlockingPolicy); + settings.setScrollingTreeIncludesFrames(m_scrollingTreeIncludesFrames); +#if ENABLE(TOUCH_EVENTS) + settings.setTouchEventEmulationEnabled(m_touchEventEmulationEnabled); +#endif + settings.setAllowsInlineMediaPlayback(m_allowsInlineMediaPlayback); + settings.setAllowsInlineMediaPlaybackAfterFullscreen(m_allowsInlineMediaPlaybackAfterFullscreen); + settings.setInlineMediaPlaybackRequiresPlaysInlineAttribute(m_inlineMediaPlaybackRequiresPlaysInlineAttribute); + settings.setQuickTimePluginReplacementEnabled(m_quickTimePluginReplacementEnabled); + settings.setYouTubeFlashPluginReplacementEnabled(m_youTubeFlashPluginReplacementEnabled); + settings.setDeferredCSSParserEnabled(m_deferredCSSParserEnabled); + settings.setInputEventsEnabled(m_inputEventsEnabled); + settings.setUserInterfaceDirectionPolicy(m_userInterfaceDirectionPolicy); + settings.setSystemLayoutDirection(m_systemLayoutDirection); + settings.setPdfImageCachingPolicy(m_pdfImageCachingPolicy); + settings.setForcedColorsAreInvertedAccessibilityValue(m_forcedColorsAreInvertedAccessibilityValue); + settings.setForcedDisplayIsMonochromeAccessibilityValue(m_forcedDisplayIsMonochromeAccessibilityValue); + settings.setForcedPrefersReducedMotionAccessibilityValue(m_forcedPrefersReducedMotionAccessibilityValue); + Settings::setAllowsAnySSLCertificate(false); + +#if ENABLE(INDEXED_DATABASE_IN_WORKERS) + RuntimeEnabledFeatures::sharedFeatures().setIndexedDBWorkersEnabled(m_indexedDBWorkersEnabled); +#endif + RuntimeEnabledFeatures::sharedFeatures().setCSSGridLayoutEnabled(m_cssGridLayoutEnabled); +#if ENABLE(WEBGL2) + RuntimeEnabledFeatures::sharedFeatures().setWebGL2Enabled(m_webGL2Enabled); +#endif } -// We can't use RefCountedSupplement because that would try to make InternalSettings RefCounted -// and InternalSettings is already RefCounted via its base class, InternalSettingsGenerated. -// Instead, we manually make InternalSettings supplement Page. class InternalSettingsWrapper : public Supplement<Page> { public: explicit InternalSettingsWrapper(Page* page) : m_internalSettings(InternalSettings::create(page)) { } virtual ~InternalSettingsWrapper() { m_internalSettings->hostDestroyed(); } #if !ASSERT_DISABLED - virtual bool isRefCountedWrapper() const override { return true; } + bool isRefCountedWrapper() const override { return true; } #endif InternalSettings* internalSettings() const { return m_internalSettings.get(); } @@ -183,12 +214,13 @@ const char* InternalSettings::supplementName() InternalSettings* InternalSettings::from(Page* page) { if (!Supplement<Page>::from(page, supplementName())) - Supplement<Page>::provideTo(page, supplementName(), adoptPtr(new InternalSettingsWrapper(page))); + Supplement<Page>::provideTo(page, supplementName(), std::make_unique<InternalSettingsWrapper>(page)); return static_cast<InternalSettingsWrapper*>(Supplement<Page>::from(page, supplementName()))->internalSettings(); } -InternalSettings::~InternalSettings() +void InternalSettings::hostDestroyed() { + m_page = nullptr; } InternalSettings::InternalSettings(Page* page) @@ -196,335 +228,613 @@ InternalSettings::InternalSettings(Page* page) , m_page(page) , m_backup(page->settings()) { +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + setAllowsAirPlayForMediaPlayback(false); +#endif +#if ENABLE(MEDIA_STREAM) + setMediaCaptureRequiresSecureConnection(false); +#endif } -void InternalSettings::resetToConsistentState() -{ - page()->setPageScaleFactor(1, IntPoint(0, 0)); - page()->setCanStartMedia(true); - - m_backup.restoreTo(*settings()); - m_backup = Backup(*settings()); - - InternalSettingsGenerated::resetToConsistentState(); -} - -Settings* InternalSettings::settings() const +Ref<InternalSettings> InternalSettings::create(Page* page) { - if (!page()) - return 0; - return &page()->settings(); + return adoptRef(*new InternalSettings(page)); } -void InternalSettings::setMockScrollbarsEnabled(bool enabled, ExceptionCode& ec) +void InternalSettings::resetToConsistentState() { - InternalSettingsGuardForSettings(); - settings()->setMockScrollbarsEnabled(enabled); -} + m_page->setPageScaleFactor(1, { 0, 0 }); + m_page->mainFrame().setPageAndTextZoomFactors(1, 1); + m_page->setCanStartMedia(true); -static bool urlIsWhitelistedForSetShadowDOMEnabled(const String& url) -{ - // This check is just for preventing fuzzers from crashing because of unintended API calls. - // You can list your test if needed. - return notFound != url.find("fast/dom/shadow/content-shadow-unknown.html") - || notFound != url.find("fast/dom/shadow/insertion-points-with-shadow-disabled.html"); -} + settings().setForcePendingWebGLPolicy(false); +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + settings().setAllowsAirPlayForMediaPlayback(false); +#endif +#if ENABLE(MEDIA_STREAM) + setMediaCaptureRequiresSecureConnection(false); +#endif -void InternalSettings::setShadowDOMEnabled(bool enabled, ExceptionCode& ec) -{ - if (!urlIsWhitelistedForSetShadowDOMEnabled(page()->mainFrame().document()->url().string())) { - ec = INVALID_ACCESS_ERR; - return; - } + m_backup.restoreTo(settings()); + m_backup = Backup { settings() }; -#if ENABLE(SHADOW_DOM) - RuntimeEnabledFeatures::sharedFeatures().setShadowDOMEnabled(enabled); -#else - // Even SHADOW_DOM is off, InternalSettings allows setShadowDOMEnabled(false) to - // have broader test coverage. But it cannot be setShadowDOMEnabled(true). - if (enabled) - ec = INVALID_ACCESS_ERR; -#endif + InternalSettingsGenerated::resetToConsistentState(); } -void InternalSettings::setAuthorShadowDOMForAnyElementEnabled(bool isEnabled) +Settings& InternalSettings::settings() const { -#if ENABLE(SHADOW_DOM) - RuntimeEnabledFeatures::sharedFeatures().setAuthorShadowDOMForAnyElementEnabled(isEnabled); -#else - UNUSED_PARAM(isEnabled); -#endif + ASSERT(m_page); + return m_page->settings(); } -void InternalSettings::setTouchEventEmulationEnabled(bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setTouchEventEmulationEnabled(bool enabled) { + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; #if ENABLE(TOUCH_EVENTS) - InternalSettingsGuardForSettings(); - settings()->setTouchEventEmulationEnabled(enabled); + settings().setTouchEventEmulationEnabled(enabled); #else UNUSED_PARAM(enabled); - UNUSED_PARAM(ec); #endif + return { }; } -void InternalSettings::setStandardFontFamily(const String& family, const String& script, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setStandardFontFamily(const String& family, const String& script) { - InternalSettingsGuardForSettings(); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; UScriptCode code = scriptNameToCode(script); if (code == USCRIPT_INVALID_CODE) - return; - m_backup.m_standardFontFamilies.add(code, settings()->standardFontFamily(code)); - settings()->setStandardFontFamily(family, code); + return { }; + m_backup.m_standardFontFamilies.add(code, settings().standardFontFamily(code)); + settings().setStandardFontFamily(family, code); + return { }; } -void InternalSettings::setSerifFontFamily(const String& family, const String& script, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setSerifFontFamily(const String& family, const String& script) { - InternalSettingsGuardForSettings(); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; UScriptCode code = scriptNameToCode(script); if (code == USCRIPT_INVALID_CODE) - return; - m_backup.m_serifFontFamilies.add(code, settings()->serifFontFamily(code)); - settings()->setSerifFontFamily(family, code); + return { }; + m_backup.m_serifFontFamilies.add(code, settings().serifFontFamily(code)); + settings().setSerifFontFamily(family, code); + return { }; } -void InternalSettings::setSansSerifFontFamily(const String& family, const String& script, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setSansSerifFontFamily(const String& family, const String& script) { - InternalSettingsGuardForSettings(); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; UScriptCode code = scriptNameToCode(script); if (code == USCRIPT_INVALID_CODE) - return; - m_backup.m_sansSerifFontFamilies.add(code, settings()->sansSerifFontFamily(code)); - settings()->setSansSerifFontFamily(family, code); + return { }; + m_backup.m_sansSerifFontFamilies.add(code, settings().sansSerifFontFamily(code)); + settings().setSansSerifFontFamily(family, code); + return { }; } -void InternalSettings::setFixedFontFamily(const String& family, const String& script, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setFixedFontFamily(const String& family, const String& script) { - InternalSettingsGuardForSettings(); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; UScriptCode code = scriptNameToCode(script); if (code == USCRIPT_INVALID_CODE) - return; - m_backup.m_fixedFontFamilies.add(code, settings()->fixedFontFamily(code)); - settings()->setFixedFontFamily(family, code); + return { }; + m_backup.m_fixedFontFamilies.add(code, settings().fixedFontFamily(code)); + settings().setFixedFontFamily(family, code); + return { }; } -void InternalSettings::setCursiveFontFamily(const String& family, const String& script, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setCursiveFontFamily(const String& family, const String& script) { - InternalSettingsGuardForSettings(); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; UScriptCode code = scriptNameToCode(script); if (code == USCRIPT_INVALID_CODE) - return; - m_backup.m_cursiveFontFamilies.add(code, settings()->cursiveFontFamily(code)); - settings()->setCursiveFontFamily(family, code); + return { }; + m_backup.m_cursiveFontFamilies.add(code, settings().cursiveFontFamily(code)); + settings().setCursiveFontFamily(family, code); + return { }; } -void InternalSettings::setFantasyFontFamily(const String& family, const String& script, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setFantasyFontFamily(const String& family, const String& script) { - InternalSettingsGuardForSettings(); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; UScriptCode code = scriptNameToCode(script); if (code == USCRIPT_INVALID_CODE) - return; - m_backup.m_fantasyFontFamilies.add(code, settings()->fantasyFontFamily(code)); - settings()->setFantasyFontFamily(family, code); + return { }; + m_backup.m_fantasyFontFamilies.add(code, settings().fantasyFontFamily(code)); + settings().setFantasyFontFamily(family, code); + return { }; } -void InternalSettings::setPictographFontFamily(const String& family, const String& script, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setPictographFontFamily(const String& family, const String& script) { - InternalSettingsGuardForSettings(); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; UScriptCode code = scriptNameToCode(script); if (code == USCRIPT_INVALID_CODE) - return; - m_backup.m_pictographFontFamilies.add(code, settings()->pictographFontFamily(code)); - settings()->setPictographFontFamily(family, code); + return { }; + m_backup.m_pictographFontFamilies.add(code, settings().pictographFontFamily(code)); + settings().setPictographFontFamily(family, code); + return { }; } -void InternalSettings::setTextAutosizingEnabled(bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setTextAutosizingEnabled(bool enabled) { + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; #if ENABLE(TEXT_AUTOSIZING) - InternalSettingsGuardForSettings(); - settings()->setTextAutosizingEnabled(enabled); + settings().setTextAutosizingEnabled(enabled); #else UNUSED_PARAM(enabled); - UNUSED_PARAM(ec); #endif + return { }; } -void InternalSettings::setTextAutosizingWindowSizeOverride(int width, int height, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setTextAutosizingWindowSizeOverride(int width, int height) { + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; #if ENABLE(TEXT_AUTOSIZING) - InternalSettingsGuardForSettings(); - settings()->setTextAutosizingWindowSizeOverride(IntSize(width, height)); + settings().setTextAutosizingWindowSizeOverride(IntSize(width, height)); #else UNUSED_PARAM(width); UNUSED_PARAM(height); - UNUSED_PARAM(ec); #endif + return { }; } -void InternalSettings::setMediaTypeOverride(const String& mediaType, ExceptionCode& ec) -{ - InternalSettingsGuardForSettings(); - settings()->setMediaTypeOverride(mediaType); -} - -void InternalSettings::setTextAutosizingFontScaleFactor(float fontScaleFactor, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setMediaTypeOverride(const String& mediaType) { -#if ENABLE(TEXT_AUTOSIZING) - InternalSettingsGuardForSettings(); - settings()->setTextAutosizingFontScaleFactor(fontScaleFactor); -#else - UNUSED_PARAM(fontScaleFactor); - UNUSED_PARAM(ec); -#endif + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setMediaTypeOverride(mediaType); + return { }; } -void InternalSettings::setCSSExclusionsEnabled(bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setCanStartMedia(bool enabled) { - UNUSED_PARAM(ec); - RuntimeEnabledFeatures::sharedFeatures().setCSSExclusionsEnabled(enabled); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + m_page->setCanStartMedia(enabled); + return { }; } -void InternalSettings::setCSSShapesEnabled(bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setAllowsAirPlayForMediaPlayback(bool allows) { - UNUSED_PARAM(ec); - RuntimeEnabledFeatures::sharedFeatures().setCSSShapesEnabled(enabled); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + settings().setAllowsAirPlayForMediaPlayback(allows); +#else + UNUSED_PARAM(allows); +#endif + return { }; } -void InternalSettings::setCanStartMedia(bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setMediaCaptureRequiresSecureConnection(bool requires) { - InternalSettingsGuardForSettings(); - m_page->setCanStartMedia(enabled); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; +#if ENABLE(MEDIA_STREAM) + settings().setMediaCaptureRequiresSecureConnection(requires); +#else + UNUSED_PARAM(requires); +#endif + return { }; } -void InternalSettings::setEditingBehavior(const String& editingBehavior, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setEditingBehavior(const String& editingBehavior) { - InternalSettingsGuardForSettings(); - if (equalIgnoringCase(editingBehavior, "win")) - settings()->setEditingBehaviorType(EditingWindowsBehavior); - else if (equalIgnoringCase(editingBehavior, "mac")) - settings()->setEditingBehaviorType(EditingMacBehavior); - else if (equalIgnoringCase(editingBehavior, "unix")) - settings()->setEditingBehaviorType(EditingUnixBehavior); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + if (equalLettersIgnoringASCIICase(editingBehavior, "win")) + settings().setEditingBehaviorType(EditingWindowsBehavior); + else if (equalLettersIgnoringASCIICase(editingBehavior, "mac")) + settings().setEditingBehaviorType(EditingMacBehavior); + else if (equalLettersIgnoringASCIICase(editingBehavior, "unix")) + settings().setEditingBehaviorType(EditingUnixBehavior); + else if (equalLettersIgnoringASCIICase(editingBehavior, "ios")) + settings().setEditingBehaviorType(EditingIOSBehavior); else - ec = SYNTAX_ERR; + return Exception { SYNTAX_ERR }; + return { }; } -void InternalSettings::setShouldDisplayTrackKind(const String& kind, bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setShouldDisplayTrackKind(const String& kind, bool enabled) { - InternalSettingsGuardForSettings(); - + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; #if ENABLE(VIDEO_TRACK) - if (!page()) - return; - CaptionUserPreferences* captionPreferences = page()->group().captionPreferences(); - - if (equalIgnoringCase(kind, "Subtitles")) - captionPreferences->setUserPrefersSubtitles(enabled); - else if (equalIgnoringCase(kind, "Captions")) - captionPreferences->setUserPrefersCaptions(enabled); - else if (equalIgnoringCase(kind, "TextDescriptions")) - captionPreferences->setUserPrefersTextDescriptions(enabled); + auto& captionPreferences = m_page->group().captionPreferences(); + if (equalLettersIgnoringASCIICase(kind, "subtitles")) + captionPreferences.setUserPrefersSubtitles(enabled); + else if (equalLettersIgnoringASCIICase(kind, "captions")) + captionPreferences.setUserPrefersCaptions(enabled); + else if (equalLettersIgnoringASCIICase(kind, "textdescriptions")) + captionPreferences.setUserPrefersTextDescriptions(enabled); else - ec = SYNTAX_ERR; + return Exception { SYNTAX_ERR }; #else UNUSED_PARAM(kind); UNUSED_PARAM(enabled); #endif + return { }; } -bool InternalSettings::shouldDisplayTrackKind(const String& kind, ExceptionCode& ec) +ExceptionOr<bool> InternalSettings::shouldDisplayTrackKind(const String& kind) { - InternalSettingsGuardForSettingsReturn(false); - + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; #if ENABLE(VIDEO_TRACK) - if (!page()) - return false; - CaptionUserPreferences* captionPreferences = page()->group().captionPreferences(); - - if (equalIgnoringCase(kind, "Subtitles")) - return captionPreferences->userPrefersSubtitles(); - if (equalIgnoringCase(kind, "Captions")) - return captionPreferences->userPrefersCaptions(); - if (equalIgnoringCase(kind, "TextDescriptions")) - return captionPreferences->userPrefersTextDescriptions(); - - ec = SYNTAX_ERR; - return false; + auto& captionPreferences = m_page->group().captionPreferences(); + if (equalLettersIgnoringASCIICase(kind, "subtitles")) + return captionPreferences.userPrefersSubtitles(); + if (equalLettersIgnoringASCIICase(kind, "captions")) + return captionPreferences.userPrefersCaptions(); + if (equalLettersIgnoringASCIICase(kind, "textdescriptions")) + return captionPreferences.userPrefersTextDescriptions(); + + return Exception { SYNTAX_ERR }; #else UNUSED_PARAM(kind); return false; #endif } -void InternalSettings::setStorageBlockingPolicy(const String& mode, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setStorageBlockingPolicy(const String& mode) { - InternalSettingsGuardForSettings(); - + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; if (mode == "AllowAll") - settings()->setStorageBlockingPolicy(SecurityOrigin::AllowAllStorage); + settings().setStorageBlockingPolicy(SecurityOrigin::AllowAllStorage); else if (mode == "BlockThirdParty") - settings()->setStorageBlockingPolicy(SecurityOrigin::BlockThirdPartyStorage); + settings().setStorageBlockingPolicy(SecurityOrigin::BlockThirdPartyStorage); else if (mode == "BlockAll") - settings()->setStorageBlockingPolicy(SecurityOrigin::BlockAllStorage); + settings().setStorageBlockingPolicy(SecurityOrigin::BlockAllStorage); + else + return Exception { SYNTAX_ERR }; + return { }; +} + +ExceptionOr<void> InternalSettings::setPreferMIMETypeForImages(bool preferMIMETypeForImages) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setPreferMIMETypeForImages(preferMIMETypeForImages); + return { }; +} + +ExceptionOr<void> InternalSettings::setImagesEnabled(bool enabled) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setImagesEnabled(enabled); + return { }; +} + +ExceptionOr<void> InternalSettings::setPDFImageCachingPolicy(const String& policy) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + if (equalLettersIgnoringASCIICase(policy, "disabled")) + settings().setPdfImageCachingPolicy(PDFImageCachingDisabled); + else if (equalLettersIgnoringASCIICase(policy, "belowmemorylimit")) + settings().setPdfImageCachingPolicy(PDFImageCachingBelowMemoryLimit); + else if (equalLettersIgnoringASCIICase(policy, "clipboundsonly")) + settings().setPdfImageCachingPolicy(PDFImageCachingClipBoundsOnly); + else if (equalLettersIgnoringASCIICase(policy, "enabled")) + settings().setPdfImageCachingPolicy(PDFImageCachingEnabled); else - ec = SYNTAX_ERR; + return Exception { SYNTAX_ERR }; + return { }; +} + +ExceptionOr<void> InternalSettings::setMinimumTimerInterval(double intervalInSeconds) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setMinimumDOMTimerInterval(std::chrono::milliseconds((std::chrono::milliseconds::rep)(intervalInSeconds * 1000))); + return { }; +} + +ExceptionOr<void> InternalSettings::setDefaultVideoPosterURL(const String& url) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setDefaultVideoPosterURL(url); + return { }; +} + +ExceptionOr<void> InternalSettings::setForcePendingWebGLPolicy(bool forced) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setForcePendingWebGLPolicy(forced); + return { }; +} + +ExceptionOr<void> InternalSettings::setTimeWithoutMouseMovementBeforeHidingControls(double time) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setTimeWithoutMouseMovementBeforeHidingControls(time); + return { }; } -void InternalSettings::setLangAttributeAwareFormControlUIEnabled(bool enabled) +ExceptionOr<void> InternalSettings::setUseLegacyBackgroundSizeShorthandBehavior(bool enabled) { - RuntimeEnabledFeatures::sharedFeatures().setLangAttributeAwareFormControlUIEnabled(enabled); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setUseLegacyBackgroundSizeShorthandBehavior(enabled); + return { }; } -void InternalSettings::setImagesEnabled(bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setAutoscrollForDragAndDropEnabled(bool enabled) { - InternalSettingsGuardForSettings(); - settings()->setImagesEnabled(enabled); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setAutoscrollForDragAndDropEnabled(enabled); + return { }; } -void InternalSettings::setMinimumTimerInterval(double intervalInSeconds, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setFontFallbackPrefersPictographs(bool preferPictographs) { - InternalSettingsGuardForSettings(); - settings()->setMinDOMTimerInterval(intervalInSeconds); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setFontFallbackPrefersPictographs(preferPictographs); + return { }; } -void InternalSettings::setDefaultVideoPosterURL(const String& url, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setWebFontsAlwaysFallBack(bool enable) { - InternalSettingsGuardForSettings(); - settings()->setDefaultVideoPosterURL(url); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setWebFontsAlwaysFallBack(enable); + return { }; } -void InternalSettings::setTimeWithoutMouseMovementBeforeHidingControls(double time, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setQuickTimePluginReplacementEnabled(bool enabled) { - InternalSettingsGuardForSettings(); - settings()->setTimeWithoutMouseMovementBeforeHidingControls(time); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setQuickTimePluginReplacementEnabled(enabled); + return { }; } -void InternalSettings::setUseLegacyBackgroundSizeShorthandBehavior(bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setYouTubeFlashPluginReplacementEnabled(bool enabled) { - InternalSettingsGuardForSettings(); - settings()->setUseLegacyBackgroundSizeShorthandBehavior(enabled); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setYouTubeFlashPluginReplacementEnabled(enabled); + return { }; } -void InternalSettings::setAutoscrollForDragAndDropEnabled(bool enabled, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setBackgroundShouldExtendBeyondPage(bool hasExtendedBackground) { - InternalSettingsGuardForSettings(); - settings()->setAutoscrollForDragAndDropEnabled(enabled); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setBackgroundShouldExtendBeyondPage(hasExtendedBackground); + return { }; } -void InternalSettings::setFontFallbackPrefersPictographs(bool preferPictographs, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setShouldConvertPositionStyleOnCopy(bool convert) { - InternalSettingsGuardForSettings(); - settings()->setFontFallbackPrefersPictographs(preferPictographs); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setShouldConvertPositionStyleOnCopy(convert); + return { }; } -void InternalSettings::setPluginReplacementEnabled(bool enabled) +ExceptionOr<void> InternalSettings::setScrollingTreeIncludesFrames(bool enabled) { - RuntimeEnabledFeatures::sharedFeatures().setPluginReplacementEnabled(enabled); + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setScrollingTreeIncludesFrames(enabled); + return { }; } -void InternalSettings::setBackgroundShouldExtendBeyondPage(bool hasExtendedBackground, ExceptionCode& ec) +ExceptionOr<void> InternalSettings::setAllowUnclampedScrollPosition(bool allowUnclamped) { - InternalSettingsGuardForSettings(); - settings()->setBackgroundShouldExtendBeyondPage(hasExtendedBackground); + if (!m_page || !m_page->mainFrame().view()) + return Exception { INVALID_ACCESS_ERR }; + + m_page->mainFrame().view()->setAllowsUnclampedScrollPositionForTesting(allowUnclamped); + return { }; } +ExceptionOr<void> InternalSettings::setAllowsInlineMediaPlayback(bool allows) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setAllowsInlineMediaPlayback(allows); + return { }; +} + +ExceptionOr<void> InternalSettings::setAllowsInlineMediaPlaybackAfterFullscreen(bool allows) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setAllowsInlineMediaPlaybackAfterFullscreen(allows); + return { }; +} + +ExceptionOr<void> InternalSettings::setInlineMediaPlaybackRequiresPlaysInlineAttribute(bool requires) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setInlineMediaPlaybackRequiresPlaysInlineAttribute(requires); + return { }; +} + +void InternalSettings::setIndexedDBWorkersEnabled(bool enabled) +{ +#if ENABLE(INDEXED_DATABASE_IN_WORKERS) + RuntimeEnabledFeatures::sharedFeatures().setIndexedDBWorkersEnabled(enabled); +#else + UNUSED_PARAM(enabled); +#endif +} + +void InternalSettings::setCSSGridLayoutEnabled(bool enabled) +{ + RuntimeEnabledFeatures::sharedFeatures().setCSSGridLayoutEnabled(enabled); +} + +void InternalSettings::setWebGL2Enabled(bool enabled) +{ +#if ENABLE(WEBGL2) + RuntimeEnabledFeatures::sharedFeatures().setWebGL2Enabled(enabled); +#else + UNUSED_PARAM(enabled); +#endif +} + +ExceptionOr<String> InternalSettings::userInterfaceDirectionPolicy() +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + switch (settings().userInterfaceDirectionPolicy()) { + case UserInterfaceDirectionPolicy::Content: + return String { ASCIILiteral { "Content" } }; + case UserInterfaceDirectionPolicy::System: + return String { ASCIILiteral { "View" } }; + } + ASSERT_NOT_REACHED(); + return Exception { INVALID_ACCESS_ERR }; +} + +ExceptionOr<void> InternalSettings::setUserInterfaceDirectionPolicy(const String& policy) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + if (equalLettersIgnoringASCIICase(policy, "content")) { + settings().setUserInterfaceDirectionPolicy(UserInterfaceDirectionPolicy::Content); + return { }; + } + if (equalLettersIgnoringASCIICase(policy, "view")) { + settings().setUserInterfaceDirectionPolicy(UserInterfaceDirectionPolicy::System); + return { }; + } + return Exception { INVALID_ACCESS_ERR }; +} + +ExceptionOr<String> InternalSettings::systemLayoutDirection() +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + switch (settings().systemLayoutDirection()) { + case LTR: + return String { ASCIILiteral { "LTR" } }; + case RTL: + return String { ASCIILiteral { "RTL" } }; + } + ASSERT_NOT_REACHED(); + return Exception { INVALID_ACCESS_ERR }; +} + +ExceptionOr<void> InternalSettings::setSystemLayoutDirection(const String& direction) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + if (equalLettersIgnoringASCIICase(direction, "ltr")) { + settings().setSystemLayoutDirection(LTR); + return { }; + } + if (equalLettersIgnoringASCIICase(direction, "rtl")) { + settings().setSystemLayoutDirection(RTL); + return { }; + } + return Exception { INVALID_ACCESS_ERR }; +} + +void InternalSettings::setAllowsAnySSLCertificate(bool allowsAnyCertificate) +{ + Settings::setAllowsAnySSLCertificate(allowsAnyCertificate); +#if USE(SOUP) + SoupNetworkSession::setShouldIgnoreTLSErrors(allowsAnyCertificate); +#endif +} + +ExceptionOr<bool> InternalSettings::deferredCSSParserEnabled() +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + return settings().deferredCSSParserEnabled(); +} + +ExceptionOr<void> InternalSettings::setDeferredCSSParserEnabled(bool enabled) +{ + if (!m_page) + return Exception { INVALID_ACCESS_ERR }; + settings().setDeferredCSSParserEnabled(enabled); + return { }; +} + +static InternalSettings::ForcedAccessibilityValue settingsToInternalSettingsValue(Settings::ForcedAccessibilityValue value) +{ + switch (value) { + case Settings::ForcedAccessibilityValue::System: + return InternalSettings::ForcedAccessibilityValue::System; + case Settings::ForcedAccessibilityValue::On: + return InternalSettings::ForcedAccessibilityValue::On; + case Settings::ForcedAccessibilityValue::Off: + return InternalSettings::ForcedAccessibilityValue::Off; + } + + ASSERT_NOT_REACHED(); + return InternalSettings::ForcedAccessibilityValue::Off; +} + +static Settings::ForcedAccessibilityValue internalSettingsToSettingsValue(InternalSettings::ForcedAccessibilityValue value) +{ + switch (value) { + case InternalSettings::ForcedAccessibilityValue::System: + return Settings::ForcedAccessibilityValue::System; + case InternalSettings::ForcedAccessibilityValue::On: + return Settings::ForcedAccessibilityValue::On; + case InternalSettings::ForcedAccessibilityValue::Off: + return Settings::ForcedAccessibilityValue::Off; + } + + ASSERT_NOT_REACHED(); + return Settings::ForcedAccessibilityValue::Off; +} + +InternalSettings::ForcedAccessibilityValue InternalSettings::forcedColorsAreInvertedAccessibilityValue() const +{ + return settingsToInternalSettingsValue(settings().forcedColorsAreInvertedAccessibilityValue()); +} + +void InternalSettings::setForcedColorsAreInvertedAccessibilityValue(InternalSettings::ForcedAccessibilityValue value) +{ + settings().setForcedColorsAreInvertedAccessibilityValue(internalSettingsToSettingsValue(value)); +} + +InternalSettings::ForcedAccessibilityValue InternalSettings::forcedDisplayIsMonochromeAccessibilityValue() const +{ + return settingsToInternalSettingsValue(settings().forcedDisplayIsMonochromeAccessibilityValue()); +} + +void InternalSettings::setForcedDisplayIsMonochromeAccessibilityValue(InternalSettings::ForcedAccessibilityValue value) +{ + settings().setForcedDisplayIsMonochromeAccessibilityValue(internalSettingsToSettingsValue(value)); +} + +InternalSettings::ForcedAccessibilityValue InternalSettings::forcedPrefersReducedMotionAccessibilityValue() const +{ + return settingsToInternalSettingsValue(settings().forcedPrefersReducedMotionAccessibilityValue()); +} + +void InternalSettings::setForcedPrefersReducedMotionAccessibilityValue(InternalSettings::ForcedAccessibilityValue value) +{ + settings().setForcedPrefersReducedMotionAccessibilityValue(internalSettingsToSettingsValue(value)); +} + +// If you add to this class, make sure that you update the Backup class for test reproducability! + } diff --git a/Source/WebCore/testing/InternalSettings.h b/Source/WebCore/testing/InternalSettings.h index 768d5752b..8df919fa0 100644 --- a/Source/WebCore/testing/InternalSettings.h +++ b/Source/WebCore/testing/InternalSettings.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,40 +24,107 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef InternalSettings_h -#define InternalSettings_h +#pragma once // FIXME (121927): This include should not be needed. #include <wtf/text/AtomicStringHash.h> #include "EditingBehaviorTypes.h" +#include "ExceptionOr.h" #include "FontGenericFamilies.h" #include "IntSize.h" #include "InternalSettingsGenerated.h" -#include <wtf/PassRefPtr.h> +#include "SecurityOrigin.h" +#include "Settings.h" +#include "WritingMode.h" namespace WebCore { -typedef int ExceptionCode; - -class Frame; -class Document; class Page; class Settings; class InternalSettings : public InternalSettingsGenerated { public: + static Ref<InternalSettings> create(Page*); + static InternalSettings* from(Page*); + void hostDestroyed(); + void resetToConsistentState(); + + ExceptionOr<void> setUsesOverlayScrollbars(bool); + ExceptionOr<void> setTouchEventEmulationEnabled(bool); + ExceptionOr<void> setStandardFontFamily(const String& family, const String& script); + ExceptionOr<void> setSerifFontFamily(const String& family, const String& script); + ExceptionOr<void> setSansSerifFontFamily(const String& family, const String& script); + ExceptionOr<void> setFixedFontFamily(const String& family, const String& script); + ExceptionOr<void> setCursiveFontFamily(const String& family, const String& script); + ExceptionOr<void> setFantasyFontFamily(const String& family, const String& script); + ExceptionOr<void> setPictographFontFamily(const String& family, const String& script); + ExceptionOr<void> setTextAutosizingEnabled(bool); + ExceptionOr<void> setTextAutosizingWindowSizeOverride(int width, int height); + ExceptionOr<void> setTextAutosizingFontScaleFactor(float); + ExceptionOr<void> setMediaTypeOverride(const String&); + ExceptionOr<void> setCanStartMedia(bool); + ExceptionOr<void> setAllowsAirPlayForMediaPlayback(bool); + ExceptionOr<void> setMediaCaptureRequiresSecureConnection(bool); + + ExceptionOr<void> setEditingBehavior(const String&); + ExceptionOr<void> setPreferMIMETypeForImages(bool); + ExceptionOr<void> setPDFImageCachingPolicy(const String&); + ExceptionOr<void> setShouldDisplayTrackKind(const String& kind, bool enabled); + ExceptionOr<bool> shouldDisplayTrackKind(const String& kind); + ExceptionOr<void> setStorageBlockingPolicy(const String&); + ExceptionOr<void> setImagesEnabled(bool); + ExceptionOr<void> setMinimumTimerInterval(double intervalInSeconds); + ExceptionOr<void> setDefaultVideoPosterURL(const String&); + ExceptionOr<void> setForcePendingWebGLPolicy(bool); + ExceptionOr<void> setTimeWithoutMouseMovementBeforeHidingControls(double); + ExceptionOr<void> setUseLegacyBackgroundSizeShorthandBehavior(bool); + ExceptionOr<void> setAutoscrollForDragAndDropEnabled(bool); + ExceptionOr<void> setFontFallbackPrefersPictographs(bool); + ExceptionOr<void> setWebFontsAlwaysFallBack(bool); + ExceptionOr<void> setQuickTimePluginReplacementEnabled(bool); + ExceptionOr<void> setYouTubeFlashPluginReplacementEnabled(bool); + ExceptionOr<void> setBackgroundShouldExtendBeyondPage(bool); + ExceptionOr<void> setShouldConvertPositionStyleOnCopy(bool); + ExceptionOr<void> setScrollingTreeIncludesFrames(bool); + ExceptionOr<void> setAllowUnclampedScrollPosition(bool); + ExceptionOr<void> setAllowsInlineMediaPlayback(bool); + ExceptionOr<void> setAllowsInlineMediaPlaybackAfterFullscreen(bool); + ExceptionOr<void> setInlineMediaPlaybackRequiresPlaysInlineAttribute(bool); + ExceptionOr<String> userInterfaceDirectionPolicy(); + ExceptionOr<void> setUserInterfaceDirectionPolicy(const String&); + ExceptionOr<String> systemLayoutDirection(); + ExceptionOr<void> setSystemLayoutDirection(const String&); + + static void setAllowsAnySSLCertificate(bool); + + ExceptionOr<bool> deferredCSSParserEnabled(); + ExceptionOr<void> setDeferredCSSParserEnabled(bool); + + enum class ForcedAccessibilityValue { System, On, Off }; + ForcedAccessibilityValue forcedColorsAreInvertedAccessibilityValue() const; + void setForcedColorsAreInvertedAccessibilityValue(ForcedAccessibilityValue); + ForcedAccessibilityValue forcedDisplayIsMonochromeAccessibilityValue() const; + void setForcedDisplayIsMonochromeAccessibilityValue(ForcedAccessibilityValue); + ForcedAccessibilityValue forcedPrefersReducedMotionAccessibilityValue() const; + void setForcedPrefersReducedMotionAccessibilityValue(ForcedAccessibilityValue); + + // RuntimeEnabledFeatures. + static void setIndexedDBWorkersEnabled(bool); + static void setCSSGridLayoutEnabled(bool); + static void setWebGL2Enabled(bool); + +private: + explicit InternalSettings(Page*); + + Settings& settings() const; + static const char* supplementName(); + class Backup { public: explicit Backup(Settings&); void restoreTo(Settings&); - bool m_originalCSSExclusionsEnabled; - bool m_originalCSSShapesEnabled; -#if ENABLE(SHADOW_DOM) - bool m_originalShadowDOMEnabled; - bool m_originalAuthorShadowDOMForAnyElementEnabled; -#endif EditingBehaviorType m_originalEditingBehavior; // Initially empty, only used if changed by a test. @@ -72,83 +139,60 @@ public: #if ENABLE(TEXT_AUTOSIZING) bool m_originalTextAutosizingEnabled; IntSize m_originalTextAutosizingWindowSizeOverride; - float m_originalTextAutosizingFontScaleFactor; #endif + String m_originalMediaTypeOverride; bool m_originalCanvasUsesAcceleratedDrawing; bool m_originalMockScrollbarsEnabled; bool m_originalUsesOverlayScrollbars; - bool m_langAttributeAwareFormControlUIEnabled; bool m_imagesEnabled; - double m_minimumTimerInterval; + bool m_preferMIMETypeForImages; + std::chrono::milliseconds m_minimumTimerInterval; #if ENABLE(VIDEO_TRACK) bool m_shouldDisplaySubtitles; bool m_shouldDisplayCaptions; bool m_shouldDisplayTextDescriptions; #endif String m_defaultVideoPosterURL; + bool m_forcePendingWebGLPolicy; bool m_originalTimeWithoutMouseMovementBeforeHidingControls; bool m_useLegacyBackgroundSizeShorthandBehavior; bool m_autoscrollForDragAndDropEnabled; - bool m_pluginReplacementEnabled; + bool m_quickTimePluginReplacementEnabled; + bool m_youTubeFlashPluginReplacementEnabled; + bool m_shouldConvertPositionStyleOnCopy; + bool m_fontFallbackPrefersPictographs; + bool m_webFontsAlwaysFallBack; + bool m_backgroundShouldExtendBeyondPage; + SecurityOrigin::StorageBlockingPolicy m_storageBlockingPolicy; + bool m_scrollingTreeIncludesFrames; +#if ENABLE(TOUCH_EVENTS) + bool m_touchEventEmulationEnabled; +#endif +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + bool m_allowsAirPlayForMediaPlayback; +#endif + bool m_allowsInlineMediaPlayback; + bool m_allowsInlineMediaPlaybackAfterFullscreen; + bool m_inlineMediaPlaybackRequiresPlaysInlineAttribute; + bool m_deferredCSSParserEnabled; + bool m_inputEventsEnabled; + + UserInterfaceDirectionPolicy m_userInterfaceDirectionPolicy; + TextDirection m_systemLayoutDirection; + PDFImageCachingPolicy m_pdfImageCachingPolicy; + Settings::ForcedAccessibilityValue m_forcedColorsAreInvertedAccessibilityValue; + Settings::ForcedAccessibilityValue m_forcedDisplayIsMonochromeAccessibilityValue; + Settings::ForcedAccessibilityValue m_forcedPrefersReducedMotionAccessibilityValue; + + // Runtime enabled settings. + bool m_indexedDBWorkersEnabled; + bool m_cssGridLayoutEnabled; + bool m_webGL2Enabled; }; - static PassRefPtr<InternalSettings> create(Page* page) - { - return adoptRef(new InternalSettings(page)); - } - static InternalSettings* from(Page*); - void hostDestroyed() { m_page = 0; } - - virtual ~InternalSettings(); - void resetToConsistentState(); - - void setMockScrollbarsEnabled(bool enabled, ExceptionCode&); - void setUsesOverlayScrollbars(bool enabled, ExceptionCode&); - void setTouchEventEmulationEnabled(bool enabled, ExceptionCode&); - void setShadowDOMEnabled(bool enabled, ExceptionCode&); - void setAuthorShadowDOMForAnyElementEnabled(bool); - void setStandardFontFamily(const String& family, const String& script, ExceptionCode&); - void setSerifFontFamily(const String& family, const String& script, ExceptionCode&); - void setSansSerifFontFamily(const String& family, const String& script, ExceptionCode&); - void setFixedFontFamily(const String& family, const String& script, ExceptionCode&); - void setCursiveFontFamily(const String& family, const String& script, ExceptionCode&); - void setFantasyFontFamily(const String& family, const String& script, ExceptionCode&); - void setPictographFontFamily(const String& family, const String& script, ExceptionCode&); - void setTextAutosizingEnabled(bool enabled, ExceptionCode&); - void setTextAutosizingWindowSizeOverride(int width, int height, ExceptionCode&); - void setTextAutosizingFontScaleFactor(float fontScaleFactor, ExceptionCode&); - void setMediaTypeOverride(const String& mediaType, ExceptionCode&); - void setCSSExclusionsEnabled(bool enabled, ExceptionCode&); - void setCSSShapesEnabled(bool enabled, ExceptionCode&); - void setCanStartMedia(bool, ExceptionCode&); - void setEditingBehavior(const String&, ExceptionCode&); - void setShouldDisplayTrackKind(const String& kind, bool enabled, ExceptionCode&); - bool shouldDisplayTrackKind(const String& kind, ExceptionCode&); - void setStorageBlockingPolicy(const String&, ExceptionCode&); - void setLangAttributeAwareFormControlUIEnabled(bool); - void setImagesEnabled(bool enabled, ExceptionCode&); - void setMinimumTimerInterval(double intervalInSeconds, ExceptionCode&); - void setDefaultVideoPosterURL(const String& url, ExceptionCode&); - void setTimeWithoutMouseMovementBeforeHidingControls(double time, ExceptionCode&); - void setUseLegacyBackgroundSizeShorthandBehavior(bool enabled, ExceptionCode&); - void setAutoscrollForDragAndDropEnabled(bool enabled, ExceptionCode&); - void setFontFallbackPrefersPictographs(bool preferPictographs, ExceptionCode&); - void setPluginReplacementEnabled(bool); - void setBackgroundShouldExtendBeyondPage(bool hasExtendedBackground, ExceptionCode&); - - -private: - explicit InternalSettings(Page*); - - Settings* settings() const; - Page* page() const { return m_page; } - static const char* supplementName(); - Page* m_page; Backup m_backup; }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/testing/InternalSettings.idl b/Source/WebCore/testing/InternalSettings.idl index f9fbfb107..d4811b79e 100644 --- a/Source/WebCore/testing/InternalSettings.idl +++ b/Source/WebCore/testing/InternalSettings.idl @@ -1,5 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. + * Copyright (C) 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,41 +24,79 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +enum ForcedAccessibilityValue { "system", "on", "off" }; + [ NoInterfaceObject, - JSGenerateToJSObject + JSGenerateToJSObject, + ExportMacro=WEBCORE_TESTSUPPORT_EXPORT, ] interface InternalSettings : InternalSettingsGenerated { - [RaisesException] void setMockScrollbarsEnabled(boolean enabled); - [RaisesException] void setTouchEventEmulationEnabled(boolean enabled); - [RaisesException] void setShadowDOMEnabled(boolean enabled); - void setAuthorShadowDOMForAnyElementEnabled(boolean isEnabled); - [RaisesException] void setStandardFontFamily(DOMString family, DOMString script); - [RaisesException] void setSerifFontFamily(DOMString family, DOMString script); - [RaisesException] void setSansSerifFontFamily(DOMString family, DOMString script); - [RaisesException] void setFixedFontFamily(DOMString family, DOMString script); - [RaisesException] void setCursiveFontFamily(DOMString family, DOMString script); - [RaisesException] void setFantasyFontFamily(DOMString family, DOMString script); - [RaisesException] void setPictographFontFamily(DOMString family, DOMString script); - [RaisesException] void setTextAutosizingEnabled(boolean enabled); - [RaisesException] void setTextAutosizingWindowSizeOverride(long width, long height); - [RaisesException] void setTextAutosizingFontScaleFactor(float fontScaleFactor); - [RaisesException] void setMediaTypeOverride(DOMString mediaTypeOverride); - [RaisesException] void setCSSExclusionsEnabled(boolean enabled); - [RaisesException] void setCSSShapesEnabled(boolean enabled); - [RaisesException] void setCanStartMedia(boolean enabled); - [RaisesException] void setEditingBehavior(DOMString behavior); - void setLangAttributeAwareFormControlUIEnabled(boolean enabled); - - [Conditional=VIDEO_TRACK, RaisesException] void setShouldDisplayTrackKind(DOMString kind, boolean enabled); - [Conditional=VIDEO_TRACK, RaisesException] boolean shouldDisplayTrackKind(DOMString trackKind); - [RaisesException] void setStorageBlockingPolicy(DOMString policy); - [RaisesException] void setImagesEnabled(boolean enabled); - [RaisesException] void setMinimumTimerInterval(double intervalInSeconds); - [RaisesException] void setDefaultVideoPosterURL(DOMString poster); - [RaisesException] void setTimeWithoutMouseMovementBeforeHidingControls(double time); - [RaisesException] void setUseLegacyBackgroundSizeShorthandBehavior(boolean enabled); - [RaisesException] void setAutoscrollForDragAndDropEnabled(boolean enabled); - [RaisesException] void setFontFallbackPrefersPictographs(boolean preferPictographs); - void setPluginReplacementEnabled(boolean enabled); - [RaisesException] void setBackgroundShouldExtendBeyondPage(boolean hasExtendedBackground); + [MayThrowException] void setTouchEventEmulationEnabled(boolean enabled); + + // Fonts, text + [MayThrowException] void setStandardFontFamily(DOMString family, DOMString script); + [MayThrowException] void setSerifFontFamily(DOMString family, DOMString script); + [MayThrowException] void setSansSerifFontFamily(DOMString family, DOMString script); + [MayThrowException] void setFixedFontFamily(DOMString family, DOMString script); + [MayThrowException] void setCursiveFontFamily(DOMString family, DOMString script); + [MayThrowException] void setFantasyFontFamily(DOMString family, DOMString script); + [MayThrowException] void setPictographFontFamily(DOMString family, DOMString script); + [MayThrowException] void setFontFallbackPrefersPictographs(boolean preferPictographs); + [MayThrowException] void setWebFontsAlwaysFallBack(boolean enable); + + [MayThrowException] void setTextAutosizingEnabled(boolean enabled); + [MayThrowException] void setTextAutosizingWindowSizeOverride(long width, long height); + + // Media + [MayThrowException] void setCanStartMedia(boolean enabled); + [Conditional=VIDEO_TRACK, MayThrowException] void setShouldDisplayTrackKind(DOMString kind, boolean enabled); + [Conditional=VIDEO_TRACK, MayThrowException] boolean shouldDisplayTrackKind(DOMString trackKind); + [MayThrowException] void setDefaultVideoPosterURL(DOMString poster); + [MayThrowException] void setTimeWithoutMouseMovementBeforeHidingControls(unrestricted double time); + [MayThrowException] void setMediaTypeOverride(DOMString mediaTypeOverride); + void setAllowsAirPlayForMediaPlayback(boolean available); + [Conditional=MEDIA_STREAM, MayThrowException] void setMediaCaptureRequiresSecureConnection(boolean enable); + + [MayThrowException] void setForcePendingWebGLPolicy(boolean forced); + + [MayThrowException] void setQuickTimePluginReplacementEnabled(boolean enabled); + [MayThrowException] void setYouTubeFlashPluginReplacementEnabled(boolean enabled); + + // Editing, forms + [MayThrowException] void setEditingBehavior(DOMString behavior); + [MayThrowException] void setShouldConvertPositionStyleOnCopy(boolean convertPosition); + [MayThrowException] void setPreferMIMETypeForImages(boolean preferMimeTypeForImage); + + // Other switches + [MayThrowException] void setStorageBlockingPolicy(DOMString policy); + [MayThrowException] void setImagesEnabled(boolean enabled); + [MayThrowException] void setPDFImageCachingPolicy(DOMString policy); + [MayThrowException] void setUseLegacyBackgroundSizeShorthandBehavior(boolean enabled); + [MayThrowException] void setAutoscrollForDragAndDropEnabled(boolean enabled); + [MayThrowException] void setBackgroundShouldExtendBeyondPage(boolean hasExtendedBackground); + [MayThrowException] void setScrollingTreeIncludesFrames(boolean enabled); + [MayThrowException] void setAllowUnclampedScrollPosition(boolean allowUnclamped); + + [MayThrowException] void setMinimumTimerInterval(unrestricted double intervalInSeconds); + [MayThrowException] void setAllowsInlineMediaPlayback(boolean allows); + [MayThrowException] void setAllowsInlineMediaPlaybackAfterFullscreen(boolean allows); + [MayThrowException] void setInlineMediaPlaybackRequiresPlaysInlineAttribute(boolean requires); + + // RuntimeEnabledFeatures. + void setIndexedDBWorkersEnabled(boolean enabled); + void setCSSGridLayoutEnabled(boolean enabled); + void setWebGL2Enabled(boolean enabled); + + [MayThrowException] DOMString userInterfaceDirectionPolicy(); + [MayThrowException] void setUserInterfaceDirectionPolicy(DOMString policy); + [MayThrowException] DOMString systemLayoutDirection(); + [MayThrowException] void setSystemLayoutDirection(DOMString direction); + + [MayThrowException] boolean deferredCSSParserEnabled(); + [MayThrowException] void setDeferredCSSParserEnabled(boolean enabled); + + attribute ForcedAccessibilityValue forcedColorsAreInvertedAccessibilityValue; + attribute ForcedAccessibilityValue forcedDisplayIsMonochromeAccessibilityValue; + attribute ForcedAccessibilityValue forcedPrefersReducedMotionAccessibilityValue; }; + diff --git a/Source/WebCore/testing/Internals.cpp b/Source/WebCore/testing/Internals.cpp index 83fa07530..6d26d556e 100644 --- a/Source/WebCore/testing/Internals.cpp +++ b/Source/WebCore/testing/Internals.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,18 +28,26 @@ #include "Internals.h" #include "AXObjectCache.h" -#include "AnimationController.h" +#include "ActiveDOMCallbackMicrotask.h" #include "ApplicationCacheStorage.h" +#include "Autofill.h" #include "BackForwardController.h" +#include "BitmapImage.h" +#include "CSSAnimationController.h" +#include "CSSKeyframesRule.h" +#include "CSSMediaRule.h" +#include "CSSStyleRule.h" +#include "CSSSupportsRule.h" +#include "CachedImage.h" #include "CachedResourceLoader.h" -#include "Chrome.h" -#include "ChromeClient.h" #include "ClientRect.h" #include "ClientRectList.h" -#include "ContentDistributor.h" +#include "ComposedTreeIterator.h" #include "Cursor.h" +#include "DOMPath.h" #include "DOMStringList.h" #include "DOMWindow.h" +#include "DisplayList.h" #include "Document.h" #include "DocumentMarker.h" #include "DocumentMarkerController.h" @@ -47,76 +55,102 @@ #include "Element.h" #include "EventHandler.h" #include "ExceptionCode.h" +#include "ExtensionStyleSheets.h" +#include "File.h" +#include "FontCache.h" #include "FormController.h" #include "FrameLoader.h" #include "FrameView.h" +#include "GCObservation.h" +#include "HTMLCanvasElement.h" #include "HTMLIFrameElement.h" +#include "HTMLImageElement.h" #include "HTMLInputElement.h" +#include "HTMLLinkElement.h" #include "HTMLNames.h" +#include "HTMLPlugInElement.h" +#include "HTMLPreloadScanner.h" #include "HTMLSelectElement.h" #include "HTMLTextAreaElement.h" +#include "HTMLVideoElement.h" #include "HistoryController.h" #include "HistoryItem.h" +#include "HitTestResult.h" +#include "IconController.h" #include "InspectorClient.h" -#include "InspectorConsoleAgent.h" #include "InspectorController.h" -#include "InspectorCounters.h" -#include "InspectorForwarding.h" #include "InspectorFrontendClientLocal.h" -#include "InspectorInstrumentation.h" #include "InspectorOverlay.h" #include "InstrumentingAgents.h" -#include "InternalSettings.h" #include "IntRect.h" +#include "InternalSettings.h" #include "Language.h" +#include "LibWebRTCProvider.h" #include "MainFrame.h" #include "MallocStatistics.h" #include "MediaPlayer.h" -#include "MediaSessionManager.h" +#include "MediaProducer.h" #include "MemoryCache.h" #include "MemoryInfo.h" +#include "MemoryPressureHandler.h" +#include "MockLibWebRTCPeerConnection.h" +#include "MockPageOverlay.h" +#include "MockPageOverlayClient.h" #include "Page.h" +#include "PageCache.h" +#include "PageOverlay.h" +#include "PathUtilities.h" +#include "PlatformMediaSessionManager.h" #include "PrintContext.h" #include "PseudoElement.h" #include "Range.h" #include "RenderEmbeddedObject.h" +#include "RenderLayerBacking.h" +#include "RenderLayerCompositor.h" #include "RenderMenuList.h" #include "RenderTreeAsText.h" #include "RenderView.h" -#include "RuntimeEnabledFeatures.h" +#include "RenderedDocumentMarker.h" +#include "ResourceLoadObserver.h" +#include "SVGDocumentExtensions.h" +#include "SVGPathStringBuilder.h" #include "SchemeRegistry.h" +#include "ScriptedAnimationController.h" #include "ScrollingCoordinator.h" +#include "ScrollingMomentumCalculator.h" #include "SerializedScriptValue.h" #include "Settings.h" #include "ShadowRoot.h" +#include "SourceBuffer.h" #include "SpellChecker.h" #include "StaticNodeList.h" +#include "StyleRule.h" +#include "StyleScope.h" #include "StyleSheetContents.h" #include "TextIterator.h" #include "TreeScope.h" #include "TypeConversions.h" +#include "UserGestureIndicator.h" +#include "UserMediaController.h" #include "ViewportArguments.h" +#include "WebCoreJSClientData.h" #include "WorkerThread.h" +#include "WritingDirection.h" +#include "XMLHttpRequest.h" #include <bytecode/CodeBlock.h> #include <inspector/InspectorAgentBase.h> +#include <inspector/InspectorFrontendChannel.h> #include <inspector/InspectorValues.h> +#include <runtime/JSCInlines.h> #include <runtime/JSCJSValue.h> #include <wtf/text/CString.h> #include <wtf/text/StringBuffer.h> +#include <wtf/text/StringBuilder.h> #if ENABLE(INPUT_TYPE_COLOR) #include "ColorChooser.h" #endif -#if ENABLE(BATTERY_STATUS) -#include "BatteryController.h" -#endif - -#if ENABLE(NETWORK_INFO) -#include "NetworkInfo.h" -#include "NetworkInfoController.h" -#endif - #if ENABLE(PROXIMITY_EVENTS) #include "DeviceProximityController.h" #endif @@ -125,9 +159,13 @@ #include <wtf/dtoa.h> #endif -#if ENABLE(ENCRYPTED_MEDIA_V2) -#include "CDM.h" -#include "MockCDM.h" +#if ENABLE(LEGACY_ENCRYPTED_MEDIA) +#include "LegacyCDM.h" +#include "LegacyMockCDM.h" +#endif + +#if ENABLE(ENCRYPTED_MEDIA) +#include "MockCDMFactory.h" #endif #if ENABLE(VIDEO_TRACK) @@ -151,19 +189,59 @@ #endif #if ENABLE(MEDIA_STREAM) -#include "MockMediaStreamCenter.h" +#include "MockRealtimeMediaSourceCenter.h" +#endif + +#if ENABLE(WEB_RTC) +#include "MockMediaEndpoint.h" #include "RTCPeerConnection.h" -#include "RTCPeerConnectionHandlerMock.h" #endif #if ENABLE(MEDIA_SOURCE) #include "MockMediaPlayerMediaSource.h" #endif +#if PLATFORM(MAC) +#include "DictionaryLookup.h" +#endif + +#if ENABLE(CONTENT_FILTERING) +#include "MockContentFilterSettings.h" +#endif + +#if ENABLE(WEB_AUDIO) +#include "AudioContext.h" +#endif + +#if ENABLE(MEDIA_SESSION) +#include "MediaSession.h" +#include "MediaSessionManager.h" +#endif + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) +#include "MediaPlaybackTargetContext.h" +#endif + +#if ENABLE(POINTER_LOCK) +#include "PointerLockController.h" +#endif + +#if USE(QUICK_LOOK) +#include "MockQuickLookHandleClient.h" +#include "QuickLook.h" +#endif + +using JSC::CallData; +using JSC::CallType; using JSC::CodeBlock; using JSC::FunctionExecutable; +using JSC::Identifier; using JSC::JSFunction; +using JSC::JSGlobalObject; +using JSC::JSObject; using JSC::JSValue; +using JSC::MarkedArgumentBuffer; +using JSC::PropertySlot; using JSC::ScriptExecutable; using JSC::StackVisitor; @@ -173,77 +251,111 @@ namespace WebCore { using namespace HTMLNames; -#if ENABLE(INSPECTOR) -class InspectorFrontendClientDummy : public InspectorFrontendClientLocal { +class InspectorStubFrontend final : public InspectorFrontendClientLocal, public FrontendChannel { public: - InspectorFrontendClientDummy(InspectorController*, Page*); - virtual ~InspectorFrontendClientDummy() { } - virtual void attachWindow(DockSide) override { } - virtual void detachWindow() override { } + InspectorStubFrontend(Page& inspectedPage, RefPtr<DOMWindow>&& frontendWindow); + virtual ~InspectorStubFrontend(); - virtual String localizedStringsURL() override { return String(); } - - virtual void bringToFront() override { } - virtual void closeWindow() override { } +private: + void attachWindow(DockSide) final { } + void detachWindow() final { } + void closeWindow() final; + void bringToFront() final { } + String localizedStringsURL() final { return String(); } + void inspectedURLChanged(const String&) final { } + void setAttachedWindowHeight(unsigned) final { } + void setAttachedWindowWidth(unsigned) final { } + + void sendMessageToFrontend(const String& message) final; + ConnectionType connectionType() const final { return ConnectionType::Local; } + + Page* frontendPage() const + { + if (!m_frontendWindow || !m_frontendWindow->document()) + return nullptr; - virtual void inspectedURLChanged(const String&) override { } + return m_frontendWindow->document()->page(); + } -protected: - virtual void setAttachedWindowHeight(unsigned) override { } - virtual void setAttachedWindowWidth(unsigned) override { } - virtual void setToolbarHeight(unsigned) override { } + RefPtr<DOMWindow> m_frontendWindow; + InspectorController& m_frontendController; }; -InspectorFrontendClientDummy::InspectorFrontendClientDummy(InspectorController* controller, Page* page) - : InspectorFrontendClientLocal(controller, page, adoptPtr(new InspectorFrontendClientLocal::Settings())) +InspectorStubFrontend::InspectorStubFrontend(Page& inspectedPage, RefPtr<DOMWindow>&& frontendWindow) + : InspectorFrontendClientLocal(&inspectedPage.inspectorController(), frontendWindow->document()->page(), std::make_unique<InspectorFrontendClientLocal::Settings>()) + , m_frontendWindow(frontendWindow.copyRef()) + , m_frontendController(frontendPage()->inspectorController()) { -} - -class InspectorFrontendChannelDummy : public InspectorFrontendChannel { -public: - explicit InspectorFrontendChannelDummy(Page*); - virtual ~InspectorFrontendChannelDummy() { } - virtual bool sendMessageToFrontend(const String& message) override; + ASSERT_ARG(frontendWindow, frontendWindow); -private: - Page* m_frontendPage; -}; + m_frontendController.setInspectorFrontendClient(this); + inspectedPage.inspectorController().connectFrontend(this); +} -InspectorFrontendChannelDummy::InspectorFrontendChannelDummy(Page* page) - : m_frontendPage(page) +InspectorStubFrontend::~InspectorStubFrontend() { + closeWindow(); } -bool InspectorFrontendChannelDummy::sendMessageToFrontend(const String& message) +void InspectorStubFrontend::closeWindow() { - return InspectorClient::doDispatchMessageOnFrontendPage(m_frontendPage, message); + if (!m_frontendWindow) + return; + + m_frontendController.setInspectorFrontendClient(nullptr); + inspectedPage()->inspectorController().disconnectFrontend(this); + + m_frontendWindow->close(); + m_frontendWindow = nullptr; +} + +void InspectorStubFrontend::sendMessageToFrontend(const String& message) +{ + ASSERT_ARG(message, !message.isEmpty()); + + InspectorClient::doDispatchMessageOnFrontendPage(frontendPage(), message); +} + +static bool markerTypeFrom(const String& markerType, DocumentMarker::MarkerType& result) +{ + if (equalLettersIgnoringASCIICase(markerType, "spelling")) + result = DocumentMarker::Spelling; + else if (equalLettersIgnoringASCIICase(markerType, "grammar")) + result = DocumentMarker::Grammar; + else if (equalLettersIgnoringASCIICase(markerType, "textmatch")) + result = DocumentMarker::TextMatch; + else if (equalLettersIgnoringASCIICase(markerType, "replacement")) + result = DocumentMarker::Replacement; + else if (equalLettersIgnoringASCIICase(markerType, "correctionindicator")) + result = DocumentMarker::CorrectionIndicator; + else if (equalLettersIgnoringASCIICase(markerType, "rejectedcorrection")) + result = DocumentMarker::RejectedCorrection; + else if (equalLettersIgnoringASCIICase(markerType, "autocorrected")) + result = DocumentMarker::Autocorrected; + else if (equalLettersIgnoringASCIICase(markerType, "spellcheckingexemption")) + result = DocumentMarker::SpellCheckingExemption; + else if (equalLettersIgnoringASCIICase(markerType, "deletedautocorrection")) + result = DocumentMarker::DeletedAutocorrection; + else if (equalLettersIgnoringASCIICase(markerType, "dictationalternatives")) + result = DocumentMarker::DictationAlternatives; +#if ENABLE(TELEPHONE_NUMBER_DETECTION) + else if (equalLettersIgnoringASCIICase(markerType, "telephonenumber")) + result = DocumentMarker::TelephoneNumber; +#endif + else + return false; + + return true; } -#endif // ENABLE(INSPECTOR) static bool markerTypesFrom(const String& markerType, DocumentMarker::MarkerTypes& result) { - if (markerType.isEmpty() || equalIgnoringCase(markerType, "all")) + DocumentMarker::MarkerType singularResult; + + if (markerType.isEmpty() || equalLettersIgnoringASCIICase(markerType, "all")) result = DocumentMarker::AllMarkers(); - else if (equalIgnoringCase(markerType, "Spelling")) - result = DocumentMarker::Spelling; - else if (equalIgnoringCase(markerType, "Grammar")) - result = DocumentMarker::Grammar; - else if (equalIgnoringCase(markerType, "TextMatch")) - result = DocumentMarker::TextMatch; - else if (equalIgnoringCase(markerType, "Replacement")) - result = DocumentMarker::Replacement; - else if (equalIgnoringCase(markerType, "CorrectionIndicator")) - result = DocumentMarker::CorrectionIndicator; - else if (equalIgnoringCase(markerType, "RejectedCorrection")) - result = DocumentMarker::RejectedCorrection; - else if (equalIgnoringCase(markerType, "Autocorrected")) - result = DocumentMarker::Autocorrected; - else if (equalIgnoringCase(markerType, "SpellCheckingExemption")) - result = DocumentMarker::SpellCheckingExemption; - else if (equalIgnoringCase(markerType, "DeletedAutocorrection")) - result = DocumentMarker::DeletedAutocorrection; - else if (equalIgnoringCase(markerType, "DictationAlternatives")) - result = DocumentMarker::DictationAlternatives; + else if (markerTypeFrom(markerType, singularResult)) + result = singularResult; else return false; @@ -252,75 +364,123 @@ static bool markerTypesFrom(const String& markerType, DocumentMarker::MarkerType const char* Internals::internalsId = "internals"; -PassRefPtr<Internals> Internals::create(Document* document) +Ref<Internals> Internals::create(Document& document) { - return adoptRef(new Internals(document)); + return adoptRef(*new Internals(document)); } Internals::~Internals() { } -void Internals::resetToConsistentState(Page* page) +void Internals::resetToConsistentState(Page& page) { - ASSERT(page); + page.setPageScaleFactor(1, IntPoint(0, 0)); + page.setPagination(Pagination()); + page.setPaginationLineGridEnabled(false); - page->setPageScaleFactor(1, IntPoint(0, 0)); - page->setPagination(Pagination()); - -#if USE(ACCELERATED_COMPOSITING) - FrameView* mainFrameView = page->mainFrame().view(); + page.setDefersLoading(false); + + page.mainFrame().setTextZoomFactor(1.0f); + + FrameView* mainFrameView = page.mainFrame().view(); if (mainFrameView) { mainFrameView->setHeaderHeight(0); mainFrameView->setFooterHeight(0); - } + page.setTopContentInset(0); + mainFrameView->setUseFixedLayout(false); + mainFrameView->setFixedLayoutSize(IntSize()); +#if USE(COORDINATED_GRAPHICS) + mainFrameView->setFixedVisibleContentRect(IntRect()); #endif - TextRun::setAllowsRoundingHacks(false); + if (auto* backing = mainFrameView->tiledBacking()) + backing->setTileSizeUpdateDelayDisabledForTesting(false); + } + + WebCore::clearDefaultPortForProtocolMapForTesting(); WebCore::overrideUserPreferredLanguages(Vector<String>()); WebCore::Settings::setUsesOverlayScrollbars(false); -#if ENABLE(INSPECTOR) - page->inspectorController().setProfilerEnabled(false); -#endif -#if ENABLE(VIDEO_TRACK) && !PLATFORM(WIN) - page->group().captionPreferences()->setCaptionsStyleSheetOverride(emptyString()); - page->group().captionPreferences()->setTestingMode(false); -#endif - if (!page->mainFrame().editor().isContinuousSpellCheckingEnabled()) - page->mainFrame().editor().toggleContinuousSpellChecking(); - if (page->mainFrame().editor().isOverwriteModeEnabled()) - page->mainFrame().editor().toggleOverwriteModeEnabled(); - cacheStorage().setDefaultOriginQuota(ApplicationCacheStorage::noQuota()); + WebCore::Settings::setUsesMockScrollAnimator(false); +#if ENABLE(VIDEO_TRACK) + page.group().captionPreferences().setTestingMode(true); + page.group().captionPreferences().setCaptionsStyleSheetOverride(emptyString()); + page.group().captionPreferences().setTestingMode(false); +#endif + if (!page.mainFrame().editor().isContinuousSpellCheckingEnabled()) + page.mainFrame().editor().toggleContinuousSpellChecking(); + if (page.mainFrame().editor().isOverwriteModeEnabled()) + page.mainFrame().editor().toggleOverwriteModeEnabled(); + page.mainFrame().loader().clearTestingOverrides(); + page.applicationCacheStorage().setDefaultOriginQuota(ApplicationCacheStorage::noQuota()); #if ENABLE(VIDEO) - MediaSessionManager::sharedManager().resetRestrictions(); + PlatformMediaSessionManager::sharedManager().resetRestrictions(); + PlatformMediaSessionManager::sharedManager().setWillIgnoreSystemInterruptions(true); #endif #if HAVE(ACCESSIBILITY) + AXObjectCache::setEnhancedUserInterfaceAccessibility(false); AXObjectCache::disableAccessibility(); #endif + + MockPageOverlayClient::singleton().uninstallAllOverlays(); + +#if ENABLE(CONTENT_FILTERING) + MockContentFilterSettings::reset(); +#endif + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + page.setMockMediaPlaybackTargetPickerEnabled(true); + page.setMockMediaPlaybackTargetPickerState(emptyString(), MediaPlaybackTargetContext::Unknown); +#endif + + page.setShowAllPlugins(false); + +#if USE(QUICK_LOOK) + MockQuickLookHandleClient::singleton().setPassword(""); + QuickLookHandle::setClientForTesting(nullptr); +#endif } -Internals::Internals(Document* document) - : ContextDestructionObserver(document) +Internals::Internals(Document& document) + : ContextDestructionObserver(&document) { -#if ENABLE(VIDEO_TRACK) && !PLATFORM(WIN) - if (document && document->page()) - document->page()->group().captionPreferences()->setTestingMode(true); +#if ENABLE(VIDEO_TRACK) + if (document.page()) + document.page()->group().captionPreferences().setTestingMode(true); #endif #if ENABLE(MEDIA_STREAM) - MockMediaStreamCenter::registerMockMediaStreamCenter(); - enableMockRTCPeerConnectionHandler(); + setMockMediaCaptureDevicesEnabled(true); + WebCore::Settings::setMediaCaptureRequiresSecureConnection(false); +#endif + +#if ENABLE(WEB_RTC) + enableMockMediaEndpoint(); + useMockRTCPeerConnectionFactory(String()); +#endif + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + if (document.page()) + document.page()->setMockMediaPlaybackTargetPickerEnabled(true); #endif + + if (contextDocument() && contextDocument()->frame()) { + setAutomaticSpellingCorrectionEnabled(true); + setAutomaticQuoteSubstitutionEnabled(false); + setAutomaticDashSubstitutionEnabled(false); + setAutomaticLinkDetectionEnabled(false); + setAutomaticTextReplacementEnabled(true); + } } Document* Internals::contextDocument() const { - return toDocument(scriptExecutionContext()); + return downcast<Document>(scriptExecutionContext()); } Frame* Internals::frame() const { if (!contextDocument()) - return 0; + return nullptr; return contextDocument()->frame(); } @@ -328,10 +488,10 @@ InternalSettings* Internals::settings() const { Document* document = contextDocument(); if (!document) - return 0; + return nullptr; Page* page = document->page(); if (!page) - return 0; + return nullptr; return InternalSettings::from(page); } @@ -340,55 +500,257 @@ unsigned Internals::workerThreadCount() const return WorkerThread::workerThreadCount(); } -String Internals::address(Node* node) +bool Internals::areSVGAnimationsPaused() const { - char buf[32]; - sprintf(buf, "%p", node); + auto* document = contextDocument(); + if (!document) + return false; - return String(buf); + if (!document->svgExtensions()) + return false; + + return document->accessSVGExtensions().areAnimationsPaused(); +} + +String Internals::address(Node& node) +{ + return String::format("%p", &node); +} + +bool Internals::nodeNeedsStyleRecalc(Node& node) +{ + return node.needsStyleRecalc(); +} + +static String styleValidityToToString(Style::Validity validity) +{ + switch (validity) { + case Style::Validity::Valid: + return "NoStyleChange"; + case Style::Validity::ElementInvalid: + return "InlineStyleChange"; + case Style::Validity::SubtreeInvalid: + return "FullStyleChange"; + case Style::Validity::SubtreeAndRenderersInvalid: + return "ReconstructRenderTree"; + } + ASSERT_NOT_REACHED(); + return ""; +} + +String Internals::styleChangeType(Node& node) +{ + node.document().styleScope().flushPendingUpdate(); + + return styleValidityToToString(node.styleValidity()); +} + +String Internals::description(JSC::JSValue value) +{ + return toString(value); } bool Internals::isPreloaded(const String& url) { Document* document = contextDocument(); - return document->cachedResourceLoader()->isPreloaded(url); + return document->cachedResourceLoader().isPreloaded(url); } bool Internals::isLoadingFromMemoryCache(const String& url) { - if (!contextDocument()) + if (!contextDocument() || !contextDocument()->page()) return false; - CachedResource* resource = memoryCache()->resourceForURL(contextDocument()->completeURL(url)); + + ResourceRequest request(contextDocument()->completeURL(url)); + request.setDomainForCachePartition(contextDocument()->topOrigin().domainForCachePartition()); + + CachedResource* resource = MemoryCache::singleton().resourceForRequest(request, contextDocument()->page()->sessionID()); return resource && resource->status() == CachedResource::Cached; } +String Internals::xhrResponseSource(XMLHttpRequest& request) +{ + if (request.resourceResponse().isNull()) + return "Null response"; + switch (request.resourceResponse().source()) { + case ResourceResponse::Source::Unknown: + return "Unknown"; + case ResourceResponse::Source::Network: + return "Network"; + case ResourceResponse::Source::DiskCache: + return "Disk cache"; + case ResourceResponse::Source::DiskCacheAfterValidation: + return "Disk cache after validation"; + case ResourceResponse::Source::MemoryCache: + return "Memory cache"; + case ResourceResponse::Source::MemoryCacheAfterValidation: + return "Memory cache after validation"; + } + ASSERT_NOT_REACHED(); + return "Error"; +} -Node* Internals::treeScopeRootNode(Node* node, ExceptionCode& ec) +bool Internals::isSharingStyleSheetContents(HTMLLinkElement& a, HTMLLinkElement& b) { - if (!node) { - ec = INVALID_ACCESS_ERR; - return 0; + if (!a.sheet() || !b.sheet()) + return false; + return &a.sheet()->contents() == &b.sheet()->contents(); +} + +bool Internals::isStyleSheetLoadingSubresources(HTMLLinkElement& link) +{ + return link.sheet() && link.sheet()->contents().isLoadingSubresources(); +} + +static ResourceRequestCachePolicy toResourceRequestCachePolicy(Internals::CachePolicy policy) +{ + switch (policy) { + case Internals::CachePolicy::UseProtocolCachePolicy: + return UseProtocolCachePolicy; + case Internals::CachePolicy::ReloadIgnoringCacheData: + return ReloadIgnoringCacheData; + case Internals::CachePolicy::ReturnCacheDataElseLoad: + return ReturnCacheDataElseLoad; + case Internals::CachePolicy::ReturnCacheDataDontLoad: + return ReturnCacheDataDontLoad; } + ASSERT_NOT_REACHED(); + return UseProtocolCachePolicy; +} - return node->treeScope().rootNode(); +void Internals::setOverrideCachePolicy(CachePolicy policy) +{ + frame()->loader().setOverrideCachePolicyForTesting(toResourceRequestCachePolicy(policy)); } -Node* Internals::parentTreeScope(Node* node, ExceptionCode& ec) +ExceptionOr<void> Internals::setCanShowModalDialogOverride(bool allow) { - if (!node) { - ec = INVALID_ACCESS_ERR; - return 0; + if (!contextDocument() || !contextDocument()->domWindow()) + return Exception { INVALID_ACCESS_ERR }; + + contextDocument()->domWindow()->setCanShowModalDialogOverride(allow); + return { }; +} + +static ResourceLoadPriority toResourceLoadPriority(Internals::ResourceLoadPriority priority) +{ + switch (priority) { + case Internals::ResourceLoadPriority::ResourceLoadPriorityVeryLow: + return ResourceLoadPriority::VeryLow; + case Internals::ResourceLoadPriority::ResourceLoadPriorityLow: + return ResourceLoadPriority::Low; + case Internals::ResourceLoadPriority::ResourceLoadPriorityMedium: + return ResourceLoadPriority::Medium; + case Internals::ResourceLoadPriority::ResourceLoadPriorityHigh: + return ResourceLoadPriority::High; + case Internals::ResourceLoadPriority::ResourceLoadPriorityVeryHigh: + return ResourceLoadPriority::VeryHigh; } - const TreeScope* parentTreeScope = node->treeScope().parentTreeScope(); - return parentTreeScope ? parentTreeScope->rootNode() : 0; + ASSERT_NOT_REACHED(); + return ResourceLoadPriority::Low; +} + +void Internals::setOverrideResourceLoadPriority(ResourceLoadPriority priority) +{ + frame()->loader().setOverrideResourceLoadPriorityForTesting(toResourceLoadPriority(priority)); +} + +void Internals::setStrictRawResourceValidationPolicyDisabled(bool disabled) +{ + frame()->loader().setStrictRawResourceValidationPolicyDisabledForTesting(disabled); +} + +void Internals::clearMemoryCache() +{ + MemoryCache::singleton().evictResources(); +} + +void Internals::pruneMemoryCacheToSize(unsigned size) +{ + MemoryCache::singleton().pruneDeadResourcesToSize(size); + MemoryCache::singleton().pruneLiveResourcesToSize(size, true); +} + +unsigned Internals::memoryCacheSize() const +{ + return MemoryCache::singleton().size(); } -unsigned Internals::lastSpatialNavigationCandidateCount(ExceptionCode& ec) const +unsigned Internals::imageFrameIndex(HTMLImageElement& element) { - if (!contextDocument() || !contextDocument()->page()) { - ec = INVALID_ACCESS_ERR; + auto* cachedImage = element.cachedImage(); + if (!cachedImage) return 0; - } + + auto* image = cachedImage->image(); + return is<BitmapImage>(image) ? downcast<BitmapImage>(*image).currentFrame() : 0; +} + +void Internals::setImageFrameDecodingDuration(HTMLImageElement& element, float duration) +{ + auto* cachedImage = element.cachedImage(); + if (!cachedImage) + return; + + auto* image = cachedImage->image(); + if (!is<BitmapImage>(image)) + return; + + downcast<BitmapImage>(*image).setFrameDecodingDurationForTesting(duration); +} + +void Internals::resetImageAnimation(HTMLImageElement& element) +{ + auto* cachedImage = element.cachedImage(); + if (!cachedImage) + return; + + auto* image = cachedImage->image(); + if (!is<BitmapImage>(image)) + return; + + image->resetAnimation(); +} + +void Internals::clearPageCache() +{ + PageCache::singleton().pruneToSizeNow(0, PruningReason::None); +} + +unsigned Internals::pageCacheSize() const +{ + return PageCache::singleton().pageCount(); +} + +void Internals::disableTileSizeUpdateDelay() +{ + Document* document = contextDocument(); + if (!document || !document->frame()) + return; + + auto* view = document->frame()->view(); + if (!view) + return; + + if (auto* backing = view->tiledBacking()) + backing->setTileSizeUpdateDelayDisabledForTesting(true); +} + +Node* Internals::treeScopeRootNode(Node& node) +{ + return &node.treeScope().rootNode(); +} + +Node* Internals::parentTreeScope(Node& node) +{ + const TreeScope* parentTreeScope = node.treeScope().parentTreeScope(); + return parentTreeScope ? &parentTreeScope->rootNode() : nullptr; +} + +ExceptionOr<unsigned> Internals::lastSpatialNavigationCandidateCount() const +{ + if (!contextDocument() || !contextDocument()->page()) + return Exception { INVALID_ACCESS_ERR }; return contextDocument()->page()->lastSpatialNavigationCandidateCount(); } @@ -398,432 +760,591 @@ unsigned Internals::numberOfActiveAnimations() const return frame()->animation().numberOfActiveAnimations(frame()->document()); } -bool Internals::animationsAreSuspended(ExceptionCode& ec) const +ExceptionOr<bool> Internals::animationsAreSuspended() const { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return false; - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; - return document->frame()->animation().isSuspended(); + return document->frame()->animation().animationsAreSuspendedForDocument(document); } -void Internals::suspendAnimations(ExceptionCode& ec) const +ExceptionOr<void> Internals::suspendAnimations() const { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return; + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; + + document->frame()->animation().suspendAnimationsForDocument(document); + + for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) { + if (Document* document = frame->document()) + frame->animation().suspendAnimationsForDocument(document); } - document->frame()->animation().suspendAnimations(); + return { }; } -void Internals::resumeAnimations(ExceptionCode& ec) const +ExceptionOr<void> Internals::resumeAnimations() const { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return; + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; + + document->frame()->animation().resumeAnimationsForDocument(document); + + for (Frame* frame = document->frame(); frame; frame = frame->tree().traverseNext()) { + if (Document* document = frame->document()) + frame->animation().resumeAnimationsForDocument(document); } - document->frame()->animation().resumeAnimations(); + return { }; } -bool Internals::pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element* element, ExceptionCode& ec) +ExceptionOr<bool> Internals::pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element& element) { - if (!element || pauseTime < 0) { - ec = INVALID_ACCESS_ERR; - return false; - } - return frame()->animation().pauseAnimationAtTime(element->renderer(), AtomicString(animationName), pauseTime); + if (pauseTime < 0) + return Exception { INVALID_ACCESS_ERR }; + return frame()->animation().pauseAnimationAtTime(element.renderer(), AtomicString(animationName), pauseTime); } -bool Internals::pauseAnimationAtTimeOnPseudoElement(const String& animationName, double pauseTime, Element* element, const String& pseudoId, ExceptionCode& ec) +ExceptionOr<bool> Internals::pauseAnimationAtTimeOnPseudoElement(const String& animationName, double pauseTime, Element& element, const String& pseudoId) { - if (!element || pauseTime < 0) { - ec = INVALID_ACCESS_ERR; - return false; - } + if (pauseTime < 0) + return Exception { INVALID_ACCESS_ERR }; - if (pseudoId != "before" && pseudoId != "after") { - ec = INVALID_ACCESS_ERR; - return false; - } + if (pseudoId != "before" && pseudoId != "after") + return Exception { INVALID_ACCESS_ERR }; - PseudoElement* pseudoElement = pseudoId == "before" ? element->beforePseudoElement() : element->afterPseudoElement(); - if (!pseudoElement) { - ec = INVALID_ACCESS_ERR; - return false; - } + PseudoElement* pseudoElement = pseudoId == "before" ? element.beforePseudoElement() : element.afterPseudoElement(); + if (!pseudoElement) + return Exception { INVALID_ACCESS_ERR }; return frame()->animation().pauseAnimationAtTime(pseudoElement->renderer(), AtomicString(animationName), pauseTime); } -bool Internals::pauseTransitionAtTimeOnElement(const String& propertyName, double pauseTime, Element* element, ExceptionCode& ec) +ExceptionOr<bool> Internals::pauseTransitionAtTimeOnElement(const String& propertyName, double pauseTime, Element& element) { - if (!element || pauseTime < 0) { - ec = INVALID_ACCESS_ERR; - return false; - } - return frame()->animation().pauseTransitionAtTime(element->renderer(), propertyName, pauseTime); + if (pauseTime < 0) + return Exception { INVALID_ACCESS_ERR }; + return frame()->animation().pauseTransitionAtTime(element.renderer(), propertyName, pauseTime); } -bool Internals::pauseTransitionAtTimeOnPseudoElement(const String& property, double pauseTime, Element* element, const String& pseudoId, ExceptionCode& ec) +ExceptionOr<bool> Internals::pauseTransitionAtTimeOnPseudoElement(const String& property, double pauseTime, Element& element, const String& pseudoId) { - if (!element || pauseTime < 0) { - ec = INVALID_ACCESS_ERR; - return false; - } + if (pauseTime < 0) + return Exception { INVALID_ACCESS_ERR }; - if (pseudoId != "before" && pseudoId != "after") { - ec = INVALID_ACCESS_ERR; - return false; - } + if (pseudoId != "before" && pseudoId != "after") + return Exception { INVALID_ACCESS_ERR }; - PseudoElement* pseudoElement = pseudoId == "before" ? element->beforePseudoElement() : element->afterPseudoElement(); - if (!pseudoElement) { - ec = INVALID_ACCESS_ERR; - return false; - } + PseudoElement* pseudoElement = pseudoId == "before" ? element.beforePseudoElement() : element.afterPseudoElement(); + if (!pseudoElement) + return Exception { INVALID_ACCESS_ERR }; return frame()->animation().pauseTransitionAtTime(pseudoElement->renderer(), property, pauseTime); } -// FIXME: Remove. -bool Internals::attached(Node* node, ExceptionCode& ec) +ExceptionOr<String> Internals::elementRenderTreeAsText(Element& element) { - if (!node) { - ec = INVALID_ACCESS_ERR; - return false; - } + element.document().updateStyleIfNeeded(); - return true; + String representation = externalRepresentation(&element); + if (representation.isEmpty()) + return Exception { INVALID_ACCESS_ERR }; + + return WTFMove(representation); } -String Internals::elementRenderTreeAsText(Element* element, ExceptionCode& ec) +bool Internals::hasPausedImageAnimations(Element& element) { - if (!element) { - ec = INVALID_ACCESS_ERR; - return String(); - } + return element.renderer() && element.renderer()->hasPausedImageAnimations(); +} - element->document().updateStyleIfNeeded(); +Ref<CSSComputedStyleDeclaration> Internals::computedStyleIncludingVisitedInfo(Element& element) const +{ + bool allowVisitedStyle = true; + return CSSComputedStyleDeclaration::create(element, allowVisitedStyle); +} - String representation = externalRepresentation(element); - if (representation.isEmpty()) { - ec = INVALID_ACCESS_ERR; - return String(); - } +Node* Internals::ensureUserAgentShadowRoot(Element& host) +{ + return &host.ensureUserAgentShadowRoot(); +} - return representation; +Node* Internals::shadowRoot(Element& host) +{ + return host.shadowRoot(); } -PassRefPtr<CSSComputedStyleDeclaration> Internals::computedStyleIncludingVisitedInfo(Node* node, ExceptionCode& ec) const +ExceptionOr<String> Internals::shadowRootType(const Node& root) const { - if (!node) { - ec = INVALID_ACCESS_ERR; - return 0; + if (!is<ShadowRoot>(root)) + return Exception { INVALID_ACCESS_ERR }; + + switch (downcast<ShadowRoot>(root).mode()) { + case ShadowRootMode::UserAgent: + return String("UserAgentShadowRoot"); + case ShadowRootMode::Closed: + return String("ClosedShadowRoot"); + case ShadowRootMode::Open: + return String("OpenShadowRoot"); + default: + ASSERT_NOT_REACHED(); + return String("Unknown"); } +} - bool allowVisitedStyle = true; - return CSSComputedStyleDeclaration::create(node, allowVisitedStyle); +String Internals::shadowPseudoId(Element& element) +{ + return element.shadowPseudoId().string(); } -Internals::ShadowRootIfShadowDOMEnabledOrNode* Internals::ensureShadowRoot(Element* host, ExceptionCode& ec) +void Internals::setShadowPseudoId(Element& element, const String& id) { - if (!host) { - ec = INVALID_ACCESS_ERR; - return 0; + return element.setPseudo(id); +} + +static unsigned deferredStyleRulesCountForList(const Vector<RefPtr<StyleRuleBase>>& childRules) +{ + unsigned count = 0; + for (auto rule : childRules) { + if (is<StyleRule>(rule.get())) { + auto* cssRule = downcast<StyleRule>(rule.get()); + if (!cssRule->propertiesWithoutDeferredParsing()) + count++; + continue; + } + + StyleRuleGroup* groupRule = nullptr; + if (is<StyleRuleMedia>(rule.get())) + groupRule = downcast<StyleRuleMedia>(rule.get()); + else if (is<StyleRuleSupports>(rule.get())) + groupRule = downcast<StyleRuleSupports>(rule.get()); + if (!groupRule) + continue; + + auto* groupChildRules = groupRule->childRulesWithoutDeferredParsing(); + if (!groupChildRules) + continue; + + count += deferredStyleRulesCountForList(*groupChildRules); } - if (ShadowRoot* shadowRoot = host->shadowRoot()) - return shadowRoot; + return count; +} - return host->createShadowRoot(ec).get(); +unsigned Internals::deferredStyleRulesCount(StyleSheet& styleSheet) +{ + return deferredStyleRulesCountForList(downcast<CSSStyleSheet>(styleSheet).contents().childRules()); } -Internals::ShadowRootIfShadowDOMEnabledOrNode* Internals::createShadowRoot(Element* host, ExceptionCode& ec) +static unsigned deferredGroupRulesCountForList(const Vector<RefPtr<StyleRuleBase>>& childRules) { - if (!host) { - ec = INVALID_ACCESS_ERR; - return 0; + unsigned count = 0; + for (auto rule : childRules) { + StyleRuleGroup* groupRule = nullptr; + if (is<StyleRuleMedia>(rule.get())) + groupRule = downcast<StyleRuleMedia>(rule.get()); + else if (is<StyleRuleSupports>(rule.get())) + groupRule = downcast<StyleRuleSupports>(rule.get()); + if (!groupRule) + continue; + + auto* groupChildRules = groupRule->childRulesWithoutDeferredParsing(); + if (!groupChildRules) + count++; + else + count += deferredGroupRulesCountForList(*groupChildRules); } - return host->createShadowRoot(ec).get(); + return count; } -Internals::ShadowRootIfShadowDOMEnabledOrNode* Internals::shadowRoot(Element* host, ExceptionCode& ec) +unsigned Internals::deferredGroupRulesCount(StyleSheet& styleSheet) { - if (!host) { - ec = INVALID_ACCESS_ERR; - return 0; - } - return host->shadowRoot(); + return deferredGroupRulesCountForList(downcast<CSSStyleSheet>(styleSheet).contents().childRules()); } -String Internals::shadowRootType(const Node* root, ExceptionCode& ec) const +static unsigned deferredKeyframesRulesCountForList(const Vector<RefPtr<StyleRuleBase>>& childRules) { - if (!root || !root->isShadowRoot()) { - ec = INVALID_ACCESS_ERR; - return String(); + unsigned count = 0; + for (auto rule : childRules) { + if (is<StyleRuleKeyframes>(rule.get())) { + auto* cssRule = downcast<StyleRuleKeyframes>(rule.get()); + if (!cssRule->keyframesWithoutDeferredParsing()) + count++; + continue; + } + + StyleRuleGroup* groupRule = nullptr; + if (is<StyleRuleMedia>(rule.get())) + groupRule = downcast<StyleRuleMedia>(rule.get()); + else if (is<StyleRuleSupports>(rule.get())) + groupRule = downcast<StyleRuleSupports>(rule.get()); + if (!groupRule) + continue; + + auto* groupChildRules = groupRule->childRulesWithoutDeferredParsing(); + if (!groupChildRules) + continue; + + count += deferredKeyframesRulesCountForList(*groupChildRules); } + + return count; +} - switch (toShadowRoot(root)->type()) { - case ShadowRoot::UserAgentShadowRoot: - return String("UserAgentShadowRoot"); - case ShadowRoot::AuthorShadowRoot: - return String("AuthorShadowRoot"); - default: - ASSERT_NOT_REACHED(); - return String("Unknown"); - } +unsigned Internals::deferredKeyframesRulesCount(StyleSheet& styleSheet) +{ + StyleSheetContents& contents = downcast<CSSStyleSheet>(styleSheet).contents(); + return deferredKeyframesRulesCountForList(contents.childRules()); } -Element* Internals::includerFor(Node*, ExceptionCode& ec) +ExceptionOr<bool> Internals::isTimerThrottled(int timeoutId) { - ec = INVALID_ACCESS_ERR; - return 0; + DOMTimer* timer = scriptExecutionContext()->findTimeout(timeoutId); + if (!timer) + return Exception { NOT_FOUND_ERR }; + return timer->m_throttleState == DOMTimer::ShouldThrottle; } -String Internals::shadowPseudoId(Element* element, ExceptionCode& ec) +bool Internals::isRequestAnimationFrameThrottled() const { - if (!element) { - ec = INVALID_ACCESS_ERR; - return String(); - } + auto* scriptedAnimationController = contextDocument()->scriptedAnimationController(); + if (!scriptedAnimationController) + return false; + return scriptedAnimationController->isThrottled(); +} - return element->shadowPseudoId().string(); +bool Internals::areTimersThrottled() const +{ + return contextDocument()->isTimerThrottlingEnabled(); } -void Internals::setShadowPseudoId(Element* element, const String& id, ExceptionCode& ec) +void Internals::setEventThrottlingBehaviorOverride(std::optional<EventThrottlingBehavior> value) { - if (!element) { - ec = INVALID_ACCESS_ERR; + Document* document = contextDocument(); + if (!document || !document->page()) + return; + + if (!value) { + document->page()->setEventThrottlingBehaviorOverride(std::nullopt); return; } - return element->setPseudo(id); + switch (value.value()) { + case Internals::EventThrottlingBehavior::Responsive: + document->page()->setEventThrottlingBehaviorOverride(WebCore::EventThrottlingBehavior::Responsive); + break; + case Internals::EventThrottlingBehavior::Unresponsive: + document->page()->setEventThrottlingBehaviorOverride(WebCore::EventThrottlingBehavior::Unresponsive); + break; + } +} + +std::optional<Internals::EventThrottlingBehavior> Internals::eventThrottlingBehaviorOverride() const +{ + Document* document = contextDocument(); + if (!document || !document->page()) + return std::nullopt; + + auto behavior = document->page()->eventThrottlingBehaviorOverride(); + if (!behavior) + return std::nullopt; + + switch (behavior.value()) { + case WebCore::EventThrottlingBehavior::Responsive: + return Internals::EventThrottlingBehavior::Responsive; + case WebCore::EventThrottlingBehavior::Unresponsive: + return Internals::EventThrottlingBehavior::Unresponsive; + } + + return std::nullopt; } -String Internals::visiblePlaceholder(Element* element) +String Internals::visiblePlaceholder(Element& element) { - if (element && isHTMLTextFormControlElement(*element)) { - if (toHTMLTextFormControlElement(*element).placeholderShouldBeVisible()) - return toHTMLTextFormControlElement(*element).placeholderElement()->textContent(); + if (is<HTMLTextFormControlElement>(element)) { + const HTMLTextFormControlElement& textFormControlElement = downcast<HTMLTextFormControlElement>(element); + if (!textFormControlElement.isPlaceholderVisible()) + return String(); + if (HTMLElement* placeholderElement = textFormControlElement.placeholderElement()) + return placeholderElement->textContent(); } return String(); } -#if ENABLE(INPUT_TYPE_COLOR) -void Internals::selectColorInColorChooser(Element* element, const String& colorValue) +void Internals::selectColorInColorChooser(HTMLInputElement& element, const String& colorValue) { - if (!isHTMLInputElement(element)) - return; - HTMLInputElement* inputElement = element->toInputElement(); - if (!inputElement) - return; - inputElement->selectColorInColorChooser(Color(colorValue)); + element.selectColor(Color(colorValue)); } -#endif -Vector<String> Internals::formControlStateOfPreviousHistoryItem(ExceptionCode& ec) +ExceptionOr<Vector<String>> Internals::formControlStateOfPreviousHistoryItem() { HistoryItem* mainItem = frame()->loader().history().previousItem(); - if (!mainItem) { - ec = INVALID_ACCESS_ERR; - return Vector<String>(); - } + if (!mainItem) + return Exception { INVALID_ACCESS_ERR }; String uniqueName = frame()->tree().uniqueName(); - if (mainItem->target() != uniqueName && !mainItem->childItemWithTarget(uniqueName)) { - ec = INVALID_ACCESS_ERR; - return Vector<String>(); - } - return mainItem->target() == uniqueName ? mainItem->documentState() : mainItem->childItemWithTarget(uniqueName)->documentState(); + if (mainItem->target() != uniqueName && !mainItem->childItemWithTarget(uniqueName)) + return Exception { INVALID_ACCESS_ERR }; + return Vector<String> { mainItem->target() == uniqueName ? mainItem->documentState() : mainItem->childItemWithTarget(uniqueName)->documentState() }; } -void Internals::setFormControlStateOfPreviousHistoryItem(const Vector<String>& state, ExceptionCode& ec) +ExceptionOr<void> Internals::setFormControlStateOfPreviousHistoryItem(const Vector<String>& state) { HistoryItem* mainItem = frame()->loader().history().previousItem(); - if (!mainItem) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!mainItem) + return Exception { INVALID_ACCESS_ERR }; String uniqueName = frame()->tree().uniqueName(); if (mainItem->target() == uniqueName) mainItem->setDocumentState(state); else if (HistoryItem* subItem = mainItem->childItemWithTarget(uniqueName)) subItem->setDocumentState(state); else - ec = INVALID_ACCESS_ERR; + return Exception { INVALID_ACCESS_ERR }; + return { }; } #if ENABLE(SPEECH_SYNTHESIS) + void Internals::enableMockSpeechSynthesizer() { Document* document = contextDocument(); if (!document || !document->domWindow()) return; - SpeechSynthesis* synthesis = DOMWindowSpeechSynthesis::speechSynthesis(document->domWindow()); + SpeechSynthesis* synthesis = DOMWindowSpeechSynthesis::speechSynthesis(*document->domWindow()); if (!synthesis) return; - synthesis->setPlatformSynthesizer(PlatformSpeechSynthesizerMock::create(synthesis)); + synthesis->setPlatformSynthesizer(std::make_unique<PlatformSpeechSynthesizerMock>(synthesis)); } + +#endif + +#if ENABLE(WEB_RTC) + +void Internals::enableMockMediaEndpoint() +{ + MediaEndpoint::create = MockMediaEndpoint::create; +} + +void Internals::emulateRTCPeerConnectionPlatformEvent(RTCPeerConnection& connection, const String& action) +{ + connection.emulatePlatformEvent(action); +} + +void Internals::useMockRTCPeerConnectionFactory(const String& testCase) +{ +#if USE(LIBWEBRTC) + Document* document = contextDocument(); + LibWebRTCProvider* provider = (document && document->page()) ? &document->page()->libWebRTCProvider() : nullptr; + WebCore::useMockRTCPeerConnectionFactory(provider, testCase); +#else + UNUSED_PARAM(testCase); +#endif +} + #endif #if ENABLE(MEDIA_STREAM) -void Internals::enableMockRTCPeerConnectionHandler() + +void Internals::setMockMediaCaptureDevicesEnabled(bool enabled) { - RTCPeerConnectionHandler::create = RTCPeerConnectionHandlerMock::create; + WebCore::Settings::setMockCaptureDevicesEnabled(enabled); } + #endif -PassRefPtr<ClientRect> Internals::absoluteCaretBounds(ExceptionCode& ec) +ExceptionOr<Ref<ClientRect>> Internals::absoluteCaretBounds() { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return ClientRect::create(); - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; return ClientRect::create(document->frame()->selection().absoluteCaretBounds()); } -PassRefPtr<ClientRect> Internals::boundingBox(Element* element, ExceptionCode& ec) +Ref<ClientRect> Internals::boundingBox(Element& element) { - if (!element) { - ec = INVALID_ACCESS_ERR; - return ClientRect::create(); - } - - element->document().updateLayoutIgnorePendingStylesheets(); - auto renderer = element->renderer(); + element.document().updateLayoutIgnorePendingStylesheets(); + auto renderer = element.renderer(); if (!renderer) return ClientRect::create(); return ClientRect::create(renderer->absoluteBoundingBoxRectIgnoringTransforms()); } -PassRefPtr<ClientRectList> Internals::inspectorHighlightRects(ExceptionCode& ec) +ExceptionOr<Ref<ClientRectList>> Internals::inspectorHighlightRects() { -#if ENABLE(INSPECTOR) Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return ClientRectList::create(); - } + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; Highlight highlight; - document->page()->inspectorController().getHighlight(&highlight); + document->page()->inspectorController().getHighlight(highlight, InspectorOverlay::CoordinateSystem::View); return ClientRectList::create(highlight.quads); -#else - UNUSED_PARAM(ec); - return ClientRectList::create(); -#endif } -String Internals::inspectorHighlightObject(ExceptionCode& ec) +ExceptionOr<String> Internals::inspectorHighlightObject() { -#if ENABLE(INSPECTOR) Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return String(); - } - RefPtr<InspectorObject> object = document->page()->inspectorController().buildObjectForHighlightedNode(); - return object ? object->toJSONString() : String(); -#else - UNUSED_PARAM(ec); - return String(); -#endif + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; + + return document->page()->inspectorController().buildObjectForHighlightedNodes()->toJSONString(); } -unsigned Internals::markerCountForNode(Node* node, const String& markerType, ExceptionCode& ec) +ExceptionOr<unsigned> Internals::markerCountForNode(Node& node, const String& markerType) { - if (!node) { - ec = INVALID_ACCESS_ERR; - return 0; - } - DocumentMarker::MarkerTypes markerTypes = 0; - if (!markerTypesFrom(markerType, markerTypes)) { - ec = SYNTAX_ERR; - return 0; - } + if (!markerTypesFrom(markerType, markerTypes)) + return Exception { SYNTAX_ERR }; - return node->document().markers().markersFor(node, markerTypes).size(); + node.document().frame()->editor().updateEditorUINowIfScheduled(); + return node.document().markers().markersFor(&node, markerTypes).size(); } -DocumentMarker* Internals::markerAt(Node* node, const String& markerType, unsigned index, ExceptionCode& ec) +ExceptionOr<RenderedDocumentMarker*> Internals::markerAt(Node& node, const String& markerType, unsigned index) { - node->document().updateLayoutIgnorePendingStylesheets(); - if (!node) { - ec = INVALID_ACCESS_ERR; - return 0; - } + node.document().updateLayoutIgnorePendingStylesheets(); DocumentMarker::MarkerTypes markerTypes = 0; - if (!markerTypesFrom(markerType, markerTypes)) { - ec = SYNTAX_ERR; - return 0; - } + if (!markerTypesFrom(markerType, markerTypes)) + return Exception { SYNTAX_ERR }; + + node.document().frame()->editor().updateEditorUINowIfScheduled(); - Vector<DocumentMarker*> markers = node->document().markers().markersFor(node, markerTypes); + Vector<RenderedDocumentMarker*> markers = node.document().markers().markersFor(&node, markerTypes); if (markers.size() <= index) - return 0; + return nullptr; return markers[index]; } -PassRefPtr<Range> Internals::markerRangeForNode(Node* node, const String& markerType, unsigned index, ExceptionCode& ec) +ExceptionOr<RefPtr<Range>> Internals::markerRangeForNode(Node& node, const String& markerType, unsigned index) { - DocumentMarker* marker = markerAt(node, markerType, index, ec); + auto result = markerAt(node, markerType, index); + if (result.hasException()) + return result.releaseException(); + auto marker = result.releaseReturnValue(); if (!marker) - return 0; - return Range::create(node->document(), node, marker->startOffset(), node, marker->endOffset()); + return nullptr; + return RefPtr<Range> { Range::create(node.document(), &node, marker->startOffset(), &node, marker->endOffset()) }; } -String Internals::markerDescriptionForNode(Node* node, const String& markerType, unsigned index, ExceptionCode& ec) +ExceptionOr<String> Internals::markerDescriptionForNode(Node& node, const String& markerType, unsigned index) { - DocumentMarker* marker = markerAt(node, markerType, index, ec); + auto result = markerAt(node, markerType, index); + if (result.hasException()) + return result.releaseException(); + auto marker = result.releaseReturnValue(); if (!marker) return String(); - return marker->description(); + return String { marker->description() }; } -void Internals::addTextMatchMarker(const Range* range, bool isActive) +ExceptionOr<String> Internals::dumpMarkerRects(const String& markerTypeString) { - range->ownerDocument().updateLayoutIgnorePendingStylesheets(); - range->ownerDocument().markers().addTextMatchMarker(range, isActive); + DocumentMarker::MarkerType markerType; + if (!markerTypeFrom(markerTypeString, markerType)) + return Exception { SYNTAX_ERR }; + + contextDocument()->markers().updateRectsForInvalidatedMarkersOfType(markerType); + auto rects = contextDocument()->markers().renderedRectsForMarkers(markerType); + + StringBuilder rectString; + rectString.appendLiteral("marker rects: "); + for (const auto& rect : rects) { + rectString.append('('); + rectString.appendNumber(rect.x()); + rectString.appendLiteral(", "); + rectString.appendNumber(rect.y()); + rectString.appendLiteral(", "); + rectString.appendNumber(rect.width()); + rectString.appendLiteral(", "); + rectString.appendNumber(rect.height()); + rectString.appendLiteral(") "); + } + return rectString.toString(); } -void Internals::setScrollViewPosition(long x, long y, ExceptionCode& ec) +void Internals::addTextMatchMarker(const Range& range, bool isActive) +{ + range.ownerDocument().updateLayoutIgnorePendingStylesheets(); + range.ownerDocument().markers().addTextMatchMarker(&range, isActive); +} + +ExceptionOr<void> Internals::setMarkedTextMatchesAreHighlighted(bool flag) { Document* document = contextDocument(); - if (!document || !document->view()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; + document->frame()->editor().setMarkedTextMatchesAreHighlighted(flag); + return { }; +} + +void Internals::invalidateFontCache() +{ + FontCache::singleton().invalidate(); +} + +ExceptionOr<void> Internals::setScrollViewPosition(int x, int y) +{ + Document* document = contextDocument(); + if (!document || !document->view()) + return Exception { INVALID_ACCESS_ERR }; + + auto& frameView = *document->view(); + bool constrainsScrollingToContentEdgeOldValue = frameView.constrainsScrollingToContentEdge(); + bool scrollbarsSuppressedOldValue = frameView.scrollbarsSuppressed(); - FrameView* frameView = document->view(); - bool constrainsScrollingToContentEdgeOldValue = frameView->constrainsScrollingToContentEdge(); - bool scrollbarsSuppressedOldValue = frameView->scrollbarsSuppressed(); + frameView.setConstrainsScrollingToContentEdge(false); + frameView.setScrollbarsSuppressed(false); + frameView.setScrollOffsetFromInternals({ x, y }); + frameView.setScrollbarsSuppressed(scrollbarsSuppressedOldValue); + frameView.setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdgeOldValue); - frameView->setConstrainsScrollingToContentEdge(false); - frameView->setScrollbarsSuppressed(false); - frameView->setScrollOffsetFromInternals(IntPoint(x, y)); - frameView->setScrollbarsSuppressed(scrollbarsSuppressedOldValue); - frameView->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdgeOldValue); + return { }; } -void Internals::setPagination(const String& mode, int gap, int pageLength, ExceptionCode& ec) +ExceptionOr<Ref<ClientRect>> Internals::layoutViewportRect() { Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return; - } - Page* page = document->page(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; + + document->updateLayoutIgnorePendingStylesheets(); + + auto& frameView = *document->view(); + return ClientRect::create(frameView.layoutViewportRect()); +} + +ExceptionOr<Ref<ClientRect>> Internals::visualViewportRect() +{ + Document* document = contextDocument(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; + + document->updateLayoutIgnorePendingStylesheets(); + + auto& frameView = *document->view(); + return ClientRect::create(frameView.visualViewportRect()); +} + +ExceptionOr<void> Internals::setViewBaseBackgroundColor(const String& colorValue) +{ + Document* document = contextDocument(); + if (!document || !document->view()) + return Exception { INVALID_ACCESS_ERR }; + + document->view()->setBaseBackgroundColor(Color(colorValue)); + return { }; +} + +ExceptionOr<void> Internals::setPagination(const String& mode, int gap, int pageLength) +{ + Document* document = contextDocument(); + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; Pagination pagination; if (mode == "Unpaginated") @@ -836,223 +1357,193 @@ void Internals::setPagination(const String& mode, int gap, int pageLength, Excep pagination.mode = Pagination::TopToBottomPaginated; else if (mode == "BottomToTopPaginated") pagination.mode = Pagination::BottomToTopPaginated; - else { - ec = SYNTAX_ERR; - return; - } + else + return Exception { SYNTAX_ERR }; pagination.gap = gap; pagination.pageLength = pageLength; - page->setPagination(pagination); + document->page()->setPagination(pagination); + + return { }; } -String Internals::configurationForViewport(float devicePixelRatio, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight, ExceptionCode& ec) +ExceptionOr<void> Internals::setPaginationLineGridEnabled(bool enabled) { Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return String(); - } - Page* page = document->page(); + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; + document->page()->setPaginationLineGridEnabled(enabled); + return { }; +} + +ExceptionOr<String> Internals::configurationForViewport(float devicePixelRatio, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight) +{ + Document* document = contextDocument(); + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; const int defaultLayoutWidthForNonMobilePages = 980; - ViewportArguments arguments = page->viewportArguments(); + ViewportArguments arguments = document->page()->viewportArguments(); ViewportAttributes attributes = computeViewportAttributes(arguments, defaultLayoutWidthForNonMobilePages, deviceWidth, deviceHeight, devicePixelRatio, IntSize(availableWidth, availableHeight)); restrictMinimumScaleFactorToViewportSize(attributes, IntSize(availableWidth, availableHeight), devicePixelRatio); restrictScaleFactorToInitialScaleIfNotUserScalable(attributes); - return "viewport size " + String::number(attributes.layoutSize.width()) + "x" + String::number(attributes.layoutSize.height()) + " scale " + String::number(attributes.initialScale) + " with limits [" + String::number(attributes.minimumScale) + ", " + String::number(attributes.maximumScale) + "] and userScalable " + (attributes.userScalable ? "true" : "false"); + return String { "viewport size " + String::number(attributes.layoutSize.width()) + "x" + String::number(attributes.layoutSize.height()) + " scale " + String::number(attributes.initialScale) + " with limits [" + String::number(attributes.minimumScale) + ", " + String::number(attributes.maximumScale) + "] and userScalable " + (attributes.userScalable ? "true" : "false") }; } -bool Internals::wasLastChangeUserEdit(Element* textField, ExceptionCode& ec) +ExceptionOr<bool> Internals::wasLastChangeUserEdit(Element& textField) { - if (!textField) { - ec = INVALID_ACCESS_ERR; - return false; - } - - if (HTMLInputElement* inputElement = textField->toInputElement()) - return inputElement->lastChangeWasUserEdit(); + if (is<HTMLInputElement>(textField)) + return downcast<HTMLInputElement>(textField).lastChangeWasUserEdit(); - // FIXME: We should be using hasTagName instead but Windows port doesn't link QualifiedNames properly. - if (textField->tagName() == "TEXTAREA") - return toHTMLTextAreaElement(textField)->lastChangeWasUserEdit(); + if (is<HTMLTextAreaElement>(textField)) + return downcast<HTMLTextAreaElement>(textField).lastChangeWasUserEdit(); - ec = INVALID_NODE_TYPE_ERR; - return false; + return Exception { INVALID_NODE_TYPE_ERR }; } -bool Internals::elementShouldAutoComplete(Element* element, ExceptionCode& ec) +bool Internals::elementShouldAutoComplete(HTMLInputElement& element) { - if (!element) { - ec = INVALID_ACCESS_ERR; - return false; - } - - if (HTMLInputElement* inputElement = element->toInputElement()) - return inputElement->shouldAutocomplete(); - - ec = INVALID_NODE_TYPE_ERR; - return false; + return element.shouldAutocomplete(); } -String Internals::suggestedValue(Element* element, ExceptionCode& ec) +void Internals::setEditingValue(HTMLInputElement& element, const String& value) { - if (!element) { - ec = INVALID_ACCESS_ERR; - return String(); - } - - HTMLInputElement* inputElement = element->toInputElement(); - if (!inputElement) { - ec = INVALID_NODE_TYPE_ERR; - return String(); - } - - return inputElement->suggestedValue(); + element.setEditingValue(value); } -void Internals::setSuggestedValue(Element* element, const String& value, ExceptionCode& ec) +void Internals::setAutofilled(HTMLInputElement& element, bool enabled) { - if (!element) { - ec = INVALID_ACCESS_ERR; - return; - } - - HTMLInputElement* inputElement = element->toInputElement(); - if (!inputElement) { - ec = INVALID_NODE_TYPE_ERR; - return; - } - - inputElement->setSuggestedValue(value); + element.setAutoFilled(enabled); } -void Internals::setEditingValue(Element* element, const String& value, ExceptionCode& ec) +static AutoFillButtonType toAutoFillButtonType(Internals::AutoFillButtonType type) { - if (!element) { - ec = INVALID_ACCESS_ERR; - return; - } - - HTMLInputElement* inputElement = element->toInputElement(); - if (!inputElement) { - ec = INVALID_NODE_TYPE_ERR; - return; + switch (type) { + case Internals::AutoFillButtonType::AutoFillButtonTypeNone: + return AutoFillButtonType::None; + case Internals::AutoFillButtonType::AutoFillButtonTypeCredentials: + return AutoFillButtonType::Credentials; + case Internals::AutoFillButtonType::AutoFillButtonTypeContacts: + return AutoFillButtonType::Contacts; } - - inputElement->setEditingValue(value); + ASSERT_NOT_REACHED(); + return AutoFillButtonType::None; } -void Internals::setAutofilled(Element* element, bool enabled, ExceptionCode& ec) +void Internals::setShowAutoFillButton(HTMLInputElement& element, AutoFillButtonType type) { - HTMLInputElement* inputElement = element->toInputElement(); - if (!inputElement) { - ec = INVALID_ACCESS_ERR; - return; - } - inputElement->setAutofilled(enabled); + element.setShowAutoFillButton(toAutoFillButtonType(type)); } -void Internals::scrollElementToRect(Element* element, long x, long y, long w, long h, ExceptionCode& ec) +ExceptionOr<void> Internals::scrollElementToRect(Element& element, int x, int y, int w, int h) { - if (!element || !element->document().view()) { - ec = INVALID_ACCESS_ERR; - return; - } - FrameView* frameView = element->document().view(); - frameView->scrollElementToRect(element, IntRect(x, y, w, h)); + FrameView* frameView = element.document().view(); + if (!frameView) + return Exception { INVALID_ACCESS_ERR }; + frameView->scrollElementToRect(element, { x, y, w, h }); + return { }; } -void Internals::paintControlTints(ExceptionCode& ec) +ExceptionOr<String> Internals::autofillFieldName(Element& element) { - Document* document = contextDocument(); - if (!document || !document->view()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!is<HTMLFormControlElement>(element)) + return Exception { INVALID_NODE_TYPE_ERR }; - FrameView* frameView = document->view(); - frameView->paintControlTints(); + return String { downcast<HTMLFormControlElement>(element).autofillData().fieldName }; } -PassRefPtr<Range> Internals::rangeFromLocationAndLength(Element* scope, int rangeLocation, int rangeLength, ExceptionCode& ec) +ExceptionOr<void> Internals::paintControlTints() { - if (!scope) { - ec = INVALID_ACCESS_ERR; - return 0; - } + Document* document = contextDocument(); + if (!document || !document->view()) + return Exception { INVALID_ACCESS_ERR }; - return TextIterator::rangeFromLocationAndLength(scope, rangeLocation, rangeLength); + document->view()->paintControlTints(); + return { }; } -unsigned Internals::locationFromRange(Element* scope, const Range* range, ExceptionCode& ec) +RefPtr<Range> Internals::rangeFromLocationAndLength(Element& scope, int rangeLocation, int rangeLength) { - if (!scope || !range) { - ec = INVALID_ACCESS_ERR; - return 0; - } + return TextIterator::rangeFromLocationAndLength(&scope, rangeLocation, rangeLength); +} +unsigned Internals::locationFromRange(Element& scope, const Range& range) +{ size_t location = 0; size_t unusedLength = 0; - TextIterator::getLocationAndLengthFromRange(scope, range, location, unusedLength); + TextIterator::getLocationAndLengthFromRange(&scope, &range, location, unusedLength); return location; } -unsigned Internals::lengthFromRange(Element* scope, const Range* range, ExceptionCode& ec) +unsigned Internals::lengthFromRange(Element& scope, const Range& range) { - if (!scope || !range) { - ec = INVALID_ACCESS_ERR; - return 0; - } - size_t unusedLocation = 0; size_t length = 0; - TextIterator::getLocationAndLengthFromRange(scope, range, unusedLocation, length); + TextIterator::getLocationAndLengthFromRange(&scope, &range, unusedLocation, length); return length; } -String Internals::rangeAsText(const Range* range, ExceptionCode& ec) +String Internals::rangeAsText(const Range& range) { - if (!range) { - ec = INVALID_ACCESS_ERR; - return String(); - } + return range.text(); +} + +Ref<Range> Internals::subrange(Range& range, int rangeLocation, int rangeLength) +{ + return TextIterator::subrange(&range, rangeLocation, rangeLength); +} + +RefPtr<Range> Internals::rangeOfStringNearLocation(const Range& searchRange, const String& text, unsigned targetOffset) +{ + return findClosestPlainText(searchRange, text, 0, targetOffset); +} + +ExceptionOr<RefPtr<Range>> Internals::rangeForDictionaryLookupAtLocation(int x, int y) +{ +#if PLATFORM(MAC) + auto* document = contextDocument(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; - return range->text(); + document->updateLayoutIgnorePendingStylesheets(); + + HitTestResult result = document->frame()->mainFrame().eventHandler().hitTestResultAtPoint(IntPoint(x, y)); + NSDictionary *options = nullptr; + return DictionaryLookup::rangeAtHitTestResult(result, &options); +#else + UNUSED_PARAM(x); + UNUSED_PARAM(y); + return Exception { INVALID_ACCESS_ERR }; +#endif } -void Internals::setDelegatesScrolling(bool enabled, ExceptionCode& ec) +ExceptionOr<void> Internals::setDelegatesScrolling(bool enabled) { Document* document = contextDocument(); // Delegate scrolling is valid only on mainframe's view. - if (!document || !document->view() || !document->page() || &document->page()->mainFrame() != document->frame()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->view() || !document->page() || &document->page()->mainFrame() != document->frame()) + return Exception { INVALID_ACCESS_ERR }; document->view()->setDelegatesScrolling(enabled); + return { }; } -int Internals::lastSpellCheckRequestSequence(ExceptionCode& ec) +ExceptionOr<int> Internals::lastSpellCheckRequestSequence() { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return -1; - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; return document->frame()->editor().spellChecker().lastRequestSequence(); } -int Internals::lastSpellCheckProcessedSequence(ExceptionCode& ec) +ExceptionOr<int> Internals::lastSpellCheckProcessedSequence() { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return -1; - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; return document->frame()->editor().spellChecker().lastProcessedSequence(); } @@ -1067,63 +1558,73 @@ void Internals::setUserPreferredLanguages(const Vector<String>& languages) WebCore::overrideUserPreferredLanguages(languages); } -unsigned Internals::wheelEventHandlerCount(ExceptionCode& ec) +Vector<String> Internals::userPreferredAudioCharacteristics() const { Document* document = contextDocument(); - if (!document) { - ec = INVALID_ACCESS_ERR; - return 0; - } + if (!document || !document->page()) + return Vector<String>(); +#if ENABLE(VIDEO_TRACK) + return document->page()->group().captionPreferences().preferredAudioCharacteristics(); +#else + return Vector<String>(); +#endif +} - return document->wheelEventHandlerCount(); +void Internals::setUserPreferredAudioCharacteristic(const String& characteristic) +{ + Document* document = contextDocument(); + if (!document || !document->page()) + return; +#if ENABLE(VIDEO_TRACK) + document->page()->group().captionPreferences().setPreferredAudioCharacteristic(characteristic); +#else + UNUSED_PARAM(characteristic); +#endif } -unsigned Internals::touchEventHandlerCount(ExceptionCode& ec) +ExceptionOr<unsigned> Internals::wheelEventHandlerCount() { Document* document = contextDocument(); - if (!document) { - ec = INVALID_ACCESS_ERR; - return 0; - } + if (!document) + return Exception { INVALID_ACCESS_ERR }; - const TouchEventTargetSet* touchHandlers = document->touchEventTargets(); - if (!touchHandlers) - return 0; + return document->wheelEventHandlerCount(); +} - unsigned count = 0; - for (TouchEventTargetSet::const_iterator iter = touchHandlers->begin(); iter != touchHandlers->end(); ++iter) - count += iter->value; - return count; +ExceptionOr<unsigned> Internals::touchEventHandlerCount() +{ + Document* document = contextDocument(); + if (!document) + return Exception { INVALID_ACCESS_ERR }; + + return document->touchEventHandlerCount(); } // FIXME: Remove the document argument. It is almost always the same as // contextDocument(), with the exception of a few tests that pass a // different document, and could just make the call through another Internals // instance instead. -PassRefPtr<NodeList> Internals::nodesFromRect(Document* document, int centerX, int centerY, unsigned topPadding, unsigned rightPadding, - unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, bool allowChildFrameContent, ExceptionCode& ec) const +ExceptionOr<RefPtr<NodeList>> Internals::nodesFromRect(Document& document, int centerX, int centerY, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, bool allowChildFrameContent) const { - if (!document || !document->frame() || !document->frame()->view()) { - ec = INVALID_ACCESS_ERR; - return 0; - } + if (!document.frame() || !document.frame()->view()) + return Exception { INVALID_ACCESS_ERR }; - Frame* frame = document->frame(); - FrameView* frameView = document->view(); - RenderView* renderView = document->renderView(); + Frame* frame = document.frame(); + FrameView* frameView = document.view(); + RenderView* renderView = document.renderView(); if (!renderView) - return 0; + return nullptr; - document->updateLayoutIgnorePendingStylesheets(); + document.updateLayoutIgnorePendingStylesheets(); float zoomFactor = frame->pageZoomFactor(); - LayoutPoint point = roundedLayoutPoint(FloatPoint(centerX * zoomFactor + frameView->scrollX(), centerY * zoomFactor + frameView->scrollY())); + LayoutPoint point(centerX * zoomFactor + frameView->scrollX(), centerY * zoomFactor + frameView->scrollY()); HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active; if (ignoreClipping) hitType |= HitTestRequest::IgnoreClipping; if (!allowShadowContent) - hitType |= HitTestRequest::DisallowShadowContent; + hitType |= HitTestRequest::DisallowUserAgentShadowContent; if (allowChildFrameContent) hitType |= HitTestRequest::AllowChildFrameContent; @@ -1131,7 +1632,7 @@ PassRefPtr<NodeList> Internals::nodesFromRect(Document* document, int centerX, i // When ignoreClipping is false, this method returns null for coordinates outside of the viewport. if (!request.ignoreClipping() && !frameView->visibleContentRect().intersects(HitTestLocation::rectForPoint(point, topPadding, rightPadding, bottomPadding, leftPadding))) - return 0; + return nullptr; Vector<Ref<Node>> matches; @@ -1148,25 +1649,11 @@ PassRefPtr<NodeList> Internals::nodesFromRect(Document* document, int centerX, i const HitTestResult::NodeSet& nodeSet = result.rectBasedTestResult(); matches.reserveInitialCapacity(nodeSet.size()); - for (auto it = nodeSet.begin(), end = nodeSet.end(); it != end; ++it) - matches.uncheckedAppend(*it->get()); + for (auto& node : nodeSet) + matches.uncheckedAppend(*node); } - return StaticNodeList::adopt(matches); -} - -void Internals::emitInspectorDidBeginFrame() -{ -#if ENABLE(INSPECTOR) - contextDocument()->frame()->page()->inspectorController().didBeginFrame(); -#endif -} - -void Internals::emitInspectorDidCancelFrame() -{ -#if ENABLE(INSPECTOR) - contextDocument()->frame()->page()->inspectorController().didCancelFrame(); -#endif + return RefPtr<NodeList> { StaticNodeList::create(WTFMove(matches)) }; } class GetCallerCodeBlockFunctor { @@ -1177,7 +1664,7 @@ public: { } - StackVisitor::Status operator()(StackVisitor& visitor) + StackVisitor::Status operator()(StackVisitor& visitor) const { ++m_iterations; if (m_iterations < 2) @@ -1190,29 +1677,28 @@ public: CodeBlock* codeBlock() const { return m_codeBlock; } private: - int m_iterations; - CodeBlock* m_codeBlock; + mutable int m_iterations; + mutable CodeBlock* m_codeBlock; }; -String Internals::parserMetaData(Deprecated::ScriptValue value) +String Internals::parserMetaData(JSC::JSValue code) { - JSC::VM* vm = contextDocument()->vm(); - JSC::ExecState* exec = vm->topCallFrame; - JSC::JSValue code = value.jsValue(); + JSC::VM& vm = contextDocument()->vm(); + JSC::ExecState* exec = vm.topCallFrame; ScriptExecutable* executable; if (!code || code.isNull() || code.isUndefined()) { GetCallerCodeBlockFunctor iter; exec->iterate(iter); CodeBlock* codeBlock = iter.codeBlock(); - executable = codeBlock->ownerExecutable(); + executable = codeBlock->ownerScriptExecutable(); } else if (code.isFunction()) { JSFunction* funcObj = JSC::jsCast<JSFunction*>(code.toObject(exec)); executable = funcObj->jsExecutable(); } else return String(); - unsigned startLine = executable->lineNo(); + unsigned startLine = executable->firstLine(); unsigned startColumn = executable->startColumn(); unsigned endLine = executable->lastLine(); unsigned endColumn = executable->endColumn(); @@ -1222,102 +1708,78 @@ String Internals::parserMetaData(Deprecated::ScriptValue value) if (executable->isFunctionExecutable()) { FunctionExecutable* funcExecutable = reinterpret_cast<FunctionExecutable*>(executable); String inferredName = funcExecutable->inferredName().string(); - result.append("function \""); + result.appendLiteral("function \""); result.append(inferredName); - result.append("\""); + result.append('"'); } else if (executable->isEvalExecutable()) - result.append("eval"); - else { - ASSERT(executable->isProgramExecutable()); - result.append("program"); - } + result.appendLiteral("eval"); + else if (executable->isModuleProgramExecutable()) + result.appendLiteral("module"); + else if (executable->isProgramExecutable()) + result.appendLiteral("program"); + else + ASSERT_NOT_REACHED(); - result.append(" { "); + result.appendLiteral(" { "); result.appendNumber(startLine); - result.append(":"); + result.append(':'); result.appendNumber(startColumn); - result.append(" - "); + result.appendLiteral(" - "); result.appendNumber(endLine); - result.append(":"); + result.append(':'); result.appendNumber(endColumn); - result.append(" }"); + result.appendLiteral(" }"); return result.toString(); } -void Internals::setBatteryStatus(const String& eventType, bool charging, double chargingTime, double dischargingTime, double level, ExceptionCode& ec) -{ - Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return; - } - -#if ENABLE(BATTERY_STATUS) - BatteryController::from(document->page())->didChangeBatteryStatus(eventType, BatteryStatus::create(charging, chargingTime, dischargingTime, level)); -#else - UNUSED_PARAM(eventType); - UNUSED_PARAM(charging); - UNUSED_PARAM(chargingTime); - UNUSED_PARAM(dischargingTime); - UNUSED_PARAM(level); -#endif -} - -void Internals::setNetworkInformation(const String& eventType, double bandwidth, bool metered, ExceptionCode& ec) -{ - Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return; - } - -#if ENABLE(NETWORK_INFO) - NetworkInfoController::from(document->page())->didChangeNetworkInformation(eventType, NetworkInfo::create(bandwidth, metered)); -#else - UNUSED_PARAM(eventType); - UNUSED_PARAM(bandwidth); - UNUSED_PARAM(metered); -#endif -} - -void Internals::setDeviceProximity(const String& eventType, double value, double min, double max, ExceptionCode& ec) +ExceptionOr<void> Internals::setDeviceProximity(const String&, double value, double min, double max) { Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; #if ENABLE(PROXIMITY_EVENTS) DeviceProximityController::from(document->page())->didChangeDeviceProximity(value, min, max); #else - UNUSED_PARAM(eventType); UNUSED_PARAM(value); UNUSED_PARAM(min); UNUSED_PARAM(max); #endif + return { }; } -bool Internals::hasSpellingMarker(int from, int length, ExceptionCode&) +void Internals::updateEditorUINowIfScheduled() +{ + if (Document* document = contextDocument()) { + if (Frame* frame = document->frame()) + frame->editor().updateEditorUINowIfScheduled(); + } +} + +bool Internals::hasSpellingMarker(int from, int length) { Document* document = contextDocument(); if (!document || !document->frame()) - return 0; + return false; + + updateEditorUINowIfScheduled(); return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length); } -bool Internals::hasAutocorrectedMarker(int from, int length, ExceptionCode&) +bool Internals::hasAutocorrectedMarker(int from, int length) { Document* document = contextDocument(); if (!document || !document->frame()) - return 0; - + return false; + + updateEditorUINowIfScheduled(); + return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Autocorrected, from, length); } -void Internals::setContinuousSpellCheckingEnabled(bool enabled, ExceptionCode&) +void Internals::setContinuousSpellCheckingEnabled(bool enabled) { if (!contextDocument() || !contextDocument()->frame()) return; @@ -1326,7 +1788,7 @@ void Internals::setContinuousSpellCheckingEnabled(bool enabled, ExceptionCode&) contextDocument()->frame()->editor().toggleContinuousSpellChecking(); } -void Internals::setAutomaticQuoteSubstitutionEnabled(bool enabled, ExceptionCode&) +void Internals::setAutomaticQuoteSubstitutionEnabled(bool enabled) { if (!contextDocument() || !contextDocument()->frame()) return; @@ -1339,7 +1801,7 @@ void Internals::setAutomaticQuoteSubstitutionEnabled(bool enabled, ExceptionCode #endif } -void Internals::setAutomaticLinkDetectionEnabled(bool enabled, ExceptionCode&) +void Internals::setAutomaticLinkDetectionEnabled(bool enabled) { if (!contextDocument() || !contextDocument()->frame()) return; @@ -1352,7 +1814,7 @@ void Internals::setAutomaticLinkDetectionEnabled(bool enabled, ExceptionCode&) #endif } -void Internals::setAutomaticDashSubstitutionEnabled(bool enabled, ExceptionCode&) +void Internals::setAutomaticDashSubstitutionEnabled(bool enabled) { if (!contextDocument() || !contextDocument()->frame()) return; @@ -1365,7 +1827,7 @@ void Internals::setAutomaticDashSubstitutionEnabled(bool enabled, ExceptionCode& #endif } -void Internals::setAutomaticTextReplacementEnabled(bool enabled, ExceptionCode&) +void Internals::setAutomaticTextReplacementEnabled(bool enabled) { if (!contextDocument() || !contextDocument()->frame()) return; @@ -1378,7 +1840,7 @@ void Internals::setAutomaticTextReplacementEnabled(bool enabled, ExceptionCode&) #endif } -void Internals::setAutomaticSpellingCorrectionEnabled(bool enabled, ExceptionCode&) +void Internals::setAutomaticSpellingCorrectionEnabled(bool enabled) { if (!contextDocument() || !contextDocument()->frame()) return; @@ -1391,16 +1853,29 @@ void Internals::setAutomaticSpellingCorrectionEnabled(bool enabled, ExceptionCod #endif } -bool Internals::isOverwriteModeEnabled(ExceptionCode&) +void Internals::handleAcceptedCandidate(const String& candidate, unsigned location, unsigned length) +{ + if (!contextDocument() || !contextDocument()->frame()) + return; + + TextCheckingResult result; + result.type = TextCheckingTypeNone; + result.location = location; + result.length = length; + result.replacement = candidate; + contextDocument()->frame()->editor().handleAcceptedCandidate(result); +} + +bool Internals::isOverwriteModeEnabled() { Document* document = contextDocument(); if (!document || !document->frame()) - return 0; + return false; return document->frame()->editor().isOverwriteModeEnabled(); } -void Internals::toggleOverwriteModeEnabled(ExceptionCode&) +void Internals::toggleOverwriteModeEnabled() { Document* document = contextDocument(); if (!document || !document->frame()) @@ -1409,107 +1884,125 @@ void Internals::toggleOverwriteModeEnabled(ExceptionCode&) document->frame()->editor().toggleOverwriteModeEnabled(); } -#if ENABLE(INSPECTOR) -unsigned Internals::numberOfLiveNodes() const -{ - return InspectorCounters::counterValue(InspectorCounters::NodeCounter); -} - -unsigned Internals::numberOfLiveDocuments() const -{ - return InspectorCounters::counterValue(InspectorCounters::DocumentCounter); +static ExceptionOr<FindOptions> parseFindOptions(const Vector<String>& optionList) +{ + const struct { + const char* name; + FindOptionFlag value; + } flagList[] = { + {"CaseInsensitive", CaseInsensitive}, + {"AtWordStarts", AtWordStarts}, + {"TreatMedialCapitalAsWordStart", TreatMedialCapitalAsWordStart}, + {"Backwards", Backwards}, + {"WrapAround", WrapAround}, + {"StartInSelection", StartInSelection}, + {"DoNotRevealSelection", DoNotRevealSelection}, + {"AtWordEnds", AtWordEnds}, + {"DoNotTraverseFlatTree", DoNotTraverseFlatTree}, + }; + FindOptions result = 0; + for (auto& option : optionList) { + bool found = false; + for (auto& flag : flagList) { + if (flag.name == option) { + result |= flag.value; + found = true; + break; + } + } + if (!found) + return Exception { SYNTAX_ERR }; + } + return result; } -Vector<String> Internals::consoleMessageArgumentCounts() const +ExceptionOr<RefPtr<Range>> Internals::rangeOfString(const String& text, RefPtr<Range>&& referenceRange, const Vector<String>& findOptions) { Document* document = contextDocument(); - if (!document || !document->page()) - return Vector<String>(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; - InstrumentingAgents* instrumentingAgents = instrumentationForPage(document->page()); - if (!instrumentingAgents) - return Vector<String>(); - InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent(); - if (!consoleAgent) - return Vector<String>(); - Vector<unsigned> counts = consoleAgent->consoleMessageArgumentCounts(); - Vector<String> result(counts.size()); - for (size_t i = 0; i < counts.size(); i++) - result[i] = String::number(counts[i]); - return result; + auto parsedOptions = parseFindOptions(findOptions); + if (parsedOptions.hasException()) + return parsedOptions.releaseException(); + + return document->frame()->editor().rangeOfString(text, referenceRange.get(), parsedOptions.releaseReturnValue()); } -PassRefPtr<DOMWindow> Internals::openDummyInspectorFrontend(const String& url) +ExceptionOr<unsigned> Internals::countMatchesForText(const String& text, const Vector<String>& findOptions, const String& markMatches) { - Page* page = contextDocument()->frame()->page(); - ASSERT(page); - - DOMWindow* window = page->mainFrame().document()->domWindow(); - ASSERT(window); - - m_frontendWindow = window->open(url, "", "", *window, *window); - ASSERT(m_frontendWindow); - - Page* frontendPage = m_frontendWindow->document()->page(); - ASSERT(frontendPage); + Document* document = contextDocument(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; - auto frontendClient = std::make_unique<InspectorFrontendClientDummy>(&page->inspectorController(), frontendPage); + auto parsedOptions = parseFindOptions(findOptions); + if (parsedOptions.hasException()) + return parsedOptions.releaseException(); - frontendPage->inspectorController().setInspectorFrontendClient(std::move(frontendClient)); + bool mark = markMatches == "mark"; + return document->frame()->editor().countMatchesForText(text, nullptr, parsedOptions.releaseReturnValue(), 1000, mark, nullptr); +} - m_frontendChannel = adoptPtr(new InspectorFrontendChannelDummy(frontendPage)); +ExceptionOr<unsigned> Internals::countFindMatches(const String& text, const Vector<String>& findOptions) +{ + Document* document = contextDocument(); + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; - page->inspectorController().connectFrontend(m_frontendChannel.get()); + auto parsedOptions = parseFindOptions(findOptions); + if (parsedOptions.hasException()) + return parsedOptions.releaseException(); - return m_frontendWindow; + return document->page()->countFindMatches(text, parsedOptions.releaseReturnValue(), 1000); } -void Internals::closeDummyInspectorFrontend() +unsigned Internals::numberOfLiveNodes() const { - Page* page = contextDocument()->frame()->page(); - ASSERT(page); - ASSERT(m_frontendWindow); - - page->inspectorController().disconnectFrontend(InspectorDisconnectReason::InspectorDestroyed); + unsigned nodeCount = 0; + for (auto* document : Document::allDocuments()) + nodeCount += document->referencingNodeCount(); + return nodeCount; +} - m_frontendChannel.release(); +unsigned Internals::numberOfLiveDocuments() const +{ + return Document::allDocuments().size(); +} - m_frontendWindow->close(m_frontendWindow->scriptExecutionContext()); - m_frontendWindow.release(); +RefPtr<DOMWindow> Internals::openDummyInspectorFrontend(const String& url) +{ + auto* inspectedPage = contextDocument()->frame()->page(); + auto* window = inspectedPage->mainFrame().document()->domWindow(); + auto frontendWindow = window->open(url, "", "", *window, *window); + m_inspectorFrontend = std::make_unique<InspectorStubFrontend>(*inspectedPage, frontendWindow.copyRef()); + return frontendWindow; } -void Internals::setInspectorResourcesDataSizeLimits(int maximumResourcesContentSize, int maximumSingleResourceContentSize, ExceptionCode& ec) +void Internals::closeDummyInspectorFrontend() { - Page* page = contextDocument()->frame()->page(); - if (!page) { - ec = INVALID_ACCESS_ERR; - return; - } - page->inspectorController().setResourcesDataSizeLimitsFromInternals(maximumResourcesContentSize, maximumSingleResourceContentSize); + m_inspectorFrontend = nullptr; } -void Internals::setJavaScriptProfilingEnabled(bool enabled, ExceptionCode& ec) +ExceptionOr<void> Internals::setInspectorIsUnderTest(bool isUnderTest) { Page* page = contextDocument()->frame()->page(); - if (!page) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!page) + return Exception { INVALID_ACCESS_ERR }; - page->inspectorController().setProfilerEnabled(enabled); + page->inspectorController().setIsUnderTest(isUnderTest); + return { }; } -#endif // ENABLE(INSPECTOR) -bool Internals::hasGrammarMarker(int from, int length, ExceptionCode&) +bool Internals::hasGrammarMarker(int from, int length) { Document* document = contextDocument(); if (!document || !document->frame()) - return 0; + return false; return document->frame()->editor().selectionStartHasMarkerFor(DocumentMarker::Grammar, from, length); } -unsigned Internals::numberOfScrollableAreas(ExceptionCode&) +unsigned Internals::numberOfScrollableAreas() { Document* document = contextDocument(); if (!document || !document->frame()) @@ -1528,66 +2021,60 @@ unsigned Internals::numberOfScrollableAreas(ExceptionCode&) return count; } -bool Internals::isPageBoxVisible(int pageNumber, ExceptionCode& ec) +ExceptionOr<bool> Internals::isPageBoxVisible(int pageNumber) { Document* document = contextDocument(); - if (!document) { - ec = INVALID_ACCESS_ERR; - return false; - } + if (!document) + return Exception { INVALID_ACCESS_ERR }; return document->isPageBoxVisible(pageNumber); } -// FIXME: Remove the document argument. It is almost always the same as -// contextDocument(), with the exception of a few tests that pass a -// different document, and could just make the call through another Internals -// instance instead. -String Internals::layerTreeAsText(Document* document, ExceptionCode& ec) const +static LayerTreeFlags toLayerTreeFlags(unsigned short flags) { - return layerTreeAsText(document, 0, ec); -} - -String Internals::layerTreeAsText(Document* document, unsigned flags, ExceptionCode& ec) const -{ - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return String(); - } - LayerTreeFlags layerTreeFlags = 0; - if (flags & LAYER_TREE_INCLUDES_VISIBLE_RECTS) + if (flags & Internals::LAYER_TREE_INCLUDES_VISIBLE_RECTS) layerTreeFlags |= LayerTreeFlagsIncludeVisibleRects; - if (flags & LAYER_TREE_INCLUDES_TILE_CACHES) + if (flags & Internals::LAYER_TREE_INCLUDES_TILE_CACHES) layerTreeFlags |= LayerTreeFlagsIncludeTileCaches; - if (flags & LAYER_TREE_INCLUDES_REPAINT_RECTS) + if (flags & Internals::LAYER_TREE_INCLUDES_REPAINT_RECTS) layerTreeFlags |= LayerTreeFlagsIncludeRepaintRects; - if (flags & LAYER_TREE_INCLUDES_PAINTING_PHASES) + if (flags & Internals::LAYER_TREE_INCLUDES_PAINTING_PHASES) layerTreeFlags |= LayerTreeFlagsIncludePaintingPhases; - if (flags & LAYER_TREE_INCLUDES_CONTENT_LAYERS) + if (flags & Internals::LAYER_TREE_INCLUDES_CONTENT_LAYERS) layerTreeFlags |= LayerTreeFlagsIncludeContentLayers; + if (flags & Internals::LAYER_TREE_INCLUDES_ACCELERATES_DRAWING) + layerTreeFlags |= LayerTreeFlagsIncludeAcceleratesDrawing; - return document->frame()->layerTreeAsText(layerTreeFlags); + return layerTreeFlags; } -String Internals::repaintRectsAsText(ExceptionCode& ec) const +// FIXME: Remove the document argument. It is almost always the same as +// contextDocument(), with the exception of a few tests that pass a +// different document, and could just make the call through another Internals +// instance instead. +ExceptionOr<String> Internals::layerTreeAsText(Document& document, unsigned short flags) const +{ + if (!document.frame()) + return Exception { INVALID_ACCESS_ERR }; + + return document.frame()->layerTreeAsText(toLayerTreeFlags(flags)); +} + +ExceptionOr<String> Internals::repaintRectsAsText() const { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return String(); - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; return document->frame()->trackedRepaintRectsAsText(); } -String Internals::scrollingStateTreeAsText(ExceptionCode& ec) const +ExceptionOr<String> Internals::scrollingStateTreeAsText() const { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return String(); - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; Page* page = document->page(); if (!page) @@ -1596,13 +2083,11 @@ String Internals::scrollingStateTreeAsText(ExceptionCode& ec) const return page->scrollingStateTreeAsText(); } -String Internals::mainThreadScrollingReasons(ExceptionCode& ec) const +ExceptionOr<String> Internals::mainThreadScrollingReasons() const { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return String(); - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; Page* page = document->page(); if (!page) @@ -1611,143 +2096,285 @@ String Internals::mainThreadScrollingReasons(ExceptionCode& ec) const return page->synchronousScrollingReasonsAsText(); } -PassRefPtr<ClientRectList> Internals::nonFastScrollableRects(ExceptionCode& ec) const +ExceptionOr<RefPtr<ClientRectList>> Internals::nonFastScrollableRects() const { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return 0; - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; Page* page = document->page(); if (!page) - return 0; + return nullptr; - return page->nonFastScrollableRects(document->frame()); + return RefPtr<ClientRectList> { page->nonFastScrollableRects() }; } -void Internals::garbageCollectDocumentResources(ExceptionCode& ec) const +ExceptionOr<void> Internals::setElementUsesDisplayListDrawing(Element& element, bool usesDisplayListDrawing) { Document* document = contextDocument(); - if (!document) { - ec = INVALID_ACCESS_ERR; - return; + if (!document || !document->renderView()) + return Exception { INVALID_ACCESS_ERR }; + + if (!element.renderer()) + return Exception { INVALID_ACCESS_ERR }; + + if (is<HTMLCanvasElement>(element)) { + downcast<HTMLCanvasElement>(element).setUsesDisplayListDrawing(usesDisplayListDrawing); + return { }; } - CachedResourceLoader* cachedResourceLoader = document->cachedResourceLoader(); - if (!cachedResourceLoader) - return; - cachedResourceLoader->garbageCollectDocumentResources(); + if (!element.renderer()->hasLayer()) + return Exception { INVALID_ACCESS_ERR }; + + RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer(); + if (!layer->isComposited()) + return Exception { INVALID_ACCESS_ERR }; + + layer->backing()->setUsesDisplayListDrawing(usesDisplayListDrawing); + return { }; } -void Internals::allowRoundingHacks() const +ExceptionOr<void> Internals::setElementTracksDisplayListReplay(Element& element, bool isTrackingReplay) { - TextRun::setAllowsRoundingHacks(true); + Document* document = contextDocument(); + if (!document || !document->renderView()) + return Exception { INVALID_ACCESS_ERR }; + + if (!element.renderer()) + return Exception { INVALID_ACCESS_ERR }; + + if (is<HTMLCanvasElement>(element)) { + downcast<HTMLCanvasElement>(element).setTracksDisplayListReplay(isTrackingReplay); + return { }; + } + + if (!element.renderer()->hasLayer()) + return Exception { INVALID_ACCESS_ERR }; + + RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer(); + if (!layer->isComposited()) + return Exception { INVALID_ACCESS_ERR }; + + layer->backing()->setIsTrackingDisplayListReplay(isTrackingReplay); + return { }; } -void Internals::insertAuthorCSS(const String& css, ExceptionCode& ec) const +ExceptionOr<String> Internals::displayListForElement(Element& element, unsigned short flags) { Document* document = contextDocument(); - if (!document) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->renderView()) + return Exception { INVALID_ACCESS_ERR }; + + if (!element.renderer()) + return Exception { INVALID_ACCESS_ERR }; + + DisplayList::AsTextFlags displayListFlags = 0; + if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS) + displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations; + + if (is<HTMLCanvasElement>(element)) + return downcast<HTMLCanvasElement>(element).displayListAsText(displayListFlags); + + if (!element.renderer()->hasLayer()) + return Exception { INVALID_ACCESS_ERR }; + + RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer(); + if (!layer->isComposited()) + return Exception { INVALID_ACCESS_ERR }; + + return layer->backing()->displayListAsText(displayListFlags); +} + +ExceptionOr<String> Internals::replayDisplayListForElement(Element& element, unsigned short flags) +{ + Document* document = contextDocument(); + if (!document || !document->renderView()) + return Exception { INVALID_ACCESS_ERR }; + + if (!element.renderer()) + return Exception { INVALID_ACCESS_ERR }; + + DisplayList::AsTextFlags displayListFlags = 0; + if (flags & DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS) + displayListFlags |= DisplayList::AsTextFlag::IncludesPlatformOperations; + + if (is<HTMLCanvasElement>(element)) + return downcast<HTMLCanvasElement>(element).replayDisplayListAsText(displayListFlags); + + if (!element.renderer()->hasLayer()) + return Exception { INVALID_ACCESS_ERR }; + + RenderLayer* layer = downcast<RenderLayerModelObject>(element.renderer())->layer(); + if (!layer->isComposited()) + return Exception { INVALID_ACCESS_ERR }; + + return layer->backing()->replayDisplayListAsText(displayListFlags); +} + +ExceptionOr<void> Internals::garbageCollectDocumentResources() const +{ + Document* document = contextDocument(); + if (!document) + return Exception { INVALID_ACCESS_ERR }; + document->cachedResourceLoader().garbageCollectDocumentResources(); + return { }; +} + +bool Internals::isUnderMemoryPressure() +{ + return MemoryPressureHandler::singleton().isUnderMemoryPressure(); +} + +void Internals::beginSimulatedMemoryPressure() +{ + MemoryPressureHandler::singleton().beginSimulatedMemoryPressure(); +} + +void Internals::endSimulatedMemoryPressure() +{ + MemoryPressureHandler::singleton().endSimulatedMemoryPressure(); +} + +ExceptionOr<void> Internals::insertAuthorCSS(const String& css) const +{ + Document* document = contextDocument(); + if (!document) + return Exception { INVALID_ACCESS_ERR }; auto parsedSheet = StyleSheetContents::create(*document); parsedSheet.get().setIsUserStyleSheet(false); parsedSheet.get().parseString(css); - document->styleSheetCollection().addAuthorSheet(std::move(parsedSheet)); + document->extensionStyleSheets().addAuthorStyleSheetForTesting(WTFMove(parsedSheet)); + return { }; } -void Internals::insertUserCSS(const String& css, ExceptionCode& ec) const +ExceptionOr<void> Internals::insertUserCSS(const String& css) const { Document* document = contextDocument(); - if (!document) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document) + return Exception { INVALID_ACCESS_ERR }; auto parsedSheet = StyleSheetContents::create(*document); parsedSheet.get().setIsUserStyleSheet(true); parsedSheet.get().parseString(css); - document->styleSheetCollection().addUserSheet(std::move(parsedSheet)); + document->extensionStyleSheets().addUserStyleSheet(WTFMove(parsedSheet)); + return { }; } -String Internals::counterValue(Element* element) +String Internals::counterValue(Element& element) { - if (!element) - return String(); + return counterValueForElement(&element); +} - return counterValueForElement(element); +int Internals::pageNumber(Element& element, float pageWidth, float pageHeight) +{ + return PrintContext::pageNumberForElement(&element, { pageWidth, pageHeight }); } -int Internals::pageNumber(Element* element, float pageWidth, float pageHeight) +Vector<String> Internals::shortcutIconURLs() const { - if (!element) - return 0; + Vector<String> vector; - return PrintContext::pageNumberForElement(element, FloatSize(pageWidth, pageHeight)); + if (!frame()) + return vector; + + auto string = frame()->loader().icon().url().string(); + if (!string.isNull()) + vector.append(string); + return vector; } -Vector<String> Internals::iconURLs(Document* document, int iconTypesMask) const +int Internals::numberOfPages(float pageWidth, float pageHeight) { - Vector<IconURL> iconURLs = document->iconURLs(iconTypesMask); - Vector<String> array; + if (!frame()) + return -1; + + return PrintContext::numberOfPages(*frame(), FloatSize(pageWidth, pageHeight)); +} - Vector<IconURL>::const_iterator iter(iconURLs.begin()); - for (; iter != iconURLs.end(); ++iter) - array.append(iter->m_iconURL.string()); +ExceptionOr<String> Internals::pageProperty(const String& propertyName, int pageNumber) const +{ + if (!frame()) + return Exception { INVALID_ACCESS_ERR }; - return array; + return PrintContext::pageProperty(frame(), propertyName.utf8().data(), pageNumber); } -Vector<String> Internals::shortcutIconURLs() const +ExceptionOr<String> Internals::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const { - return iconURLs(contextDocument(), Favicon); + if (!frame()) + return Exception { INVALID_ACCESS_ERR }; + + return PrintContext::pageSizeAndMarginsInPixels(frame(), pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft); } -Vector<String> Internals::allIconURLs() const +ExceptionOr<float> Internals::pageScaleFactor() const { - return iconURLs(contextDocument(), Favicon | TouchIcon | TouchPrecomposedIcon); + Document* document = contextDocument(); + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; + + return document->page()->pageScaleFactor(); } -int Internals::numberOfPages(float pageWidth, float pageHeight) +ExceptionOr<void> Internals::setPageScaleFactor(float scaleFactor, int x, int y) { - if (!frame()) - return -1; + Document* document = contextDocument(); + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; - return PrintContext::numberOfPages(frame(), FloatSize(pageWidth, pageHeight)); + document->page()->setPageScaleFactor(scaleFactor, IntPoint(x, y)); + return { }; } -String Internals::pageProperty(String propertyName, int pageNumber, ExceptionCode& ec) const +ExceptionOr<void> Internals::setPageZoomFactor(float zoomFactor) { - if (!frame()) { - ec = INVALID_ACCESS_ERR; - return String(); - } + Document* document = contextDocument(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; - return PrintContext::pageProperty(frame(), propertyName.utf8().data(), pageNumber); + document->frame()->setPageZoomFactor(zoomFactor); + return { }; } -String Internals::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft, ExceptionCode& ec) const +ExceptionOr<void> Internals::setTextZoomFactor(float zoomFactor) { - if (!frame()) { - ec = INVALID_ACCESS_ERR; - return String(); - } + Document* document = contextDocument(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; - return PrintContext::pageSizeAndMarginsInPixels(frame(), pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft); + document->frame()->setTextZoomFactor(zoomFactor); + return { }; } -void Internals::setPageScaleFactor(float scaleFactor, int x, int y, ExceptionCode& ec) +ExceptionOr<void> Internals::setUseFixedLayout(bool useFixedLayout) { Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return; - } - Page* page = document->page(); - page->setPageScaleFactor(scaleFactor, IntPoint(x, y)); + if (!document || !document->view()) + return Exception { INVALID_ACCESS_ERR }; + + document->view()->setUseFixedLayout(useFixedLayout); + return { }; +} + +ExceptionOr<void> Internals::setFixedLayoutSize(int width, int height) +{ + Document* document = contextDocument(); + if (!document || !document->view()) + return Exception { INVALID_ACCESS_ERR }; + + document->view()->setFixedLayoutSize(IntSize(width, height)); + return { }; +} + +ExceptionOr<void> Internals::setViewExposedRect(float x, float y, float width, float height) +{ + Document* document = contextDocument(); + if (!document || !document->view()) + return Exception { INVALID_ACCESS_ERR }; + + document->view()->setViewExposedRect(FloatRect(x, y, width, height)); + return { }; } void Internals::setHeaderHeight(float height) @@ -1755,12 +2382,8 @@ void Internals::setHeaderHeight(float height) Document* document = contextDocument(); if (!document || !document->view()) return; -#if USE(ACCELERATED_COMPOSITING) - FrameView* frameView = document->view(); - frameView->setHeaderHeight(height); -#else - UNUSED_PARAM(height); -#endif + + document->view()->setHeaderHeight(height); } void Internals::setFooterHeight(float height) @@ -1768,52 +2391,61 @@ void Internals::setFooterHeight(float height) Document* document = contextDocument(); if (!document || !document->view()) return; -#if USE(ACCELERATED_COMPOSITING) - FrameView* frameView = document->view(); - frameView->setFooterHeight(height); -#endif + + document->view()->setFooterHeight(height); +} + +void Internals::setTopContentInset(float contentInset) +{ + Document* document = contextDocument(); + if (!document || !document->page()) + return; + + document->page()->setTopContentInset(contentInset); } #if ENABLE(FULLSCREEN_API) -void Internals::webkitWillEnterFullScreenForElement(Element* element) + +void Internals::webkitWillEnterFullScreenForElement(Element& element) { Document* document = contextDocument(); if (!document) return; - document->webkitWillEnterFullScreenForElement(element); + document->webkitWillEnterFullScreenForElement(&element); } -void Internals::webkitDidEnterFullScreenForElement(Element* element) +void Internals::webkitDidEnterFullScreenForElement(Element& element) { Document* document = contextDocument(); if (!document) return; - document->webkitDidEnterFullScreenForElement(element); + document->webkitDidEnterFullScreenForElement(&element); } -void Internals::webkitWillExitFullScreenForElement(Element* element) +void Internals::webkitWillExitFullScreenForElement(Element& element) { Document* document = contextDocument(); if (!document) return; - document->webkitWillExitFullScreenForElement(element); + document->webkitWillExitFullScreenForElement(&element); } -void Internals::webkitDidExitFullScreenForElement(Element* element) +void Internals::webkitDidExitFullScreenForElement(Element& element) { Document* document = contextDocument(); if (!document) return; - document->webkitDidExitFullScreenForElement(element); + document->webkitDidExitFullScreenForElement(&element); } + #endif void Internals::setApplicationCacheOriginQuota(unsigned long long quota) { Document* document = contextDocument(); - if (!document) + if (!document || !document->page()) return; - cacheStorage().storeUpdatedQuotaForOrigin(document->securityOrigin(), quota); + document->page()->applicationCacheStorage().storeUpdatedQuotaForOrigin(&document->securityOrigin(), quota); } void Internals::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme) @@ -1826,17 +2458,22 @@ void Internals::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(const SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(scheme); } -PassRefPtr<MallocStatistics> Internals::mallocStatistics() const +void Internals::registerDefaultPortForProtocol(unsigned short port, const String& protocol) +{ + registerDefaultPortForProtocolForTesting(port, protocol); +} + +Ref<MallocStatistics> Internals::mallocStatistics() const { return MallocStatistics::create(); } -PassRefPtr<TypeConversions> Internals::typeConversions() const +Ref<TypeConversions> Internals::typeConversions() const { return TypeConversions::create(); } -PassRefPtr<MemoryInfo> Internals::memoryInfo() const +Ref<MemoryInfo> Internals::memoryInfo() const { return MemoryInfo::create(); } @@ -1847,50 +2484,113 @@ Vector<String> Internals::getReferencedFilePaths() const return FormController::getReferencedFilePaths(frame()->loader().history().currentItem()->documentState()); } -void Internals::startTrackingRepaints(ExceptionCode& ec) +ExceptionOr<void> Internals::startTrackingRepaints() { Document* document = contextDocument(); - if (!document || !document->view()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->view()) + return Exception { INVALID_ACCESS_ERR }; - FrameView* frameView = document->view(); - frameView->setTracksRepaints(true); + document->view()->setTracksRepaints(true); + return { }; } -void Internals::stopTrackingRepaints(ExceptionCode& ec) +ExceptionOr<void> Internals::stopTrackingRepaints() { Document* document = contextDocument(); - if (!document || !document->view()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->view()) + return Exception { INVALID_ACCESS_ERR }; + + document->view()->setTracksRepaints(false); + return { }; +} + +ExceptionOr<void> Internals::startTrackingLayerFlushes() +{ + Document* document = contextDocument(); + if (!document || !document->renderView()) + return Exception { INVALID_ACCESS_ERR }; + + document->renderView()->compositor().startTrackingLayerFlushes(); + return { }; +} - FrameView* frameView = document->view(); - frameView->setTracksRepaints(false); +ExceptionOr<unsigned> Internals::layerFlushCount() +{ + Document* document = contextDocument(); + if (!document || !document->renderView()) + return Exception { INVALID_ACCESS_ERR }; + + return document->renderView()->compositor().layerFlushCount(); } -void Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(ExceptionCode& ec) +ExceptionOr<void> Internals::startTrackingStyleRecalcs() { - updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(nullptr, ec); + Document* document = contextDocument(); + if (!document) + return Exception { INVALID_ACCESS_ERR }; + + document->startTrackingStyleRecalcs(); + return { }; } -void Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node* node, ExceptionCode& ec) +ExceptionOr<unsigned> Internals::styleRecalcCount() +{ + Document* document = contextDocument(); + if (!document) + return Exception { INVALID_ACCESS_ERR }; + + return document->styleRecalcCount(); +} + +unsigned Internals::lastStyleUpdateSize() const +{ + Document* document = contextDocument(); + if (!document) + return 0; + return document->lastStyleUpdateSizeForTesting(); +} + +ExceptionOr<void> Internals::startTrackingCompositingUpdates() +{ + Document* document = contextDocument(); + if (!document || !document->renderView()) + return Exception { INVALID_ACCESS_ERR }; + + document->renderView()->compositor().startTrackingCompositingUpdates(); + return { }; +} + +ExceptionOr<unsigned> Internals::compositingUpdateCount() +{ + Document* document = contextDocument(); + if (!document || !document->renderView()) + return Exception { INVALID_ACCESS_ERR }; + + return document->renderView()->compositor().compositingUpdateCount(); +} + +ExceptionOr<void> Internals::updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node* node) { Document* document; if (!node) document = contextDocument(); - else if (node->isDocumentNode()) - document = toDocument(node); - else if (node->hasTagName(HTMLNames::iframeTag)) - document = toHTMLIFrameElement(node)->contentDocument(); - else { - ec = TypeError; - return; - } + else if (is<Document>(*node)) + document = downcast<Document>(node); + else if (is<HTMLIFrameElement>(*node)) + document = downcast<HTMLIFrameElement>(*node).contentDocument(); + else + return Exception { TypeError }; - document->updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasksSynchronously); + document->updateLayoutIgnorePendingStylesheets(Document::RunPostLayoutTasks::Synchronously); + return { }; +} + +unsigned Internals::layoutCount() const +{ + Document* document = contextDocument(); + if (!document || !document->view()) + return 0; + return document->view()->layoutCount(); } #if !PLATFORM(IOS) @@ -1948,55 +2648,59 @@ static const char* cursorTypeToString(Cursor::Type cursorType) } #endif -String Internals::getCurrentCursorInfo(ExceptionCode& ec) +ExceptionOr<String> Internals::getCurrentCursorInfo() { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return String(); - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; #if !PLATFORM(IOS) Cursor cursor = document->frame()->eventHandler().currentMouseCursor(); StringBuilder result; - result.append("type="); + result.appendLiteral("type="); result.append(cursorTypeToString(cursor.type())); - result.append(" hotSpot="); + result.appendLiteral(" hotSpot="); result.appendNumber(cursor.hotSpot().x()); - result.append(","); + result.append(','); result.appendNumber(cursor.hotSpot().y()); if (cursor.image()) { - IntSize size = cursor.image()->size(); - result.append(" image="); + FloatSize size = cursor.image()->size(); + result.appendLiteral(" image="); result.appendNumber(size.width()); - result.append("x"); + result.append('x'); result.appendNumber(size.height()); } #if ENABLE(MOUSE_CURSOR_SCALE) if (cursor.imageScaleFactor() != 1) { - result.append(" scale="); + result.appendLiteral(" scale="); NumberToStringBuffer buffer; result.append(numberToFixedPrecisionString(cursor.imageScaleFactor(), 8, buffer, true)); } #endif return result.toString(); #else - return "FAIL: Cursor details not available on this platform."; + return String { "FAIL: Cursor details not available on this platform." }; #endif } -PassRefPtr<ArrayBuffer> Internals::serializeObject(PassRefPtr<SerializedScriptValue> value) const +Ref<ArrayBuffer> Internals::serializeObject(const RefPtr<SerializedScriptValue>& value) const { - Vector<uint8_t> bytes = value->data(); + auto& bytes = value->data(); return ArrayBuffer::create(bytes.data(), bytes.size()); } -PassRefPtr<SerializedScriptValue> Internals::deserializeBuffer(PassRefPtr<ArrayBuffer> buffer) const +Ref<SerializedScriptValue> Internals::deserializeBuffer(ArrayBuffer& buffer) const { Vector<uint8_t> bytes; - bytes.append(static_cast<const uint8_t*>(buffer->data()), buffer->byteLength()); - return SerializedScriptValue::adopt(bytes); + bytes.append(static_cast<const uint8_t*>(buffer.data()), buffer.byteLength()); + return SerializedScriptValue::adopt(WTFMove(bytes)); +} + +bool Internals::isFromCurrentWorld(JSC::JSValue value) const +{ + auto& state = *contextDocument()->vm().topCallFrame; + return !value.isObject() || &worldForDOMObject(asObject(value)) == ¤tWorld(&state); } void Internals::setUsesOverlayScrollbars(bool enabled) @@ -2004,247 +2708,1008 @@ void Internals::setUsesOverlayScrollbars(bool enabled) WebCore::Settings::setUsesOverlayScrollbars(enabled); } +void Internals::setUsesMockScrollAnimator(bool enabled) +{ + WebCore::Settings::setUsesMockScrollAnimator(enabled); +} + void Internals::forceReload(bool endToEnd) { frame()->loader().reload(endToEnd); } -#if ENABLE(ENCRYPTED_MEDIA_V2) +void Internals::enableAutoSizeMode(bool enabled, int minimumWidth, int minimumHeight, int maximumWidth, int maximumHeight) +{ + auto* document = contextDocument(); + if (!document || !document->view()) + return; + document->view()->enableAutoSizeMode(enabled, IntSize(minimumWidth, minimumHeight), IntSize(maximumWidth, maximumHeight)); +} + +#if ENABLE(LEGACY_ENCRYPTED_MEDIA) + void Internals::initializeMockCDM() { - CDM::registerCDMFactory(MockCDM::create, MockCDM::supportsKeySystem, MockCDM::supportsKeySystemAndMimeType); + CDM::registerCDMFactory([] (CDM* cdm) { return std::make_unique<MockCDM>(cdm); }, + MockCDM::supportsKeySystem, MockCDM::supportsKeySystemAndMimeType); } + #endif -String Internals::markerTextForListItem(Element* element, ExceptionCode& ec) +#if ENABLE(ENCRYPTED_MEDIA) + +Ref<MockCDMFactory> Internals::registerMockCDM() { - if (!element) { - ec = INVALID_ACCESS_ERR; - return String(); - } - return WebCore::markerTextForListItem(element); + return MockCDMFactory::create(); } -String Internals::getImageSourceURL(Element* element, ExceptionCode& ec) +#endif + +String Internals::markerTextForListItem(Element& element) { - if (!element) { - ec = INVALID_ACCESS_ERR; - return String(); - } - return element->imageSourceURL(); + return WebCore::markerTextForListItem(&element); +} + +String Internals::toolTipFromElement(Element& element) const +{ + HitTestResult result; + result.setInnerNode(&element); + TextDirection direction; + return result.title(direction); +} + +String Internals::getImageSourceURL(Element& element) +{ + return element.imageSourceURL(); } #if ENABLE(VIDEO) -void Internals::simulateAudioInterruption(Node* node) + +void Internals::simulateAudioInterruption(HTMLMediaElement& element) { #if USE(GSTREAMER) - HTMLMediaElement* element = toHTMLMediaElement(node); - element->player()->simulateAudioInterruption(); + element.player()->simulateAudioInterruption(); #else - UNUSED_PARAM(node); + UNUSED_PARAM(element); #endif } -#endif -bool Internals::isSelectPopupVisible(Node* node) +ExceptionOr<bool> Internals::mediaElementHasCharacteristic(HTMLMediaElement& element, const String& characteristic) { - if (!isHTMLSelectElement(node)) - return false; + if (equalLettersIgnoringASCIICase(characteristic, "audible")) + return element.hasAudio(); + if (equalLettersIgnoringASCIICase(characteristic, "visual")) + return element.hasVideo(); + if (equalLettersIgnoringASCIICase(characteristic, "legible")) + return element.hasClosedCaptions(); + + return Exception { SYNTAX_ERR }; +} - HTMLSelectElement* select = toHTMLSelectElement(node); +#endif - auto renderer = select->renderer(); - if (!renderer->isMenuList()) +bool Internals::isSelectPopupVisible(HTMLSelectElement& element) +{ + auto* renderer = element.renderer(); + ASSERT(renderer); + if (!is<RenderMenuList>(*renderer)) return false; #if !PLATFORM(IOS) - RenderMenuList* menuList = toRenderMenuList(renderer); - return menuList->popupIsVisible(); + return downcast<RenderMenuList>(*renderer).popupIsVisible(); #else return false; -#endif // !PLATFORM(IOS) +#endif } -String Internals::captionsStyleSheetOverride(ExceptionCode& ec) +ExceptionOr<String> Internals::captionsStyleSheetOverride() { Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return emptyString(); - } + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; -#if ENABLE(VIDEO_TRACK) && !PLATFORM(WIN) - return document->page()->group().captionPreferences()->captionsStyleSheetOverride(); +#if ENABLE(VIDEO_TRACK) + return document->page()->group().captionPreferences().captionsStyleSheetOverride(); #else - return emptyString(); + return String { emptyString() }; #endif } -void Internals::setCaptionsStyleSheetOverride(const String& override, ExceptionCode& ec) +ExceptionOr<void> Internals::setCaptionsStyleSheetOverride(const String& override) { Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; -#if ENABLE(VIDEO_TRACK) && !PLATFORM(WIN) - document->page()->group().captionPreferences()->setCaptionsStyleSheetOverride(override); +#if ENABLE(VIDEO_TRACK) + document->page()->group().captionPreferences().setCaptionsStyleSheetOverride(override); #else UNUSED_PARAM(override); #endif + return { }; } -void Internals::setPrimaryAudioTrackLanguageOverride(const String& language, ExceptionCode& ec) +ExceptionOr<void> Internals::setPrimaryAudioTrackLanguageOverride(const String& language) { Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; -#if ENABLE(VIDEO_TRACK) && !PLATFORM(WIN) - document->page()->group().captionPreferences()->setPrimaryAudioTrackLanguageOverride(language); +#if ENABLE(VIDEO_TRACK) + document->page()->group().captionPreferences().setPrimaryAudioTrackLanguageOverride(language); #else UNUSED_PARAM(language); #endif + return { }; } -void Internals::setCaptionDisplayMode(const String& mode, ExceptionCode& ec) +ExceptionOr<void> Internals::setCaptionDisplayMode(const String& mode) { Document* document = contextDocument(); - if (!document || !document->page()) { - ec = INVALID_ACCESS_ERR; - return; - } + if (!document || !document->page()) + return Exception { INVALID_ACCESS_ERR }; -#if ENABLE(VIDEO_TRACK) && !PLATFORM(WIN) - CaptionUserPreferences* captionPreferences = document->page()->group().captionPreferences(); +#if ENABLE(VIDEO_TRACK) + auto& captionPreferences = document->page()->group().captionPreferences(); - if (equalIgnoringCase(mode, "Automatic")) - captionPreferences->setCaptionDisplayMode(CaptionUserPreferences::Automatic); - else if (equalIgnoringCase(mode, "ForcedOnly")) - captionPreferences->setCaptionDisplayMode(CaptionUserPreferences::ForcedOnly); - else if (equalIgnoringCase(mode, "AlwaysOn")) - captionPreferences->setCaptionDisplayMode(CaptionUserPreferences::AlwaysOn); + if (equalLettersIgnoringASCIICase(mode, "automatic")) + captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::Automatic); + else if (equalLettersIgnoringASCIICase(mode, "forcedonly")) + captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::ForcedOnly); + else if (equalLettersIgnoringASCIICase(mode, "alwayson")) + captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::AlwaysOn); + else if (equalLettersIgnoringASCIICase(mode, "manual")) + captionPreferences.setCaptionDisplayMode(CaptionUserPreferences::Manual); else - ec = SYNTAX_ERR; + return Exception { SYNTAX_ERR }; #else UNUSED_PARAM(mode); #endif + return { }; } #if ENABLE(VIDEO) -PassRefPtr<TimeRanges> Internals::createTimeRanges(Float32Array* startTimes, Float32Array* endTimes) + +Ref<TimeRanges> Internals::createTimeRanges(Float32Array& startTimes, Float32Array& endTimes) { - ASSERT(startTimes && endTimes); - ASSERT(startTimes->length() == endTimes->length()); - RefPtr<TimeRanges> ranges = TimeRanges::create(); + ASSERT(startTimes.length() == endTimes.length()); + Ref<TimeRanges> ranges = TimeRanges::create(); - unsigned count = std::min(startTimes->length(), endTimes->length()); + unsigned count = std::min(startTimes.length(), endTimes.length()); for (unsigned i = 0; i < count; ++i) - ranges->add(startTimes->item(i), endTimes->item(i)); + ranges->add(startTimes.item(i), endTimes.item(i)); return ranges; } -double Internals::closestTimeToTimeRanges(double time, TimeRanges* ranges) +double Internals::closestTimeToTimeRanges(double time, TimeRanges& ranges) { - return ranges->nearest(time); + return ranges.nearest(time); } + #endif -PassRefPtr<ClientRect> Internals::selectionBounds(ExceptionCode& ec) +ExceptionOr<Ref<ClientRect>> Internals::selectionBounds() { Document* document = contextDocument(); - if (!document || !document->frame()) { - ec = INVALID_ACCESS_ERR; - return ClientRect::create(); - } + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; - return ClientRect::create(document->frame()->selection().bounds()); + return ClientRect::create(document->frame()->selection().selectionBounds()); } #if ENABLE(VIBRATION) + bool Internals::isVibrating() { - Page* page = contextDocument()->page(); - ASSERT(page); - - return Vibration::from(page)->isVibrating(); + auto* document = contextDocument(); + auto* page = document ? document->page() : nullptr; + return page && Vibration::from(page)->isVibrating(); } + #endif -bool Internals::isPluginUnavailabilityIndicatorObscured(Element* element, ExceptionCode& ec) +ExceptionOr<bool> Internals::isPluginUnavailabilityIndicatorObscured(Element& element) { - if (!element) { - ec = INVALID_ACCESS_ERR; - return false; - } - - auto renderer = element->renderer(); - if (!renderer || !renderer->isEmbeddedObject()) { - ec = INVALID_ACCESS_ERR; - return false; - } + auto* renderer = element.renderer(); + if (!is<RenderEmbeddedObject>(renderer)) + return Exception { INVALID_ACCESS_ERR }; - RenderEmbeddedObject* embed = toRenderEmbeddedObject(renderer); - return embed->isReplacementObscured(); + return downcast<RenderEmbeddedObject>(*renderer).isReplacementObscured(); } - + +bool Internals::isPluginSnapshotted(Element& element) +{ + return is<HTMLPlugInElement>(element) && downcast<HTMLPlugInElement>(element).displayState() <= HTMLPlugInElement::DisplayingSnapshot; +} + #if ENABLE(MEDIA_SOURCE) + void Internals::initializeMockMediaSource() { #if USE(AVFOUNDATION) WebCore::Settings::setAVFoundationEnabled(false); #endif +#if USE(GSTREAMER) + WebCore::Settings::setGStreamerEnabled(false); +#endif MediaPlayerFactorySupport::callRegisterMediaEngine(MockMediaPlayerMediaSource::registerMediaEngine); } + +Vector<String> Internals::bufferedSamplesForTrackID(SourceBuffer& buffer, const AtomicString& trackID) +{ + return buffer.bufferedSamplesForTrackID(trackID); +} + +Vector<String> Internals::enqueuedSamplesForTrackID(SourceBuffer& buffer, const AtomicString& trackID) +{ + return buffer.enqueuedSamplesForTrackID(trackID); +} + +void Internals::setShouldGenerateTimestamps(SourceBuffer& buffer, bool flag) +{ + buffer.setShouldGenerateTimestamps(flag); +} + #endif -void Internals::beginMediaSessionInterruption() +#if ENABLE(VIDEO) + +ExceptionOr<void> Internals::beginMediaSessionInterruption(const String& interruptionString) { - MediaSessionManager::sharedManager().beginInterruption(); + PlatformMediaSession::InterruptionType interruption = PlatformMediaSession::SystemInterruption; + + if (equalLettersIgnoringASCIICase(interruptionString, "system")) + interruption = PlatformMediaSession::SystemInterruption; + else if (equalLettersIgnoringASCIICase(interruptionString, "systemsleep")) + interruption = PlatformMediaSession::SystemSleep; + else if (equalLettersIgnoringASCIICase(interruptionString, "enteringbackground")) + interruption = PlatformMediaSession::EnteringBackground; + else if (equalLettersIgnoringASCIICase(interruptionString, "suspendedunderlock")) + interruption = PlatformMediaSession::SuspendedUnderLock; + else + return Exception { INVALID_ACCESS_ERR }; + + PlatformMediaSessionManager::sharedManager().beginInterruption(interruption); + return { }; } void Internals::endMediaSessionInterruption(const String& flagsString) { - MediaSession::EndInterruptionFlags flags = MediaSession::NoFlags; + PlatformMediaSession::EndInterruptionFlags flags = PlatformMediaSession::NoFlags; - if (equalIgnoringCase(flagsString, "MayResumePlaying")) - flags = MediaSession::MayResumePlaying; + if (equalLettersIgnoringASCIICase(flagsString, "mayresumeplaying")) + flags = PlatformMediaSession::MayResumePlaying; - MediaSessionManager::sharedManager().endInterruption(flags); + PlatformMediaSessionManager::sharedManager().endInterruption(flags); +} + +void Internals::applicationDidEnterForeground() const +{ + PlatformMediaSessionManager::sharedManager().applicationDidEnterForeground(); +} + +void Internals::applicationWillEnterBackground() const +{ + PlatformMediaSessionManager::sharedManager().applicationWillEnterBackground(); +} + +static PlatformMediaSession::MediaType mediaTypeFromString(const String& mediaTypeString) +{ + if (equalLettersIgnoringASCIICase(mediaTypeString, "video")) + return PlatformMediaSession::Video; + if (equalLettersIgnoringASCIICase(mediaTypeString, "audio")) + return PlatformMediaSession::Audio; + if (equalLettersIgnoringASCIICase(mediaTypeString, "videoaudio")) + return PlatformMediaSession::VideoAudio; + if (equalLettersIgnoringASCIICase(mediaTypeString, "webaudio")) + return PlatformMediaSession::WebAudio; + + return PlatformMediaSession::None; +} + +ExceptionOr<void> Internals::setMediaSessionRestrictions(const String& mediaTypeString, const String& restrictionsString) +{ + PlatformMediaSession::MediaType mediaType = mediaTypeFromString(mediaTypeString); + if (mediaType == PlatformMediaSession::None) + return Exception { INVALID_ACCESS_ERR }; + + PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType); + PlatformMediaSessionManager::sharedManager().removeRestriction(mediaType, restrictions); + + restrictions = PlatformMediaSessionManager::NoRestrictions; + + Vector<String> restrictionsArray; + restrictionsString.split(',', false, restrictionsArray); + for (auto& restrictionString : restrictionsArray) { + if (equalLettersIgnoringASCIICase(restrictionString, "concurrentplaybacknotpermitted")) + restrictions |= PlatformMediaSessionManager::ConcurrentPlaybackNotPermitted; + if (equalLettersIgnoringASCIICase(restrictionString, "backgroundprocessplaybackrestricted")) + restrictions |= PlatformMediaSessionManager::BackgroundProcessPlaybackRestricted; + if (equalLettersIgnoringASCIICase(restrictionString, "backgroundtabplaybackrestricted")) + restrictions |= PlatformMediaSessionManager::BackgroundTabPlaybackRestricted; + if (equalLettersIgnoringASCIICase(restrictionString, "interruptedplaybacknotpermitted")) + restrictions |= PlatformMediaSessionManager::InterruptedPlaybackNotPermitted; + } + PlatformMediaSessionManager::sharedManager().addRestriction(mediaType, restrictions); + return { }; +} + +ExceptionOr<String> Internals::mediaSessionRestrictions(const String& mediaTypeString) const +{ + PlatformMediaSession::MediaType mediaType = mediaTypeFromString(mediaTypeString); + if (mediaType == PlatformMediaSession::None) + return Exception { INVALID_ACCESS_ERR }; + + PlatformMediaSessionManager::SessionRestrictions restrictions = PlatformMediaSessionManager::sharedManager().restrictions(mediaType); + if (restrictions == PlatformMediaSessionManager::NoRestrictions) + return String(); + + StringBuilder builder; + if (restrictions & PlatformMediaSessionManager::ConcurrentPlaybackNotPermitted) + builder.append("concurrentplaybacknotpermitted"); + if (restrictions & PlatformMediaSessionManager::BackgroundProcessPlaybackRestricted) { + if (!builder.isEmpty()) + builder.append(','); + builder.append("backgroundprocessplaybackrestricted"); + } + if (restrictions & PlatformMediaSessionManager::BackgroundTabPlaybackRestricted) { + if (!builder.isEmpty()) + builder.append(','); + builder.append("backgroundtabplaybackrestricted"); + } + if (restrictions & PlatformMediaSessionManager::InterruptedPlaybackNotPermitted) { + if (!builder.isEmpty()) + builder.append(','); + builder.append("interruptedplaybacknotpermitted"); + } + return builder.toString(); +} + +void Internals::setMediaElementRestrictions(HTMLMediaElement& element, const String& restrictionsString) +{ + MediaElementSession::BehaviorRestrictions restrictions = element.mediaSession().behaviorRestrictions(); + element.mediaSession().removeBehaviorRestriction(restrictions); + + restrictions = MediaElementSession::NoRestrictions; + + Vector<String> restrictionsArray; + restrictionsString.split(',', false, restrictionsArray); + for (auto& restrictionString : restrictionsArray) { + if (equalLettersIgnoringASCIICase(restrictionString, "norestrictions")) + restrictions |= MediaElementSession::NoRestrictions; + if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforload")) + restrictions |= MediaElementSession::RequireUserGestureForLoad; + if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforvideoratechange")) + restrictions |= MediaElementSession::RequireUserGestureForVideoRateChange; + if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforfullscreen")) + restrictions |= MediaElementSession::RequireUserGestureForFullscreen; + if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsenttoloadmedia")) + restrictions |= MediaElementSession::RequirePageConsentToLoadMedia; + if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsenttoresumemedia")) + restrictions |= MediaElementSession::RequirePageConsentToResumeMedia; +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + if (equalLettersIgnoringASCIICase(restrictionString, "requireusergesturetoshowplaybacktargetpicker")) + restrictions |= MediaElementSession::RequireUserGestureToShowPlaybackTargetPicker; + if (equalLettersIgnoringASCIICase(restrictionString, "wirelessvideoplaybackdisabled")) + restrictions |= MediaElementSession::WirelessVideoPlaybackDisabled; +#endif + if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforaudioratechange")) + restrictions |= MediaElementSession::RequireUserGestureForAudioRateChange; + if (equalLettersIgnoringASCIICase(restrictionString, "metadatapreloadingnotpermitted")) + restrictions |= MediaElementSession::MetadataPreloadingNotPermitted; + if (equalLettersIgnoringASCIICase(restrictionString, "autopreloadingnotpermitted")) + restrictions |= MediaElementSession::AutoPreloadingNotPermitted; + if (equalLettersIgnoringASCIICase(restrictionString, "invisibleautoplaynotpermitted")) + restrictions |= MediaElementSession::InvisibleAutoplayNotPermitted; + if (equalLettersIgnoringASCIICase(restrictionString, "overrideusergesturerequirementformaincontent")) + restrictions |= MediaElementSession::OverrideUserGestureRequirementForMainContent; + } + element.mediaSession().addBehaviorRestriction(restrictions); +} + +ExceptionOr<void> Internals::postRemoteControlCommand(const String& commandString, float argument) +{ + PlatformMediaSession::RemoteControlCommandType command; + PlatformMediaSession::RemoteCommandArgument parameter { argument }; + + if (equalLettersIgnoringASCIICase(commandString, "play")) + command = PlatformMediaSession::PlayCommand; + else if (equalLettersIgnoringASCIICase(commandString, "pause")) + command = PlatformMediaSession::PauseCommand; + else if (equalLettersIgnoringASCIICase(commandString, "stop")) + command = PlatformMediaSession::StopCommand; + else if (equalLettersIgnoringASCIICase(commandString, "toggleplaypause")) + command = PlatformMediaSession::TogglePlayPauseCommand; + else if (equalLettersIgnoringASCIICase(commandString, "beginseekingbackward")) + command = PlatformMediaSession::BeginSeekingBackwardCommand; + else if (equalLettersIgnoringASCIICase(commandString, "endseekingbackward")) + command = PlatformMediaSession::EndSeekingBackwardCommand; + else if (equalLettersIgnoringASCIICase(commandString, "beginseekingforward")) + command = PlatformMediaSession::BeginSeekingForwardCommand; + else if (equalLettersIgnoringASCIICase(commandString, "endseekingforward")) + command = PlatformMediaSession::EndSeekingForwardCommand; + else if (equalLettersIgnoringASCIICase(commandString, "seektoplaybackposition")) + command = PlatformMediaSession::SeekToPlaybackPositionCommand; + else + return Exception { INVALID_ACCESS_ERR }; + + PlatformMediaSessionManager::sharedManager().didReceiveRemoteControlCommand(command, ¶meter); + return { }; +} + +bool Internals::elementIsBlockingDisplaySleep(HTMLMediaElement& element) const +{ + return element.isDisablingSleep(); +} + +#endif // ENABLE(VIDEO) + +#if ENABLE(MEDIA_SESSION) + +void Internals::sendMediaSessionStartOfInterruptionNotification(MediaSessionInterruptingCategory category) +{ + MediaSessionManager::singleton().didReceiveStartOfInterruptionNotification(category); +} + +void Internals::sendMediaSessionEndOfInterruptionNotification(MediaSessionInterruptingCategory category) +{ + MediaSessionManager::singleton().didReceiveEndOfInterruptionNotification(category); +} + +String Internals::mediaSessionCurrentState(MediaSession* session) const +{ + switch (session->currentState()) { + case MediaSession::State::Active: + return "active"; + case MediaSession::State::Interrupted: + return "interrupted"; + case MediaSession::State::Idle: + return "idle"; + } +} + +double Internals::mediaElementPlayerVolume(HTMLMediaElement* element) const +{ + ASSERT_ARG(element, element); + return element->playerVolume(); +} + +void Internals::sendMediaControlEvent(MediaControlEvent event) +{ + // FIXME: No good reason to use a single function with an argument instead of three functions. + switch (event) { + case MediControlEvent::PlayPause: + MediaSessionManager::singleton().togglePlayback(); + break; + case MediControlEvent::NextTrack: + MediaSessionManager::singleton().skipToNextTrack(); + break; + case MediControlEvent::PreviousTrack: + MediaSessionManager::singleton().skipToPreviousTrack(); + break; + } +} + +#endif // ENABLE(MEDIA_SESSION) + +#if ENABLE(WEB_AUDIO) + +void Internals::setAudioContextRestrictions(AudioContext& context, const String& restrictionsString) +{ + AudioContext::BehaviorRestrictions restrictions = context.behaviorRestrictions(); + context.removeBehaviorRestriction(restrictions); + + restrictions = AudioContext::NoRestrictions; + + Vector<String> restrictionsArray; + restrictionsString.split(',', false, restrictionsArray); + for (auto& restrictionString : restrictionsArray) { + if (equalLettersIgnoringASCIICase(restrictionString, "norestrictions")) + restrictions |= AudioContext::NoRestrictions; + if (equalLettersIgnoringASCIICase(restrictionString, "requireusergestureforaudiostart")) + restrictions |= AudioContext::RequireUserGestureForAudioStartRestriction; + if (equalLettersIgnoringASCIICase(restrictionString, "requirepageconsentforaudiostart")) + restrictions |= AudioContext::RequirePageConsentForAudioStartRestriction; + } + context.addBehaviorRestriction(restrictions); +} + +#endif + +void Internals::simulateSystemSleep() const +{ +#if ENABLE(VIDEO) + PlatformMediaSessionManager::sharedManager().systemWillSleep(); +#endif } -void Internals::setMediaSessionRestrictions(const String& mediaTypeString, const String& restrictionsString, ExceptionCode& ec) +void Internals::simulateSystemWake() const { - MediaSession::MediaType mediaType = MediaSession::None; - if (equalIgnoringCase(mediaTypeString, "Video")) - mediaType = MediaSession::Video; - else if (equalIgnoringCase(mediaTypeString, "Audio")) - mediaType = MediaSession::Audio; - else if (equalIgnoringCase(mediaTypeString, "WebAudio")) - mediaType = MediaSession::WebAudio; - else { - ec = INVALID_ACCESS_ERR; +#if ENABLE(VIDEO) + PlatformMediaSessionManager::sharedManager().systemDidWake(); +#endif +} + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + +void Internals::setMockMediaPlaybackTargetPickerEnabled(bool enabled) +{ + Page* page = contextDocument()->frame()->page(); + ASSERT(page); + + page->setMockMediaPlaybackTargetPickerEnabled(enabled); +} + +ExceptionOr<void> Internals::setMockMediaPlaybackTargetPickerState(const String& deviceName, const String& deviceState) +{ + Page* page = contextDocument()->frame()->page(); + ASSERT(page); + + MediaPlaybackTargetContext::State state = MediaPlaybackTargetContext::Unknown; + + if (equalLettersIgnoringASCIICase(deviceState, "deviceavailable")) + state = MediaPlaybackTargetContext::OutputDeviceAvailable; + else if (equalLettersIgnoringASCIICase(deviceState, "deviceunavailable")) + state = MediaPlaybackTargetContext::OutputDeviceUnavailable; + else if (equalLettersIgnoringASCIICase(deviceState, "unknown")) + state = MediaPlaybackTargetContext::Unknown; + else + return Exception { INVALID_ACCESS_ERR }; + + page->setMockMediaPlaybackTargetPickerState(deviceName, state); + return { }; +} + +#endif + +ExceptionOr<Ref<MockPageOverlay>> Internals::installMockPageOverlay(PageOverlayType type) +{ + Document* document = contextDocument(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; + + return MockPageOverlayClient::singleton().installOverlay(document->frame()->mainFrame(), type == PageOverlayType::View ? PageOverlay::OverlayType::View : PageOverlay::OverlayType::Document); +} + +ExceptionOr<String> Internals::pageOverlayLayerTreeAsText(unsigned short flags) const +{ + Document* document = contextDocument(); + if (!document || !document->frame()) + return Exception { INVALID_ACCESS_ERR }; + + document->updateLayout(); + + return MockPageOverlayClient::singleton().layerTreeAsText(document->frame()->mainFrame(), toLayerTreeFlags(flags)); +} + +void Internals::setPageMuted(const String& states) +{ + Document* document = contextDocument(); + if (!document) + return; + + WebCore::MediaProducer::MutedStateFlags state = MediaProducer::NoneMuted; + Vector<String> stateString; + states.split(',', false, stateString); + for (auto& muteString : stateString) { + if (equalLettersIgnoringASCIICase(muteString, "audio")) + state |= MediaProducer::AudioIsMuted; + if (equalLettersIgnoringASCIICase(muteString, "capturedevices")) + state |= MediaProducer::CaptureDevicesAreMuted; + } + + if (Page* page = document->page()) + page->setMuted(state); +} + +String Internals::pageMediaState() +{ + Document* document = contextDocument(); + if (!document || !document->page()) + return emptyString(); + + WebCore::MediaProducer::MediaStateFlags state = document->page()->mediaState(); + StringBuilder string; + if (state & MediaProducer::IsPlayingAudio) + string.append("IsPlayingAudio,"); + if (state & MediaProducer::IsPlayingVideo) + string.append("IsPlayingVideo,"); + if (state & MediaProducer::IsPlayingToExternalDevice) + string.append("IsPlayingToExternalDevice,"); + if (state & MediaProducer::RequiresPlaybackTargetMonitoring) + string.append("RequiresPlaybackTargetMonitoring,"); + if (state & MediaProducer::ExternalDeviceAutoPlayCandidate) + string.append("ExternalDeviceAutoPlayCandidate,"); + if (state & MediaProducer::DidPlayToEnd) + string.append("DidPlayToEnd,"); + if (state & MediaProducer::IsSourceElementPlaying) + string.append("IsSourceElementPlaying,"); + + if (state & MediaProducer::IsNextTrackControlEnabled) + string.append("IsNextTrackControlEnabled,"); + if (state & MediaProducer::IsPreviousTrackControlEnabled) + string.append("IsPreviousTrackControlEnabled,"); + + if (state & MediaProducer::HasPlaybackTargetAvailabilityListener) + string.append("HasPlaybackTargetAvailabilityListener,"); + if (state & MediaProducer::HasAudioOrVideo) + string.append("HasAudioOrVideo,"); + if (state & MediaProducer::HasActiveAudioCaptureDevice) + string.append("HasActiveAudioCaptureDevice,"); + if (state & MediaProducer::HasActiveVideoCaptureDevice) + string.append("HasActiveVideoCaptureDevice,"); + + if (string.isEmpty()) + string.append("IsNotPlaying"); + else + string.resize(string.length() - 1); + + return string.toString(); +} + +void Internals::setPageDefersLoading(bool defersLoading) +{ + Document* document = contextDocument(); + if (!document) + return; + if (Page* page = document->page()) + page->setDefersLoading(defersLoading); +} + +RefPtr<File> Internals::createFile(const String& path) +{ + Document* document = contextDocument(); + if (!document) + return nullptr; + + URL url = document->completeURL(path); + if (!url.isLocalFile()) + return nullptr; + + return File::create(url.fileSystemPath()); +} + +void Internals::queueMicroTask(int testNumber) +{ + Document* document = contextDocument(); + if (!document) return; + + auto microtask = std::make_unique<ActiveDOMCallbackMicrotask>(MicrotaskQueue::mainThreadQueue(), *document, [document, testNumber]() { + document->addConsoleMessage(MessageSource::JS, MessageLevel::Debug, makeString("MicroTask #", String::number(testNumber), " has run.")); + }); + + MicrotaskQueue::mainThreadQueue().append(WTFMove(microtask)); +} + +#if ENABLE(CONTENT_FILTERING) + +MockContentFilterSettings& Internals::mockContentFilterSettings() +{ + return MockContentFilterSettings::singleton(); +} + +#endif + +#if ENABLE(CSS_SCROLL_SNAP) + +static void appendOffsets(StringBuilder& builder, const Vector<LayoutUnit>& snapOffsets) +{ + bool justStarting = true; + + builder.appendLiteral("{ "); + for (auto& coordinate : snapOffsets) { + if (!justStarting) + builder.appendLiteral(", "); + else + justStarting = false; + + builder.append(String::number(coordinate.toUnsigned())); } + builder.appendLiteral(" }"); +} + +void Internals::setPlatformMomentumScrollingPredictionEnabled(bool enabled) +{ + ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled(enabled); +} - MediaSessionManager::SessionRestrictions restrictions = MediaSessionManager::sharedManager().restrictions(mediaType); - MediaSessionManager::sharedManager().removeRestriction(mediaType, restrictions); +ExceptionOr<String> Internals::scrollSnapOffsets(Element& element) +{ + if (!element.renderBox()) + return String(); + + element.document().updateLayout(); - restrictions = MediaSessionManager::NoRestrictions; + RenderBox& box = *element.renderBox(); + ScrollableArea* scrollableArea; - if (equalIgnoringCase(restrictionsString, "ConcurrentPlaybackNotPermitted")) - restrictions = MediaSessionManager::ConcurrentPlaybackNotPermitted; - if (equalIgnoringCase(restrictionsString, "InlineVideoPlaybackRestricted")) - restrictions += MediaSessionManager::InlineVideoPlaybackRestricted; - if (equalIgnoringCase(restrictionsString, "MetadataPreloadingNotPermitted")) - restrictions += MediaSessionManager::MetadataPreloadingNotPermitted; - if (equalIgnoringCase(restrictionsString, "AutoPreloadingNotPermitted")) - restrictions += MediaSessionManager::AutoPreloadingNotPermitted; + if (box.isBody()) { + FrameView* frameView = box.frame().mainFrame().view(); + if (!frameView || !frameView->isScrollable()) + return Exception { INVALID_ACCESS_ERR }; + scrollableArea = frameView; + + } else { + if (!box.canBeScrolledAndHasScrollableArea()) + return Exception { INVALID_ACCESS_ERR }; + scrollableArea = box.layer(); + } + + if (!scrollableArea) + return String(); + + StringBuilder result; + + if (auto* offsets = scrollableArea->horizontalSnapOffsets()) { + if (offsets->size()) { + result.appendLiteral("horizontal = "); + appendOffsets(result, *offsets); + } + } + + if (auto* offsets = scrollableArea->verticalSnapOffsets()) { + if (offsets->size()) { + if (result.length()) + result.appendLiteral(", "); + + result.appendLiteral("vertical = "); + appendOffsets(result, *offsets); + } + } + + return result.toString(); +} + +#endif + +bool Internals::testPreloaderSettingViewport() +{ + return testPreloadScannerViewportSupport(contextDocument()); +} + +ExceptionOr<String> Internals::pathStringWithShrinkWrappedRects(const Vector<double>& rectComponents, double radius) +{ + if (rectComponents.size() % 4) + return Exception { INVALID_ACCESS_ERR }; + + Vector<FloatRect> rects; + for (unsigned i = 0; i < rectComponents.size(); i += 4) + rects.append(FloatRect(rectComponents[i], rectComponents[i + 1], rectComponents[i + 2], rectComponents[i + 3])); + + SVGPathStringBuilder builder; + PathUtilities::pathWithShrinkWrappedRects(rects, radius).apply([&builder](const PathElement& element) { + switch (element.type) { + case PathElementMoveToPoint: + builder.moveTo(element.points[0], false, AbsoluteCoordinates); + return; + case PathElementAddLineToPoint: + builder.lineTo(element.points[0], AbsoluteCoordinates); + return; + case PathElementAddQuadCurveToPoint: + builder.curveToQuadratic(element.points[0], element.points[1], AbsoluteCoordinates); + return; + case PathElementAddCurveToPoint: + builder.curveToCubic(element.points[0], element.points[1], element.points[2], AbsoluteCoordinates); + return; + case PathElementCloseSubpath: + builder.closePath(); + return; + } + ASSERT_NOT_REACHED(); + }); + return builder.result(); +} + + +String Internals::getCurrentMediaControlsStatusForElement(HTMLMediaElement& mediaElement) +{ +#if !ENABLE(MEDIA_CONTROLS_SCRIPT) + UNUSED_PARAM(mediaElement); + return String(); +#else + return mediaElement.getCurrentMediaControlsStatus(); +#endif +} + +#if !PLATFORM(COCOA) + +String Internals::userVisibleString(const DOMURL&) +{ + // Cocoa-specific function. Could ASSERT_NOT_REACHED, but that's probably overkill. + return String(); +} + +#endif + +void Internals::setShowAllPlugins(bool show) +{ + Document* document = contextDocument(); + if (!document) + return; + + Page* page = document->page(); + if (!page) + return; + + page->setShowAllPlugins(show); +} + +#if ENABLE(READABLE_STREAM_API) + +bool Internals::isReadableStreamDisturbed(JSC::ExecState& state, JSValue stream) +{ + JSGlobalObject* globalObject = state.vmEntryGlobalObject(); + JSVMClientData* clientData = static_cast<JSVMClientData*>(state.vm().clientData); + const Identifier& privateName = clientData->builtinFunctions().readableStreamInternalsBuiltins().isReadableStreamDisturbedPrivateName(); + JSValue value; + PropertySlot propertySlot(value, PropertySlot::InternalMethodType::Get); + globalObject->methodTable()->getOwnPropertySlot(globalObject, &state, privateName, propertySlot); + value = propertySlot.getValue(&state, privateName); + ASSERT(value.isFunction()); + + JSObject* function = value.getObject(); + CallData callData; + CallType callType = JSC::getCallData(function, callData); + ASSERT(callType != JSC::CallType::None); + MarkedArgumentBuffer arguments; + arguments.append(stream); + JSValue returnedValue = JSC::call(&state, function, callType, callData, JSC::jsUndefined(), arguments); + ASSERT(returnedValue.isBoolean()); + + return returnedValue.asBoolean(); +} + +#endif + +String Internals::resourceLoadStatisticsForOrigin(const String& origin) +{ + return ResourceLoadObserver::sharedObserver().statisticsForOrigin(origin); +} - MediaSessionManager::sharedManager().addRestriction(mediaType, restrictions); +void Internals::setResourceLoadStatisticsEnabled(bool enable) +{ + Settings::setResourceLoadStatisticsEnabled(enable); +} + +String Internals::composedTreeAsText(Node& node) +{ + if (!is<ContainerNode>(node)) + return emptyString(); + return WebCore::composedTreeAsText(downcast<ContainerNode>(node)); } +bool Internals::isProcessingUserGesture() +{ + return UserGestureIndicator::processingUserGesture(); } + +RefPtr<GCObservation> Internals::observeGC(JSC::JSValue value) +{ + if (!value.isObject()) + return nullptr; + return GCObservation::create(asObject(value)); +} + +void Internals::setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection) +{ + Document* document = contextDocument(); + if (!document) + return; + + Page* page = document->page(); + if (!page) + return; + + page->setUserInterfaceLayoutDirection(userInterfaceLayoutDirection == UserInterfaceLayoutDirection::LTR ? WebCore::UserInterfaceLayoutDirection::LTR : WebCore::UserInterfaceLayoutDirection::RTL); +} + +#if !PLATFORM(COCOA) + +bool Internals::userPrefersReducedMotion() const +{ + return false; +} + +#endif + +void Internals::reportBacktrace() +{ + WTFReportBacktrace(); +} + +void Internals::setBaseWritingDirection(BaseWritingDirection direction) +{ + if (auto* document = contextDocument()) { + if (auto* frame = document->frame()) { + switch (direction) { + case BaseWritingDirection::Ltr: + frame->editor().setBaseWritingDirection(LeftToRightWritingDirection); + break; + case BaseWritingDirection::Rtl: + frame->editor().setBaseWritingDirection(RightToLeftWritingDirection); + break; + case BaseWritingDirection::Natural: + frame->editor().setBaseWritingDirection(NaturalWritingDirection); + break; + } + } + } +} + +#if ENABLE(POINTER_LOCK) +bool Internals::pageHasPendingPointerLock() const +{ + Document* document = contextDocument(); + if (!document) + return false; + + Page* page = document->page(); + if (!page) + return false; + + return page->pointerLockController().lockPending(); +} + +bool Internals::pageHasPointerLock() const +{ + Document* document = contextDocument(); + if (!document) + return false; + + Page* page = document->page(); + if (!page) + return false; + + auto& controller = page->pointerLockController(); + return controller.element() && !controller.lockPending(); +} +#endif + +Vector<String> Internals::accessKeyModifiers() const +{ + Vector<String> accessKeyModifierStrings; + + for (auto modifier : EventHandler::accessKeyModifiers()) { + switch (modifier) { + case PlatformEvent::Modifier::AltKey: + accessKeyModifierStrings.append(ASCIILiteral("altKey")); + break; + case PlatformEvent::Modifier::CtrlKey: + accessKeyModifierStrings.append(ASCIILiteral("ctrlKey")); + break; + case PlatformEvent::Modifier::MetaKey: + accessKeyModifierStrings.append(ASCIILiteral("metaKey")); + break; + case PlatformEvent::Modifier::ShiftKey: + accessKeyModifierStrings.append(ASCIILiteral("shiftKey")); + break; + case PlatformEvent::Modifier::CapsLockKey: + accessKeyModifierStrings.append(ASCIILiteral("capsLockKey")); + break; + } + } + + return accessKeyModifierStrings; +} + +#if PLATFORM(IOS) +void Internals::setQuickLookPassword(const String& password) +{ +#if USE(QUICK_LOOK) + auto& quickLookHandleClient = MockQuickLookHandleClient::singleton(); + QuickLookHandle::setClientForTesting(&quickLookHandleClient); + quickLookHandleClient.setPassword(password); +#else + UNUSED_PARAM(password); +#endif +} +#endif + +void Internals::setAsRunningUserScripts(Document& document) +{ + if (document.page()) + document.page()->setAsRunningUserScripts(); +} + +} // namespace WebCore diff --git a/Source/WebCore/testing/Internals.h b/Source/WebCore/testing/Internals.h index 1b936332a..f5c08a87d 100644 --- a/Source/WebCore/testing/Internals.h +++ b/Source/WebCore/testing/Internals.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,184 +24,237 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef Internals_h -#define Internals_h +#pragma once #include "CSSComputedStyleDeclaration.h" #include "ContextDestructionObserver.h" -#include "ExceptionCodePlaceholder.h" -#include "NodeList.h" -#include <bindings/ScriptValue.h> -#include <runtime/ArrayBuffer.h> +#include "ExceptionOr.h" +#include "PageConsoleClient.h" #include <runtime/Float32Array.h> -#include <wtf/PassRefPtr.h> -#include <wtf/RefCounted.h> -#include <wtf/text/WTFString.h> + +#if ENABLE(MEDIA_SESSION) +#include "MediaSessionInterruptionProvider.h" +#endif namespace WebCore { +class AudioContext; class ClientRect; class ClientRectList; -class DOMStringList; +class DOMURL; class DOMWindow; class Document; -class DocumentMarker; class Element; +class File; class Frame; -class InspectorFrontendChannelDummy; +class GCObservation; +class HTMLImageElement; +class HTMLInputElement; +class HTMLLinkElement; +class HTMLMediaElement; +class HTMLSelectElement; +class InspectorStubFrontend; class InternalSettings; +class MallocStatistics; +class MediaSession; class MemoryInfo; -class Node; +class MockCDMFactory; +class MockContentFilterSettings; +class MockPageOverlay; +class NodeList; class Page; class Range; -class ScriptExecutionContext; -class ShadowRoot; -class MallocStatistics; +class RenderedDocumentMarker; +class RTCPeerConnection; class SerializedScriptValue; +class SourceBuffer; +class StyleSheet; class TimeRanges; class TypeConversions; +class XMLHttpRequest; -typedef int ExceptionCode; - -class Internals : public RefCounted<Internals> - , public ContextDestructionObserver { +class Internals final : public RefCounted<Internals>, private ContextDestructionObserver { public: - static PassRefPtr<Internals> create(Document*); + static Ref<Internals> create(Document&); virtual ~Internals(); - static void resetToConsistentState(Page*); + static void resetToConsistentState(Page&); - String elementRenderTreeAsText(Element*, ExceptionCode&); + ExceptionOr<String> elementRenderTreeAsText(Element&); + bool hasPausedImageAnimations(Element&); - String address(Node*); + String address(Node&); + bool nodeNeedsStyleRecalc(Node&); + String styleChangeType(Node&); + String description(JSC::JSValue); bool isPreloaded(const String& url); bool isLoadingFromMemoryCache(const String& url); - - PassRefPtr<CSSComputedStyleDeclaration> computedStyleIncludingVisitedInfo(Node*, ExceptionCode&) const; - -#if ENABLE(SHADOW_DOM) - typedef ShadowRoot ShadowRootIfShadowDOMEnabledOrNode; -#else - typedef Node ShadowRootIfShadowDOMEnabledOrNode; -#endif - ShadowRootIfShadowDOMEnabledOrNode* ensureShadowRoot(Element* host, ExceptionCode&); - ShadowRootIfShadowDOMEnabledOrNode* createShadowRoot(Element* host, ExceptionCode&); - ShadowRootIfShadowDOMEnabledOrNode* shadowRoot(Element* host, ExceptionCode&); - String shadowRootType(const Node*, ExceptionCode&) const; - Element* includerFor(Node*, ExceptionCode&); - String shadowPseudoId(Element*, ExceptionCode&); - void setShadowPseudoId(Element*, const String&, ExceptionCode&); + String xhrResponseSource(XMLHttpRequest&); + bool isSharingStyleSheetContents(HTMLLinkElement&, HTMLLinkElement&); + bool isStyleSheetLoadingSubresources(HTMLLinkElement&); + enum class CachePolicy { UseProtocolCachePolicy, ReloadIgnoringCacheData, ReturnCacheDataElseLoad, ReturnCacheDataDontLoad }; + void setOverrideCachePolicy(CachePolicy); + ExceptionOr<void> setCanShowModalDialogOverride(bool allow); + enum class ResourceLoadPriority { ResourceLoadPriorityVeryLow, ResourceLoadPriorityLow, ResourceLoadPriorityMedium, ResourceLoadPriorityHigh, ResourceLoadPriorityVeryHigh }; + void setOverrideResourceLoadPriority(ResourceLoadPriority); + void setStrictRawResourceValidationPolicyDisabled(bool); + + void clearMemoryCache(); + void pruneMemoryCacheToSize(unsigned size); + unsigned memoryCacheSize() const; + + unsigned imageFrameIndex(HTMLImageElement&); + void setImageFrameDecodingDuration(HTMLImageElement&, float duration); + void resetImageAnimation(HTMLImageElement&); + + void clearPageCache(); + unsigned pageCacheSize() const; + + void disableTileSizeUpdateDelay(); + + Ref<CSSComputedStyleDeclaration> computedStyleIncludingVisitedInfo(Element&) const; + + Node* ensureUserAgentShadowRoot(Element& host); + Node* shadowRoot(Element& host); + ExceptionOr<String> shadowRootType(const Node&) const; + String shadowPseudoId(Element&); + void setShadowPseudoId(Element&, const String&); + + // CSS Deferred Parsing Testing + unsigned deferredStyleRulesCount(StyleSheet&); + unsigned deferredGroupRulesCount(StyleSheet&); + unsigned deferredKeyframesRulesCount(StyleSheet&); + + // DOMTimers throttling testing. + ExceptionOr<bool> isTimerThrottled(int timeoutId); + bool isRequestAnimationFrameThrottled() const; + bool areTimersThrottled() const; + + enum EventThrottlingBehavior { Responsive, Unresponsive }; + void setEventThrottlingBehaviorOverride(std::optional<EventThrottlingBehavior>); + std::optional<EventThrottlingBehavior> eventThrottlingBehaviorOverride() const; // Spatial Navigation testing. - unsigned lastSpatialNavigationCandidateCount(ExceptionCode&) const; + ExceptionOr<unsigned> lastSpatialNavigationCandidateCount() const; // CSS Animation testing. unsigned numberOfActiveAnimations() const; - bool animationsAreSuspended(ExceptionCode&) const; - void suspendAnimations(ExceptionCode&) const; - void resumeAnimations(ExceptionCode&) const; - bool pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element*, ExceptionCode&); - bool pauseAnimationAtTimeOnPseudoElement(const String& animationName, double pauseTime, Element*, const String& pseudoId, ExceptionCode&); + ExceptionOr<bool> animationsAreSuspended() const; + ExceptionOr<void> suspendAnimations() const; + ExceptionOr<void> resumeAnimations() const; + ExceptionOr<bool> pauseAnimationAtTimeOnElement(const String& animationName, double pauseTime, Element&); + ExceptionOr<bool> pauseAnimationAtTimeOnPseudoElement(const String& animationName, double pauseTime, Element&, const String& pseudoId); // CSS Transition testing. - bool pauseTransitionAtTimeOnElement(const String& propertyName, double pauseTime, Element*, ExceptionCode&); - bool pauseTransitionAtTimeOnPseudoElement(const String& property, double pauseTime, Element*, const String& pseudoId, ExceptionCode&); + ExceptionOr<bool> pauseTransitionAtTimeOnElement(const String& propertyName, double pauseTime, Element&); + ExceptionOr<bool> pauseTransitionAtTimeOnPseudoElement(const String& property, double pauseTime, Element&, const String& pseudoId); - Node* treeScopeRootNode(Node*, ExceptionCode&); - Node* parentTreeScope(Node*, ExceptionCode&); - bool hasSelectorForIdInShadow(Element* host, const String& idValue, ExceptionCode&); - bool hasSelectorForClassInShadow(Element* host, const String& className, ExceptionCode&); - bool hasSelectorForAttributeInShadow(Element* host, const String& attributeName, ExceptionCode&); - bool hasSelectorForPseudoClassInShadow(Element* host, const String& pseudoClass, ExceptionCode&); + Node* treeScopeRootNode(Node&); + Node* parentTreeScope(Node&); - bool attached(Node*, ExceptionCode&); + String visiblePlaceholder(Element&); + void selectColorInColorChooser(HTMLInputElement&, const String& colorValue); + ExceptionOr<Vector<String>> formControlStateOfPreviousHistoryItem(); + ExceptionOr<void> setFormControlStateOfPreviousHistoryItem(const Vector<String>&); - String visiblePlaceholder(Element*); -#if ENABLE(INPUT_TYPE_COLOR) - void selectColorInColorChooser(Element*, const String& colorValue); -#endif - Vector<String> formControlStateOfPreviousHistoryItem(ExceptionCode&); - void setFormControlStateOfPreviousHistoryItem(const Vector<String>&, ExceptionCode&); + ExceptionOr<Ref<ClientRect>> absoluteCaretBounds(); + + Ref<ClientRect> boundingBox(Element&); - PassRefPtr<ClientRect> absoluteCaretBounds(ExceptionCode&); + ExceptionOr<Ref<ClientRectList>> inspectorHighlightRects(); + ExceptionOr<String> inspectorHighlightObject(); - PassRefPtr<ClientRect> boundingBox(Element*, ExceptionCode&); + ExceptionOr<unsigned> markerCountForNode(Node&, const String&); + ExceptionOr<RefPtr<Range>> markerRangeForNode(Node&, const String& markerType, unsigned index); + ExceptionOr<String> markerDescriptionForNode(Node&, const String& markerType, unsigned index); + ExceptionOr<String> dumpMarkerRects(const String& markerType); + void addTextMatchMarker(const Range&, bool isActive); + ExceptionOr<void> setMarkedTextMatchesAreHighlighted(bool); - PassRefPtr<ClientRectList> inspectorHighlightRects(ExceptionCode&); - String inspectorHighlightObject(ExceptionCode&); + void invalidateFontCache(); - unsigned markerCountForNode(Node*, const String&, ExceptionCode&); - PassRefPtr<Range> markerRangeForNode(Node*, const String& markerType, unsigned index, ExceptionCode&); - String markerDescriptionForNode(Node*, const String& markerType, unsigned index, ExceptionCode&); - void addTextMatchMarker(const Range*, bool isActive); + ExceptionOr<void> setScrollViewPosition(int x, int y); + + ExceptionOr<Ref<ClientRect>> layoutViewportRect(); + ExceptionOr<Ref<ClientRect>> visualViewportRect(); + + ExceptionOr<void> setViewBaseBackgroundColor(const String& colorValue); - void setScrollViewPosition(long x, long y, ExceptionCode&); - void setPagination(const String& mode, int gap, ExceptionCode& ec) { setPagination(mode, gap, 0, ec); } - void setPagination(const String& mode, int gap, int pageLength, ExceptionCode&); - String configurationForViewport(float devicePixelRatio, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight, ExceptionCode&); + ExceptionOr<void> setPagination(const String& mode, int gap, int pageLength); + ExceptionOr<void> setPaginationLineGridEnabled(bool); + ExceptionOr<String> configurationForViewport(float devicePixelRatio, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight); - bool wasLastChangeUserEdit(Element* textField, ExceptionCode&); - bool elementShouldAutoComplete(Element* inputElement, ExceptionCode&); - String suggestedValue(Element* inputElement, ExceptionCode&); - void setSuggestedValue(Element* inputElement, const String&, ExceptionCode&); - void setEditingValue(Element* inputElement, const String&, ExceptionCode&); - void setAutofilled(Element*, bool enabled, ExceptionCode&); - void scrollElementToRect(Element*, long x, long y, long w, long h, ExceptionCode&); + ExceptionOr<bool> wasLastChangeUserEdit(Element& textField); + bool elementShouldAutoComplete(HTMLInputElement&); + void setEditingValue(HTMLInputElement&, const String&); + void setAutofilled(HTMLInputElement&, bool enabled); + enum class AutoFillButtonType { AutoFillButtonTypeNone, AutoFillButtonTypeContacts, AutoFillButtonTypeCredentials }; + void setShowAutoFillButton(HTMLInputElement&, AutoFillButtonType); + ExceptionOr<void> scrollElementToRect(Element&, int x, int y, int w, int h); - void paintControlTints(ExceptionCode&); + ExceptionOr<String> autofillFieldName(Element&); - PassRefPtr<Range> rangeFromLocationAndLength(Element* scope, int rangeLocation, int rangeLength, ExceptionCode&); - unsigned locationFromRange(Element* scope, const Range*, ExceptionCode&); - unsigned lengthFromRange(Element* scope, const Range*, ExceptionCode&); - String rangeAsText(const Range*, ExceptionCode&); + ExceptionOr<void> paintControlTints(); - void setDelegatesScrolling(bool enabled, ExceptionCode&); + RefPtr<Range> rangeFromLocationAndLength(Element& scope, int rangeLocation, int rangeLength); + unsigned locationFromRange(Element& scope, const Range&); + unsigned lengthFromRange(Element& scope, const Range&); + String rangeAsText(const Range&); + Ref<Range> subrange(Range&, int rangeLocation, int rangeLength); + ExceptionOr<RefPtr<Range>> rangeForDictionaryLookupAtLocation(int x, int y); + RefPtr<Range> rangeOfStringNearLocation(const Range&, const String&, unsigned); - int lastSpellCheckRequestSequence(ExceptionCode&); - int lastSpellCheckProcessedSequence(ExceptionCode&); + ExceptionOr<void> setDelegatesScrolling(bool enabled); + + ExceptionOr<int> lastSpellCheckRequestSequence(); + ExceptionOr<int> lastSpellCheckProcessedSequence(); Vector<String> userPreferredLanguages() const; void setUserPreferredLanguages(const Vector<String>&); - unsigned wheelEventHandlerCount(ExceptionCode&); - unsigned touchEventHandlerCount(ExceptionCode&); + Vector<String> userPreferredAudioCharacteristics() const; + void setUserPreferredAudioCharacteristic(const String&); + + ExceptionOr<unsigned> wheelEventHandlerCount(); + ExceptionOr<unsigned> touchEventHandlerCount(); + + ExceptionOr<RefPtr<NodeList>> nodesFromRect(Document&, int x, int y, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, bool allowChildFrameContent) const; - PassRefPtr<NodeList> nodesFromRect(Document*, int x, int y, unsigned topPadding, unsigned rightPadding, - unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, bool allowChildFrameContent, ExceptionCode&) const; + String parserMetaData(JSC::JSValue = JSC::JSValue::JSUndefined); - void emitInspectorDidBeginFrame(); - void emitInspectorDidCancelFrame(); + void updateEditorUINowIfScheduled(); - String parserMetaData(Deprecated::ScriptValue = Deprecated::ScriptValue()); + bool hasSpellingMarker(int from, int length); + bool hasGrammarMarker(int from, int length); + bool hasAutocorrectedMarker(int from, int length); + void setContinuousSpellCheckingEnabled(bool); + void setAutomaticQuoteSubstitutionEnabled(bool); + void setAutomaticLinkDetectionEnabled(bool); + void setAutomaticDashSubstitutionEnabled(bool); + void setAutomaticTextReplacementEnabled(bool); + void setAutomaticSpellingCorrectionEnabled(bool); - bool hasSpellingMarker(int from, int length, ExceptionCode&); - bool hasGrammarMarker(int from, int length, ExceptionCode&); - bool hasAutocorrectedMarker(int from, int length, ExceptionCode&); - void setContinuousSpellCheckingEnabled(bool enabled, ExceptionCode&); - void setAutomaticQuoteSubstitutionEnabled(bool enabled, ExceptionCode&); - void setAutomaticLinkDetectionEnabled(bool enabled, ExceptionCode&); - void setAutomaticDashSubstitutionEnabled(bool enabled, ExceptionCode&); - void setAutomaticTextReplacementEnabled(bool enabled, ExceptionCode&); - void setAutomaticSpellingCorrectionEnabled(bool enabled, ExceptionCode&); + void handleAcceptedCandidate(const String& candidate, unsigned location, unsigned length); - bool isOverwriteModeEnabled(ExceptionCode&); - void toggleOverwriteModeEnabled(ExceptionCode&); + bool isOverwriteModeEnabled(); + void toggleOverwriteModeEnabled(); - unsigned numberOfScrollableAreas(ExceptionCode&); + ExceptionOr<RefPtr<Range>> rangeOfString(const String&, RefPtr<Range>&&, const Vector<String>& findOptions); + ExceptionOr<unsigned> countMatchesForText(const String&, const Vector<String>& findOptions, const String& markMatches); + ExceptionOr<unsigned> countFindMatches(const String&, const Vector<String>& findOptions); - bool isPageBoxVisible(int pageNumber, ExceptionCode&); + unsigned numberOfScrollableAreas(); + + ExceptionOr<bool> isPageBoxVisible(int pageNumber); static const char* internalsId; InternalSettings* settings() const; unsigned workerThreadCount() const; + bool areSVGAnimationsPaused() const; - void setBatteryStatus(const String& eventType, bool charging, double chargingTime, double dischargingTime, double level, ExceptionCode&); - - void setNetworkInformation(const String& eventType, double bandwidth, bool metered, ExceptionCode&); - - void setDeviceProximity(const String& eventType, double value, double min, double max, ExceptionCode&); + ExceptionOr<void> setDeviceProximity(const String& eventType, double value, double min, double max); enum { // Values need to be kept in sync with Internals.idl. @@ -209,140 +262,283 @@ public: LAYER_TREE_INCLUDES_TILE_CACHES = 2, LAYER_TREE_INCLUDES_REPAINT_RECTS = 4, LAYER_TREE_INCLUDES_PAINTING_PHASES = 8, - LAYER_TREE_INCLUDES_CONTENT_LAYERS = 16 + LAYER_TREE_INCLUDES_CONTENT_LAYERS = 16, + LAYER_TREE_INCLUDES_ACCELERATES_DRAWING = 32, + }; + ExceptionOr<String> layerTreeAsText(Document&, unsigned short flags) const; + ExceptionOr<String> repaintRectsAsText() const; + ExceptionOr<String> scrollingStateTreeAsText() const; + ExceptionOr<String> mainThreadScrollingReasons() const; + ExceptionOr<RefPtr<ClientRectList>> nonFastScrollableRects() const; + + ExceptionOr<void> setElementUsesDisplayListDrawing(Element&, bool usesDisplayListDrawing); + ExceptionOr<void> setElementTracksDisplayListReplay(Element&, bool isTrackingReplay); + + enum { + // Values need to be kept in sync with Internals.idl. + DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS = 1, }; - String layerTreeAsText(Document*, unsigned flags, ExceptionCode&) const; - String layerTreeAsText(Document*, ExceptionCode&) const; - String repaintRectsAsText(ExceptionCode&) const; - String scrollingStateTreeAsText(ExceptionCode&) const; - String mainThreadScrollingReasons(ExceptionCode&) const; - PassRefPtr<ClientRectList> nonFastScrollableRects(ExceptionCode&) const; + ExceptionOr<String> displayListForElement(Element&, unsigned short flags); + ExceptionOr<String> replayDisplayListForElement(Element&, unsigned short flags); - void garbageCollectDocumentResources(ExceptionCode&) const; + ExceptionOr<void> garbageCollectDocumentResources() const; - void allowRoundingHacks() const; + void beginSimulatedMemoryPressure(); + void endSimulatedMemoryPressure(); + bool isUnderMemoryPressure(); - void insertAuthorCSS(const String&, ExceptionCode&) const; - void insertUserCSS(const String&, ExceptionCode&) const; + ExceptionOr<void> insertAuthorCSS(const String&) const; + ExceptionOr<void> insertUserCSS(const String&) const; -#if ENABLE(INSPECTOR) unsigned numberOfLiveNodes() const; unsigned numberOfLiveDocuments() const; - Vector<String> consoleMessageArgumentCounts() const; - PassRefPtr<DOMWindow> openDummyInspectorFrontend(const String& url); + + RefPtr<DOMWindow> openDummyInspectorFrontend(const String& url); void closeDummyInspectorFrontend(); - void setInspectorResourcesDataSizeLimits(int maximumResourcesContentSize, int maximumSingleResourceContentSize, ExceptionCode&); - void setJavaScriptProfilingEnabled(bool enabled, ExceptionCode&); -#endif + ExceptionOr<void> setInspectorIsUnderTest(bool); - String counterValue(Element*); + String counterValue(Element&); - int pageNumber(Element*, float pageWidth = 800, float pageHeight = 600); + int pageNumber(Element&, float pageWidth = 800, float pageHeight = 600); Vector<String> shortcutIconURLs() const; - Vector<String> allIconURLs() const; int numberOfPages(float pageWidthInPixels = 800, float pageHeightInPixels = 600); - String pageProperty(String, int, ExceptionCode& = ASSERT_NO_EXCEPTION) const; - String pageSizeAndMarginsInPixels(int, int, int, int, int, int, int, ExceptionCode& = ASSERT_NO_EXCEPTION) const; + ExceptionOr<String> pageProperty(const String& propertyName, int pageNumber) const; + ExceptionOr<String> pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) const; + + ExceptionOr<float> pageScaleFactor() const; - void setPageScaleFactor(float scaleFactor, int x, int y, ExceptionCode&); + ExceptionOr<void> setPageScaleFactor(float scaleFactor, int x, int y); + ExceptionOr<void> setPageZoomFactor(float); + ExceptionOr<void> setTextZoomFactor(float); + + ExceptionOr<void> setUseFixedLayout(bool); + ExceptionOr<void> setFixedLayoutSize(int width, int height); + ExceptionOr<void> setViewExposedRect(float left, float top, float width, float height); void setHeaderHeight(float); void setFooterHeight(float); + void setTopContentInset(float); + #if ENABLE(FULLSCREEN_API) - void webkitWillEnterFullScreenForElement(Element*); - void webkitDidEnterFullScreenForElement(Element*); - void webkitWillExitFullScreenForElement(Element*); - void webkitDidExitFullScreenForElement(Element*); + void webkitWillEnterFullScreenForElement(Element&); + void webkitDidEnterFullScreenForElement(Element&); + void webkitWillExitFullScreenForElement(Element&); + void webkitDidExitFullScreenForElement(Element&); #endif - void setApplicationCacheOriginQuota(unsigned long long); + WEBCORE_TESTSUPPORT_EXPORT void setApplicationCacheOriginQuota(unsigned long long); void registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme); void removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(const String& scheme); - PassRefPtr<MallocStatistics> mallocStatistics() const; - PassRefPtr<TypeConversions> typeConversions() const; - PassRefPtr<MemoryInfo> memoryInfo() const; + void registerDefaultPortForProtocol(unsigned short port, const String& protocol); + + Ref<MallocStatistics> mallocStatistics() const; + Ref<TypeConversions> typeConversions() const; + Ref<MemoryInfo> memoryInfo() const; Vector<String> getReferencedFilePaths() const; - void startTrackingRepaints(ExceptionCode&); - void stopTrackingRepaints(ExceptionCode&); - void updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(ExceptionCode&); - void updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node*, ExceptionCode&); + ExceptionOr<void> startTrackingRepaints(); + ExceptionOr<void> stopTrackingRepaints(); + + ExceptionOr<void> startTrackingLayerFlushes(); + ExceptionOr<unsigned> layerFlushCount(); + + ExceptionOr<void> startTrackingStyleRecalcs(); + ExceptionOr<unsigned> styleRecalcCount(); + unsigned lastStyleUpdateSize() const; + + ExceptionOr<void> startTrackingCompositingUpdates(); + ExceptionOr<unsigned> compositingUpdateCount(); - PassRefPtr<ArrayBuffer> serializeObject(PassRefPtr<SerializedScriptValue>) const; - PassRefPtr<SerializedScriptValue> deserializeBuffer(PassRefPtr<ArrayBuffer>) const; + ExceptionOr<void> updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(Node*); + unsigned layoutCount() const; - void setUsesOverlayScrollbars(bool enabled); + Ref<ArrayBuffer> serializeObject(const RefPtr<SerializedScriptValue>&) const; + Ref<SerializedScriptValue> deserializeBuffer(ArrayBuffer&) const; - String getCurrentCursorInfo(ExceptionCode&); + bool isFromCurrentWorld(JSC::JSValue) const; - String markerTextForListItem(Element*, ExceptionCode&); + void setUsesOverlayScrollbars(bool); + void setUsesMockScrollAnimator(bool); + + ExceptionOr<String> getCurrentCursorInfo(); + + String markerTextForListItem(Element&); + + String toolTipFromElement(Element&) const; void forceReload(bool endToEnd); -#if ENABLE(ENCRYPTED_MEDIA_V2) + void enableAutoSizeMode(bool enabled, int minimumWidth, int minimumHeight, int maximumWidth, int maximumHeight); + +#if ENABLE(LEGACY_ENCRYPTED_MEDIA) void initializeMockCDM(); #endif +#if ENABLE(ENCRYPTED_MEDIA) + Ref<MockCDMFactory> registerMockCDM(); +#endif + #if ENABLE(SPEECH_SYNTHESIS) void enableMockSpeechSynthesizer(); #endif #if ENABLE(MEDIA_STREAM) + void setMockMediaCaptureDevicesEnabled(bool); +#endif + +#if ENABLE(WEB_RTC) + void enableMockMediaEndpoint(); void enableMockRTCPeerConnectionHandler(); + void emulateRTCPeerConnectionPlatformEvent(RTCPeerConnection&, const String& action); + void useMockRTCPeerConnectionFactory(const String&); #endif - String getImageSourceURL(Element*, ExceptionCode&); + String getImageSourceURL(Element&); #if ENABLE(VIDEO) - void simulateAudioInterruption(Node*); + void simulateAudioInterruption(HTMLMediaElement&); + ExceptionOr<bool> mediaElementHasCharacteristic(HTMLMediaElement&, const String&); #endif - bool isSelectPopupVisible(Node*); + bool isSelectPopupVisible(HTMLSelectElement&); - String captionsStyleSheetOverride(ExceptionCode&); - void setCaptionsStyleSheetOverride(const String&, ExceptionCode&); - void setPrimaryAudioTrackLanguageOverride(const String&, ExceptionCode&); - void setCaptionDisplayMode(const String&, ExceptionCode&); + ExceptionOr<String> captionsStyleSheetOverride(); + ExceptionOr<void> setCaptionsStyleSheetOverride(const String&); + ExceptionOr<void> setPrimaryAudioTrackLanguageOverride(const String&); + ExceptionOr<void> setCaptionDisplayMode(const String&); #if ENABLE(VIDEO) - PassRefPtr<TimeRanges> createTimeRanges(Float32Array* startTimes, Float32Array* endTimes); - double closestTimeToTimeRanges(double time, TimeRanges*); + Ref<TimeRanges> createTimeRanges(Float32Array& startTimes, Float32Array& endTimes); + double closestTimeToTimeRanges(double time, TimeRanges&); #endif - PassRefPtr<ClientRect> selectionBounds(ExceptionCode&); + ExceptionOr<Ref<ClientRect>> selectionBounds(); #if ENABLE(VIBRATION) bool isVibrating(); #endif - bool isPluginUnavailabilityIndicatorObscured(Element*, ExceptionCode&); + ExceptionOr<bool> isPluginUnavailabilityIndicatorObscured(Element&); + bool isPluginSnapshotted(Element&); #if ENABLE(MEDIA_SOURCE) - void initializeMockMediaSource(); + WEBCORE_TESTSUPPORT_EXPORT void initializeMockMediaSource(); + Vector<String> bufferedSamplesForTrackID(SourceBuffer&, const AtomicString&); + Vector<String> enqueuedSamplesForTrackID(SourceBuffer&, const AtomicString&); + void setShouldGenerateTimestamps(SourceBuffer&, bool); #endif - void beginMediaSessionInterruption(); +#if ENABLE(VIDEO) + ExceptionOr<void> beginMediaSessionInterruption(const String&); void endMediaSessionInterruption(const String&); - void setMediaSessionRestrictions(const String& mediaType, const String& restrictions, ExceptionCode& ec); + void applicationDidEnterForeground() const; + void applicationWillEnterBackground() const; + ExceptionOr<void> setMediaSessionRestrictions(const String& mediaType, const String& restrictions); + ExceptionOr<String> mediaSessionRestrictions(const String& mediaType) const; + void setMediaElementRestrictions(HTMLMediaElement&, const String& restrictions); + ExceptionOr<void> postRemoteControlCommand(const String&, float argument); + bool elementIsBlockingDisplaySleep(HTMLMediaElement&) const; +#endif + +#if ENABLE(MEDIA_SESSION) + void sendMediaSessionStartOfInterruptionNotification(MediaSessionInterruptingCategory); + void sendMediaSessionEndOfInterruptionNotification(MediaSessionInterruptingCategory); + String mediaSessionCurrentState(MediaSession&) const; + double mediaElementPlayerVolume(HTMLMediaElement&) const; + enum class MediaControlEvent { PlayPause, NextTrack, PreviousTrack }; + void sendMediaControlEvent(MediaControlEvent); +#endif + +#if ENABLE(WIRELESS_PLAYBACK_TARGET) + void setMockMediaPlaybackTargetPickerEnabled(bool); + ExceptionOr<void> setMockMediaPlaybackTargetPickerState(const String& deviceName, const String& deviceState); +#endif + +#if ENABLE(WEB_AUDIO) + void setAudioContextRestrictions(AudioContext&, const String& restrictions); +#endif + + void simulateSystemSleep() const; + void simulateSystemWake() const; + + enum class PageOverlayType { View, Document }; + ExceptionOr<Ref<MockPageOverlay>> installMockPageOverlay(PageOverlayType); + ExceptionOr<String> pageOverlayLayerTreeAsText(unsigned short flags) const; + + void setPageMuted(const String&); + String pageMediaState(); + + void setPageDefersLoading(bool); + + RefPtr<File> createFile(const String&); + void queueMicroTask(int); + bool testPreloaderSettingViewport(); + +#if ENABLE(CONTENT_FILTERING) + MockContentFilterSettings& mockContentFilterSettings(); +#endif + +#if ENABLE(CSS_SCROLL_SNAP) + ExceptionOr<String> scrollSnapOffsets(Element&); + void setPlatformMomentumScrollingPredictionEnabled(bool); +#endif + + ExceptionOr<String> pathStringWithShrinkWrappedRects(const Vector<double>& rectComponents, double radius); + + String getCurrentMediaControlsStatusForElement(HTMLMediaElement&); + + String userVisibleString(const DOMURL&); + void setShowAllPlugins(bool); + + String resourceLoadStatisticsForOrigin(const String& origin); + void setResourceLoadStatisticsEnabled(bool); + +#if ENABLE(READABLE_STREAM_API) + bool isReadableStreamDisturbed(JSC::ExecState&, JSC::JSValue); +#endif + + String composedTreeAsText(Node&); + + bool isProcessingUserGesture(); + + RefPtr<GCObservation> observeGC(JSC::JSValue); + + enum class UserInterfaceLayoutDirection { LTR, RTL }; + void setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection); + + bool userPrefersReducedMotion() const; + + void reportBacktrace(); + + enum class BaseWritingDirection { Natural, Ltr, Rtl }; + void setBaseWritingDirection(BaseWritingDirection); + +#if ENABLE(POINTER_LOCK) + bool pageHasPendingPointerLock() const; + bool pageHasPointerLock() const; +#endif + + Vector<String> accessKeyModifiers() const; + +#if PLATFORM(IOS) + void setQuickLookPassword(const String&); +#endif + + void setAsRunningUserScripts(Document&); private: - explicit Internals(Document*); + explicit Internals(Document&); Document* contextDocument() const; Frame* frame() const; - Vector<String> iconURLs(Document*, int iconTypesMask) const; - DocumentMarker* markerAt(Node*, const String& markerType, unsigned index, ExceptionCode&); -#if ENABLE(INSPECTOR) - RefPtr<DOMWindow> m_frontendWindow; - OwnPtr<InspectorFrontendChannelDummy> m_frontendChannel; -#endif + ExceptionOr<RenderedDocumentMarker*> markerAt(Node&, const String& markerType, unsigned index); + + std::unique_ptr<InspectorStubFrontend> m_inspectorFrontend; }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/testing/Internals.idl b/Source/WebCore/testing/Internals.idl index 6b0c22795..155b70b4a 100644 --- a/Source/WebCore/testing/Internals.idl +++ b/Source/WebCore/testing/Internals.idl @@ -1,6 +1,6 @@ /* * Copyright (C) 2012 Google Inc. All rights reserved. - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013-2017 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,189 +24,297 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +enum PageOverlayType { + "view", + "document" +}; + +// These map to ResourceRequestCachePolicy. +enum CachePolicy { + "UseProtocolCachePolicy", + "ReloadIgnoringCacheData", + "ReturnCacheDataElseLoad", + "ReturnCacheDataDontLoad" +}; + +// FIXME: Strings in an enum should not have the name of the enum as a prefix. +enum ResourceLoadPriority { + "ResourceLoadPriorityVeryLow", + "ResourceLoadPriorityLow", + "ResourceLoadPriorityMedium", + "ResourceLoadPriorityHigh", + "ResourceLoadPriorityVeryHigh" +}; + +[Conditional=MEDIA_SESSION] enum MediaSessionInterruptingCategory { + "content", + "transient", + "transient-solo" +}; + +[Conditional=MEDIA_SESSION] enum MediaControlEvent { + "play-pause", + "next-track", + "previous-track" +}; + +// FIXME: Strings in an enum should not have the name of the enum as a prefix. +enum AutoFillButtonType { + "AutoFillButtonTypeNone", + "AutoFillButtonTypeContacts", + "AutoFillButtonTypeCredentials" +}; + +enum UserInterfaceLayoutDirection { + "LTR", + "RTL" +}; + +enum BaseWritingDirection { + "Natural", + "Ltr", + "Rtl" +}; + +enum EventThrottlingBehavior { + "responsive", + "unresponsive" +}; + [ + ExportMacro=WEBCORE_TESTSUPPORT_EXPORT, NoInterfaceObject, ] interface Internals { DOMString address(Node node); + boolean nodeNeedsStyleRecalc(Node node); + DOMString styleChangeType(Node node); + DOMString description(any value); + + // Animated image pausing testing. + boolean hasPausedImageAnimations(Element element); - [RaisesException] DOMString elementRenderTreeAsText(Element element); + [MayThrowException] DOMString elementRenderTreeAsText(Element element); boolean isPreloaded(DOMString url); boolean isLoadingFromMemoryCache(DOMString url); - - [RaisesException] CSSStyleDeclaration computedStyleIncludingVisitedInfo(Node node); - -#if defined(ENABLE_SHADOW_DOM) && ENABLE_SHADOW_DOM - [RaisesException] ShadowRoot ensureShadowRoot(Element host); - [RaisesException] ShadowRoot createShadowRoot(Element host); - [RaisesException] ShadowRoot shadowRoot(Element host); -#else - [RaisesException] Node ensureShadowRoot(Element host); - [RaisesException] Node createShadowRoot(Element host); - [RaisesException] Node shadowRoot(Element host); -#endif - [RaisesException] DOMString shadowRootType(Node root); - [RaisesException] Element includerFor(Node node); - [RaisesException] DOMString shadowPseudoId(Element element); - [RaisesException] void setShadowPseudoId(Element element, DOMString id); - [RaisesException] Node treeScopeRootNode(Node node); - [RaisesException] Node parentTreeScope(Node node); + DOMString xhrResponseSource(XMLHttpRequest xhr); + boolean isSharingStyleSheetContents(HTMLLinkElement a, HTMLLinkElement b); + boolean isStyleSheetLoadingSubresources(HTMLLinkElement link); + void clearMemoryCache(); + void pruneMemoryCacheToSize(long size); + long memoryCacheSize(); + void setOverrideCachePolicy(CachePolicy policy); + void setOverrideResourceLoadPriority(ResourceLoadPriority priority); + void setStrictRawResourceValidationPolicyDisabled(boolean disabled); + + void clearPageCache(); + unsigned long pageCacheSize(); + + CSSStyleDeclaration computedStyleIncludingVisitedInfo(Element element); + + Node ensureUserAgentShadowRoot(Element host); + Node shadowRoot(Element host); + + // CSS Deferred Parsing Testing. + long deferredStyleRulesCount(StyleSheet sheet); + long deferredGroupRulesCount(StyleSheet sheet); + long deferredKeyframesRulesCount(StyleSheet sheet); + + [MayThrowException] DOMString shadowRootType(Node root); + DOMString shadowPseudoId(Element element); + void setShadowPseudoId(Element element, DOMString id); + Node treeScopeRootNode(Node node); + Node parentTreeScope(Node node); // Spatial Navigation testing - [RaisesException] unsigned long lastSpatialNavigationCandidateCount(); + [MayThrowException] unsigned long lastSpatialNavigationCandidateCount(); // CSS Animation testing. unsigned long numberOfActiveAnimations(); - [RaisesException] void suspendAnimations(); - [RaisesException] void resumeAnimations(); - [RaisesException] boolean animationsAreSuspended(); - [RaisesException] boolean pauseAnimationAtTimeOnElement(DOMString animationName, double pauseTime, Element element); - [RaisesException] boolean pauseAnimationAtTimeOnPseudoElement(DOMString animationName, double pauseTime, Element element, DOMString pseudoId); + [MayThrowException] void suspendAnimations(); + [MayThrowException] void resumeAnimations(); + [MayThrowException] boolean animationsAreSuspended(); + [MayThrowException] boolean pauseAnimationAtTimeOnElement(DOMString animationName, unrestricted double pauseTime, Element element); + [MayThrowException] boolean pauseAnimationAtTimeOnPseudoElement(DOMString animationName, unrestricted double pauseTime, Element element, DOMString pseudoId); // CSS Transition testing. - [RaisesException] boolean pauseTransitionAtTimeOnElement(DOMString propertyName, double pauseTime, Element element); - [RaisesException] boolean pauseTransitionAtTimeOnPseudoElement(DOMString property, double pauseTime, Element element, DOMString pseudoId); - - [RaisesException] boolean attached(Node node); + [MayThrowException] boolean pauseTransitionAtTimeOnElement(DOMString propertyName, unrestricted double pauseTime, Element element); + [MayThrowException] boolean pauseTransitionAtTimeOnPseudoElement(DOMString property, unrestricted double pauseTime, Element element, DOMString pseudoId); DOMString visiblePlaceholder(Element element); -#if defined(ENABLE_INPUT_TYPE_COLOR) && ENABLE_INPUT_TYPE_COLOR - void selectColorInColorChooser(Element element, DOMString colorValue); -#endif - [RaisesException] DOMString[] formControlStateOfPreviousHistoryItem(); - [RaisesException] void setFormControlStateOfPreviousHistoryItem(sequence<DOMString> values); + void selectColorInColorChooser(HTMLInputElement element, DOMString colorValue); + [MayThrowException] sequence<DOMString> formControlStateOfPreviousHistoryItem(); + [MayThrowException] void setFormControlStateOfPreviousHistoryItem(sequence<DOMString> values); - [RaisesException] ClientRect absoluteCaretBounds(); + [MayThrowException] ClientRect absoluteCaretBounds(); - [RaisesException] ClientRect boundingBox(Element element); + ClientRect boundingBox(Element element); - [RaisesException] ClientRectList inspectorHighlightRects(); - [RaisesException] DOMString inspectorHighlightObject(); + [MayThrowException] ClientRectList inspectorHighlightRects(); + [MayThrowException] DOMString inspectorHighlightObject(); - [RaisesException] unsigned long markerCountForNode(Node node, DOMString markerType); - [RaisesException] Range markerRangeForNode(Node node, DOMString markerType, unsigned long index); - [RaisesException] DOMString markerDescriptionForNode(Node node, DOMString markerType, unsigned long index); + [MayThrowException] unsigned long markerCountForNode(Node node, DOMString markerType); + [MayThrowException] Range? markerRangeForNode(Node node, DOMString markerType, unsigned long index); + [MayThrowException] DOMString markerDescriptionForNode(Node node, DOMString markerType, unsigned long index); + [MayThrowException] DOMString dumpMarkerRects(DOMString markerType); void addTextMatchMarker(Range range, boolean isActive); + [MayThrowException] void setMarkedTextMatchesAreHighlighted(boolean flag); + + void invalidateFontCache(); + + [MayThrowException] void setScrollViewPosition(long x, long y); + + [MayThrowException] ClientRect layoutViewportRect(); + [MayThrowException] ClientRect visualViewportRect(); + + [MayThrowException] void setViewBaseBackgroundColor(DOMString colorValue); - [RaisesException] void setScrollViewPosition(long x, long y); + [MayThrowException] void setPagination(DOMString mode, long gap, optional long pageLength = 0); + [MayThrowException] void setPaginationLineGridEnabled(boolean enabled); - [RaisesException] void setPagination(DOMString mode, long gap, optional long pageLength); + [MayThrowException] DOMString configurationForViewport(unrestricted float devicePixelRatio, long deviceWidth, long deviceHeight, long availableWidth, long availableHeight); - [RaisesException] DOMString configurationForViewport(float devicePixelRatio, - long deviceWidth, - long deviceHeight, - long availableWidth, - long availableHeight); + [MayThrowException] boolean wasLastChangeUserEdit(Element textField); + boolean elementShouldAutoComplete(HTMLInputElement inputElement); + void setEditingValue(HTMLInputElement inputElement, DOMString value); + void setAutofilled(HTMLInputElement inputElement, boolean enabled); + void setShowAutoFillButton(HTMLInputElement inputElement, AutoFillButtonType autoFillButtonType); - [RaisesException] boolean wasLastChangeUserEdit(Element textField); - [RaisesException] boolean elementShouldAutoComplete(Element inputElement); - [RaisesException] DOMString suggestedValue(Element inputElement); - [RaisesException] void setSuggestedValue(Element inputElement, DOMString value); - [RaisesException] void setEditingValue(Element inputElement, DOMString value); - [RaisesException] void setAutofilled(Element inputElement, boolean enabled); + [MayThrowException] Range? rangeOfString(DOMString text, Range? referenceRange, sequence<DOMString> findOptions); + [MayThrowException] unsigned long countMatchesForText(DOMString text, sequence<DOMString> findOptions, DOMString markMatches); + [MayThrowException] unsigned long countFindMatches(DOMString text, sequence<DOMString> findOptions); - [RaisesException] void paintControlTints(); + [MayThrowException] DOMString autofillFieldName(Element formControlElement); - [RaisesException] void scrollElementToRect(Element element, long x, long y, long w, long h); + [MayThrowException] void paintControlTints(); - [RaisesException] Range rangeFromLocationAndLength(Element scope, long rangeLocation, long rangeLength); - [RaisesException] unsigned long locationFromRange(Element scope, Range range); - [RaisesException] unsigned long lengthFromRange(Element scope, Range range); - [RaisesException] DOMString rangeAsText(Range range); + [MayThrowException] void scrollElementToRect(Element element, long x, long y, long w, long h); - [RaisesException] void setDelegatesScrolling(boolean enabled); + Range? rangeFromLocationAndLength(Element scope, long rangeLocation, long rangeLength); + unsigned long locationFromRange(Element scope, Range range); + unsigned long lengthFromRange(Element scope, Range range); + DOMString rangeAsText(Range range); + Range subrange(Range range, long rangeLocation, long rangeLength); + [MayThrowException] Range? rangeForDictionaryLookupAtLocation(long x, long y); + Range? rangeOfStringNearLocation(Range range, DOMString text, long targetOffset); - [RaisesException] long lastSpellCheckRequestSequence(); - [RaisesException] long lastSpellCheckProcessedSequence(); + [MayThrowException] void setDelegatesScrolling(boolean enabled); + + [MayThrowException] long lastSpellCheckRequestSequence(); + [MayThrowException] long lastSpellCheckProcessedSequence(); sequence<DOMString> userPreferredLanguages(); void setUserPreferredLanguages(sequence<DOMString> languages); - [RaisesException] unsigned long wheelEventHandlerCount(); - [RaisesException] unsigned long touchEventHandlerCount(); + sequence<DOMString> userPreferredAudioCharacteristics(); + void setUserPreferredAudioCharacteristic(DOMString characteristic); + + [MayThrowException] unsigned long wheelEventHandlerCount(); + [MayThrowException] unsigned long touchEventHandlerCount(); - [RaisesException] NodeList nodesFromRect(Document document, long x, long y, + [MayThrowException] NodeList? nodesFromRect(Document document, long x, long y, unsigned long topPadding, unsigned long rightPadding, unsigned long bottomPadding, unsigned long leftPadding, boolean ignoreClipping, boolean allowShadowContent, boolean allowChildFrameContent); - void emitInspectorDidBeginFrame(); - void emitInspectorDidCancelFrame(); - // Calling parserMetaData() with no arguments gets the metadata for the script of the current scope. DOMString parserMetaData(optional any func); - [RaisesException] boolean hasSpellingMarker(long from, long length); - [RaisesException] boolean hasGrammarMarker(long from, long length); - [RaisesException] boolean hasAutocorrectedMarker(long from, long length); - [RaisesException] void setContinuousSpellCheckingEnabled(boolean enabled); - [RaisesException] void setAutomaticQuoteSubstitutionEnabled(boolean enabled); - [RaisesException] void setAutomaticLinkDetectionEnabled(boolean enabled); - [RaisesException] void setAutomaticDashSubstitutionEnabled(boolean enabled); - [RaisesException] void setAutomaticTextReplacementEnabled(boolean enabled); - [RaisesException] void setAutomaticSpellingCorrectionEnabled(boolean enabled); + void updateEditorUINowIfScheduled(); + + boolean hasSpellingMarker(long from, long length); + boolean hasGrammarMarker(long from, long length); + boolean hasAutocorrectedMarker(long from, long length); + void setContinuousSpellCheckingEnabled(boolean enabled); + void setAutomaticQuoteSubstitutionEnabled(boolean enabled); + void setAutomaticLinkDetectionEnabled(boolean enabled); + void setAutomaticDashSubstitutionEnabled(boolean enabled); + void setAutomaticTextReplacementEnabled(boolean enabled); + void setAutomaticSpellingCorrectionEnabled(boolean enabled); + + void handleAcceptedCandidate(DOMString candidate, unsigned long location, unsigned long length); - [RaisesException] boolean isOverwriteModeEnabled(); - [RaisesException] void toggleOverwriteModeEnabled(); + boolean isOverwriteModeEnabled(); + void toggleOverwriteModeEnabled(); - [RaisesException] unsigned long numberOfScrollableAreas(); + unsigned long numberOfScrollableAreas(); - [RaisesException] boolean isPageBoxVisible(long pageNumber); + [MayThrowException] boolean isPageBoxVisible(long pageNumber); + + unsigned long imageFrameIndex(HTMLImageElement element); + void setImageFrameDecodingDuration(HTMLImageElement element, unrestricted float duration); + void resetImageAnimation(HTMLImageElement element); readonly attribute InternalSettings settings; readonly attribute unsigned long workerThreadCount; + readonly attribute boolean areSVGAnimationsPaused; + // Flags for layerTreeAsText. const unsigned short LAYER_TREE_INCLUDES_VISIBLE_RECTS = 1; const unsigned short LAYER_TREE_INCLUDES_TILE_CACHES = 2; const unsigned short LAYER_TREE_INCLUDES_REPAINT_RECTS = 4; const unsigned short LAYER_TREE_INCLUDES_PAINTING_PHASES = 8; const unsigned short LAYER_TREE_INCLUDES_CONTENT_LAYERS = 16; - [RaisesException] DOMString layerTreeAsText(Document document, optional unsigned short flags); + const unsigned short LAYER_TREE_INCLUDES_ACCELERATES_DRAWING = 32; + [MayThrowException] DOMString layerTreeAsText(Document document, optional unsigned short flags = 0); - [RaisesException] DOMString scrollingStateTreeAsText(); - [RaisesException] DOMString mainThreadScrollingReasons(); // FIXME: rename to synchronousScrollingReasons(). - [RaisesException] ClientRectList nonFastScrollableRects(); + [MayThrowException] DOMString scrollingStateTreeAsText(); + [MayThrowException] DOMString mainThreadScrollingReasons(); // FIXME: rename to synchronousScrollingReasons(). + [MayThrowException] ClientRectList? nonFastScrollableRects(); - [RaisesException] DOMString repaintRectsAsText(); + [MayThrowException] DOMString repaintRectsAsText(); - [RaisesException] void garbageCollectDocumentResources(); + // These throw if the element does not have a compositing layer. + [MayThrowException] void setElementUsesDisplayListDrawing(Element element, boolean usesDisplayListDrawing); + [MayThrowException] void setElementTracksDisplayListReplay(Element element, boolean trackReplay); - void allowRoundingHacks(); + // Flags for displayListForElement. + const unsigned short DISPLAY_LIST_INCLUDES_PLATFORM_OPERATIONS = 1; + // Returns the recorded display list. + [MayThrowException] DOMString displayListForElement(Element element, optional unsigned short flags = 0); + // Returns the display list that was actually painted. + [MayThrowException] DOMString replayDisplayListForElement(Element element, optional unsigned short flags = 0); - [RaisesException] void insertAuthorCSS(DOMString css); - [RaisesException] void insertUserCSS(DOMString css); + [MayThrowException] void garbageCollectDocumentResources(); -#if defined(ENABLE_BATTERY_STATUS) && ENABLE_BATTERY_STATUS - [RaisesException] void setBatteryStatus(DOMString eventType, boolean charging, double chargingTime, double dischargingTime, double level); -#endif + [MayThrowException] void insertAuthorCSS(DOMString css); + [MayThrowException] void insertUserCSS(DOMString css); -#if defined(ENABLE_NETWORK_INFO) && ENABLE_NETWORK_INFO - [RaisesException] void setNetworkInformation(DOMString eventType, double bandwidth, boolean metered); -#endif + readonly attribute boolean isUnderMemoryPressure; + void beginSimulatedMemoryPressure(); + void endSimulatedMemoryPressure(); #if defined(ENABLE_PROXIMITY_EVENTS) && ENABLE_PROXIMITY_EVENTS - [RaisesException] void setDeviceProximity(DOMString eventType, double value, double min, double max); + [MayThrowException] void setDeviceProximity(DOMString eventType, unrestricted double value, unrestricted double min, unrestricted double max); #endif - [Conditional=INSPECTOR] unsigned long numberOfLiveNodes(); - [Conditional=INSPECTOR] unsigned long numberOfLiveDocuments(); - [Conditional=INSPECTOR] sequence<DOMString> consoleMessageArgumentCounts(); - [Conditional=INSPECTOR] DOMWindow openDummyInspectorFrontend(DOMString url); - [Conditional=INSPECTOR] void closeDummyInspectorFrontend(); - [Conditional=INSPECTOR, RaisesException] void setInspectorResourcesDataSizeLimits(long maximumResourcesContentSize, long maximumSingleResourceContentSize); - [Conditional=INSPECTOR, RaisesException] void setJavaScriptProfilingEnabled(boolean creates); + unsigned long numberOfLiveNodes(); + unsigned long numberOfLiveDocuments(); + DOMWindow? openDummyInspectorFrontend(DOMString url); + void closeDummyInspectorFrontend(); + [MayThrowException] void setInspectorIsUnderTest(boolean isUnderTest); DOMString counterValue(Element element); - long pageNumber(Element element, optional float pageWidth, optional float pageHeight); - DOMString[] shortcutIconURLs(); - DOMString[] allIconURLs(); - long numberOfPages(optional double pageWidthInPixels, optional double pageHeightInPixels); - [RaisesException] DOMString pageProperty(DOMString propertyName, long pageNumber); - [RaisesException] DOMString pageSizeAndMarginsInPixels(long pageIndex, long width, long height, long marginTop, long marginRight, long marginBottom, long marginLeft); + long pageNumber(Element element, optional unrestricted float pageWidth = 800, optional unrestricted float pageHeight = 600); + sequence<DOMString> shortcutIconURLs(); + long numberOfPages(optional unrestricted double pageWidthInPixels = 800, optional unrestricted double pageHeightInPixels = 600); + [MayThrowException] DOMString pageProperty(DOMString propertyName, long pageNumber); + [MayThrowException] DOMString pageSizeAndMarginsInPixels(long pageIndex, long width, long height, long marginTop, long marginRight, long marginBottom, long marginLeft); - [RaisesException] void setPageScaleFactor(float scaleFactor, long x, long y); + [MayThrowException] void setPageScaleFactor(unrestricted float scaleFactor, long x, long y); + [MayThrowException] float pageScaleFactor(); - void setHeaderHeight(float height); - void setFooterHeight(float height); + [MayThrowException] void setPageZoomFactor(unrestricted float zoomFactor); + [MayThrowException] void setTextZoomFactor(unrestricted float zoomFactor); + + [MayThrowException] void setUseFixedLayout(boolean useFixedLayout); + [MayThrowException] void setFixedLayoutSize(long width, long height); + + [MayThrowException] void setViewExposedRect(unrestricted float x, unrestricted float y, unrestricted float width, unrestricted float height); + + void setHeaderHeight(unrestricted float height); + void setFooterHeight(unrestricted float height); + + void setTopContentInset(unrestricted float contentInset); #if defined(ENABLE_FULLSCREEN_API) && ENABLE_FULLSCREEN_API void webkitWillEnterFullScreenForElement(Element element); @@ -220,64 +328,180 @@ void registerURLSchemeAsBypassingContentSecurityPolicy(DOMString scheme); void removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(DOMString scheme); + void registerDefaultPortForProtocol(unsigned short port, DOMString scheme); + MallocStatistics mallocStatistics(); TypeConversions typeConversions(); MemoryInfo memoryInfo(); - DOMString[] getReferencedFilePaths(); + sequence<DOMString> getReferencedFilePaths(); - // These functions both reset the tracked repaint rects. They are inteded to be used in the following order: + // These functions both reset the tracked repaint rects. They are intended to be used in the following order: // startTrackingRepaints, repaintRectsAsText, stopTrackingRepaints. - [RaisesException] void startTrackingRepaints(); - [RaisesException] void stopTrackingRepaints(); + [MayThrowException] void startTrackingRepaints(); + [MayThrowException] void stopTrackingRepaints(); + + [MayThrowException] void startTrackingLayerFlushes(); + [MayThrowException] unsigned long layerFlushCount(); + + // Query if a timer is currently throttled, to debug timer throttling. + [MayThrowException] boolean isTimerThrottled(long timerHandle); + + boolean isRequestAnimationFrameThrottled(); + boolean areTimersThrottled(); + + // Override the behavior of WebPage::eventThrottlingDelay(), which only affects iOS. + attribute EventThrottlingBehavior? eventThrottlingBehaviorOverride; + + [MayThrowException] void startTrackingStyleRecalcs(); + [MayThrowException] unsigned long styleRecalcCount(); + readonly attribute unsigned long lastStyleUpdateSize; + + [MayThrowException] void startTrackingCompositingUpdates(); + [MayThrowException] unsigned long compositingUpdateCount(); // |node| should be Document, HTMLIFrameElement, or unspecified. // If |node| is an HTMLIFrameElement, it assumes node.contentDocument is - // specified without security checks. Unspecified means this document. - [RaisesException] void updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(optional Node node); + // specified without security checks. Unspecified or null means this document. + [MayThrowException] void updateLayoutIgnorePendingStylesheetsAndRunPostLayoutTasks(optional Node? node = null); + + readonly attribute unsigned long layoutCount; // Returns a string with information about the mouse cursor used at the specified client location. - [RaisesException] DOMString getCurrentCursorInfo(); + [MayThrowException] DOMString getCurrentCursorInfo(); - [RaisesException] DOMString markerTextForListItem(Element element); + DOMString markerTextForListItem(Element element); + + DOMString toolTipFromElement(Element element); SerializedScriptValue deserializeBuffer(ArrayBuffer buffer); - ArrayBuffer serializeObject(SerializedScriptValue obj); + ArrayBuffer serializeObject(SerializedScriptValue object); + + boolean isFromCurrentWorld(any obj); void setUsesOverlayScrollbars(boolean enabled); + void setUsesMockScrollAnimator(boolean enabled); void forceReload(boolean endToEnd); - [Conditional=VIDEO] void simulateAudioInterruption(Node node); + void enableAutoSizeMode(boolean enabled, long minimumWidth, long minimumHeight, long maximumWidth, long maximumHeight); - [Conditional=ENCRYPTED_MEDIA_V2] void initializeMockCDM(); + [Conditional=VIDEO] void simulateAudioInterruption(HTMLMediaElement element); + [Conditional=VIDEO, MayThrowException] boolean mediaElementHasCharacteristic(HTMLMediaElement element, DOMString characteristic); + + [Conditional=LEGACY_ENCRYPTED_MEDIA] void initializeMockCDM(); + [Conditional=ENCRYPTED_MEDIA] MockCDMFactory registerMockCDM(); [Conditional=SPEECH_SYNTHESIS] void enableMockSpeechSynthesizer(); - [RaisesException] DOMString getImageSourceURL(Element element); + DOMString getImageSourceURL(Element element); - [Conditional=VIDEO_TRACK, RaisesException] DOMString captionsStyleSheetOverride(); - [Conditional=VIDEO_TRACK, RaisesException] void setCaptionsStyleSheetOverride(DOMString override); - [Conditional=VIDEO_TRACK, RaisesException] void setPrimaryAudioTrackLanguageOverride(DOMString language); - [Conditional=VIDEO_TRACK, RaisesException] void setCaptionDisplayMode(DOMString mode); + [Conditional=VIDEO_TRACK, MayThrowException] DOMString captionsStyleSheetOverride(); + [Conditional=VIDEO_TRACK, MayThrowException] void setCaptionsStyleSheetOverride(DOMString override); + [Conditional=VIDEO_TRACK, MayThrowException] void setPrimaryAudioTrackLanguageOverride(DOMString language); + [Conditional=VIDEO_TRACK, MayThrowException] void setCaptionDisplayMode(DOMString mode); [Conditional=VIDEO] TimeRanges createTimeRanges(Float32Array startTimes, Float32Array endTimes); - [Conditional=VIDEO] double closestTimeToTimeRanges(double time, TimeRanges ranges); + [Conditional=VIDEO] unrestricted double closestTimeToTimeRanges(unrestricted double time, TimeRanges ranges); - boolean isSelectPopupVisible(Node node); + boolean isSelectPopupVisible(HTMLSelectElement element); #if defined(ENABLE_VIBRATION) && ENABLE_VIBRATION boolean isVibrating(); #endif - [RaisesException] boolean isPluginUnavailabilityIndicatorObscured(Element element); + [MayThrowException] boolean isPluginUnavailabilityIndicatorObscured(Element element); + boolean isPluginSnapshotted(Element element); + + [MayThrowException] ClientRect selectionBounds(); - [RaisesException] ClientRect selectionBounds(); - [Conditional=MEDIA_SOURCE] void initializeMockMediaSource(); + [Conditional=MEDIA_SOURCE] sequence<DOMString> bufferedSamplesForTrackID(SourceBuffer buffer, DOMString trackID); + [Conditional=MEDIA_SOURCE] sequence<DOMString> enqueuedSamplesForTrackID(SourceBuffer buffer, DOMString trackID); + [Conditional=MEDIA_SOURCE] void setShouldGenerateTimestamps(SourceBuffer buffer, boolean flag); + + [Conditional=VIDEO, MayThrowException] void beginMediaSessionInterruption(DOMString interruptionType); + [Conditional=VIDEO] void endMediaSessionInterruption(DOMString flags); + [Conditional=MEDIA_SESSION] void sendMediaSessionStartOfInterruptionNotification(MediaSessionInterruptingCategory category); + [Conditional=MEDIA_SESSION] void sendMediaSessionEndOfInterruptionNotification(MediaSessionInterruptingCategory category); + [Conditional=MEDIA_SESSION] DOMString mediaSessionCurrentState(MediaSession session); + [Conditional=MEDIA_SESSION] double mediaElementPlayerVolume(HTMLMediaElement element); + [Conditional=MEDIA_SESSION] void sendMediaControlEvent(MediaControlEvent event); + [Conditional=VIDEO] void applicationDidEnterForeground(); + [Conditional=VIDEO] void applicationWillEnterBackground(); + [Conditional=VIDEO, MayThrowException] void setMediaSessionRestrictions(DOMString mediaType, DOMString restrictions); + [Conditional=VIDEO, MayThrowException] DOMString mediaSessionRestrictions(DOMString mediaType); + [Conditional=VIDEO] void setMediaElementRestrictions(HTMLMediaElement element, DOMString restrictions); + [Conditional=WEB_AUDIO] void setAudioContextRestrictions(AudioContext context, DOMString restrictions); + [Conditional=VIDEO, MayThrowException] void postRemoteControlCommand(DOMString command, optional unrestricted float argument = 0); + [Conditional=WIRELESS_PLAYBACK_TARGET] void setMockMediaPlaybackTargetPickerEnabled(boolean enabled); + [Conditional=WIRELESS_PLAYBACK_TARGET, MayThrowException] void setMockMediaPlaybackTargetPickerState(DOMString deviceName, DOMString deviceState); + [Conditional=MEDIA_STREAM] void setMockMediaCaptureDevicesEnabled(boolean enabled); + [Conditional=WEB_RTC] void emulateRTCPeerConnectionPlatformEvent(RTCPeerConnection connection, DOMString action); + [Conditional=WEB_RTC] void useMockRTCPeerConnectionFactory(DOMString testCase); + + [Conditional=VIDEO] void simulateSystemSleep(); + [Conditional=VIDEO] void simulateSystemWake(); + [Conditional=VIDEO] boolean elementIsBlockingDisplaySleep(HTMLMediaElement element); + + [MayThrowException] MockPageOverlay installMockPageOverlay(PageOverlayType type); + [MayThrowException] DOMString pageOverlayLayerTreeAsText(optional unsigned short flags = 0); + + void setPageMuted(DOMString mutedState); + DOMString pageMediaState(); + + void setPageDefersLoading(boolean defersLoading); + + File? createFile(DOMString url); + void queueMicroTask(long testNumber); + boolean testPreloaderSettingViewport(); + + [Conditional=CONTENT_FILTERING] readonly attribute MockContentFilterSettings mockContentFilterSettings; + +#if defined(ENABLE_CSS_SCROLL_SNAP) && ENABLE_CSS_SCROLL_SNAP + [MayThrowException] DOMString scrollSnapOffsets(Element element); + void setPlatformMomentumScrollingPredictionEnabled(boolean enabled); +#endif + + [MayThrowException] DOMString pathStringWithShrinkWrappedRects(sequence<double> rectComponents, double radius); + + [Conditional=VIDEO] DOMString getCurrentMediaControlsStatusForElement(HTMLMediaElement element); + + DOMString userVisibleString(DOMURL url); + + void setShowAllPlugins(boolean showAll); + + [Conditional=READABLE_STREAM_API, CallWith=ScriptState] boolean isReadableStreamDisturbed(any stream); + + DOMString resourceLoadStatisticsForOrigin(DOMString domain); + void setResourceLoadStatisticsEnabled(boolean enable); + + [MayThrowException] void setCanShowModalDialogOverride(boolean allow); + + DOMString composedTreeAsText(Node parent); + + boolean isProcessingUserGesture(); + + GCObservation? observeGC(any observed); + + void setUserInterfaceLayoutDirection(UserInterfaceLayoutDirection userInterfaceLayoutDirection); + void setBaseWritingDirection(BaseWritingDirection direction); + + boolean userPrefersReducedMotion(); + + void reportBacktrace(); + + [Conditional=POINTER_LOCK] boolean pageHasPendingPointerLock(); + [Conditional=POINTER_LOCK] boolean pageHasPointerLock(); + + sequence<DOMString> accessKeyModifiers(); + +#if defined(WTF_PLATFORM_IOS) && WTF_PLATFORM_IOS + void setQuickLookPassword(DOMString password); +#endif + + [CallWith=Document] void setAsRunningUserScripts(); - void beginMediaSessionInterruption(); - void endMediaSessionInterruption(DOMString flags); - [RaisesException] void setMediaSessionRestrictions(DOMString mediaType, DOMString restrictions); + void disableTileSizeUpdateDelay(); }; diff --git a/Source/WebCore/testing/LegacyMockCDM.cpp b/Source/WebCore/testing/LegacyMockCDM.cpp new file mode 100644 index 000000000..b1a56aa21 --- /dev/null +++ b/Source/WebCore/testing/LegacyMockCDM.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``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 ITS 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 "LegacyMockCDM.h" + +#if ENABLE(LEGACY_ENCRYPTED_MEDIA) + +#include "LegacyCDM.h" +#include "LegacyCDMSession.h" +#include "WebKitMediaKeyError.h" +#include <runtime/JSCInlines.h> +#include <runtime/TypedArrayInlines.h> +#include <runtime/Uint8Array.h> + +namespace WebCore { + +class MockCDMSession : public CDMSession { +public: + MockCDMSession(CDMSessionClient*); + virtual ~MockCDMSession() { } + + void setClient(CDMSessionClient* client) override { m_client = client; } + const String& sessionId() const override { return m_sessionId; } + RefPtr<Uint8Array> generateKeyRequest(const String& mimeType, Uint8Array* initData, String& destinationURL, unsigned short& errorCode, uint32_t& systemCode) override; + void releaseKeys() override; + bool update(Uint8Array*, RefPtr<Uint8Array>& nextMessage, unsigned short& errorCode, uint32_t& systemCode) override; + +protected: + CDMSessionClient* m_client; + String m_sessionId; +}; + +bool MockCDM::supportsKeySystem(const String& keySystem) +{ + return equalLettersIgnoringASCIICase(keySystem, "com.webcore.mock"); +} + +bool MockCDM::supportsKeySystemAndMimeType(const String& keySystem, const String& mimeType) +{ + if (!supportsKeySystem(keySystem)) + return false; + + return equalLettersIgnoringASCIICase(mimeType, "video/mock"); +} + +bool MockCDM::supportsMIMEType(const String& mimeType) +{ + return equalLettersIgnoringASCIICase(mimeType, "video/mock"); +} + +std::unique_ptr<CDMSession> MockCDM::createSession(CDMSessionClient* client) +{ + return std::make_unique<MockCDMSession>(client); +} + +static Uint8Array* initDataPrefix() +{ + const unsigned char prefixData[] = { 'm', 'o', 'c', 'k' }; + static Uint8Array* prefix = Uint8Array::create(prefixData, WTF_ARRAY_LENGTH(prefixData)).leakRef(); + + return prefix; +} + +static Uint8Array* keyPrefix() +{ + static const unsigned char prefixData[] = {'k', 'e', 'y'}; + static Uint8Array* prefix = Uint8Array::create(prefixData, WTF_ARRAY_LENGTH(prefixData)).leakRef(); + + return prefix; +} + +static Uint8Array* keyRequest() +{ + static const unsigned char requestData[] = {'r', 'e', 'q', 'u', 'e', 's', 't'}; + static Uint8Array* request = Uint8Array::create(requestData, WTF_ARRAY_LENGTH(requestData)).leakRef(); + + return request; +} + +static String generateSessionId() +{ + static int monotonicallyIncreasingSessionId = 0; + return String::number(monotonicallyIncreasingSessionId++); +} + +MockCDMSession::MockCDMSession(CDMSessionClient* client) + : m_client(client) + , m_sessionId(generateSessionId()) +{ +} + +RefPtr<Uint8Array> MockCDMSession::generateKeyRequest(const String&, Uint8Array* initData, String&, unsigned short& errorCode, uint32_t&) +{ + for (unsigned i = 0; i < initDataPrefix()->length(); ++i) { + if (!initData || i >= initData->length() || initData->item(i) != initDataPrefix()->item(i)) { + errorCode = WebKitMediaKeyError::MEDIA_KEYERR_UNKNOWN; + return nullptr; + } + } + return keyRequest(); +} + +void MockCDMSession::releaseKeys() +{ + // no-op +} + +bool MockCDMSession::update(Uint8Array* key, RefPtr<Uint8Array>&, unsigned short& errorCode, uint32_t&) +{ + for (unsigned i = 0; i < keyPrefix()->length(); ++i) { + if (i >= key->length() || key->item(i) != keyPrefix()->item(i)) { + errorCode = WebKitMediaKeyError::MEDIA_KEYERR_CLIENT; + return false; + } + } + return true; +} + +} + +#endif // ENABLE(LEGACY_ENCRYPTED_MEDIA) diff --git a/Source/WebCore/testing/LegacyMockCDM.h b/Source/WebCore/testing/LegacyMockCDM.h new file mode 100644 index 000000000..0161ad3d8 --- /dev/null +++ b/Source/WebCore/testing/LegacyMockCDM.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#if ENABLE(LEGACY_ENCRYPTED_MEDIA) + +#include "LegacyCDMPrivate.h" + +namespace WebCore { + +class CDM; + +class MockCDM : public CDMPrivateInterface { +public: + explicit MockCDM(CDM* cdm) + : m_cdm(cdm) + { } + + // CDMFactory support: + static bool supportsKeySystem(const String&); + static bool supportsKeySystemAndMimeType(const String& keySystem, const String& mimeType); + + virtual ~MockCDM() { } + + bool supportsMIMEType(const String& mimeType) override; + std::unique_ptr<CDMSession> createSession(CDMSessionClient*) override; + +protected: + CDM* m_cdm; +}; + +} // namespace WebCore + +#endif // ENABLE(LEGACY_ENCRYPTED_MEDIA) diff --git a/Source/WebCore/testing/MallocStatistics.h b/Source/WebCore/testing/MallocStatistics.h index 3f07bbd9f..f08c4e212 100644 --- a/Source/WebCore/testing/MallocStatistics.h +++ b/Source/WebCore/testing/MallocStatistics.h @@ -23,18 +23,16 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MallocStatistics_h -#define MallocStatistics_h +#pragma once #include <wtf/FastMalloc.h> -#include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> namespace WebCore { class MallocStatistics : public RefCounted<MallocStatistics> { public: - static PassRefPtr<MallocStatistics> create() { return adoptRef(new MallocStatistics()); } + static Ref<MallocStatistics> create() { return adoptRef(*new MallocStatistics); } size_t reservedVMBytes() const { return m_stats.reservedVMBytes; } size_t committedVMBytes() const { return m_stats.committedVMBytes; } @@ -50,5 +48,3 @@ private: }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/testing/MallocStatistics.idl b/Source/WebCore/testing/MallocStatistics.idl index d9c817b91..c6e471e0b 100644 --- a/Source/WebCore/testing/MallocStatistics.idl +++ b/Source/WebCore/testing/MallocStatistics.idl @@ -25,7 +25,8 @@ [ NoInterfaceObject, - ImplementationLacksVTable + ImplementationLacksVTable, + ExportMacro=WEBCORE_TESTSUPPORT_EXPORT, ] interface MallocStatistics { readonly attribute unsigned long reservedVMBytes; readonly attribute unsigned long committedVMBytes; diff --git a/Source/WebCore/testing/MemoryInfo.h b/Source/WebCore/testing/MemoryInfo.h index d4d298443..06084a83f 100644 --- a/Source/WebCore/testing/MemoryInfo.h +++ b/Source/WebCore/testing/MemoryInfo.h @@ -28,26 +28,25 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef MemoryInfo_h -#define MemoryInfo_h +#pragma once +#include "CommonVM.h" #include "JSDOMWindow.h" -#include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> namespace WebCore { class MemoryInfo : public RefCounted<MemoryInfo> { public: - static PassRefPtr<MemoryInfo> create() { return adoptRef(new MemoryInfo); } + static Ref<MemoryInfo> create() { return adoptRef(*new MemoryInfo); } size_t usedJSHeapSize() const { return m_usedJSHeapSize; } size_t totalJSHeapSize() const { return m_totalJSHeapSize; } private: MemoryInfo() - : m_usedJSHeapSize(JSDOMWindow::commonVM()->heap.size()) - , m_totalJSHeapSize(JSDOMWindow::commonVM()->heap.capacity()) + : m_usedJSHeapSize(commonVM().heap.size()) + , m_totalJSHeapSize(commonVM().heap.capacity()) { } @@ -56,5 +55,3 @@ private: }; } // namespace WebCore - -#endif // MemoryInfo_h diff --git a/Source/WebCore/testing/MemoryInfo.idl b/Source/WebCore/testing/MemoryInfo.idl index 6eb998721..54c7cff21 100644 --- a/Source/WebCore/testing/MemoryInfo.idl +++ b/Source/WebCore/testing/MemoryInfo.idl @@ -30,7 +30,8 @@ [ NoInterfaceObject, - ImplementationLacksVTable + ImplementationLacksVTable, + ExportMacro=WEBCORE_TESTSUPPORT_EXPORT, ] interface MemoryInfo { readonly attribute unsigned long usedJSHeapSize; readonly attribute unsigned long totalJSHeapSize; diff --git a/Source/WebCore/testing/MockCDMFactory.cpp b/Source/WebCore/testing/MockCDMFactory.cpp new file mode 100644 index 000000000..f3b4a47e6 --- /dev/null +++ b/Source/WebCore/testing/MockCDMFactory.cpp @@ -0,0 +1,382 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockCDMFactory.h" + +#if ENABLE(ENCRYPTED_MEDIA) + +#include "InitDataRegistry.h" +#include "UUID.h" +#include <runtime/ArrayBuffer.h> +#include <wtf/text/StringHash.h> +#include <wtf/text/StringView.h> + +namespace WebCore { + +MockCDMFactory::MockCDMFactory() + : m_supportedSessionTypes({ MediaKeySessionType::Temporary, MediaKeySessionType::PersistentUsageRecord, MediaKeySessionType::PersistentLicense }) + , m_weakPtrFactory(this) +{ + CDM::registerCDMFactory(*this); +} + +MockCDMFactory::~MockCDMFactory() +{ + unregister(); +} + +void MockCDMFactory::unregister() +{ + if (m_registered) { + CDM::unregisterCDMFactory(*this); + m_registered = false; + } +} + +bool MockCDMFactory::supportsKeySystem(const String& keySystem) +{ + return equalIgnoringASCIICase(keySystem, "org.webkit.mock"); +} + +void MockCDMFactory::addKeysToSessionWithID(const String& id, Vector<Ref<SharedBuffer>>&& keys) +{ + auto addResult = m_sessions.add(id, WTFMove(keys)); + if (addResult.isNewEntry) + return; + + auto& value = addResult.iterator->value; + for (auto& key : keys) + value.append(WTFMove(key)); +} + +Vector<Ref<SharedBuffer>> MockCDMFactory::removeKeysFromSessionWithID(const String& id) +{ + auto it = m_sessions.find(id); + if (it == m_sessions.end()) + return { }; + + return WTFMove(it->value); +} + +std::optional<const Vector<Ref<SharedBuffer>>&> MockCDMFactory::keysForSessionWithID(const String& id) const +{ + auto it = m_sessions.find(id); + if (it == m_sessions.end()) + return std::nullopt; + return it->value; +} + +void MockCDMFactory::setSupportedDataTypes(Vector<String>&& types) +{ + m_supportedDataTypes.clear(); + for (auto& type : types) + m_supportedDataTypes.append(type); +} + +std::unique_ptr<CDMPrivate> MockCDMFactory::createCDM(CDM&) +{ + return std::make_unique<MockCDM>(m_weakPtrFactory.createWeakPtr()); +} + +MockCDM::MockCDM(WeakPtr<MockCDMFactory> factory) + : m_factory(WTFMove(factory)) + , m_weakPtrFactory(this) +{ +} + +bool MockCDM::supportsInitDataType(const AtomicString& initDataType) const +{ + if (m_factory) + return m_factory->supportedDataTypes().contains(initDataType); + return false; +} + +bool MockCDM::supportsConfiguration(const MediaKeySystemConfiguration&) const +{ + // NOTE: Implement; + return true; + +} + +bool MockCDM::supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const +{ + // NOTE: Implement; + return true; +} + +bool MockCDM::supportsSessionTypeWithConfiguration(MediaKeySessionType& sessionType, const MediaKeySystemConfiguration&) const +{ + if (!m_factory || !m_factory->supportedSessionTypes().contains(sessionType)) + return false; + + // NOTE: Implement configuration checking; + return true; +} + +bool MockCDM::supportsRobustness(const String& robustness) const +{ + if (m_factory) + return m_factory->supportedRobustness().contains(robustness); + return false; +} + +MediaKeysRequirement MockCDM::distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const +{ + if (m_factory) + return m_factory->distinctiveIdentifiersRequirement(); + return MediaKeysRequirement::Optional; +} + +MediaKeysRequirement MockCDM::persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const +{ + if (m_factory) + return m_factory->persistentStateRequirement(); + return MediaKeysRequirement::Optional; +} + +bool MockCDM::distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&) const +{ + // NOTE: Implement; + return true; +} + +RefPtr<CDMInstance> MockCDM::createInstance() +{ + if (m_factory && !m_factory->canCreateInstances()) + return nullptr; + return adoptRef(new MockCDMInstance(m_weakPtrFactory.createWeakPtr())); +} + +void MockCDM::loadAndInitialize() +{ + // No-op. +} + +bool MockCDM::supportsServerCertificates() const +{ + return m_factory && m_factory->supportsServerCertificates(); +} + +bool MockCDM::supportsSessions() const +{ + return m_factory && m_factory->supportsSessions(); +} + +bool MockCDM::supportsInitData(const AtomicString& initDataType, const SharedBuffer& initData) const +{ + if (!supportsInitDataType(initDataType)) + return false; + + UNUSED_PARAM(initData); + return true; +} + +RefPtr<SharedBuffer> MockCDM::sanitizeResponse(const SharedBuffer& response) const +{ + if (!charactersAreAllASCII(reinterpret_cast<const LChar*>(response.data()), response.size())) + return nullptr; + + Vector<String> responseArray; + String(response.data(), response.size()).split(ASCIILiteral(" "), responseArray); + + if (!responseArray.contains(String(ASCIILiteral("valid-response")))) + return nullptr; + + return response.copy(); +} + +std::optional<String> MockCDM::sanitizeSessionId(const String& sessionId) const +{ + if (equalLettersIgnoringASCIICase(sessionId, "valid-loaded-session")) + return sessionId; + return std::nullopt; +} + +MockCDMInstance::MockCDMInstance(WeakPtr<MockCDM> cdm) + : m_cdm(cdm) +{ +} + +CDMInstance::SuccessValue MockCDMInstance::initializeWithConfiguration(const MediaKeySystemConfiguration& configuration) +{ + if (!m_cdm || !m_cdm->supportsConfiguration(configuration)) + return Failed; + + return Succeeded; +} + +CDMInstance::SuccessValue MockCDMInstance::setDistinctiveIdentifiersAllowed(bool distinctiveIdentifiersAllowed) +{ + if (m_distinctiveIdentifiersAllowed == distinctiveIdentifiersAllowed) + return Succeeded; + + auto* factory = m_cdm ? m_cdm->factory() : nullptr; + + if (!factory || (!distinctiveIdentifiersAllowed && factory->distinctiveIdentifiersRequirement() == MediaKeysRequirement::Required)) + return Failed; + + m_distinctiveIdentifiersAllowed = distinctiveIdentifiersAllowed; + return Succeeded; +} + +CDMInstance::SuccessValue MockCDMInstance::setPersistentStateAllowed(bool persistentStateAllowed) +{ + if (m_persistentStateAllowed == persistentStateAllowed) + return Succeeded; + + MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr; + + if (!factory || (!persistentStateAllowed && factory->persistentStateRequirement() == MediaKeysRequirement::Required)) + return Failed; + + m_persistentStateAllowed = persistentStateAllowed; + return Succeeded; +} + +CDMInstance::SuccessValue MockCDMInstance::setServerCertificate(Ref<SharedBuffer>&& certificate) +{ + StringView certificateStringView(reinterpret_cast<const LChar*>(certificate->data()), certificate->size()); + + if (equalIgnoringASCIICase(certificateStringView, "valid")) + return Succeeded; + return Failed; +} + +void MockCDMInstance::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback) +{ + MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr; + if (!factory) { + callback(SharedBuffer::create(), emptyAtom, false, SuccessValue::Failed); + return; + } + + if (!factory->supportedSessionTypes().contains(licenseType) || !factory->supportedDataTypes().contains(initDataType)) { + callback(SharedBuffer::create(), emptyString(), false, SuccessValue::Failed); + return; + } + + auto keyIDs = InitDataRegistry::shared().extractKeyIDs(initDataType, initData); + if (keyIDs.isEmpty()) { + callback(SharedBuffer::create(), emptyString(), false, SuccessValue::Failed); + return; + } + + String sessionID = createCanonicalUUIDString(); + factory->addKeysToSessionWithID(sessionID, WTFMove(keyIDs)); + + CString license { "license" }; + callback(SharedBuffer::create(license.data(), license.length()), sessionID, false, SuccessValue::Succeeded); +} + +void MockCDMInstance::updateLicense(const String& sessionID, LicenseType, const SharedBuffer& response, LicenseUpdateCallback callback) +{ + MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr; + if (!factory) { + callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed); + return; + } + + Vector<String> responseVector; + String(response.data(), response.size()).split(ASCIILiteral(" "), responseVector); + + if (responseVector.contains(String(ASCIILiteral("invalid-format")))) { + callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed); + return; + } + + std::optional<KeyStatusVector> changedKeys; + if (responseVector.contains(String(ASCIILiteral("keys-changed")))) { + std::optional<const Vector<Ref<SharedBuffer>>&> keys = factory->keysForSessionWithID(sessionID); + if (keys) { + KeyStatusVector keyStatusVector; + keyStatusVector.reserveInitialCapacity(keys->size()); + for (auto& key : *keys) + keyStatusVector.uncheckedAppend({ key.copyRef(), KeyStatus::Usable }); + + changedKeys = WTFMove(keyStatusVector); + } + } + + // FIXME: Session closure, expiration and message handling should be implemented + // once the relevant algorithms are supported. + + callback(false, WTFMove(changedKeys), std::nullopt, std::nullopt, SuccessValue::Succeeded); +} + +void MockCDMInstance::loadSession(LicenseType, const String&, const String&, LoadSessionCallback callback) +{ + MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr; + if (!factory) { + callback(std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed, SessionLoadFailure::Other); + return; + } + + // FIXME: Key status and expiration handling should be implemented once the relevant algorithms are supported. + + CString messageData { "session loaded" }; + Message message { MessageType::LicenseRenewal, SharedBuffer::create(messageData.data(), messageData.length()) }; + + callback(std::nullopt, std::nullopt, WTFMove(message), SuccessValue::Succeeded, SessionLoadFailure::None); +} + +void MockCDMInstance::closeSession(const String& sessionID, CloseSessionCallback callback) +{ + MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr; + if (!factory) { + callback(); + return; + } + + factory->removeSessionWithID(sessionID); + callback(); +} + +void MockCDMInstance::removeSessionData(const String& id, LicenseType, RemoveSessionDataCallback callback) +{ + MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr; + if (!factory) { + callback({ }, std::nullopt, SuccessValue::Failed); + return; + } + + auto keys = factory->removeKeysFromSessionWithID(id); + KeyStatusVector keyStatusVector; + keyStatusVector.reserveInitialCapacity(keys.size()); + for (auto& key : keys) + keyStatusVector.uncheckedAppend({ WTFMove(key), KeyStatus::Released }); + + CString message { "remove-message" }; + callback(WTFMove(keyStatusVector), SharedBuffer::create(message.data(), message.length()), SuccessValue::Succeeded); +} + +void MockCDMInstance::storeRecordOfKeyUsage(const String&) +{ + // FIXME: This should be implemented along with the support for persistent-usage-record sessions. +} + +} + +#endif diff --git a/Source/WebCore/testing/MockCDMFactory.h b/Source/WebCore/testing/MockCDMFactory.h new file mode 100644 index 000000000..9e36a881b --- /dev/null +++ b/Source/WebCore/testing/MockCDMFactory.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#if ENABLE(ENCRYPTED_MEDIA) + +#include "CDM.h" +#include "CDMInstance.h" +#include "CDMPrivate.h" +#include "MediaKeysRequirement.h" +#include <wtf/HashMap.h> +#include <wtf/RefCounted.h> +#include <wtf/Vector.h> +#include <wtf/WeakPtr.h> + +namespace WebCore { + +class MockCDMFactory : public RefCounted<MockCDMFactory>, private CDMFactory { +public: + static Ref<MockCDMFactory> create() { return adoptRef(*new MockCDMFactory); } + ~MockCDMFactory(); + + const Vector<AtomicString>& supportedDataTypes() const { return m_supportedDataTypes; } + void setSupportedDataTypes(Vector<String>&&); + + const Vector<MediaKeySessionType>& supportedSessionTypes() const { return m_supportedSessionTypes; } + void setSupportedSessionTypes(Vector<MediaKeySessionType>&& types) { m_supportedSessionTypes = WTFMove(types); } + + const Vector<String>& supportedRobustness() const { return m_supportedRobustness; } + void setSupportedRobustness(Vector<String>&& robustness) { m_supportedRobustness = WTFMove(robustness); } + + MediaKeysRequirement distinctiveIdentifiersRequirement() const { return m_distinctiveIdentifiersRequirement; } + void setDistinctiveIdentifiersRequirement(MediaKeysRequirement requirement) { m_distinctiveIdentifiersRequirement = requirement; } + + MediaKeysRequirement persistentStateRequirement() const { return m_persistentStateRequirement; } + void setPersistentStateRequirement(MediaKeysRequirement requirement) { m_persistentStateRequirement = requirement; } + + bool canCreateInstances() const { return m_canCreateInstances; } + void setCanCreateInstances(bool flag) { m_canCreateInstances = flag; } + + bool supportsServerCertificates() const { return m_supportsServerCertificates; } + void setSupportsServerCertificates(bool flag) { m_supportsServerCertificates = flag; } + + bool supportsSessions() const { return m_supportsSessions; } + void setSupportsSessions(bool flag) { m_supportsSessions = flag; } + + void unregister(); + + bool hasSessionWithID(const String& id) { return m_sessions.contains(id); } + void removeSessionWithID(const String& id) { m_sessions.remove(id); } + void addKeysToSessionWithID(const String& id, Vector<Ref<SharedBuffer>>&&); + std::optional<const Vector<Ref<SharedBuffer>>&> keysForSessionWithID(const String& id) const; + Vector<Ref<SharedBuffer>> removeKeysFromSessionWithID(const String& id); + +private: + MockCDMFactory(); + std::unique_ptr<CDMPrivate> createCDM(CDM&) final; + bool supportsKeySystem(const String&) final; + + MediaKeysRequirement m_distinctiveIdentifiersRequirement { MediaKeysRequirement::Optional }; + MediaKeysRequirement m_persistentStateRequirement { MediaKeysRequirement::Optional }; + Vector<AtomicString> m_supportedDataTypes; + Vector<MediaKeySessionType> m_supportedSessionTypes; + Vector<String> m_supportedRobustness; + bool m_registered { true }; + bool m_canCreateInstances { true }; + bool m_supportsServerCertificates { true }; + bool m_supportsSessions { true }; + WeakPtrFactory<MockCDMFactory> m_weakPtrFactory; + HashMap<String, Vector<Ref<SharedBuffer>>> m_sessions; +}; + +class MockCDM : public CDMPrivate { +public: + MockCDM(WeakPtr<MockCDMFactory>); + + MockCDMFactory* factory() { return m_factory.get(); } + +private: + friend class MockCDMInstance; + + bool supportsInitDataType(const AtomicString&) const final; + bool supportsConfiguration(const MediaKeySystemConfiguration&) const final; + bool supportsConfigurationWithRestrictions(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const final; + bool supportsSessionTypeWithConfiguration(MediaKeySessionType&, const MediaKeySystemConfiguration&) const final; + bool supportsRobustness(const String&) const final; + MediaKeysRequirement distinctiveIdentifiersRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const final; + MediaKeysRequirement persistentStateRequirement(const MediaKeySystemConfiguration&, const MediaKeysRestrictions&) const final; + bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const MediaKeySystemConfiguration&) const final; + RefPtr<CDMInstance> createInstance() final; + void loadAndInitialize() final; + bool supportsServerCertificates() const final; + bool supportsSessions() const final; + bool supportsInitData(const AtomicString&, const SharedBuffer&) const final; + RefPtr<SharedBuffer> sanitizeResponse(const SharedBuffer&) const final; + std::optional<String> sanitizeSessionId(const String&) const final; + + WeakPtr<MockCDMFactory> m_factory; + WeakPtrFactory<MockCDM> m_weakPtrFactory; +}; + +class MockCDMInstance : public CDMInstance { +public: + MockCDMInstance(WeakPtr<MockCDM>); + +private: + SuccessValue initializeWithConfiguration(const MediaKeySystemConfiguration&) final; + SuccessValue setDistinctiveIdentifiersAllowed(bool) final; + SuccessValue setPersistentStateAllowed(bool) final; + SuccessValue setServerCertificate(Ref<SharedBuffer>&&) final; + void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) final; + void updateLicense(const String&, LicenseType, const SharedBuffer&, LicenseUpdateCallback) final; + void loadSession(LicenseType, const String&, const String&, LoadSessionCallback) final; + void closeSession(const String&, CloseSessionCallback) final; + void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback) final; + void storeRecordOfKeyUsage(const String&) final; + + WeakPtr<MockCDM> m_cdm; + bool m_distinctiveIdentifiersAllowed { true }; + bool m_persistentStateAllowed { true }; +}; + +} + +#endif diff --git a/Source/WebCore/testing/MockCDMFactory.idl b/Source/WebCore/testing/MockCDMFactory.idl new file mode 100644 index 000000000..90d382ec6 --- /dev/null +++ b/Source/WebCore/testing/MockCDMFactory.idl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +[ + Conditional=ENCRYPTED_MEDIA, + NoInterfaceObject, + ExportMacro=WEBCORE_TESTSUPPORT_EXPORT, +] interface MockCDMFactory { + attribute sequence<DOMString> supportedDataTypes; + attribute sequence<DOMString> supportedRobustness; + attribute sequence<MediaKeySessionType> supportedSessionTypes; + attribute MediaKeysRequirement distinctiveIdentifiersRequirement; + attribute MediaKeysRequirement persistentStateRequirement; + attribute boolean canCreateInstances; + attribute boolean supportsServerCertificates; + attribute boolean supportsSessions; + + void unregister(); +}; + diff --git a/Source/WebCore/testing/MockContentFilter.cpp b/Source/WebCore/testing/MockContentFilter.cpp new file mode 100644 index 000000000..d773f472d --- /dev/null +++ b/Source/WebCore/testing/MockContentFilter.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockContentFilter.h" + +#if ENABLE(CONTENT_FILTERING) + +#include "ContentFilter.h" +#include "ContentFilterUnblockHandler.h" +#include "Logging.h" +#include "ResourceRequest.h" +#include "ResourceResponse.h" +#include "SharedBuffer.h" +#include <mutex> +#include <wtf/text/CString.h> + +namespace WebCore { + +using Decision = MockContentFilterSettings::Decision; +using DecisionPoint = MockContentFilterSettings::DecisionPoint; + +void MockContentFilter::ensureInstalled() +{ + static std::once_flag onceFlag; + std::call_once(onceFlag, []{ + ContentFilter::addType<MockContentFilter>(); + }); +} + +static inline MockContentFilterSettings& settings() +{ + return MockContentFilterSettings::singleton(); +} + +bool MockContentFilter::enabled() +{ + bool enabled = settings().enabled(); + LOG(ContentFiltering, "MockContentFilter is %s.\n", enabled ? "enabled" : "not enabled"); + return enabled; +} + +std::unique_ptr<MockContentFilter> MockContentFilter::create() +{ + return std::make_unique<MockContentFilter>(); +} + +void MockContentFilter::willSendRequest(ResourceRequest& request, const ResourceResponse& redirectResponse) +{ + if (!enabled()) { + m_state = State::Allowed; + return; + } + + if (redirectResponse.isNull()) + maybeDetermineStatus(DecisionPoint::AfterWillSendRequest); + else + maybeDetermineStatus(DecisionPoint::AfterRedirect); + + if (m_state == State::Filtering) + return; + + String modifiedRequestURLString { settings().modifiedRequestURL() }; + if (modifiedRequestURLString.isEmpty()) + return; + + URL modifiedRequestURL { request.url(), modifiedRequestURLString }; + if (!modifiedRequestURL.isValid()) { + LOG(ContentFiltering, "MockContentFilter failed to convert %s to a WebCore::URL.\n", modifiedRequestURL.string().ascii().data()); + return; + } + + request.setURL(modifiedRequestURL); +} + +void MockContentFilter::responseReceived(const ResourceResponse&) +{ + maybeDetermineStatus(DecisionPoint::AfterResponse); +} + +void MockContentFilter::addData(const char*, int) +{ + maybeDetermineStatus(DecisionPoint::AfterAddData); +} + +void MockContentFilter::finishedAddingData() +{ + maybeDetermineStatus(DecisionPoint::AfterFinishedAddingData); +} + +Ref<SharedBuffer> MockContentFilter::replacementData() const +{ + ASSERT(didBlockData()); + return SharedBuffer::create(m_replacementData.data(), m_replacementData.size()); +} + +ContentFilterUnblockHandler MockContentFilter::unblockHandler() const +{ + ASSERT(didBlockData()); + using DecisionHandlerFunction = ContentFilterUnblockHandler::DecisionHandlerFunction; + + return ContentFilterUnblockHandler { + MockContentFilterSettings::unblockURLHost(), [](DecisionHandlerFunction decisionHandler) { + bool shouldAllow { settings().unblockRequestDecision() == Decision::Allow }; + if (shouldAllow) + settings().setDecision(Decision::Allow); + LOG(ContentFiltering, "MockContentFilter %s the unblock request.\n", shouldAllow ? "allowed" : "did not allow"); + decisionHandler(shouldAllow); + } + }; +} + +String MockContentFilter::unblockRequestDeniedScript() const +{ + return ASCIILiteral("unblockRequestDenied()"); +} + +void MockContentFilter::maybeDetermineStatus(DecisionPoint decisionPoint) +{ + if (m_state != State::Filtering || decisionPoint != settings().decisionPoint()) + return; + + LOG(ContentFiltering, "MockContentFilter stopped buffering with state %u at decision point %u.\n", m_state, decisionPoint); + + m_state = settings().decision() == Decision::Allow ? State::Allowed : State::Blocked; + if (m_state != State::Blocked) + return; + + m_replacementData.clear(); + const CString utf8BlockedString = settings().blockedString().utf8(); + m_replacementData.append(utf8BlockedString.data(), utf8BlockedString.length()); +} + +} // namespace WebCore + +#endif // ENABLE(CONTENT_FILTERING) diff --git a/Source/WebCore/testing/MockContentFilter.h b/Source/WebCore/testing/MockContentFilter.h new file mode 100644 index 000000000..c99d2aeb9 --- /dev/null +++ b/Source/WebCore/testing/MockContentFilter.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#include "MockContentFilterSettings.h" +#include "PlatformContentFilter.h" + +namespace WebCore { + +class MockContentFilter final : public PlatformContentFilter { + friend std::unique_ptr<MockContentFilter> std::make_unique<MockContentFilter>(); + +public: + static void ensureInstalled(); + static std::unique_ptr<MockContentFilter> create(); + + void willSendRequest(ResourceRequest&, const ResourceResponse&) override; + void responseReceived(const ResourceResponse&) override; + void addData(const char* data, int length) override; + void finishedAddingData() override; + Ref<SharedBuffer> replacementData() const override; +#if ENABLE(CONTENT_FILTERING) + ContentFilterUnblockHandler unblockHandler() const override; +#endif + String unblockRequestDeniedScript() const override; + +private: + static bool enabled(); + + MockContentFilter() = default; + void maybeDetermineStatus(MockContentFilterSettings::DecisionPoint); + + Vector<char> m_replacementData; +}; + +} // namespace WebCore diff --git a/Source/WebCore/testing/MockContentFilterSettings.cpp b/Source/WebCore/testing/MockContentFilterSettings.cpp new file mode 100644 index 000000000..a6d8f6dbb --- /dev/null +++ b/Source/WebCore/testing/MockContentFilterSettings.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockContentFilterSettings.h" + +#if ENABLE(CONTENT_FILTERING) + +#include "ContentFilter.h" +#include "ContentFilterUnblockHandler.h" +#include "MockContentFilter.h" +#include <wtf/NeverDestroyed.h> + +namespace WebCore { + +MockContentFilterSettings& MockContentFilterSettings::singleton() +{ + static NeverDestroyed<MockContentFilterSettings> settings; + return settings; +} + +void MockContentFilterSettings::reset() +{ + singleton() = MockContentFilterSettings(); +} + +void MockContentFilterSettings::setEnabled(bool enabled) +{ + MockContentFilter::ensureInstalled(); + m_enabled = enabled; +} + +const String& MockContentFilterSettings::unblockRequestURL() const +{ + static NeverDestroyed<String> unblockRequestURL = makeString(ContentFilter::urlScheme(), "://", unblockURLHost()); + return unblockRequestURL; +} + +}; // namespace WebCore + +#endif // ENABLE(CONTENT_FILTERING) diff --git a/Source/WebCore/testing/MockContentFilterSettings.h b/Source/WebCore/testing/MockContentFilterSettings.h new file mode 100644 index 000000000..5e8afdf83 --- /dev/null +++ b/Source/WebCore/testing/MockContentFilterSettings.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#include <wtf/NeverDestroyed.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class MockContentFilterSettings { + friend class NeverDestroyed<MockContentFilterSettings>; + +public: + enum class DecisionPoint { + AfterWillSendRequest, + AfterRedirect, + AfterResponse, + AfterAddData, + AfterFinishedAddingData, + Never + }; + + enum class Decision { + Allow, + Block + }; + + WTF_EXPORT_PRIVATE static MockContentFilterSettings& singleton(); + static void reset(); + static const char* unblockURLHost() { return "mock-unblock"; } + + // Trick the generated bindings into thinking we're RefCounted. + void ref() { } + void deref() { } + + bool enabled() const { return m_enabled; } + WTF_EXPORT_PRIVATE void setEnabled(bool); + + const String& blockedString() const { return m_blockedString; } + void setBlockedString(const String& blockedString) { m_blockedString = blockedString; } + + DecisionPoint decisionPoint() const { return m_decisionPoint; } + void setDecisionPoint(DecisionPoint decisionPoint) { m_decisionPoint = decisionPoint; } + + Decision decision() const { return m_decision; } + void setDecision(Decision decision) { m_decision = decision; } + + Decision unblockRequestDecision() const { return m_unblockRequestDecision; } + void setUnblockRequestDecision(Decision unblockRequestDecision) { m_unblockRequestDecision = unblockRequestDecision; } + + const String& unblockRequestURL() const; + + const String& modifiedRequestURL() const { return m_modifiedRequestURL; } + void setModifiedRequestURL(const String& modifiedRequestURL) { m_modifiedRequestURL = modifiedRequestURL; } + +private: + MockContentFilterSettings() = default; + MockContentFilterSettings(const MockContentFilterSettings&) = delete; + MockContentFilterSettings& operator=(const MockContentFilterSettings&) = default; + + bool m_enabled { false }; + DecisionPoint m_decisionPoint { DecisionPoint::AfterResponse }; + Decision m_decision { Decision::Allow }; + Decision m_unblockRequestDecision { Decision::Block }; + String m_blockedString; + String m_modifiedRequestURL; +}; + +} // namespace WebCore diff --git a/Source/WebCore/testing/MockContentFilterSettings.idl b/Source/WebCore/testing/MockContentFilterSettings.idl new file mode 100644 index 000000000..d401ae901 --- /dev/null +++ b/Source/WebCore/testing/MockContentFilterSettings.idl @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +[ + Conditional=CONTENT_FILTERING, + NoInterfaceObject, + ImplementationLacksVTable +] interface MockContentFilterSettings { + attribute boolean enabled; + attribute DOMString blockedString; + attribute DOMString modifiedRequestURL; + + const octet DECISION_POINT_AFTER_WILL_SEND_REQUEST = 0; + const octet DECISION_POINT_AFTER_REDIRECT = 1; + const octet DECISION_POINT_AFTER_RESPONSE = 2; + const octet DECISION_POINT_AFTER_ADD_DATA = 3; + const octet DECISION_POINT_AFTER_FINISHED_ADDING_DATA = 4; + const octet DECISION_POINT_NEVER = 5; + [Custom] attribute octet decisionPoint; + + const octet DECISION_ALLOW = 0; + const octet DECISION_BLOCK = 1; + [Custom] attribute octet decision; + [Custom] attribute octet unblockRequestDecision; + + readonly attribute DOMString unblockRequestURL; +}; diff --git a/Source/WebCore/testing/MockGamepad.cpp b/Source/WebCore/testing/MockGamepad.cpp new file mode 100644 index 000000000..a49af87b3 --- /dev/null +++ b/Source/WebCore/testing/MockGamepad.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockGamepad.h" + +#if ENABLE(GAMEPAD) + +#include <wtf/CurrentTime.h> + +namespace WebCore { + +MockGamepad::MockGamepad(unsigned index, const String& gamepadID, unsigned axisCount, unsigned buttonCount) + : PlatformGamepad(index) +{ + m_connectTime = m_lastUpdateTime = monotonicallyIncreasingTime(); + updateDetails(gamepadID, axisCount, buttonCount); +} + +void MockGamepad::updateDetails(const String& gamepadID, unsigned axisCount, unsigned buttonCount) +{ + m_id = gamepadID; + m_axisValues = Vector<double>(axisCount, 0.0); + m_buttonValues = Vector<double>(buttonCount, 0.0); + m_lastUpdateTime = monotonicallyIncreasingTime(); +} + +bool MockGamepad::setAxisValue(unsigned index, double value) +{ + if (index >= m_axisValues.size()) { + LOG_ERROR("MockGamepad (%u): Attempt to set value on axis %u which doesn't exist", m_index, index); + return false; + } + + m_axisValues[index] = value; + m_lastUpdateTime = monotonicallyIncreasingTime(); + return true; +} + +bool MockGamepad::setButtonValue(unsigned index, double value) +{ + if (index >= m_buttonValues.size()) { + LOG_ERROR("MockGamepad (%u): Attempt to set value on button %u which doesn't exist", m_index, index); + return false; + } + + m_buttonValues[index] = value; + m_lastUpdateTime = monotonicallyIncreasingTime(); + return true; +} + +} // namespace WebCore + +#endif // ENABLE(GAMEPAD) diff --git a/Source/WebCore/testing/MockGamepad.h b/Source/WebCore/testing/MockGamepad.h new file mode 100644 index 000000000..728f7d21c --- /dev/null +++ b/Source/WebCore/testing/MockGamepad.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#if ENABLE(GAMEPAD) + +#include "PlatformGamepad.h" + +namespace WebCore { + +class MockGamepad : public PlatformGamepad { +public: + MockGamepad(unsigned index, const String& gamepadID, unsigned axisCount, unsigned buttonCount); + + const Vector<double>& axisValues() const final { return m_axisValues; } + const Vector<double>& buttonValues() const final { return m_buttonValues; } + + void updateDetails(const String& gamepadID, unsigned axisCount, unsigned buttonCount); + bool setAxisValue(unsigned index, double value); + bool setButtonValue(unsigned index, double value); + +private: + Vector<double> m_axisValues; + Vector<double> m_buttonValues; +}; + +} + +#endif // ENABLE(GAMEPAD) diff --git a/Source/WebCore/testing/MockGamepadProvider.cpp b/Source/WebCore/testing/MockGamepadProvider.cpp new file mode 100644 index 000000000..ef21e5096 --- /dev/null +++ b/Source/WebCore/testing/MockGamepadProvider.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockGamepadProvider.h" + +#if ENABLE(GAMEPAD) + +#include "GamepadProviderClient.h" +#include "MockGamepad.h" +#include <wtf/MainThread.h> + +namespace WebCore { + +MockGamepadProvider& MockGamepadProvider::singleton() +{ + static NeverDestroyed<MockGamepadProvider> sharedProvider; + return sharedProvider; +} + +MockGamepadProvider::MockGamepadProvider() +{ +} + +void MockGamepadProvider::startMonitoringGamepads(GamepadProviderClient& client) +{ + ASSERT(!m_clients.contains(&client)); + m_clients.add(&client); +} + +void MockGamepadProvider::stopMonitoringGamepads(GamepadProviderClient& client) +{ + ASSERT(m_clients.contains(&client)); + m_clients.remove(&client); +} + +void MockGamepadProvider::setMockGamepadDetails(unsigned index, const String& gamepadID, unsigned axisCount, unsigned buttonCount) +{ + if (index >= m_mockGamepadVector.size()) + m_mockGamepadVector.resize(index + 1); + + if (m_mockGamepadVector[index]) + m_mockGamepadVector[index]->updateDetails(gamepadID, axisCount, buttonCount); + else + m_mockGamepadVector[index] = std::make_unique<MockGamepad>(index, gamepadID, axisCount, buttonCount); +} + +bool MockGamepadProvider::connectMockGamepad(unsigned index) +{ + if (index < m_connectedGamepadVector.size() && m_connectedGamepadVector[index]) { + LOG_ERROR("MockGamepadProvider: Attempt to connect a fake gamepad that is already connected (%u)", index); + return false; + } + + if (index >= m_mockGamepadVector.size() || !m_mockGamepadVector[index]) { + LOG_ERROR("MockGamepadProvider: Attempt to connect a fake gamepad that doesn't have details set(%u)", index); + return false; + } + + if (m_connectedGamepadVector.size() <= index) + m_connectedGamepadVector.reserveCapacity(index + 1); + + while (m_connectedGamepadVector.size() <= index) + m_connectedGamepadVector.uncheckedAppend(nullptr); + + m_connectedGamepadVector[index] = m_mockGamepadVector[index].get(); + + for (auto& client : m_clients) + client->platformGamepadConnected(*m_connectedGamepadVector[index]); + + return true; +} + +bool MockGamepadProvider::disconnectMockGamepad(unsigned index) +{ + if (index >= m_connectedGamepadVector.size() || !m_connectedGamepadVector[index]) { + LOG_ERROR("MockGamepadProvider: Attempt to disconnect a fake gamepad that is not connected (%u)", index); + return false; + } + if (m_connectedGamepadVector[index] != m_mockGamepadVector[index].get()) { + LOG_ERROR("MockGamepadProvider: Vectors of fake gamepads and connected gamepads have gotten out of sync"); + return false; + } + + m_connectedGamepadVector[index] = nullptr; + + for (auto& client : m_clients) + client->platformGamepadDisconnected(*m_mockGamepadVector[index]); + + return true; +} + +bool MockGamepadProvider::setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value) +{ + if (index >= m_mockGamepadVector.size() || !m_mockGamepadVector[index]) { + LOG_ERROR("MockGamepadProvider: Attempt to set axis value on a fake gamepad that doesn't exist (%u)", index); + return false; + } + + m_mockGamepadVector[index]->setAxisValue(axisIndex, value); + gamepadInputActivity(); + return true; +} + +bool MockGamepadProvider::setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value) +{ + if (index >= m_mockGamepadVector.size() || !m_mockGamepadVector[index]) { + LOG_ERROR("MockGamepadProvider: Attempt to set button value on a fake gamepad that doesn't exist (%u)", index); + return false; + } + + m_mockGamepadVector[index]->setButtonValue(buttonIndex, value); + setShouldMakeGamepadsVisibile(); + gamepadInputActivity(); + return true; +} + +void MockGamepadProvider::gamepadInputActivity() +{ + if (!m_shouldScheduleActivityCallback) + return; + + m_shouldScheduleActivityCallback = false; + callOnMainThread([this]() { + dispatchPlatformGamepadInputActivity(); + + m_shouldScheduleActivityCallback = true; + }); +} + +} // namespace WebCore + +#endif // ENABLE(GAMEPAD) diff --git a/Source/WebCore/testing/MockGamepadProvider.h b/Source/WebCore/testing/MockGamepadProvider.h new file mode 100644 index 000000000..9dd31e5fb --- /dev/null +++ b/Source/WebCore/testing/MockGamepadProvider.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2016 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#if ENABLE(GAMEPAD) + +#include "GamepadProvider.h" +#include "MockGamepad.h" +#include <wtf/NeverDestroyed.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class MockGamepadProvider : public GamepadProvider { + WTF_MAKE_NONCOPYABLE(MockGamepadProvider); + friend class NeverDestroyed<MockGamepadProvider>; +public: + WEBCORE_EXPORT static MockGamepadProvider& singleton(); + + virtual ~MockGamepadProvider() { } + + WEBCORE_EXPORT void startMonitoringGamepads(GamepadProviderClient&) final; + WEBCORE_EXPORT void stopMonitoringGamepads(GamepadProviderClient&) final; + WEBCORE_EXPORT const Vector<PlatformGamepad*>& platformGamepads() final { return m_connectedGamepadVector; } + bool isMockGamepadProvider() const final { return true; } + + void setMockGamepadDetails(unsigned index, const String& gamepadID, unsigned axisCount, unsigned buttonCount); + bool setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value); + bool setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value); + bool connectMockGamepad(unsigned index); + bool disconnectMockGamepad(unsigned index); + +private: + MockGamepadProvider(); + + void gamepadInputActivity(); + + Vector<PlatformGamepad*> m_connectedGamepadVector; + Vector<std::unique_ptr<MockGamepad>> m_mockGamepadVector; + + bool m_shouldScheduleActivityCallback { true }; +}; + +} + +#endif // ENABLE(GAMEPAD) diff --git a/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp b/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp new file mode 100644 index 000000000..963493125 --- /dev/null +++ b/Source/WebCore/testing/MockLibWebRTCPeerConnection.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2017 Apple Inc. + * + * 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockLibWebRTCPeerConnection.h" + +#if USE(LIBWEBRTC) + +#include "LibWebRTCProvider.h" +#include <sstream> +#include <webrtc/api/mediastream.h> +#include <wtf/Function.h> +#include <wtf/MainThread.h> +#include <wtf/NeverDestroyed.h> + +namespace WebCore { + +static inline rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>& getRealPeerConnectionFactory() +{ + static NeverDestroyed<rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>> realPeerConnectionFactory; + return realPeerConnectionFactory; +} + +static inline webrtc::PeerConnectionFactoryInterface* realPeerConnectionFactory() +{ + return getRealPeerConnectionFactory().get(); +} + +void useMockRTCPeerConnectionFactory(LibWebRTCProvider* provider, const String& testCase) +{ + if (provider && !realPeerConnectionFactory()) { + auto& factory = getRealPeerConnectionFactory(); + factory = &provider->factory(); + } + + LibWebRTCProvider::setPeerConnectionFactory(MockLibWebRTCPeerConnectionFactory::create(String(testCase))); +} + +class MockLibWebRTCPeerConnectionForIceCandidates : public MockLibWebRTCPeerConnection { +public: + explicit MockLibWebRTCPeerConnectionForIceCandidates(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { } + virtual ~MockLibWebRTCPeerConnectionForIceCandidates() = default; +private: + void gotLocalDescription() final; +}; + +void MockLibWebRTCPeerConnectionForIceCandidates::gotLocalDescription() +{ + // Let's gather candidates + LibWebRTCProvider::callOnWebRTCSignalingThread([this]() { + MockLibWebRTCIceCandidate candidate("2013266431 1 udp 2013266432 192.168.0.100 38838 typ host generation 0", "1"); + m_observer.OnIceCandidate(&candidate); + }); + LibWebRTCProvider::callOnWebRTCSignalingThread([this]() { + MockLibWebRTCIceCandidate candidate("1019216383 1 tcp 1019216384 192.168.0.100 9 typ host tcptype passive generation 0", "1"); + m_observer.OnIceCandidate(&candidate); + }); + LibWebRTCProvider::callOnWebRTCSignalingThread([this]() { + MockLibWebRTCIceCandidate candidate("1677722111 1 tcp 1677722112 172.18.0.1 47989 typ srflx raddr 192.168.0.100 rport 47989 generation 0", "1"); + m_observer.OnIceCandidate(&candidate); + }); + LibWebRTCProvider::callOnWebRTCSignalingThread([this]() { + m_observer.OnIceGatheringChange(webrtc::PeerConnectionInterface::kIceGatheringComplete); + }); +} + +class MockLibWebRTCPeerConnectionForIceConnectionState : public MockLibWebRTCPeerConnection { +public: + explicit MockLibWebRTCPeerConnectionForIceConnectionState(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { } + virtual ~MockLibWebRTCPeerConnectionForIceConnectionState() = default; + +private: + void gotLocalDescription() final; +}; + +void MockLibWebRTCPeerConnectionForIceConnectionState::gotLocalDescription() +{ + m_observer.OnIceConnectionChange(kIceConnectionChecking); + m_observer.OnIceConnectionChange(kIceConnectionConnected); + m_observer.OnIceConnectionChange(kIceConnectionCompleted); + m_observer.OnIceConnectionChange(kIceConnectionFailed); + m_observer.OnIceConnectionChange(kIceConnectionDisconnected); + m_observer.OnIceConnectionChange(kIceConnectionNew); +} + +template<typename U> static inline void releaseInNetworkThread(MockLibWebRTCPeerConnection& mock, U& observer) +{ + mock.AddRef(); + observer.AddRef(); + callOnMainThread([&mock, &observer] { + LibWebRTCProvider::callOnWebRTCNetworkThread([&mock, &observer]() { + observer.Release(); + mock.Release(); + }); + }); +} + +class MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileCreatingOffer : public MockLibWebRTCPeerConnection { +public: + explicit MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileCreatingOffer(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { } + virtual ~MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileCreatingOffer() = default; + +private: + void CreateOffer(webrtc::CreateSessionDescriptionObserver* observer, const webrtc::MediaConstraintsInterface*) final { releaseInNetworkThread(*this, *observer); } +}; + +class MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats : public MockLibWebRTCPeerConnection { +public: + explicit MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { } + virtual ~MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats() = default; + +private: + bool GetStats(webrtc::StatsObserver*, webrtc::MediaStreamTrackInterface*, StatsOutputLevel) final; +}; + +bool MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats::GetStats(webrtc::StatsObserver* observer, webrtc::MediaStreamTrackInterface*, StatsOutputLevel) +{ + releaseInNetworkThread(*this, *observer); + return true; +} + +class MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileSettingDescription : public MockLibWebRTCPeerConnection { +public: + explicit MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileSettingDescription(webrtc::PeerConnectionObserver& observer) : MockLibWebRTCPeerConnection(observer) { } + virtual ~MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileSettingDescription() = default; + +private: + void SetLocalDescription(webrtc::SetSessionDescriptionObserver* observer, webrtc::SessionDescriptionInterface*) final { releaseInNetworkThread(*this, *observer); } +}; + +MockLibWebRTCPeerConnectionFactory::MockLibWebRTCPeerConnectionFactory(String&& testCase) + : m_testCase(WTFMove(testCase)) +{ + if (m_testCase == "TwoRealPeerConnections") { + m_numberOfRealPeerConnections = 2; + return; + } + if (m_testCase == "OneRealPeerConnection") + m_numberOfRealPeerConnections = 1; +} + +rtc::scoped_refptr<webrtc::PeerConnectionInterface> MockLibWebRTCPeerConnectionFactory::CreatePeerConnection(const webrtc::PeerConnectionInterface::RTCConfiguration& configuration, std::unique_ptr<cricket::PortAllocator> portAllocator, std::unique_ptr<rtc::RTCCertificateGeneratorInterface> generator, webrtc::PeerConnectionObserver* observer) +{ + if (m_numberOfRealPeerConnections) { + auto connection = realPeerConnectionFactory()->CreatePeerConnection(configuration, WTFMove(portAllocator), WTFMove(generator), observer); + --m_numberOfRealPeerConnections; + return connection; + } + + if (m_testCase == "ICECandidates") + return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionForIceCandidates>(*observer); + + if (m_testCase == "ICEConnectionState") + return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionForIceConnectionState>(*observer); + + if (m_testCase == "LibWebRTCReleasingWhileCreatingOffer") + return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileCreatingOffer>(*observer); + + if (m_testCase == "LibWebRTCReleasingWhileGettingStats") + return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileGettingStats>(*observer); + + if (m_testCase == "LibWebRTCReleasingWhileSettingDescription") + return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionReleasedInNetworkThreadWhileSettingDescription>(*observer); + + return new rtc::RefCountedObject<MockLibWebRTCPeerConnection>(*observer); +} + +rtc::scoped_refptr<webrtc::MediaStreamInterface> MockLibWebRTCPeerConnectionFactory::CreateLocalMediaStream(const std::string& label) +{ + return new rtc::RefCountedObject<webrtc::MediaStream>(label); +} + +void MockLibWebRTCPeerConnection::SetLocalDescription(webrtc::SetSessionDescriptionObserver* observer, webrtc::SessionDescriptionInterface*) +{ + LibWebRTCProvider::callOnWebRTCSignalingThread([this, observer] { + observer->OnSuccess(); + gotLocalDescription(); + }); +} + +void MockLibWebRTCPeerConnection::SetRemoteDescription(webrtc::SetSessionDescriptionObserver* observer, webrtc::SessionDescriptionInterface* sessionDescription) +{ + LibWebRTCProvider::callOnWebRTCSignalingThread([observer] { + observer->OnSuccess(); + }); + ASSERT(sessionDescription); + if (sessionDescription->type() == "offer") { + std::string sdp; + sessionDescription->ToString(&sdp); + + m_isInitiator = false; + m_isReceivingAudio = sdp.find("m=audio") != std::string::npos; + m_isReceivingVideo = sdp.find("m=video") != std::string::npos; + } +} + +rtc::scoped_refptr<webrtc::DataChannelInterface> MockLibWebRTCPeerConnection::CreateDataChannel(const std::string& label, const webrtc::DataChannelInit* init) +{ + webrtc::DataChannelInit parameters; + if (init) + parameters = *init; + return new rtc::RefCountedObject<MockLibWebRTCDataChannel>(std::string(label), parameters.ordered, parameters.reliable, parameters.id); +} + +bool MockLibWebRTCPeerConnection::AddStream(webrtc::MediaStreamInterface* stream) +{ + m_stream = stream; + LibWebRTCProvider::callOnWebRTCSignalingThread([observer = &m_observer] { + observer->OnRenegotiationNeeded(); + }); + return true; +} + +void MockLibWebRTCPeerConnection::RemoveStream(webrtc::MediaStreamInterface*) +{ + LibWebRTCProvider::callOnWebRTCSignalingThread([observer = &m_observer] { + observer->OnRenegotiationNeeded(); + }); + m_stream = nullptr; +} + +void MockLibWebRTCPeerConnection::CreateOffer(webrtc::CreateSessionDescriptionObserver* observer, const webrtc::MediaConstraintsInterface*) +{ + LibWebRTCProvider::callOnWebRTCSignalingThread([this, observer] { + std::ostringstream sdp; + sdp << + "v=0\r\n" + "o=- 5667094644266930845 " << m_counter++ << " IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n"; + if (m_stream) { + unsigned partCounter = 1; + sdp << "a=msid-semantic:WMS " << m_stream->label() << "\r\n"; + for (auto& audioTrack : m_stream->GetAudioTracks()) { + sdp << + "m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=sendrecv\r\n" + "a=mid:part" << partCounter++ << "\r\n" + "a=rtpmap:111 OPUS/48000/2\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=ssrc:3409173717 cname:/chKzCS9K6KOgL0n\r\n" + "a=msid:" << m_stream->label() << " " << audioTrack->id() << "\r\n" + "a=ice-ufrag:e/B1\r\n" + "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n" + "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n" + "a=setup:actpass\r\n"; + } + for (auto& videoTrack : m_stream->GetVideoTracks()) { + sdp << + "m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=sendrecv\r\n" + "a=mid:part" << partCounter++ << "\r\n" + "a=rtpmap:103 H264/90000\r\n" + "a=rtpmap:100 VP8/90000\r\n" + "a=rtpmap:120 RTX/90000\r\n" + "a=fmtp:103 packetization-mode=1\r\n" + "a=fmtp:120 apt=100;rtx-time=200\r\n" + "a=rtcp-fb:100 nack\r\n" + "a=rtcp-fb:103 nack pli\r\n" + "a=rtcp-fb:100 nack pli\r\n" + "a=rtcp-fb:103 ccm fir\r\n" + "a=rtcp-fb:100 ccm fir\r\n" + "a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n" + "a=msid:" << m_stream->label() << " " << videoTrack->id() << "\r\n" + "a=ice-ufrag:e/B1\r\n" + "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n" + "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n" + "a=setup:actpass\r\n"; + } + } + MockLibWebRTCSessionDescription description(sdp.str()); + observer->OnSuccess(&description); + }); +} + +void MockLibWebRTCPeerConnection::CreateAnswer(webrtc::CreateSessionDescriptionObserver* observer, const webrtc::MediaConstraintsInterface*) +{ + LibWebRTCProvider::callOnWebRTCSignalingThread([this, observer] { + std::ostringstream sdp; + sdp << + "v=0\r\n" + "o=- 5667094644266930846 " << m_counter++ << " IN IP4 127.0.0.1\r\n" + "s=-\r\n" + "t=0 0\r\n"; + if (m_stream) { + for (auto& audioTrack : m_stream->GetAudioTracks()) { + ASSERT_UNUSED(audioTrack, !!audioTrack); + sdp << + "m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=recvonly\r\n" + "a=mid:part1\r\n" + "a=rtpmap:111 OPUS/48000/2\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=ssrc:3409173717 cname:/chKzCS9K6KOgL0m\r\n" + "a=ice-ufrag:e/B1\r\n" + "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n" + "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n" + "a=setup:active\r\n"; + } + for (auto& videoTrack : m_stream->GetVideoTracks()) { + ASSERT_UNUSED(videoTrack, !!videoTrack); + sdp << + "m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=recvonly\r\n" + "a=mid:part2\r\n" + "a=rtpmap:103 H264/90000\r\n" + "a=rtpmap:100 VP8/90000\r\n" + "a=rtpmap:120 RTX/90000\r\n" + "a=fmtp:103 packetization-mode=1\r\n" + "a=fmtp:120 apt=100;rtx-time=200\r\n" + "a=rtcp-fb:100 nack\r\n" + "a=rtcp-fb:103 nack pli\r\n" + "a=rtcp-fb:100 nack pli\r\n" + "a=rtcp-fb:103 ccm fir\r\n" + "a=rtcp-fb:100 ccm fir\r\n" + "a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n" + "a=ice-ufrag:e/B1\r\n" + "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n" + "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n" + "a=setup:active\r\n"; + } + } else if (!m_isInitiator) { + if (m_isReceivingAudio) { + sdp << + "m=audio 9 UDP/TLS/RTP/SAVPF 111 8 0\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=recvonly\r\n" + "a=mid:part1\r\n" + "a=rtpmap:111 OPUS/48000/2\r\n" + "a=rtpmap:8 PCMA/8000\r\n" + "a=rtpmap:0 PCMU/8000\r\n" + "a=ssrc:3409173717 cname:/chKzCS9K6KOgL0m\r\n" + "a=ice-ufrag:e/B1\r\n" + "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n" + "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n" + "a=setup:active\r\n"; + } + if (m_isReceivingVideo) { + sdp << + "m=video 9 UDP/TLS/RTP/SAVPF 103 100 120\r\n" + "c=IN IP4 0.0.0.0\r\n" + "a=rtcp-mux\r\n" + "a=recvonly\r\n" + "a=mid:part2\r\n" + "a=rtpmap:103 H264/90000\r\n" + "a=rtpmap:100 VP8/90000\r\n" + "a=rtpmap:120 RTX/90000\r\n" + "a=fmtp:103 packetization-mode=1\r\n" + "a=fmtp:120 apt=100;rtx-time=200\r\n" + "a=rtcp-fb:100 nack\r\n" + "a=rtcp-fb:103 nack pli\r\n" + "a=rtcp-fb:100 nack pli\r\n" + "a=rtcp-fb:103 ccm fir\r\n" + "a=rtcp-fb:100 ccm fir\r\n" + "a=ssrc:3409173718 cname:/chKzCS9K6KOgL0n\r\n" + "a=ice-ufrag:e/B1\r\n" + "a=ice-pwd:Yotk3Im3mnyi+1Q38p51MDub\r\n" + "a=fingerprint:sha-256 8B:87:09:8A:5D:C2:F3:33:EF:C5:B1:F6:84:3A:3D:D6:A3:E2:9C:17:4C:E7:46:3B:1B:CE:84:98:DD:8E:AF:7B\r\n" + "a=setup:active\r\n"; + } + } + MockLibWebRTCSessionDescription description(sdp.str()); + observer->OnSuccess(&description); + }); +} + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/testing/MockLibWebRTCPeerConnection.h b/Source/WebCore/testing/MockLibWebRTCPeerConnection.h new file mode 100644 index 000000000..a050897d0 --- /dev/null +++ b/Source/WebCore/testing/MockLibWebRTCPeerConnection.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2017 Apple Inc. + * + * 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#if USE(LIBWEBRTC) + +#include "LibWebRTCMacros.h" +#include <webrtc/api/mediastreaminterface.h> +#include <webrtc/api/peerconnectioninterface.h> +#include <wtf/text/WTFString.h> + +namespace WebCore { + +class LibWebRTCProvider; + +void useMockRTCPeerConnectionFactory(LibWebRTCProvider*, const String&); + +class MockLibWebRTCPeerConnection : public webrtc::PeerConnectionInterface { +public: + virtual ~MockLibWebRTCPeerConnection() { } + +protected: + explicit MockLibWebRTCPeerConnection(webrtc::PeerConnectionObserver& observer) : m_observer(observer) { } + +private: + rtc::scoped_refptr<webrtc::StreamCollectionInterface> local_streams() override { return nullptr; } + rtc::scoped_refptr<webrtc::StreamCollectionInterface> remote_streams() override { return nullptr; } + rtc::scoped_refptr<webrtc::DtmfSenderInterface> CreateDtmfSender(webrtc::AudioTrackInterface*) override { return nullptr; } + const webrtc::SessionDescriptionInterface* local_description() const override { return nullptr; } + const webrtc::SessionDescriptionInterface* remote_description() const override { return nullptr; } + bool AddIceCandidate(const webrtc::IceCandidateInterface*) override { return true; } + void RegisterUMAObserver(webrtc::UMAObserver*) override { } + SignalingState signaling_state() override { return kStable; } + IceConnectionState ice_connection_state() override { return kIceConnectionNew; } + IceGatheringState ice_gathering_state() override { return kIceGatheringNew; } + void StopRtcEventLog() override { } + void Close() override { } + +protected: + void SetRemoteDescription(webrtc::SetSessionDescriptionObserver*, webrtc::SessionDescriptionInterface*) final; + void CreateAnswer(webrtc::CreateSessionDescriptionObserver*, const webrtc::MediaConstraintsInterface*) final; + rtc::scoped_refptr<webrtc::DataChannelInterface> CreateDataChannel(const std::string&, const webrtc::DataChannelInit*) final; + bool AddStream(webrtc::MediaStreamInterface*) final; + void RemoveStream(webrtc::MediaStreamInterface*) final; + + void SetLocalDescription(webrtc::SetSessionDescriptionObserver*, webrtc::SessionDescriptionInterface*) override; + bool GetStats(webrtc::StatsObserver*, webrtc::MediaStreamTrackInterface*, StatsOutputLevel) override { return false; } + void CreateOffer(webrtc::CreateSessionDescriptionObserver*, const webrtc::MediaConstraintsInterface*) override; + + virtual void gotLocalDescription() { } + + webrtc::PeerConnectionObserver& m_observer; + unsigned m_counter { 0 }; + rtc::scoped_refptr<webrtc::MediaStreamInterface> m_stream; + bool m_isInitiator { true }; + bool m_isReceivingAudio { false }; + bool m_isReceivingVideo { false }; +}; + +class MockLibWebRTCSessionDescription: public webrtc::SessionDescriptionInterface { +public: + explicit MockLibWebRTCSessionDescription(std::string&& sdp) : m_sdp(WTFMove(sdp)) { } + +private: + bool ToString(std::string* out) const final { *out = m_sdp; return true; } + + cricket::SessionDescription* description() final { return nullptr; } + const cricket::SessionDescription* description() const final { return nullptr; } + std::string session_id() const final { return ""; } + std::string session_version() const final { return ""; } + std::string type() const final { return ""; } + bool AddCandidate(const webrtc::IceCandidateInterface*) final { return true; } + size_t number_of_mediasections() const final { return 0; } + const webrtc::IceCandidateCollection* candidates(size_t) const final { return nullptr; } + + std::string m_sdp; +}; + +class MockLibWebRTCIceCandidate : public webrtc::IceCandidateInterface { +public: + MockLibWebRTCIceCandidate(const char* sdp, const char* sdpMid) + : m_sdp(sdp) + , m_sdpMid(sdpMid) { } + +private: + std::string sdp_mid() const final { return m_sdpMid; } + int sdp_mline_index() const final { return 0; } + const cricket::Candidate& candidate() const final { return m_candidate; } + bool ToString(std::string* out) const final { *out = m_sdp; return true; } + +protected: + const char* m_sdp; + const char* m_sdpMid; + cricket::Candidate m_candidate; +}; + +class MockLibWebRTCAudioTrack : public webrtc::AudioTrackInterface { +public: + explicit MockLibWebRTCAudioTrack(const std::string& id, webrtc::AudioSourceInterface* source) + : m_id(id) + , m_source(source) { } + +private: + webrtc::AudioSourceInterface* GetSource() const final { return m_source; } + void AddSink(webrtc::AudioTrackSinkInterface*) final { } + void RemoveSink(webrtc::AudioTrackSinkInterface*) final { } + void RegisterObserver(webrtc::ObserverInterface*) final { } + void UnregisterObserver(webrtc::ObserverInterface*) final { } + + std::string kind() const final { return "audio"; } + std::string id() const final { return m_id; } + bool enabled() const final { return m_enabled; } + TrackState state() const final { return kLive; } + bool set_enabled(bool enabled) final { m_enabled = enabled; return true; } + + bool m_enabled; + std::string m_id; + webrtc::AudioSourceInterface* m_source { nullptr }; +}; + +class MockLibWebRTCVideoTrack : public webrtc::VideoTrackInterface { +public: + explicit MockLibWebRTCVideoTrack(const std::string& id, webrtc::VideoTrackSourceInterface* source) + : m_id(id) + , m_source(source) { } + +private: + webrtc::VideoTrackSourceInterface* GetSource() const final { return m_source; } + void RegisterObserver(webrtc::ObserverInterface*) final { } + void UnregisterObserver(webrtc::ObserverInterface*) final { } + + std::string kind() const final { return "video"; } + std::string id() const final { return m_id; } + bool enabled() const final { return m_enabled; } + TrackState state() const final { return kLive; } + bool set_enabled(bool enabled) final { m_enabled = enabled; return true; } + + bool m_enabled; + std::string m_id; + webrtc::VideoTrackSourceInterface* m_source { nullptr }; +}; + +class MockLibWebRTCDataChannel : public webrtc::DataChannelInterface { +public: + MockLibWebRTCDataChannel(std::string&& label, bool ordered, bool reliable, int id) + : m_label(WTFMove(label)) + , m_ordered(ordered) + , m_reliable(reliable) + , m_id(id) { } + +private: + void RegisterObserver(webrtc::DataChannelObserver*) final { } + void UnregisterObserver() final { } + std::string label() const final { return m_label; } + bool reliable() const final { return m_reliable; } + bool ordered() const final { return m_ordered; } + + int id() const final { return m_id; } + DataState state() const final { return kConnecting; } + uint64_t buffered_amount() const final { return 0; } + void Close() final { } + bool Send(const webrtc::DataBuffer&) final { return true; } + + std::string m_label; + bool m_ordered { true }; + bool m_reliable { false }; + int m_id { -1 }; +}; + +class MockLibWebRTCPeerConnectionFactory : public webrtc::PeerConnectionFactoryInterface { +public: + static rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> create(String&& testCase) { return new rtc::RefCountedObject<MockLibWebRTCPeerConnectionFactory>(WTFMove(testCase)); } + +protected: + MockLibWebRTCPeerConnectionFactory(String&&); + +private: + rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(const webrtc::PeerConnectionInterface::RTCConfiguration&, const webrtc::MediaConstraintsInterface*, std::unique_ptr<cricket::PortAllocator>, std::unique_ptr<rtc::RTCCertificateGeneratorInterface>, webrtc::PeerConnectionObserver*) final { return nullptr; } + + rtc::scoped_refptr<webrtc::PeerConnectionInterface> CreatePeerConnection(const webrtc::PeerConnectionInterface::RTCConfiguration&, std::unique_ptr<cricket::PortAllocator>, std::unique_ptr<rtc::RTCCertificateGeneratorInterface>, webrtc::PeerConnectionObserver*) final; + + rtc::scoped_refptr<webrtc::MediaStreamInterface> CreateLocalMediaStream(const std::string&) final; + + void SetOptions(const Options&) final { } + rtc::scoped_refptr<webrtc::AudioSourceInterface> CreateAudioSource(const cricket::AudioOptions&) final { return nullptr; } + rtc::scoped_refptr<webrtc::AudioSourceInterface> CreateAudioSource(const webrtc::MediaConstraintsInterface*) final { return nullptr; } + + rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> CreateVideoSource(cricket::VideoCapturer*) final { return nullptr; } + rtc::scoped_refptr<webrtc::VideoTrackSourceInterface> CreateVideoSource(cricket::VideoCapturer*, const webrtc::MediaConstraintsInterface*) final { return nullptr; } + + rtc::scoped_refptr<webrtc::VideoTrackInterface> CreateVideoTrack(const std::string& id, webrtc::VideoTrackSourceInterface* source) final { return new rtc::RefCountedObject<MockLibWebRTCVideoTrack>(id, source); } + rtc::scoped_refptr<webrtc::AudioTrackInterface> CreateAudioTrack(const std::string& id, webrtc::AudioSourceInterface* source) final { return new rtc::RefCountedObject<MockLibWebRTCAudioTrack>(id, source); } + bool StartAecDump(rtc::PlatformFile, int64_t) final { return false; } + void StopAecDump() final { } + + bool StartRtcEventLog(rtc::PlatformFile, int64_t) final { return false; } + bool StartRtcEventLog(rtc::PlatformFile) final { return false; } + void StopRtcEventLog() final { } + +private: + String m_testCase; + unsigned m_numberOfRealPeerConnections { 0 }; +}; + +} // namespace WebCore + +#endif // USE(LIBWEBRTC) diff --git a/Source/WebCore/testing/MockPageOverlay.cpp b/Source/WebCore/testing/MockPageOverlay.cpp new file mode 100644 index 000000000..3bfa6d9a7 --- /dev/null +++ b/Source/WebCore/testing/MockPageOverlay.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockPageOverlay.h" + +#include "Document.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "MainFrame.h" +#include "PageOverlayController.h" +#include "PlatformMouseEvent.h" + +namespace WebCore { + +Ref<MockPageOverlay> MockPageOverlay::create(PageOverlay* overlay) +{ + return adoptRef(*new MockPageOverlay(overlay)); +} + +MockPageOverlay::MockPageOverlay(PageOverlay* overlay) + : m_overlay(overlay) +{ +} + +void MockPageOverlay::setFrame(double x, double y, double width, double height) +{ + m_overlay->setFrame(IntRect(x, y, width, height)); +} + +} diff --git a/Source/WebCore/testing/MockPageOverlay.h b/Source/WebCore/testing/MockPageOverlay.h new file mode 100644 index 000000000..21956e038 --- /dev/null +++ b/Source/WebCore/testing/MockPageOverlay.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#include "PageOverlay.h" + +namespace WebCore { + +class MainFrame; + +class MockPageOverlay : public RefCounted<MockPageOverlay> { +public: + static Ref<MockPageOverlay> create(PageOverlay*); + + void setFrame(double x, double y, double width, double height); + + PageOverlay* overlay() const { return m_overlay.get(); } + +private: + explicit MockPageOverlay(PageOverlay*); + + RefPtr<PageOverlay> m_overlay; +}; + +} // namespace WebCore diff --git a/Source/WebCore/testing/MockPageOverlay.idl b/Source/WebCore/testing/MockPageOverlay.idl new file mode 100644 index 000000000..7a5a4a81b --- /dev/null +++ b/Source/WebCore/testing/MockPageOverlay.idl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2015 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +[ + NoInterfaceObject, + ImplementationLacksVTable +] interface MockPageOverlay { + void setFrame(double x, double y, double width, double height); +}; diff --git a/Source/WebCore/testing/MockPageOverlayClient.cpp b/Source/WebCore/testing/MockPageOverlayClient.cpp new file mode 100644 index 000000000..d0b4bab4c --- /dev/null +++ b/Source/WebCore/testing/MockPageOverlayClient.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2014 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockPageOverlayClient.h" + +#include "Document.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "MainFrame.h" +#include "Page.h" +#include "PageOverlayController.h" +#include "PlatformMouseEvent.h" +#include <wtf/NeverDestroyed.h> +#include <wtf/text/StringBuilder.h> + +namespace WebCore { + +MockPageOverlayClient& MockPageOverlayClient::singleton() +{ + static NeverDestroyed<MockPageOverlayClient> sharedClient; + return sharedClient.get(); +} + +MockPageOverlayClient::MockPageOverlayClient() +{ +} + +Ref<MockPageOverlay> MockPageOverlayClient::installOverlay(MainFrame& mainFrame, PageOverlay::OverlayType overlayType) +{ + auto overlay = PageOverlay::create(*this, overlayType); + mainFrame.pageOverlayController().installPageOverlay(overlay, PageOverlay::FadeMode::DoNotFade); + + auto mockOverlay = MockPageOverlay::create(overlay.ptr()); + m_overlays.add(mockOverlay.ptr()); + + return mockOverlay; +} + +void MockPageOverlayClient::uninstallAllOverlays() +{ + while (!m_overlays.isEmpty()) { + RefPtr<MockPageOverlay> mockOverlay = m_overlays.takeAny(); + PageOverlayController* overlayController = mockOverlay->overlay()->controller(); + ASSERT(overlayController); + overlayController->uninstallPageOverlay(*mockOverlay->overlay(), PageOverlay::FadeMode::DoNotFade); + } +} + +String MockPageOverlayClient::layerTreeAsText(MainFrame& mainFrame, LayerTreeFlags flags) +{ + GraphicsLayer* viewOverlayRoot = mainFrame.pageOverlayController().viewOverlayRootLayer(); + GraphicsLayer* documentOverlayRoot = mainFrame.pageOverlayController().documentOverlayRootLayer(); + + return "View-relative:\n" + (viewOverlayRoot ? viewOverlayRoot->layerTreeAsText(flags | LayerTreeAsTextIncludePageOverlayLayers) : "(no view-relative overlay root)") + + "\n\nDocument-relative:\n" + (documentOverlayRoot ? documentOverlayRoot->layerTreeAsText(flags | LayerTreeAsTextIncludePageOverlayLayers) : "(no document-relative overlay root)"); +} + +void MockPageOverlayClient::willMoveToPage(PageOverlay&, Page*) +{ +} + +void MockPageOverlayClient::didMoveToPage(PageOverlay& overlay, Page* page) +{ + if (page) + overlay.setNeedsDisplay(); +} + +void MockPageOverlayClient::drawRect(PageOverlay& overlay, GraphicsContext& context, const IntRect& dirtyRect) +{ + StringBuilder message; + message.appendLiteral("MockPageOverlayClient::drawRect dirtyRect ("); + message.appendNumber(dirtyRect.x()); + message.appendLiteral(", "); + message.appendNumber(dirtyRect.y()); + message.appendLiteral(", "); + message.appendNumber(dirtyRect.width()); + message.appendLiteral(", "); + message.appendNumber(dirtyRect.height()); + message.appendLiteral(")"); + overlay.page()->mainFrame().document()->addConsoleMessage(MessageSource::Other, MessageLevel::Debug, message.toString()); + + GraphicsContextStateSaver stateSaver(context); + + FloatRect insetRect = overlay.bounds(); + + if (overlay.overlayType() == PageOverlay::OverlayType::Document) { + context.setStrokeColor(Color(0, 255, 0)); + insetRect.inflate(-50); + } else { + context.setStrokeColor(Color(0, 0, 255)); + insetRect.inflate(-20); + } + + context.strokeRect(insetRect, 20); +} + +bool MockPageOverlayClient::mouseEvent(PageOverlay& overlay, const PlatformMouseEvent& event) +{ + StringBuilder message; + message.appendLiteral("MockPageOverlayClient::mouseEvent location ("); + message.appendNumber(event.position().x()); + message.appendLiteral(", "); + message.appendNumber(event.position().y()); + message.appendLiteral(")"); + overlay.page()->mainFrame().document()->addConsoleMessage(MessageSource::Other, MessageLevel::Debug, message.toString()); + + return false; +} + +void MockPageOverlayClient::didScrollFrame(PageOverlay&, Frame&) +{ +} + +bool MockPageOverlayClient::copyAccessibilityAttributeStringValueForPoint(PageOverlay&, String /* attribute */, FloatPoint, String&) +{ + return false; +} + +bool MockPageOverlayClient::copyAccessibilityAttributeBoolValueForPoint(PageOverlay&, String /* attribute */, FloatPoint, bool&) +{ + return false; +} + +Vector<String> MockPageOverlayClient::copyAccessibilityAttributeNames(PageOverlay&, bool /* parameterizedNames */) +{ + return Vector<String>(); +} + +} diff --git a/Source/WebCore/testing/MockPageOverlayClient.h b/Source/WebCore/testing/MockPageOverlayClient.h new file mode 100644 index 000000000..377d7ab04 --- /dev/null +++ b/Source/WebCore/testing/MockPageOverlayClient.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2014 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#include "Frame.h" +#include "MockPageOverlay.h" +#include "PageOverlay.h" +#include <wtf/HashSet.h> + +namespace WebCore { + +class MainFrame; + +class MockPageOverlayClient final : public PageOverlay::Client { + friend class NeverDestroyed<MockPageOverlayClient>; +public: + static MockPageOverlayClient& singleton(); + + explicit MockPageOverlayClient(); + + Ref<MockPageOverlay> installOverlay(MainFrame&, PageOverlay::OverlayType); + void uninstallAllOverlays(); + + String layerTreeAsText(MainFrame&, LayerTreeFlags); + + virtual ~MockPageOverlayClient() { } + +private: + void willMoveToPage(PageOverlay&, Page*) override; + void didMoveToPage(PageOverlay&, Page*) override; + void drawRect(PageOverlay&, GraphicsContext&, const IntRect& dirtyRect) override; + bool mouseEvent(PageOverlay&, const PlatformMouseEvent&) override; + void didScrollFrame(PageOverlay&, Frame&) override; + + bool copyAccessibilityAttributeStringValueForPoint(PageOverlay&, String /* attribute */, FloatPoint, String&) override; + bool copyAccessibilityAttributeBoolValueForPoint(PageOverlay&, String /* attribute */, FloatPoint, bool&) override; + Vector<String> copyAccessibilityAttributeNames(PageOverlay&, bool /* parameterizedNames */) override; + + HashSet<RefPtr<MockPageOverlay>> m_overlays; +}; + +} // namespace WebCore diff --git a/Source/WebCore/testing/MockQuickLookHandleClient.cpp b/Source/WebCore/testing/MockQuickLookHandleClient.cpp new file mode 100644 index 000000000..ca8197e10 --- /dev/null +++ b/Source/WebCore/testing/MockQuickLookHandleClient.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2017 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. AND ITS CONTRIBUTORS ``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 ITS 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 "MockQuickLookHandleClient.h" + +#if USE(QUICK_LOOK) + +#include <wtf/MainThread.h> +#include <wtf/RunLoop.h> + +namespace WebCore { + +MockQuickLookHandleClient& MockQuickLookHandleClient::singleton() +{ + static NeverDestroyed<MockQuickLookHandleClient> sharedClient; + return sharedClient.get(); +} + +void MockQuickLookHandleClient::didRequestPassword(Function<void(const String&)>&& completionHandler) +{ + ASSERT(isMainThread()); + RunLoop::current().dispatch([completionHandler = WTFMove(completionHandler), password = m_password] { + completionHandler(password); + }); +} + +} // namespace WebCore + +#endif // USE(QUICK_LOOK) diff --git a/Source/WebCore/testing/MockQuickLookHandleClient.h b/Source/WebCore/testing/MockQuickLookHandleClient.h new file mode 100644 index 000000000..39cef17b9 --- /dev/null +++ b/Source/WebCore/testing/MockQuickLookHandleClient.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 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. AND ITS CONTRIBUTORS ``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 ITS 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. + */ + +#pragma once + +#if USE(QUICK_LOOK) + +#include "QuickLookHandleClient.h" +#include <wtf/NeverDestroyed.h> + +namespace WebCore { + +class MockQuickLookHandleClient final : public QuickLookHandleClient { +public: + static MockQuickLookHandleClient& singleton(); + + void setPassword(const String& password) { m_password = password; } + + bool supportsPasswordEntry() const override { return true; } + void didRequestPassword(Function<void(const String&)>&&) override; + +private: + friend class NeverDestroyed<MockQuickLookHandleClient>; + MockQuickLookHandleClient() = default; + + String m_password; +}; + +} // namespace WebCore + +#endif // USE(QUICK_LOOK) diff --git a/Source/WebCore/testing/TypeConversions.h b/Source/WebCore/testing/TypeConversions.h index 826387502..b352b17d1 100644 --- a/Source/WebCore/testing/TypeConversions.h +++ b/Source/WebCore/testing/TypeConversions.h @@ -23,18 +23,41 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TypeConversions_h -#define TypeConversions_h +#pragma once +#include "Node.h" #include <wtf/FastMalloc.h> -#include <wtf/PassRefPtr.h> +#include <wtf/HashMap.h> #include <wtf/RefCounted.h> +#include <wtf/Variant.h> +#include <wtf/Vector.h> +#include <wtf/text/WTFString.h> namespace WebCore { class TypeConversions : public RefCounted<TypeConversions> { public: - static PassRefPtr<TypeConversions> create() { return adoptRef(new TypeConversions()); } + static Ref<TypeConversions> create() { return adoptRef(*new TypeConversions()); } + + enum class UnionType { + Node, + Sequence, + Dictionary + }; + + struct OtherDictionary { + int longValue; + String stringValue; + }; + + using DictionaryUnion = Variant<RefPtr<Node>, Vector<String>, OtherDictionary>; + + struct Dictionary { + int longValue; + String stringValue; + Vector<String> sequenceValue; + DictionaryUnion unionValue; + }; long testLong() { return m_long; } void setTestLong(long value) { m_long = value; } @@ -71,21 +94,71 @@ public: void setTestUnsignedShort(uint16_t value) { m_UnsignedShort = value; } uint16_t testEnforceRangeUnsignedShort() { return m_UnsignedShort; } void setTestEnforceRangeUnsignedShort(uint16_t value) { m_UnsignedShort = value; } + + const String& testString() const { return m_string; } + void setTestString(const String& string) { m_string = string; } + const String& testUSVString() const { return m_usvstring; } + void setTestUSVString(const String& usvstring) { m_usvstring = usvstring; } + const String& testByteString() const { return m_byteString; } + void setTestByteString(const String& byteString) { m_byteString = byteString; } + + const Vector<WTF::KeyValuePair<String, int>>& testLongRecord() const { return m_longRecord; } + void setTestLongRecord(const Vector<WTF::KeyValuePair<String, int>>& value) { m_longRecord = value; } + const Vector<WTF::KeyValuePair<String, RefPtr<Node>>>& testNodeRecord() const { return m_nodeRecord; } + void setTestNodeRecord(const Vector<WTF::KeyValuePair<String, RefPtr<Node>>>& value) { m_nodeRecord = value; } + const Vector<WTF::KeyValuePair<String, Vector<String>>>& testSequenceRecord() const { return m_sequenceRecord; } + void setTestSequenceRecord(const Vector<WTF::KeyValuePair<String, Vector<String>>>& value) { m_sequenceRecord = value; } + + using TestUnion = Variant<String, int, bool, RefPtr<Node>, Vector<int>>; + const TestUnion& testUnion() const { return m_union; } + void setTestUnion(const TestUnion& value) { m_union = value; } + + void setTypeConversionsDictionary(Dictionary&& dictionary) + { + m_typeConversionsDictionaryLongValue = dictionary.longValue; + m_typeConversionsDictionaryStringValue = WTFMove(dictionary.stringValue); + m_typeConversionsDictionarySequenceValue = WTFMove(dictionary.sequenceValue); + m_typeConversionsDictionaryUnionValue = WTFMove(dictionary.unionValue); + } + + int typeConversionsDictionaryLongValue() { return m_typeConversionsDictionaryLongValue; } + String typeConversionsDictionaryStringValue() { return m_typeConversionsDictionaryStringValue; } + const Vector<String>& typeConversionsDictionarySequenceValue() { return m_typeConversionsDictionarySequenceValue; } + const DictionaryUnion& typeConversionsDictionaryUnionValue() { return m_typeConversionsDictionaryUnionValue; } + UnionType typeConversionsDictionaryUnionType() + { + return WTF::switchOn(m_typeConversionsDictionaryUnionValue, + [](const RefPtr<Node>&) -> UnionType { return UnionType::Node; }, + [](const Vector<String>&) -> UnionType { return UnionType::Sequence; }, + [](const OtherDictionary&) -> UnionType { return UnionType::Dictionary; } + ); + } + private: TypeConversions() { } - long m_long; - unsigned long m_unsignedLong; - long long m_longLong; - unsigned long long m_unsignedLongLong; - int8_t m_byte; - uint8_t m_octet; - int16_t m_short; - uint16_t m_UnsignedShort; + long m_long { 0 }; + unsigned long m_unsignedLong { 0 }; + long long m_longLong { 0 }; + unsigned long long m_unsignedLongLong { 0 }; + int8_t m_byte { 0 }; + uint8_t m_octet { 0 }; + int16_t m_short { 0 }; + uint16_t m_UnsignedShort { 0 }; + String m_string; + String m_usvstring; + String m_byteString; + Vector<WTF::KeyValuePair<String, int>> m_longRecord; + Vector<WTF::KeyValuePair<String, RefPtr<Node>>> m_nodeRecord; + Vector<WTF::KeyValuePair<String, Vector<String>>> m_sequenceRecord; + TestUnion m_union; + + int m_typeConversionsDictionaryLongValue { 0 }; + String m_typeConversionsDictionaryStringValue; + Vector<String> m_typeConversionsDictionarySequenceValue; + DictionaryUnion m_typeConversionsDictionaryUnionValue; }; } // namespace WebCore - -#endif diff --git a/Source/WebCore/testing/TypeConversions.idl b/Source/WebCore/testing/TypeConversions.idl index f02d73c70..5a5908941 100644 --- a/Source/WebCore/testing/TypeConversions.idl +++ b/Source/WebCore/testing/TypeConversions.idl @@ -23,9 +23,12 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +enum UnionType { "node", "sequence", "dictionary" }; + [ NoInterfaceObject, - ImplementationLacksVTable + ImplementationLacksVTable, + ExportMacro=WEBCORE_TESTSUPPORT_EXPORT, ] interface TypeConversions { attribute long testLong; [EnforceRange] attribute long testEnforceRangeLong; @@ -46,4 +49,37 @@ [EnforceRange] attribute short testEnforceRangeShort; attribute unsigned short testUnsignedShort; [EnforceRange] attribute unsigned short testEnforceRangeUnsignedShort; + + attribute DOMString testString; + attribute ByteString testByteString; + attribute USVString testUSVString; + + void setTestLongRecord(record<DOMString, long> record); + record<DOMString, long> testLongRecord(); + + void setTestNodeRecord(record<USVString, Node> record); + record<USVString, Node> testNodeRecord(); + + void setTestSequenceRecord(record<ByteString, sequence<DOMString>> record); + record<ByteString, sequence<DOMString>> testSequenceRecord(); + + attribute (DOMString or long or boolean or Node or sequence<long>) testUnion; + + void setTypeConversionsDictionary(TypeConversionsDictionary d); + readonly attribute long typeConversionsDictionaryLongValue; + readonly attribute DOMString typeConversionsDictionaryStringValue; + readonly attribute sequence<DOMString> typeConversionsDictionarySequenceValue; + readonly attribute UnionType typeConversionsDictionaryUnionType; +}; + +dictionary TypeConversionsOtherDictionary { + long longValue = 0; + DOMString stringValue = ""; +}; + +dictionary TypeConversionsDictionary { + long longValue = 0; + DOMString stringValue = ""; + sequence<DOMString> sequenceValue = []; + (Node or sequence<DOMString> or TypeConversionsOtherDictionary) unionValue = null; }; diff --git a/Source/WebCore/testing/WebCoreTestShimLibrary.cpp b/Source/WebCore/testing/WebCoreTestShimLibrary.cpp new file mode 100644 index 000000000..edf3d388c --- /dev/null +++ b/Source/WebCore/testing/WebCoreTestShimLibrary.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``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 ITS 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 <TargetConditionals.h> + +#if !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE + +#include "DynamicLinkerInterposing.h" +#include <Carbon/Carbon.h> + +static int sSecureInputEnableCount; + +static OSStatus shimEnableSecureEventInput() +{ + ++sSecureInputEnableCount; + return noErr; +} + +static OSStatus shimDisableSecureEventInput() +{ + if (!sSecureInputEnableCount) + return paramErr; + --sSecureInputEnableCount; + return noErr; +} + +static Boolean shimIsSecureEventInputEnabled() +{ + return sSecureInputEnableCount; +} + +DYLD_INTERPOSE(shimEnableSecureEventInput, EnableSecureEventInput) +DYLD_INTERPOSE(shimDisableSecureEventInput, DisableSecureEventInput) +DYLD_INTERPOSE(shimIsSecureEventInputEnabled, IsSecureEventInputEnabled) + +#endif // !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE diff --git a/Source/WebCore/testing/js/WebCoreTestSupport.cpp b/Source/WebCore/testing/js/WebCoreTestSupport.cpp index 92623793c..faffd0c4a 100644 --- a/Source/WebCore/testing/js/WebCoreTestSupport.cpp +++ b/Source/WebCore/testing/js/WebCoreTestSupport.cpp @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2011, 2015 Google Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,8 +32,15 @@ #include "Internals.h" #include "JSDocument.h" #include "JSInternals.h" +#include "LogInitialization.h" +#include "MockGamepadProvider.h" +#include "Page.h" +#include "URLParser.h" +#include "WheelEventTestTrigger.h" #include <JavaScriptCore/APICast.h> +#include <JavaScriptCore/JSValueRef.h> #include <interpreter/CallFrame.h> +#include <runtime/IdentifierInlines.h> using namespace JSC; using namespace WebCore; @@ -45,8 +53,8 @@ void injectInternalsObject(JSContextRef context) JSLockHolder lock(exec); JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()); ScriptExecutionContext* scriptContext = globalObject->scriptExecutionContext(); - if (scriptContext->isDocument()) - globalObject->putDirect(exec->vm(), Identifier(exec, Internals::internalsId), toJS(exec, globalObject, Internals::create(toDocument(scriptContext)))); + if (is<Document>(*scriptContext)) + globalObject->putDirect(exec->vm(), Identifier::fromString(exec, Internals::internalsId), toJS(exec, globalObject, Internals::create(downcast<Document>(*scriptContext)))); } void resetInternalsObject(JSContextRef context) @@ -55,9 +63,121 @@ void resetInternalsObject(JSContextRef context) JSLockHolder lock(exec); JSDOMGlobalObject* globalObject = jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()); ScriptExecutionContext* scriptContext = globalObject->scriptExecutionContext(); - Page* page = toDocument(scriptContext)->frame()->page(); - Internals::resetToConsistentState(page); + Page* page = downcast<Document>(scriptContext)->frame()->page(); + Internals::resetToConsistentState(*page); InternalSettings::from(page)->resetToConsistentState(); } +void monitorWheelEvents(WebCore::Frame& frame) +{ + Page* page = frame.page(); + if (!page) + return; + + page->ensureTestTrigger(); +} + +void setTestCallbackAndStartNotificationTimer(WebCore::Frame& frame, JSContextRef context, JSObjectRef jsCallbackFunction) +{ + Page* page = frame.page(); + if (!page || !page->expectsWheelEventTriggers()) + return; + + JSValueProtect(context, jsCallbackFunction); + + page->ensureTestTrigger().setTestCallbackAndStartNotificationTimer([=](void) { + JSObjectCallAsFunction(context, jsCallbackFunction, nullptr, 0, nullptr, nullptr); + JSValueUnprotect(context, jsCallbackFunction); + }); +} + +void clearWheelEventTestTrigger(WebCore::Frame& frame) +{ + Page* page = frame.page(); + if (!page) + return; + + page->clearTrigger(); +} + +void setLogChannelToAccumulate(const String& name) +{ +#if !LOG_DISABLED + WebCore::setLogChannelToAccumulate(name); +#else + UNUSED_PARAM(name); +#endif +} + +void initializeLogChannelsIfNecessary() +{ +#if !LOG_DISABLED || !RELEASE_LOG_DISABLED + WebCore::initializeLogChannelsIfNecessary(); +#endif +} + +void setAllowsAnySSLCertificate(bool allowAnySSLCertificate) +{ + InternalSettings::setAllowsAnySSLCertificate(allowAnySSLCertificate); +} + +void installMockGamepadProvider() +{ +#if ENABLE(GAMEPAD) + GamepadProvider::setSharedProvider(MockGamepadProvider::singleton()); +#endif +} + +void connectMockGamepad(unsigned gamepadIndex) +{ +#if ENABLE(GAMEPAD) + MockGamepadProvider::singleton().connectMockGamepad(gamepadIndex); +#else + UNUSED_PARAM(gamepadIndex); +#endif +} + +void disconnectMockGamepad(unsigned gamepadIndex) +{ +#if ENABLE(GAMEPAD) + MockGamepadProvider::singleton().disconnectMockGamepad(gamepadIndex); +#else + UNUSED_PARAM(gamepadIndex); +#endif +} + +void setMockGamepadDetails(unsigned gamepadIndex, const WTF::String& gamepadID, unsigned axisCount, unsigned buttonCount) +{ +#if ENABLE(GAMEPAD) + MockGamepadProvider::singleton().setMockGamepadDetails(gamepadIndex, gamepadID, axisCount, buttonCount); +#else + UNUSED_PARAM(gamepadIndex); + UNUSED_PARAM(gamepadID); + UNUSED_PARAM(axisCount); + UNUSED_PARAM(buttonCount); +#endif +} + +void setMockGamepadAxisValue(unsigned gamepadIndex, unsigned axisIndex, double axisValue) +{ +#if ENABLE(GAMEPAD) + MockGamepadProvider::singleton().setMockGamepadAxisValue(gamepadIndex, axisIndex, axisValue); +#else + UNUSED_PARAM(gamepadIndex); + UNUSED_PARAM(axisIndex); + UNUSED_PARAM(axisValue); +#endif +} + +void setMockGamepadButtonValue(unsigned gamepadIndex, unsigned buttonIndex, double buttonValue) +{ +#if ENABLE(GAMEPAD) + MockGamepadProvider::singleton().setMockGamepadButtonValue(gamepadIndex, buttonIndex, buttonValue); +#else + UNUSED_PARAM(gamepadIndex); + UNUSED_PARAM(buttonIndex); + UNUSED_PARAM(buttonValue); +#endif +} + } diff --git a/Source/WebCore/testing/js/WebCoreTestSupport.h b/Source/WebCore/testing/js/WebCoreTestSupport.h index de7fc747f..564094a52 100644 --- a/Source/WebCore/testing/js/WebCoreTestSupport.h +++ b/Source/WebCore/testing/js/WebCoreTestSupport.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2011 Google Inc. All rights reserved. + * Copyright (C) 2011, 2015 Google Inc. All rights reserved. + * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,22 +24,43 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef WebCoreTestSupport_h -#define WebCoreTestSupport_h +#pragma once typedef const struct OpaqueJSContext* JSContextRef; +typedef struct OpaqueJSString* JSStringRef; +typedef struct OpaqueJSValue* JSObjectRef; -#if PLATFORM(MAC) +#if PLATFORM(COCOA) #define TEST_SUPPORT_EXPORT WTF_EXPORT_PRIVATE #else #define TEST_SUPPORT_EXPORT #endif +namespace WTF { +class String; +} + +namespace WebCore { +class Frame; +} + namespace WebCoreTestSupport { void injectInternalsObject(JSContextRef) TEST_SUPPORT_EXPORT; void resetInternalsObject(JSContextRef) TEST_SUPPORT_EXPORT; +void monitorWheelEvents(WebCore::Frame&) TEST_SUPPORT_EXPORT; +void setTestCallbackAndStartNotificationTimer(WebCore::Frame&, JSContextRef, JSObjectRef) TEST_SUPPORT_EXPORT; +void clearWheelEventTestTrigger(WebCore::Frame&) TEST_SUPPORT_EXPORT; -} // namespace WebCore +void setLogChannelToAccumulate(const WTF::String& name) TEST_SUPPORT_EXPORT; +void initializeLogChannelsIfNecessary() TEST_SUPPORT_EXPORT; +void setAllowsAnySSLCertificate(bool) TEST_SUPPORT_EXPORT; -#endif +void installMockGamepadProvider() TEST_SUPPORT_EXPORT; +void connectMockGamepad(unsigned index) TEST_SUPPORT_EXPORT; +void disconnectMockGamepad(unsigned index) TEST_SUPPORT_EXPORT; +void setMockGamepadDetails(unsigned index, const WTF::String& gamepadID, unsigned axisCount, unsigned buttonCount) TEST_SUPPORT_EXPORT; +void setMockGamepadAxisValue(unsigned index, unsigned axisIndex, double value) TEST_SUPPORT_EXPORT; +void setMockGamepadButtonValue(unsigned index, unsigned buttonIndex, double value) TEST_SUPPORT_EXPORT; + +} // namespace WebCoreTestSupport diff --git a/Source/WebCore/testing/js/WebCoreTestSupportPrefix.cpp b/Source/WebCore/testing/js/WebCoreTestSupportPrefix.cpp new file mode 100644 index 000000000..30eaa33c4 --- /dev/null +++ b/Source/WebCore/testing/js/WebCoreTestSupportPrefix.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 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 "WebCoreTestSupportPrefix.h" diff --git a/Source/WebCore/testing/js/WebCoreTestSupportPrefix.h b/Source/WebCore/testing/js/WebCoreTestSupportPrefix.h new file mode 100644 index 000000000..da9b0fce9 --- /dev/null +++ b/Source/WebCore/testing/js/WebCoreTestSupportPrefix.h @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2015 Apple Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +/* This prefix file should contain only: + * 1) files to precompile for faster builds + * 2) in one case at least: OS-X-specific performance bug workarounds + * 3) the special trick to catch us using new or delete without including "config.h" + * The project should be able to build without this header, although we rarely test that. + */ + +/* Things that need to be defined globally should go into "config.h". */ + +#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE) +#include "cmakeconfig.h" +#endif + +#include <wtf/Platform.h> + +#if defined(__APPLE__) +#ifdef __cplusplus +#define NULL __null +#else +#define NULL ((void *)0) +#endif +#endif + +#if OS(WINDOWS) + +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x601 +#endif + +#ifndef WINVER +#define WINVER 0x0601 +#endif + +#if !USE(CURL) +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h +#endif +#endif + +#undef WEBCORE_EXPORT +#define WEBCORE_EXPORT WTF_IMPORT_DECLARATION +#define WEBCORE_TESTSUPPORT_EXPORT WTF_EXPORT_DECLARATION + +#else + +#include <pthread.h> + +#define WEBCORE_TESTSUPPORT_EXPORT WEBCORE_EXPORT + +#endif // OS(WINDOWS) + +#include <fcntl.h> +#include <sys/types.h> +#if defined(__APPLE__) +#include <regex.h> +#endif + +#include <setjmp.h> + +#include <signal.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#if defined(__APPLE__) +#include <unistd.h> +#endif + +#ifdef __cplusplus +#include <algorithm> +#include <cstddef> +#include <new> +#endif + +#if defined(__APPLE__) +#include <sys/param.h> +#endif +#include <sys/stat.h> +#if defined(__APPLE__) +#include <sys/resource.h> +#include <sys/time.h> +#endif + +#include <CoreFoundation/CoreFoundation.h> +#if PLATFORM(WIN_CAIRO) +#include <ConditionalMacros.h> +#include <windows.h> +#else + +#if OS(WINDOWS) +#if USE(CG) + +// FIXME <rdar://problem/8208868> Remove support for obsolete ColorSync API, CoreServices header in CoreGraphics +// We can remove this once the new ColorSync APIs are available in an internal Safari SDK. +#include <ColorSync/ColorSync.h> +#ifdef __COLORSYNCDEPRECATED__ +#define COREGRAPHICS_INCLUDES_CORESERVICES_HEADER +#define OBSOLETE_COLORSYNC_API +#endif +#endif +#if USE(CFURLCONNECTION) +#include <CFNetwork/CFNetwork.h> +// On Windows, dispatch.h needs to be included before certain CFNetwork headers. +#include <dispatch/dispatch.h> +#endif +#include <windows.h> +#else +#if !PLATFORM(IOS) +#include <CoreServices/CoreServices.h> +#endif // !PLATFORM(IOS) +#endif // OS(WINDOWS) + +#endif + +#ifdef __OBJC__ +#if PLATFORM(IOS) +#import <Foundation/Foundation.h> +#else +#import <Cocoa/Cocoa.h> +#endif // PLATFORM(IOS) +#endif + +#ifdef __cplusplus +#define new ("if you use new/delete make sure to include config.h at the top of the file"()) +#define delete ("if you use new/delete make sure to include config.h at the top of the file"()) +#endif + +/* When C++ exceptions are disabled, the C++ library defines |try| and |catch| + * to allow C++ code that expects exceptions to build. These definitions + * interfere with Objective-C++ uses of Objective-C exception handlers, which + * use |@try| and |@catch|. As a workaround, undefine these macros. */ +#ifdef __OBJC__ +#undef try +#undef catch +#endif + |