blob: 38aedc0fe49d17fc946c3fc62876d258ab50168e [file] [log] [blame]
/*
* Copyright (C) 2018-2024 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 "Quirks.h"
#include "AccessibilityObject.h"
#include "Attr.h"
#include "ContainerNodeInlines.h"
#include "DeprecatedGlobalSettings.h"
#include "Document.h"
#include "DocumentInlines.h"
#include "DocumentLoader.h"
#include "DocumentStorageAccess.h"
#include "ElementAncestorIteratorInlines.h"
#include "ElementInlines.h"
#include "ElementTargetingTypes.h"
#include "EventNames.h"
#include "EventTargetInlines.h"
#include "FrameLoader.h"
#include "HTMLArticleElement.h"
#include "HTMLBodyElement.h"
#include "HTMLCollection.h"
#include "HTMLDivElement.h"
#include "HTMLMetaElement.h"
#include "HTMLNames.h"
#include "HTMLObjectElement.h"
#include "HTMLTextAreaElement.h"
#include "HTMLVideoElement.h"
#include "JSEventListener.h"
#include "KeyframeEffect.h"
#include "LayoutUnit.h"
#include "LocalDOMWindow.h"
#include "LocalFrameView.h"
#include "MouseEvent.h"
#include "NetworkStorageSession.h"
#include "NodeRenderStyle.h"
#include "OrganizationStorageAccessPromptQuirk.h"
#include "PlatformMouseEvent.h"
#include "QuirksData.h"
#include "RegistrableDomain.h"
#include "ResourceLoadObserver.h"
#include "ResourceRequest.h"
#include "SVGElementTypeHelpers.h"
#include "SVGPathElement.h"
#include "SVGSVGElement.h"
#include "ScriptController.h"
#include "ScriptSourceCode.h"
#include "Settings.h"
#include "SpaceSplitString.h"
#include "TrustedFonts.h"
#include "TypedElementDescendantIteratorInlines.h"
#include "UserAgent.h"
#include "UserContentTypes.h"
#include "UserScript.h"
#include "UserScriptTypes.h"
#include <JavaScriptCore/CodeBlock.h>
#include <JavaScriptCore/JSLock.h>
#include <JavaScriptCore/ScriptExecutable.h>
#include <JavaScriptCore/SourceCode.h>
#include <JavaScriptCore/SourceProvider.h>
#include <JavaScriptCore/StackVisitor.h>
#include <wtf/TZoneMallocInlines.h>
#include <wtf/text/MakeString.h>
#if PLATFORM(IOS_FAMILY)
#include <pal/system/ios/UserInterfaceIdiom.h>
#endif
#if PLATFORM(COCOA)
#include <wtf/cocoa/RuntimeApplicationChecksCocoa.h>
#endif
namespace WebCore {
WTF_MAKE_TZONE_ALLOCATED_IMPL(Quirks);
static inline OptionSet<AutoplayQuirk> allowedAutoplayQuirks(Document& document)
{
auto* loader = document.loader();
if (!loader)
return { };
return loader->allowedAutoplayQuirks();
}
static inline OptionSet<AutoplayQuirk> allowedAutoplayQuirks(Document* document)
{
if (!document)
return { };
return allowedAutoplayQuirks(*document);
}
static HashMap<RegistrableDomain, String>& updatableStorageAccessUserAgentStringQuirks()
{
// FIXME: Make this a member of Quirks.
static MainThreadNeverDestroyed<HashMap<RegistrableDomain, String>> map;
return map.get();
}
#if USE(APPLE_INTERNAL_SDK)
#import <WebKitAdditions/QuirksAdditions.cpp>
#else
static inline bool needsDesktopUserAgentInternal(const URL&) { return false; }
static inline bool shouldPreventOrientationMediaQueryFromEvaluatingToLandscapeInternal(const URL&) { return false; }
static inline String standardUserAgentWithApplicationNameIncludingCompatOverridesInternal(const String&, const String&, UserAgentType) { return { }; }
static inline bool shouldNotAutoUpgradeToHTTPSNavigationInternal(const URL&) { return false; }
#endif
Quirks::Quirks(Document& document)
: m_document(document)
{
determineRelevantQuirks();
}
Quirks::~Quirks() = default;
inline bool Quirks::needsQuirks() const
{
return m_document && m_document->settings().needsSiteSpecificQuirks();
}
bool Quirks::shouldIgnoreInvalidSignal() const
{
return needsQuirks();
}
// FIXME: Add more options to the helper to cover more patterns.
// - end of domain
// - full domain
// - path?
// or make different helpers
bool Quirks::isDomain(const String& domainString) const
{
return RegistrableDomain(topDocumentURL()).string() == domainString;
}
bool Quirks::domainStartsWith(const String& prefix) const
{
return RegistrableDomain(topDocumentURL()).string().startsWith(prefix);
}
bool Quirks::isEmbedDomain(const String& domainString) const
{
if (m_document->isTopDocument())
return false;
return RegistrableDomain(m_document->url()).string() == domainString;
}
// ceac.state.gov https://bugs.webkit.org/show_bug.cgi?id=193478
// weather.com rdar://139689157
bool Quirks::needsFormControlToBeMouseFocusable() const
{
#if PLATFORM(MAC)
return needsQuirks() && m_quirksData.needsFormControlToBeMouseFocusableQuirk;
#else
return false;
#endif // PLATFORM(MAC)
}
bool Quirks::needsAutoplayPlayPauseEvents() const
{
if (!needsQuirks())
return false;
if (m_quirksData.shouldDispatchPlayPauseEventsOnResume)
return true;
Ref document = *m_document;
if (allowedAutoplayQuirks(document).contains(AutoplayQuirk::SynthesizedPauseEvents))
return true;
return allowedAutoplayQuirks(document->protectedMainFrameDocument().get()).contains(AutoplayQuirk::SynthesizedPauseEvents);
}
// netflix.com https://bugs.webkit.org/show_bug.cgi?id=173030
// This quirk handles several scenarios:
// - Inserting / Removing Airpods
// - macOS w/ Touch Bar
// - iOS PiP
bool Quirks::needsSeekingSupportDisabled() const
{
return needsQuirks() && m_quirksData.needsSeekingSupportDisabledQuirk;
}
// netflix.com https://bugs.webkit.org/show_bug.cgi?id=193301
bool Quirks::needsPerDocumentAutoplayBehavior() const
{
#if PLATFORM(MAC)
Ref document = *m_document;
ASSERT(document->isTopDocument());
return needsQuirks() && allowedAutoplayQuirks(document).contains(AutoplayQuirk::PerDocumentAutoplayBehavior);
#else
return needsQuirks() && m_quirksData.isNetflix;
#endif
}
// zoom.com https://bugs.webkit.org/show_bug.cgi?id=223180
bool Quirks::shouldAutoplayWebAudioForArbitraryUserGesture() const
{
return needsQuirks() && m_quirksData.shouldAutoplayWebAudioForArbitraryUserGestureQuirk;
}
// youtube.com https://bugs.webkit.org/show_bug.cgi?id=195598
bool Quirks::hasBrokenEncryptedMediaAPISupportQuirk() const
{
#if ENABLE(THUNDER)
return false;
#else
return needsQuirks() && m_quirksData.hasBrokenEncryptedMediaAPISupportQuirk;
#endif
}
// docs.google.com https://bugs.webkit.org/show_bug.cgi?id=161984
bool Quirks::isTouchBarUpdateSuppressedForHiddenContentEditable() const
{
#if PLATFORM(MAC)
return needsQuirks() && m_quirksData.isTouchBarUpdateSuppressedForHiddenContentEditableQuirk;
#else
return false;
#endif
}
// icloud.com rdar://26013388
// trix-editor.org rdar://28242210
// onedrive.live.com rdar://26013388
// added in https://bugs.webkit.org/show_bug.cgi?id=161996
bool Quirks::isNeverRichlyEditableForTouchBar() const
{
#if PLATFORM(MAC)
return needsQuirks() && m_quirksData.isNeverRichlyEditableForTouchBarQuirk;
#else
return false;
#endif
}
// docs.google.com rdar://49864669
// FIXME https://bugs.webkit.org/show_bug.cgi?id=260698
bool Quirks::shouldSuppressAutocorrectionAndAutocapitalizationInHiddenEditableAreas() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.shouldSuppressAutocorrectionAndAutocapitalizationInHiddenEditableAreasQuirk;
#else
return false;
#endif
}
// weebly.com rdar://48003980
// medium.com rdar://50457837
bool Quirks::shouldDispatchSyntheticMouseEventsWhenModifyingSelection() const
{
if (m_document->settings().shouldDispatchSyntheticMouseEventsWhenModifyingSelection())
return true;
return needsQuirks() && m_quirksData.shouldDispatchSyntheticMouseEventsWhenModifyingSelectionQuirk;
}
// www.youtube.com rdar://52361019
bool Quirks::needsYouTubeMouseOutQuirk() const
{
#if PLATFORM(IOS_FAMILY)
if (m_document->settings().shouldDispatchSyntheticMouseOutAfterSyntheticClick())
return true;
return needsQuirks() && m_quirksData.needsYouTubeMouseOutQuirk;
#else
return false;
#endif
}
// safe.menlosecurity.com rdar://135114489
// FIXME (rdar://138585709): Remove this quirk for safe.menlosecurity.com once investigation into text corruption on the site is completed and the issue is resolved.
bool Quirks::shouldDisableWritingSuggestionsByDefault() const
{
return needsQuirks() && m_quirksData.shouldDisableWritingSuggestionsByDefaultQuirk;
}
void Quirks::updateStorageAccessUserAgentStringQuirks(HashMap<RegistrableDomain, String>&& userAgentStringQuirks)
{
auto& quirks = updatableStorageAccessUserAgentStringQuirks();
quirks.clear();
for (auto&& [domain, userAgent] : userAgentStringQuirks)
quirks.add(WTFMove(domain), WTFMove(userAgent));
}
String Quirks::storageAccessUserAgentStringQuirkForDomain(const URL& url)
{
if (!needsQuirks())
return { };
const auto& quirks = updatableStorageAccessUserAgentStringQuirks();
RegistrableDomain domain { url };
auto iterator = quirks.find(domain);
if (iterator == quirks.end())
return { };
if (domain == "live.com"_s && url.host() != "teams.live.com"_s)
return { };
return iterator->value;
}
bool Quirks::isYoutubeEmbedDomain() const
{
return isEmbedDomain("youtube.com"_s) || isEmbedDomain("youtube-nocookie.com"_s);
}
bool Quirks::shouldDisableElementFullscreenQuirk() const
{
#if PLATFORM(IOS_FAMILY)
if (!needsQuirks())
return false;
// Vimeo.com has incorrect layout on iOS on certain videos with wider
// aspect ratios than the device's screen in landscape mode.
// (Ref: rdar://116531089)
// Instagram.com stories flow under the notch and status bar
// (Ref: rdar://121014613)
// x.com (Twitter) video embeds have controls that are too tiny and
// show page behind fullscreen.
// (Ref: rdar://121473410)
// YouTube.com does not provide AirPlay controls in fullscreen
// (Ref: rdar://121471373)
if (!m_quirksData.shouldDisableElementFullscreen && !m_document->isTopDocument()) {
m_quirksData.shouldDisableElementFullscreen = isEmbedDomain("x.com"_s)
|| (PAL::currentUserInterfaceIdiomIsSmallScreen() && isYoutubeEmbedDomain());
}
return m_quirksData.shouldDisableElementFullscreen;
#else
return false;
#endif
}
#if ENABLE(TOUCH_EVENTS)
// rdar://49124313
// desmos.com rdar://47068176
// flipkart.com rdar://49648520
// soundcloud.com rdar://52915981
// naver.com rdar://48068610
// mybinder.org rdar://51770057
bool Quirks::shouldDispatchSimulatedMouseEvents(const EventTarget* target) const
{
if (m_document->settings().mouseEventsSimulationEnabled())
return true;
if (!needsQuirks())
return false;
auto doShouldDispatchChecks = [this] () -> QuirksData::ShouldDispatchSimulatedMouseEvents {
auto* loader = m_document->loader();
if (!loader || loader->simulatedMouseEventsDispatchPolicy() != SimulatedMouseEventsDispatchPolicy::Allow)
return QuirksData::ShouldDispatchSimulatedMouseEvents::No;
if (m_quirksData.isAmazon)
return QuirksData::ShouldDispatchSimulatedMouseEvents::Yes;
if (m_quirksData.isGoogleMaps)
return QuirksData::ShouldDispatchSimulatedMouseEvents::Yes;
if (m_quirksData.isSoundCloud)
return QuirksData::ShouldDispatchSimulatedMouseEvents::Yes;
const URL& topDocumentURL = this->topDocumentURL();
const auto registrableDomainString = RegistrableDomain(topDocumentURL).string();
if (registrableDomainString == "wix.com"_s) {
// Disable simulated mouse dispatching for template selection.
return startsWithLettersIgnoringASCIICase(topDocumentURL.path(), "/website/templates/"_s) ? QuirksData::ShouldDispatchSimulatedMouseEvents::No : QuirksData::ShouldDispatchSimulatedMouseEvents::Yes;
}
if (registrableDomainString == "airtable.com"_s)
return QuirksData::ShouldDispatchSimulatedMouseEvents::Yes;
if (registrableDomainString == "flipkart.com"_s)
return QuirksData::ShouldDispatchSimulatedMouseEvents::Yes;
if (registrableDomainString == "mybinder.org"_s)
return QuirksData::ShouldDispatchSimulatedMouseEvents::DependingOnTargetFor_mybinder_org;
auto host = topDocumentURL.host();
if (host == "naver.com"_s)
return QuirksData::ShouldDispatchSimulatedMouseEvents::Yes;
if (host.endsWith(".naver.com"_s)) {
// Disable the quirk for tv.naver.com subdomain to be able to simulate hover on videos.
if (host == "tv.naver.com"_s)
return QuirksData::ShouldDispatchSimulatedMouseEvents::No;
// Disable the quirk for mail.naver.com subdomain to be able to tap on mail subjects.
if (host == "mail.naver.com"_s)
return QuirksData::ShouldDispatchSimulatedMouseEvents::No;
// Disable the quirk on the mobile site.
// FIXME: Maybe this quirk should be disabled for "m." subdomains on all sites? These are generally mobile sites that don't need mouse events.
if (host == "m.naver.com"_s)
return QuirksData::ShouldDispatchSimulatedMouseEvents::No;
return QuirksData::ShouldDispatchSimulatedMouseEvents::Yes;
}
return QuirksData::ShouldDispatchSimulatedMouseEvents::No;
};
if (m_quirksData.shouldDispatchSimulatedMouseEventsQuirk == QuirksData::ShouldDispatchSimulatedMouseEvents::Unknown)
m_quirksData.shouldDispatchSimulatedMouseEventsQuirk = doShouldDispatchChecks();
switch (m_quirksData.shouldDispatchSimulatedMouseEventsQuirk) {
case QuirksData::ShouldDispatchSimulatedMouseEvents::Unknown:
ASSERT_NOT_REACHED();
return false;
case QuirksData::ShouldDispatchSimulatedMouseEvents::No:
return false;
case QuirksData::ShouldDispatchSimulatedMouseEvents::DependingOnTargetFor_mybinder_org:
for (RefPtr node = dynamicDowncast<Node>(target); node; node = node->parentNode()) {
// This uses auto* instead of RefPtr as otherwise GCC does not compile.
if (auto* element = dynamicDowncast<Element>(*node); element && element->hasClassName("lm-DockPanel-tabBar"_s))
return true;
}
return false;
case QuirksData::ShouldDispatchSimulatedMouseEvents::Yes:
return true;
}
ASSERT_NOT_REACHED();
return false;
}
// amazon.com rdar://49124529
// soundcloud.com rdar://52915981
bool Quirks::shouldDispatchedSimulatedMouseEventsAssumeDefaultPrevented(EventTarget* target) const
{
if (!needsQuirks() || !shouldDispatchSimulatedMouseEvents(target))
return false;
if (!m_quirksData.shouldDispatchedSimulatedMouseEventsAssumeDefaultPreventedQuirk)
return false;
RefPtr element = dynamicDowncast<Element>(target);
if (!element)
return false;
if (m_quirksData.isAmazon) {
// When panning on an Amazon product image, we're either touching on the #magnifierLens element
// or its previous sibling.
if (element->getIdAttribute() == "magnifierLens"_s)
return true;
if (auto* sibling = element->nextElementSibling())
return sibling->getIdAttribute() == "magnifierLens"_s;
}
if (m_quirksData.isSoundCloud)
return element->hasClassName("sceneLayer"_s);
return false;
}
// sites.google.com rdar://58653069
bool Quirks::shouldPreventDispatchOfTouchEvent(const AtomString& touchEventType, EventTarget* target) const
{
if (!needsQuirks())
return false;
if (!m_quirksData.shouldPreventDispatchOfTouchEventQuirk)
return false;
if (RefPtr element = dynamicDowncast<Element>(target); element && touchEventType == eventNames().touchendEvent)
return element->hasClassName("DPvwYc"_s) && element->hasClassName("sm8sCf"_s);
return false;
}
#endif
// live.com rdar://52116170
// sharepoint.com rdar://52116170
// maps.google.com https://bugs.webkit.org/show_bug.cgi?id=214945
bool Quirks::shouldAvoidResizingWhenInputViewBoundsChange() const
{
return needsQuirks() && m_quirksData.shouldAvoidResizingWhenInputViewBoundsChangeQuirk;
}
// mailchimp.com rdar://47868965
bool Quirks::shouldDisablePointerEventsQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.shouldDisablePointerEventsQuirk;
#else
return false;
#endif
}
// docs.google.com https://bugs.webkit.org/show_bug.cgi?id=199587
bool Quirks::needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommand() const
{
#if PLATFORM(IOS_FAMILY)
if (m_document->settings().needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommandQuirk())
return true;
return needsQuirks() && m_quirksData.isGoogleDocs;
#else
return false;
#endif
}
// docs.google.com https://bugs.webkit.org/show_bug.cgi?id=199587
bool Quirks::inputMethodUsesCorrectKeyEventOrder() const
{
return false;
}
// FIXME: Remove after the site is fixed, <rdar://problem/50374200>
// mail.google.com rdar://49403416
bool Quirks::needsGMailOverflowScrollQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsGMailOverflowScrollQuirk;
#else
return false;
#endif
}
// web.skype.com webkit.org/b/275941
bool Quirks::needsIPadSkypeOverflowScrollQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsIPadSkypeOverflowScrollQuirk;
#else
return false;
#endif
}
// FIXME: Remove after the site is fixed, <rdar://problem/50374311>
// youtube.com rdar://49582231
bool Quirks::needsYouTubeOverflowScrollQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsYouTubeOverflowScrollQuirk;
#else
return false;
#endif
}
// amazon.com rdar://128962002
bool Quirks::needsPrimeVideoUserSelectNoneQuirk() const
{
#if PLATFORM(MAC)
return needsQuirks() && m_quirksData.needsPrimeVideoUserSelectNoneQuirk;
#else
return false;
#endif
}
// facebook.com https://webkit.org/b/295071
// FIXME: https://webkit.org/b/295318
bool Quirks::needsFacebookRemoveNotSupportedQuirk() const
{
return needsQuirks() && m_quirksData.needsFacebookRemoveNotSupportedQuirk;
}
// youtube.com rdar://135886305
// NOTE: Also remove `BuilderConverter::convertScrollbarWidth` and related code when removing this quirk.
bool Quirks::needsScrollbarWidthThinDisabledQuirk() const
{
return needsQuirks() && m_quirksData.needsScrollbarWidthThinDisabledQuirk;
}
// spotify.com rdar://138918575
bool Quirks::needsBodyScrollbarWidthNoneDisabledQuirk() const
{
return needsQuirks() && m_quirksData.needsBodyScrollbarWidthNoneDisabledQuirk;
}
// gizmodo.com rdar://102227302
bool Quirks::needsFullscreenDisplayNoneQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsFullscreenDisplayNoneQuirk;
#else
return false;
#endif
}
// cnn.com rdar://119640248
bool Quirks::needsFullscreenObjectFitQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsFullscreenObjectFitQuirk;
#else
return false;
#endif
}
// zomato.com <rdar://problem/128962778>
bool Quirks::needsZomatoEmailLoginLabelQuirk() const
{
#if PLATFORM(MAC)
return needsQuirks() && m_quirksData.needsZomatoEmailLoginLabelQuirk;
#else
return false;
#endif
}
// maps.google.com rdar://67358928
bool Quirks::needsGoogleMapsScrollingQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsGoogleMapsScrollingQuirk;
#else
return false;
#endif
}
// translate.google.com rdar://106539018
bool Quirks::needsGoogleTranslateScrollingQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsGoogleTranslateScrollingQuirk;
#else
return false;
#endif
}
// Kugou Music rdar://74602294
bool Quirks::shouldOmitHTMLDocumentSupportedPropertyNames()
{
#if PLATFORM(COCOA)
static bool shouldOmitHTMLDocumentSupportedPropertyNames = !linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::HTMLDocumentSupportedPropertyNames);
return shouldOmitHTMLDocumentSupportedPropertyNames;
#else
return false;
#endif
}
// rdar://110097836
bool Quirks::shouldSilenceResizeObservers() const
{
#if PLATFORM(IOS) || PLATFORM(VISION)
if (!needsQuirks())
return false;
// ResizeObservers are silenced on YouTube during the 'homing out' snapshout sequence to
// resolve rdar://109837319. This is due to a bug on the site that is causing unexpected
// content layout and can be removed when it is addressed.
auto* page = m_document->page();
if (!page || !page->isTakingSnapshotsForApplicationSuspension())
return false;
return m_quirksData.shouldSilenceResizeObservers;
#else
return false;
#endif
}
bool Quirks::shouldSilenceWindowResizeEventsDuringApplicationSnapshotting() const
{
#if PLATFORM(IOS) || PLATFORM(VISION)
if (!needsQuirks())
return false;
if (!m_quirksData.shouldSilenceWindowResizeEventsDuringApplicationSnapshotting)
return false;
// We silence window resize events during the 'homing out' snapshot sequence when on icloud.com/mail
// to address <rdar://131836301>, on nytimes.com to address <rdar://problem/59763843>, and on
// x.com (twitter) to address <rdar://problem/58804852> & <rdar://problem/61731801>.
auto* page = m_document->page();
if (!page || !page->isTakingSnapshotsForApplicationSuspension())
return false;
return true;
#else
return false;
#endif
}
bool Quirks::shouldSilenceMediaQueryListChangeEvents() const
{
#if PLATFORM(IOS) || PLATFORM(VISION)
if (!needsQuirks())
return false;
if (!m_quirksData.shouldSilenceMediaQueryListChangeEvents)
return false;
// We silence MediaQueryList's change events during the 'homing out' snapshot sequence when on x.com (twitter)
// to address <rdar://problem/58804852> & <rdar://problem/61731801>.
auto* page = m_document->page();
if (!page || !page->isTakingSnapshotsForApplicationSuspension())
return false;
return true;
#else
return false;
#endif
}
// zillow.com rdar://53103732
bool Quirks::shouldAvoidScrollingWhenFocusedContentIsVisible() const
{
return needsQuirks() && m_quirksData.shouldAvoidScrollingWhenFocusedContentIsVisibleQuirk;
}
// Some input only specify image/* as an acceptable type, which is failing sometimes for certains domain names
// which do not support HEIC.
bool Quirks::shouldTranscodeHeicImagesForURL(const URL& url)
{
auto quirksDomain = RegistrableDomain(url);
// zillow.com rdar://79872092
if (quirksDomain.string() == "zillow.com"_s)
return true;
// canva.com https://webkit.org/b/293886
if (quirksDomain.string() == "canva.com"_s)
return true;
return false;
}
// att.com rdar://55185021
bool Quirks::shouldUseLegacySelectPopoverDismissalBehaviorInDataActivation() const
{
return needsQuirks() && m_quirksData.shouldUseLegacySelectPopoverDismissalBehaviorInDataActivationQuirk;
}
// ralphlauren.com rdar://55629493
bool Quirks::shouldIgnoreAriaForFastPathContentObservationCheck() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.shouldIgnoreAriaForFastPathContentObservationCheckQuirk;
#else
return false;
#endif
}
// wikipedia.org https://webkit.org/b/247636
bool Quirks::shouldIgnoreViewportArgumentsToAvoidExcessiveZoom() const
{
#if ENABLE(META_VIEWPORT)
return needsQuirks() && m_quirksData.shouldIgnoreViewportArgumentsToAvoidExcessiveZoomQuirk;
#endif
return false;
}
// slack.com rdar://138614711
bool Quirks::shouldIgnoreViewportArgumentsToAvoidEnlargedView() const
{
#if ENABLE(META_VIEWPORT)
return needsQuirks() && m_quirksData.shouldIgnoreViewportArgumentsToAvoidEnlargedViewQuirk;
#endif
return false;
}
// docs.google.com https://bugs.webkit.org/show_bug.cgi?id=199933
bool Quirks::shouldOpenAsAboutBlank(const String& stringToOpen) const
{
#if PLATFORM(IOS_FAMILY)
if (!needsQuirks())
return false;
auto openerURL = m_document->url();
if (openerURL.host() != "docs.google.com"_s)
return false;
if (!m_document->frame() || !m_document->frame()->loader().userAgent(openerURL).contains("Macintosh"_s))
return false;
URL urlToOpen { URL { }, stringToOpen };
if (!urlToOpen.protocolIsAbout())
return false;
return !equalLettersIgnoringASCIICase(urlToOpen.host(), "blank"_s) && !equalLettersIgnoringASCIICase(urlToOpen.host(), "srcdoc"_s);
#else
UNUSED_PARAM(stringToOpen);
return false;
#endif
}
// vimeo.com rdar://55759025
bool Quirks::needsPreloadAutoQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsPreloadAutoQuirk;
#else
return false;
#endif
}
// vimeo.com rdar://56996057
// docs.google.com rdar://59893415
// bing.com rdar://133223599
bool Quirks::shouldBypassBackForwardCache() const
{
if (!needsQuirks())
return false;
if (!m_quirksData.maybeBypassBackForwardCache)
return false;
RefPtr document = m_document.get();
// Vimeo.com used to bypass the back/forward cache by serving "Cache-Control: no-store" over HTTPS.
// We started caching such content in r250437 but the vimeo.com content unfortunately is not currently compatible
// because it changes the opacity of its body to 0 when navigating away and fails to restore the original opacity
// when coming back from the back/forward cache (e.g. in 'pageshow' event handler). See <rdar://problem/56996057>.
if (m_quirksData.isVimeo && topDocumentURL().protocolIs("https"_s)) {
if (auto* documentLoader = document->frame() ? document->frame()->loader().documentLoader() : nullptr)
return documentLoader->response().cacheControlContainsNoStore();
}
// Spinner issue from image search for bing.com.
if (m_quirksData.isBing) {
static MainThreadNeverDestroyed<const AtomString> imageSearchDialogID("sb_sbidialog"_s);
if (RefPtr element = document->getElementById(imageSearchDialogID.get()))
return element->renderer();
}
// Login issue on bankofamerica.com (rdar://104938789).
if (m_quirksData.isBankOfAmerica) {
if (RefPtr window = document->window()) {
if (window->hasEventListeners(eventNames().unloadEvent)) {
static MainThreadNeverDestroyed<const AtomString> signInId("signIn"_s);
static MainThreadNeverDestroyed<const AtomString> loadingClass("loading"_s);
RefPtr signinButton = document->getElementById(signInId.get());
return signinButton && signinButton->hasClassName(loadingClass.get());
}
}
}
if (m_quirksData.isGoogleProperty) {
// Google Docs used to bypass the back/forward cache by serving "Cache-Control: no-store" over HTTPS.
// We started caching such content in r250437 but the Google Docs index page unfortunately is not currently compatible
// because it puts an overlay (with class "docs-homescreen-freeze-el-full") over the page when navigating away and fails
// to remove it when coming back from the back/forward cache (e.g. in 'pageshow' event handler). See <rdar://problem/57670064>.
// Note that this does not check for docs.google.com host because of hosted G Suite apps.
static MainThreadNeverDestroyed<const AtomString> googleDocsOverlayDivClass("docs-homescreen-freeze-el-full"_s);
RefPtr firstChildInBody = document->body() ? document->body()->firstChild() : nullptr;
if (RefPtr div = dynamicDowncast<HTMLDivElement>(firstChildInBody))
return div->hasClassName(googleDocsOverlayDivClass);
}
return false;
}
// bungalow.com: rdar://61658940
// sfusd.edu: rdar://116292738
bool Quirks::shouldBypassAsyncScriptDeferring() const
{
// Deferring 'mapbox-gl.js' script on bungalow.com causes the script to get in a bad state (rdar://problem/61658940).
// Deferring the google maps script on sfusd.edu may get the page in a bad state (rdar://116292738).
return needsQuirks() && m_quirksData.shouldBypassAsyncScriptDeferring;
}
// smoothscroll JS library rdar://52712513
bool Quirks::shouldMakeEventListenerPassive(const EventTarget& eventTarget, const EventTypeInfo& eventType)
{
auto eventTargetIsRoot = [](const EventTarget& eventTarget) {
if (is<LocalDOMWindow>(eventTarget))
return true;
if (RefPtr node = dynamicDowncast<Node>(eventTarget)) {
if (is<Document>(*node))
return true;
Ref document = node->document();
return document->documentElement() == node || document->body() == node;
}
return false;
};
auto documentFromEventTarget = [](const EventTarget& eventTarget) -> Document* {
return downcast<Document>(eventTarget.scriptExecutionContext());
};
if (eventType.isInCategory(EventCategory::TouchScrollBlocking)) {
if (eventTargetIsRoot(eventTarget)) {
if (RefPtr document = documentFromEventTarget(eventTarget))
return document->settings().passiveTouchListenersAsDefaultOnDocument();
}
return false;
}
if (eventType.isInCategory(EventCategory::Wheel)) {
if (eventTargetIsRoot(eventTarget)) {
if (RefPtr document = documentFromEventTarget(eventTarget))
return document->settings().passiveWheelListenersAsDefaultOnDocument();
}
return false;
}
return false;
}
#if ENABLE(MEDIA_STREAM)
// warbyparker.com rdar://72839707
// baidu.com rdar://56421276
bool Quirks::shouldEnableLegacyGetUserMediaQuirk() const
{
return needsQuirks() && m_quirksData.shouldEnableLegacyGetUserMediaQuirk;
}
// zoom.us rdar://118185086
bool Quirks::shouldDisableImageCaptureQuirk() const
{
return needsQuirks() && m_quirksData.shouldDisableImageCaptureQuirk;
}
bool Quirks::shouldEnableSpeakerSelectionPermissionsPolicyQuirk() const
{
return needsQuirks() && m_quirksData.shouldEnableSpeakerSelectionPermissionsPolicyQuirk;
}
bool Quirks::shouldEnableEnumerateDeviceQuirk() const
{
return needsQuirks() && m_quirksData.shouldEnableEnumerateDeviceQuirk;
}
#endif
bool Quirks::shouldUnloadHeavyFrame() const
{
return needsQuirks() && m_quirksData.shouldUnloadHeavyFrames;
}
// hulu.com rdar://55041979
bool Quirks::needsCanPlayAfterSeekedQuirk() const
{
return needsQuirks() && m_quirksData.needsCanPlayAfterSeekedQuirk;
}
// wikipedia.org rdar://54856323
bool Quirks::shouldLayOutAtMinimumWindowWidthWhenIgnoringScalingConstraints() const
{
// FIXME: We should consider replacing this with a heuristic to determine whether
// or not the edges of the page mostly lack content after shrinking to fit.
return needsQuirks() && m_quirksData.shouldLayOutAtMinimumWindowWidthWhenIgnoringScalingConstraintsQuirk;
}
// mail.yahoo.com rdar://63511613
bool Quirks::shouldAvoidPastingImagesAsWebContent() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.shouldAvoidPastingImagesAsWebContent;
#else
return false;
#endif
}
bool Quirks::shouldNotAutoUpgradeToHTTPSNavigation(const URL& url)
{
return needsQuirks() && shouldNotAutoUpgradeToHTTPSNavigationInternal(url);
}
// kinja.com and related sites rdar://60601895
static bool isKinjaLoginAvatarElement(const Element& element)
{
// The click event handler has been found to trigger on a div or
// span with these class names, or the svg, or the svg's path.
if (element.hasClass() && (element.hasClassName("js_switch-to-burner-login"_s)
|| element.hasClassName("js_header-userbutton"_s)
|| element.hasClassName("sc-1il3uru-3"_s) || element.hasClassName("cIhKfd"_s)
|| element.hasClassName("iyvn34-0"_s) || element.hasClassName("bYIjtl"_s))) {
return true;
}
RefPtr<const Element> svgElement;
if (is<SVGSVGElement>(element))
svgElement = element;
else if (is<SVGPathElement>(element) && is<SVGSVGElement>(element.parentElement()))
svgElement = element.parentElement();
return svgElement && svgElement->attributeWithoutSynchronization(HTMLNames::aria_labelAttr) == "UserFilled icon"_s;
}
// teams.microsoft.com https://bugs.webkit.org/show_bug.cgi?id=219505
bool Quirks::isMicrosoftTeamsRedirectURL(const URL& url)
{
return url.host() == "teams.microsoft.com"_s && url.query().contains("Retried+3+times+without+success"_s);
}
static bool isStorageAccessQuirkDomainAndElement(const URL& url, const Element& element)
{
// Microsoft Teams login case.
// FIXME(218779): Remove this quirk once microsoft.com completes their login flow redesign.
if (url.host() == "www.microsoft.com"_s) {
return element.hasClass()
&& (element.hasClassName("glyph_signIn_circle"_s)
|| element.hasClassName("mectrl_headertext"_s)
|| element.hasClassName("mectrl_header"_s));
}
// Sony Network Entertainment login case.
// FIXME(218760): Remove this quirk once playstation.com completes their login flow redesign.
if (url.host() == "www.playstation.com"_s || url.host() == "my.playstation.com"_s) {
return element.hasClass()
&& (element.hasClassName("web-toolbar__signin-button"_s)
|| element.hasClassName("web-toolbar__signin-button-label"_s)
|| element.hasClassName("sb-signin-button"_s));
}
return false;
}
// playstation.com - rdar://72062985
bool Quirks::hasStorageAccessForAllLoginDomains(const HashSet<RegistrableDomain>& loginDomains, const RegistrableDomain& topFrameDomain)
{
for (auto& loginDomain : loginDomains) {
if (!ResourceLoadObserver::shared().hasCrossPageStorageAccess(loginDomain, topFrameDomain))
return false;
}
return true;
}
Quirks::StorageAccessResult Quirks::requestStorageAccessAndHandleClick(CompletionHandler<void(ShouldDispatchClick)>&& completionHandler) const
{
RefPtr document = m_document.get();
auto firstPartyDomain = RegistrableDomain(topDocumentURL());
auto domainsInNeedOfStorageAccess = NetworkStorageSession::subResourceDomainsInNeedOfStorageAccessForFirstParty(firstPartyDomain);
if (!domainsInNeedOfStorageAccess || domainsInNeedOfStorageAccess.value().isEmpty()) {
completionHandler(ShouldDispatchClick::No);
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
}
if (hasStorageAccessForAllLoginDomains(*domainsInNeedOfStorageAccess, firstPartyDomain)) {
completionHandler(ShouldDispatchClick::No);
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
}
auto domainInNeedOfStorageAccess = RegistrableDomain(*domainsInNeedOfStorageAccess.value().begin().get());
if (!document) {
completionHandler(ShouldDispatchClick::No);
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
}
document->addConsoleMessage(MessageSource::Other, MessageLevel::Info, makeString("requestStorageAccess is invoked on behalf of domain \""_s, domainInNeedOfStorageAccess.string(), "\""_s));
DocumentStorageAccess::requestStorageAccessForNonDocumentQuirk(*document, WTFMove(domainInNeedOfStorageAccess), [firstPartyDomain, domainInNeedOfStorageAccess, completionHandler = WTFMove(completionHandler)](StorageAccessWasGranted storageAccessGranted) mutable {
if (storageAccessGranted == StorageAccessWasGranted::No) {
completionHandler(ShouldDispatchClick::Yes);
return;
}
ResourceLoadObserver::shared().setDomainsWithCrossPageStorageAccess({ { firstPartyDomain, Vector<RegistrableDomain> { domainInNeedOfStorageAccess } } }, [completionHandler = WTFMove(completionHandler)] () mutable {
completionHandler(ShouldDispatchClick::Yes);
});
});
return Quirks::StorageAccessResult::ShouldCancelEvent;
}
RefPtr<Document> Quirks::protectedDocument() const
{
return m_document.get();
}
void Quirks::triggerOptionalStorageAccessIframeQuirk(const URL& frameURL, CompletionHandler<void()>&& completionHandler) const
{
if (RefPtr document = m_document.get()) {
if (document->frame() && !m_document->frame()->isMainFrame()) {
auto& mainFrame = document->frame()->mainFrame();
if (auto* localMainFrame = dynamicDowncast<LocalFrame>(mainFrame); localMainFrame && localMainFrame->document()) {
localMainFrame->document()->quirks().triggerOptionalStorageAccessIframeQuirk(frameURL, WTFMove(completionHandler));
return;
}
}
bool isMSOLoginButNotMSTeams = document->url().hasQuery() && document->url().host() == "login.microsoftonline.com"_s && !document->url().query().contains("redirect_uri=https%3A%2F%2Fteams.microsoft.com"_s);
if (!isMSOLoginButNotMSTeams && subFrameDomainsForStorageAccessQuirk().contains(RegistrableDomain { frameURL })) {
return DocumentStorageAccess::requestStorageAccessForNonDocumentQuirk(*document, RegistrableDomain { frameURL }, [completionHandler = WTFMove(completionHandler)](StorageAccessWasGranted) mutable {
completionHandler();
});
}
}
completionHandler();
}
// rdar://64549429
Quirks::StorageAccessResult Quirks::triggerOptionalStorageAccessQuirk(Element& element, const PlatformMouseEvent& platformEvent, const AtomString& eventType, int detail, Element* relatedTarget, bool isParentProcessAFullWebBrowser, IsSyntheticClick isSyntheticClick) const
{
if (!DeprecatedGlobalSettings::trackingPreventionEnabled() || !isParentProcessAFullWebBrowser)
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
if (!needsQuirks())
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
RegistrableDomain domain { m_document->url() };
static NeverDestroyed<HashSet<RegistrableDomain>> kinjaQuirks = [] {
HashSet<RegistrableDomain> set;
set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("jalopnik.com"_s));
set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("kotaku.com"_s));
set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("theroot.com"_s));
set.add(RegistrableDomain::uncheckedCreateFromRegistrableDomainString("theinventory.com"_s));
return set;
}();
static NeverDestroyed kinjaURL = URL { "https://kinja.com"_str };
static NeverDestroyed<RegistrableDomain> kinjaDomain { kinjaURL };
static NeverDestroyed<RegistrableDomain> youTubeDomain = RegistrableDomain::uncheckedCreateFromRegistrableDomainString("youtube.com"_s);
static NeverDestroyed<String> loginPopupWindowFeatureString = "toolbar=no,location=yes,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,copyhistory=no,width=599,height=600,top=420,left=980.5"_s;
static NeverDestroyed<UserScript> kinjaLoginUserScript { "function triggerLoginForm() { let elements = document.getElementsByClassName('js_header-userbutton'); if (elements && elements[0]) { elements[0].click(); clearInterval(interval); } } let interval = setInterval(triggerLoginForm, 200);"_s, URL(aboutBlankURL()), Vector<String>(), Vector<String>(), UserScriptInjectionTime::DocumentEnd, UserContentInjectedFrames::InjectInTopFrameOnly };
if (isAnyClick(eventType)) {
RefPtr document = m_document.get();
if (!document)
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
// Embedded YouTube case.
if (element.hasClass() && domain == youTubeDomain && !document->isTopDocument() && ResourceLoadObserver::shared().hasHadUserInteraction(youTubeDomain)) {
if (element.hasClassName("ytp-watch-later-icon"_s) || element.hasClassName("ytp-watch-later-icon"_s)) {
if (ResourceLoadObserver::shared().hasHadUserInteraction(youTubeDomain)) {
DocumentStorageAccess::requestStorageAccessForDocumentQuirk(*document, [](StorageAccessWasGranted) { });
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
}
}
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
}
// Kinja login case.
if (kinjaQuirks.get().contains(domain) && isKinjaLoginAvatarElement(element)) {
if (ResourceLoadObserver::shared().hasHadUserInteraction(kinjaDomain)) {
DocumentStorageAccess::requestStorageAccessForNonDocumentQuirk(*document, kinjaDomain.get().isolatedCopy(), [](StorageAccessWasGranted) { });
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
}
RefPtr window = document->window();
if (!window)
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
ExceptionOr<RefPtr<WindowProxy>> proxyOrException = window->open(*window, *window, kinjaURL->string(), emptyAtom(), loginPopupWindowFeatureString);
if (proxyOrException.hasException())
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
auto proxy = proxyOrException.releaseReturnValue();
auto* abstractFrame = proxy->frame();
if (RefPtr frame = dynamicDowncast<LocalFrame>(abstractFrame)) {
auto world = ScriptController::createWorld("kinjaComQuirkWorld"_s, ScriptController::WorldType::User);
frame->injectUserScriptImmediately(world.get(), kinjaLoginUserScript);
return Quirks::StorageAccessResult::ShouldCancelEvent;
}
}
// If the click is synthetic, the user has already gone through the storage access flow and we should not request again.
if (isStorageAccessQuirkDomainAndElement(document->url(), element) && isSyntheticClick == IsSyntheticClick::No) {
return requestStorageAccessAndHandleClick([element = WeakPtr { element }, platformEvent, eventType, detail, relatedTarget = WeakPtr { relatedTarget }] (ShouldDispatchClick shouldDispatchClick) mutable {
RefPtr protectedElement = element.get();
if (!protectedElement)
return;
if (shouldDispatchClick == ShouldDispatchClick::Yes)
protectedElement->dispatchMouseEvent(platformEvent, eventType, detail, RefPtr { relatedTarget.get() }.get(), IsSyntheticClick::Yes);
});
}
}
return Quirks::StorageAccessResult::ShouldNotCancelEvent;
}
// youtube.com rdar://66242343
bool Quirks::needsVP9FullRangeFlagQuirk() const
{
return needsQuirks() && m_quirksData.needsVP9FullRangeFlagQuirk;
}
// facebook.com: rdar://67273166
// forbes.com:
// reddit.com: rdar://80550715
// twitter.com: rdar://73369869
bool Quirks::requiresUserGestureToPauseInPictureInPicture() const
{
#if ENABLE(VIDEO_PRESENTATION_MODE)
// Facebook, X (twitter), and Reddit will naively pause a <video> element that has scrolled out of the viewport,
// regardless of whether that element is currently in PiP mode.
// We should remove the quirk once <rdar://problem/67273166>, <rdar://problem/73369869>, and <rdar://problem/80645747> have been fixed.
return needsQuirks() && m_quirksData.requiresUserGestureToPauseInPictureInPictureQuirk;
#else
return false;
#endif
}
// bbc.co.uk: rdar://126494734
bool Quirks::returnNullPictureInPictureElementDuringFullscreenChange() const
{
return needsQuirks() && m_quirksData.returnNullPictureInPictureElementDuringFullscreenChangeQuirk;
}
// twitter.com: rdar://73369869
bool Quirks::requiresUserGestureToLoadInPictureInPicture() const
{
#if ENABLE(VIDEO_PRESENTATION_MODE)
// X (Twitter) will remove the "src" attribute of a <video> element that has scrolled out of the viewport and
// load the <video> element with an empty "src" regardless of whether that element is currently in PiP mode.
// We should remove the quirk once <rdar://problem/73369869> has been fixed.
return needsQuirks() && m_quirksData.requiresUserGestureToLoadInPictureInPictureQuirk;
#else
return false;
#endif
}
// vimeo.com: rdar://problem/70788878
bool Quirks::blocksReturnToFullscreenFromPictureInPictureQuirk() const
{
#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO_PRESENTATION_MODE)
// Some sites (e.g., vimeo.com) do not set element's styles properly when a video
// returns to fullscreen from picture-in-picture. This quirk disables the "return to fullscreen
// from picture-in-picture" feature for those sites. We should remove the quirk once
// rdar://problem/73167931 has been fixed.
return needsQuirks() && m_quirksData.blocksReturnToFullscreenFromPictureInPictureQuirk;
#else
return false;
#endif
}
// vimeo.com: rdar://107592139
bool Quirks::blocksEnteringStandardFullscreenFromPictureInPictureQuirk() const
{
#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO_PRESENTATION_MODE)
// Vimeo enters fullscreen when starting playback from the inline play button while already in PIP.
// This behavior is revealing a bug in the fullscreen handling. See rdar://107592139.
return needsQuirks() && m_quirksData.blocksEnteringStandardFullscreenFromPictureInPictureQuirk;
#else
return false;
#endif
}
// espn.com: rdar://problem/73227900
// vimeo.com: rdar://problem/73227900
bool Quirks::shouldDisableEndFullscreenEventWhenEnteringPictureInPictureFromFullscreenQuirk() const
{
#if ENABLE(VIDEO_PRESENTATION_MODE)
// This quirk disables the "webkitendfullscreen" event when a video enters picture-in-picture
// from fullscreen for the sites which cannot handle the event properly in that case.
// We should remove once the quirks have been fixed.
// <rdar://90393832> vimeo.com
return needsQuirks() && m_quirksData.shouldDisableEndFullscreenEventWhenEnteringPictureInPictureFromFullscreenQuirk;
#else
return false;
#endif
}
// teams.live.com rdar://88678598
// teams.microsoft.com rdar://90434296
bool Quirks::shouldAllowNavigationToCustomProtocolWithoutUserGesture(StringView protocol, const SecurityOriginData& requesterOrigin)
{
return protocol == "msteams"_s && (requesterOrigin.host() == "teams.live.com"_s || requesterOrigin.host() == "teams.microsoft.com"_s);
}
#if PLATFORM(IOS) || PLATFORM(VISION)
// espn.com: rdar://problem/95651814
bool Quirks::allowLayeredFullscreenVideos() const
{
return needsQuirks() && m_quirksData.allowLayeredFullscreenVideos;
}
#endif
#if PLATFORM(VISION)
// x.com: rdar://132850672
// FIXME (rdar://124579556): Remove once 'x.com' adjusts video handling for visionOS.
bool Quirks::shouldDisableFullscreenVideoAspectRatioAdaptiveSizing() const
{
return needsQuirks() && m_quirksData.shouldDisableFullscreenVideoAspectRatioAdaptiveSizingQuirk;
}
#endif
// play.hbomax.com https://bugs.webkit.org/show_bug.cgi?id=244737
bool Quirks::shouldEnableFontLoadingAPIQuirk() const
{
if (!needsQuirks() || m_document->settings().downloadableBinaryFontTrustedTypes() == DownloadableBinaryFontTrustedTypes::Any)
return false;
return m_quirksData.shouldEnableFontLoadingAPIQuirk;
}
// hulu.com rdar://100199996
bool Quirks::needsVideoShouldMaintainAspectRatioQuirk() const
{
return needsQuirks() && m_quirksData.needsVideoShouldMaintainAspectRatioQuirk;
}
// Marcus: <rdar://101086391>.
// Pandora: <rdar://100243111>.
// Soundcloud: <rdar://102913500>.
bool Quirks::shouldExposeShowModalDialog() const
{
return needsQuirks() && m_quirksData.shouldExposeShowModalDialog;
}
// marcus.com rdar://102959860
bool Quirks::shouldNavigatorPluginsBeEmpty() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.shouldNavigatorPluginsBeEmpty;
#else
return false;
#endif
}
// Fix for the UNIQLO app (rdar://104519846).
bool Quirks::shouldDisableLazyIframeLoadingQuirk() const
{
return needsQuirks() && m_quirksData.shouldDisableLazyIframeLoadingQuirk;
}
// Breaks express checkout on victoriassecret.com (rdar://104818312).
bool Quirks::shouldDisableFetchMetadata() const
{
return needsQuirks() && m_quirksData.shouldDisableFetchMetadata;
}
bool Quirks::shouldBlockFetchWithNewlineAndLessThan() const
{
return needsQuirks() && m_quirksData.shouldBlockFetchWithNewlineAndLessThan;
}
// Push state file path restrictions break Mimeo Photo Plugin (rdar://112445672).
bool Quirks::shouldDisablePushStateFilePathRestrictions() const
{
return needsQuirks() && m_quirksData.shouldDisablePushStateFilePathRestrictions;
}
// ungap/@custom-elements polyfill (rdar://problem/111008826).
bool Quirks::needsConfigurableIndexedPropertiesQuirk() const
{
return needsQuirks() && m_needsConfigurableIndexedPropertiesQuirk;
}
// Canvas fingerprinting (rdar://107564162)
String Quirks::advancedPrivacyProtectionSubstituteDataURLForScriptWithFeatures(const String& lastDrawnText, int canvasWidth, int canvasHeight) const
{
if (!needsQuirks())
return { };
Ref document = *m_document;
if (!document->settings().canvasFingerprintingQuirkEnabled() || !document->noiseInjectionHashSalt())
return { };
if ("<@nv45. F1n63r,Pr1n71n6!"_s != lastDrawnText || canvasWidth != 280 || canvasHeight != 60)
return { };
if (!document->globalObject())
return { };
Ref vm = document->globalObject()->vm();
auto* callFrame = vm->topCallFrame;
if (!callFrame)
return { };
bool sourceMatchesExpectedLength = false;
JSC::StackVisitor::visit(callFrame, vm.get(), [&](auto& visitor) {
if (visitor->isImplementationVisibilityPrivate())
return IterationStatus::Continue;
auto* codeBlock = visitor->codeBlock();
if (!codeBlock)
return IterationStatus::Continue;
auto* scriptExecutable = codeBlock->ownerExecutable();
if (!scriptExecutable)
return IterationStatus::Continue;
RefPtr sourceProvider = scriptExecutable->source().provider();
if (!sourceProvider)
return IterationStatus::Continue;
auto sourceCodeLength = sourceProvider->source().length();
sourceMatchesExpectedLength = sourceCodeLength == 212053 || sourceCodeLength == 219192;
return IterationStatus::Done;
});
if (!sourceMatchesExpectedLength)
return { };
return "data:image/png;base64,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A"_s;
}
// DOFUS Touch app (rdar://112679186)
bool Quirks::needsResettingTransitionCancelsRunningTransitionQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.needsResettingTransitionCancelsRunningTransitionQuirk;
#else
return false;
#endif
}
// Microsoft office online generates data URLs with incorrect padding on Safari only (rdar://114573089).
bool Quirks::shouldDisableDataURLPaddingValidation() const
{
return needsQuirks() && m_quirksData.shouldDisableDataURLPaddingValidation;
}
bool Quirks::needsDisableDOMPasteAccessQuirk() const
{
if (!needsQuirks())
return false;
if (m_quirksData.needsDisableDOMPasteAccessQuirk)
return *m_quirksData.needsDisableDOMPasteAccessQuirk;
m_quirksData.needsDisableDOMPasteAccessQuirk = [&] {
RefPtr document = m_document.get();
if (!document)
return false;
auto* globalObject = document->globalObject();
if (!globalObject)
return false;
Ref vm = globalObject->vm();
JSC::JSLockHolder lock(vm);
auto tableauPrepProperty = JSC::Identifier::fromString(vm, "tableauPrep"_s);
return globalObject->hasProperty(globalObject, tableauPrepProperty);
}();
return *m_quirksData.needsDisableDOMPasteAccessQuirk;
}
// rdar://133423460
bool Quirks::shouldPreventOrientationMediaQueryFromEvaluatingToLandscape() const
{
return needsQuirks() && m_quirksData.shouldPreventOrientationMediaQueryFromEvaluatingToLandscapeQuirk;
}
// rdar://133423460
bool Quirks::shouldFlipScreenDimensions() const
{
#if ENABLE(FLIP_SCREEN_DIMENSIONS_QUIRKS)
return needsQuirks() && m_quirksData.shouldFlipScreenDimensionsQuirk;
#else
return false;
#endif
}
// This section is dedicated to UA override for iPad. iPads (but iPad Mini) are sending a desktop user agent
// to websites. In some cases, the website breaks in some ways, not expecting a touch interface for the website.
// Controls not active or too small, form factor, etc. In this case it is better to send the iPad Mini UA.
// FIXME: find the reference radars and/or bugs.webkit.org issues on why these were added in the first place.
// FIXME: There is no check currently on needsQuirks(), this needs to be fixed so it makes it easier
// to deactivate them for testing.
bool Quirks::needsIPadMiniUserAgent(const URL& url)
{
auto host = url.host();
// FIXME: Remove this quirk when <rdar://problem/61733101> is complete.
if (host == "roblox.com"_s || host.endsWith(".roblox.com"_s))
return true;
// FIXME: Remove this quirk when <rdar://122481999> is complete.
if (host == "spotify.com"_s || host.endsWith(".spotify.com"_s) || host.endsWith(".spotifycdn.com"_s))
return true;
// FIXME: Remove this quirk if seatguru decides to adjust their site. See https://webkit.org/b/276947
if (host == "seatguru.com"_s || host.endsWith(".seatguru.com"_s))
return true;
// FIXME: Remove this quirk once <rdar://113978106> is no longer happening.
if (host == "www.indiatimes.com"_s)
return true;
return false;
}
bool Quirks::needsIPhoneUserAgent(const URL& url)
{
#if PLATFORM(IOS_FAMILY)
if (url.host() == "shopee.sg"_s && url.path() == "/payment/account-linking/landing"_s)
return true;
#else
UNUSED_PARAM(url);
#endif
return false;
}
std::optional<String> Quirks::needsCustomUserAgentOverride(const URL& url, const String& applicationNameForUserAgent)
{
auto hostDomain = RegistrableDomain(url);
auto firefoxUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:139.0) Gecko/20100101 Firefox/139.0"_s;
// FIXME(rdar://83078414): Remove once 101edu.co and aktiv.com removes the unsupported message.
if (hostDomain.string() == "app.101edu.co")
return firefoxUserAgent;
if (hostDomain.string() == "app.aktiv.com")
return firefoxUserAgent;
#if PLATFORM(COCOA)
// FIXME(rdar://148759791): Remove this once TikTok removes the outdated error message.
if (hostDomain.string() == "tiktok.com"_s)
return makeStringByReplacingAll(standardUserAgentWithApplicationName(applicationNameForUserAgent), "like Gecko"_s, "like Gecko, like Chrome/136."_s);
#else
UNUSED_PARAM(url);
UNUSED_PARAM(applicationNameForUserAgent);
#endif
return { };
}
bool Quirks::needsDesktopUserAgent(const URL& url)
{
return needsDesktopUserAgentInternal(url);
}
bool Quirks::needsPartitionedCookies(const ResourceRequest& request)
{
if (request.isTopSite())
return false;
return request.url().protocolIsInHTTPFamily() && request.url().host().endsWith(".billpaysite.com"_s);
}
// premierleague.com: rdar://123721211
bool Quirks::shouldIgnorePlaysInlineRequirementQuirk() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.shouldIgnorePlaysInlineRequirementQuirk;
#else
return false;
#endif
}
bool Quirks::shouldUseEphemeralPartitionedStorageForDOMCookies(const URL& url) const
{
if (!needsQuirks())
return false;
auto firstPartyDomain = RegistrableDomain(protectedDocument()->firstPartyForCookies()).string();
auto domain = RegistrableDomain(url).string();
// rdar://113830141
if (firstPartyDomain == "cagreatamerica.com"_s && domain == "queue-it.net"_s)
return true;
return false;
}
// rdar://155649992
bool Quirks::shouldAllowDownloadsInSpiteOfCSP() const
{
if (!needsQuirks())
return false;
return isDomain("dropbox.com"_s);
}
// rdar://127398734
bool Quirks::needsLaxSameSiteCookieQuirk(const URL& requestURL) const
{
if (!needsQuirks())
return false;
auto url = protectedDocument()->url();
return url.protocolIs("https"_s) && url.host() == "login.microsoftonline.com"_s && requestURL.protocolIs("https"_s) && requestURL.host() == "www.bing.com"_s;
}
String Quirks::standardUserAgentWithApplicationNameIncludingCompatOverrides(const String& applicationName, const String& userAgentOSVersion, UserAgentType type)
{
return standardUserAgentWithApplicationNameIncludingCompatOverridesInternal(applicationName, userAgentOSVersion, type);
}
#if ENABLE(TEXT_AUTOSIZING)
// news.ycombinator.com: rdar://127246368
bool Quirks::shouldIgnoreTextAutoSizing() const
{
return needsQuirks() && m_quirksData.shouldIgnoreTextAutoSizingQuirk;
}
#endif
std::optional<TargetedElementSelectors> Quirks::defaultVisibilityAdjustmentSelectors(const URL& requestURL)
{
#if ENABLE(VISIBILITY_ADJUSTMENT_QUIRKS)
return defaultVisibilityAdjustmentSelectorsInternal(requestURL);
#else
UNUSED_PARAM(requestURL);
return { };
#endif
}
String Quirks::scriptToEvaluateBeforeRunningScriptFromURL(const URL& scriptURL)
{
#if PLATFORM(IOS_FAMILY)
static constexpr auto chromeUserAgentScript = "(function() { let userAgent = navigator.userAgent; Object.defineProperty(navigator, 'userAgent', { get: () => { return userAgent + ' Chrome/130.0.0.0 Android/15.0'; }, configurable: true }); })();"_s;
if (!needsQuirks())
return { };
if (!m_quirksData.needsScriptToEvaluateBeforeRunningScriptFromURLQuirk)
return { };
// player.anyclip.com rdar://138789765
if (m_quirksData.isThesaurus && scriptURL.lastPathComponent().endsWith("lre.js"_s)) [[unlikely]] {
if (scriptURL.host() == "player.anyclip.com"_s)
return chromeUserAgentScript;
}
if (m_quirksData.needsGoogleTranslateScrollingQuirk && !scriptURL.isEmpty()) [[unlikely]]
return chromeUserAgentScript;
#if ENABLE(DESKTOP_CONTENT_MODE_QUIRKS)
if (m_quirksData.isWebEx && scriptURL.lastPathComponent().startsWith("pushdownload."_s)) [[unlikely]]
return "Object.defineProperty(window, 'Touch', { get: () => undefined });"_s;
#endif
#else
UNUSED_PARAM(scriptURL);
#endif
return { };
}
// disneyplus: rdar://137613110
bool Quirks::shouldHideCoarsePointerCharacteristics() const
{
#if PLATFORM(IOS_FAMILY)
return needsQuirks() && m_quirksData.shouldHideCoarsePointerCharacteristicsQuirk;
#else
return false;
#endif
}
// hulu.com rdar://126096361
bool Quirks::implicitMuteWhenVolumeSetToZero() const
{
return needsQuirks() && m_quirksData.implicitMuteWhenVolumeSetToZero;
}
#if ENABLE(TOUCH_EVENTS)
bool Quirks::shouldOmitTouchEventDOMAttributesForDesktopWebsite(const URL& requestURL)
{
return requestURL.host() == "secure.chase.com"_s;
}
// soylent.*; rdar://113314067
bool Quirks::shouldDispatchPointerOutAfterHandlingSyntheticClick() const
{
return needsQuirks() && m_quirksData.shouldDispatchPointerOutAfterHandlingSyntheticClick;
}
#endif // ENABLE(TOUCH_EVENTS)
// max.com: rdar://138424489
bool Quirks::needsZeroMaxTouchPointsQuirk() const
{
#if ENABLE(DESKTOP_CONTENT_MODE_QUIRKS)
return needsQuirks() && m_quirksData.needsZeroMaxTouchPointsQuirk;
#else
return false;
#endif
}
// imdb.com: rdar://137991466
bool Quirks::needsChromeMediaControlsPseudoElement() const
{
return needsQuirks() && m_quirksData.needsChromeMediaControlsPseudoElementQuirk;
}
#if PLATFORM(IOS_FAMILY)
bool Quirks::shouldHideSoftTopScrollEdgeEffectDuringFocus(const Element& focusedElement) const
{
if (!needsQuirks() || !m_quirksData.shouldHideSoftTopScrollEdgeEffectDuringFocusQuirk)
return false;
return focusedElement.getIdAttribute().contains("crossword"_s);
}
// store.steampowered.com: rdar://142573562
bool Quirks::shouldTreatAddingMouseOutEventListenerAsContentChange() const
{
return needsQuirks() && m_quirksData.shouldTreatAddingMouseOutEventListenerAsContentChange;
}
// cbssports.com <rdar://139478801>.
// docs.google.com <rdar://59402637>.
bool Quirks::shouldSynthesizeTouchEventsAfterNonSyntheticClick(const Element& target) const
{
if (!needsQuirks())
return false;
if (!m_quirksData.shouldSynthesizeTouchEventsAfterNonSyntheticClickQuirk)
return false;
if (m_quirksData.isCBSSports)
return target.nodeName() == "AVIA-BUTTON"_s;
if (m_quirksData.isGoogleDocs) {
unsigned numberOfAncestorsToCheck = 3;
for (Ref ancestor : lineageOfType<HTMLElement>(target)) {
if (ancestor->hasClassName("docs-ml-promotion-action-container"_s))
return true;
if (!--numberOfAncestorsToCheck)
break;
}
}
return false;
}
static AccessibilityRole accessibilityRole(const Element& element)
{
return AccessibilityObject::ariaRoleToWebCoreRole(element.attributeWithoutSynchronization(HTMLNames::roleAttr));
}
// walmart.com: rdar://123734840
// live.outlook.com: rdar://152277211
bool Quirks::shouldIgnoreContentObservationForClick(const Node& targetNode) const
{
if (!needsQuirks())
return false;
if (!m_quirksData.mayNeedToIgnoreContentObservation)
return false;
if (m_quirksData.isGoogleMaps) {
for (Ref ancestor : lineageOfType<HTMLElement>(targetNode)) {
if (ancestor->attributeWithoutSynchronization(HTMLNames::aria_labelAttr) == "Suggestions"_s)
return true;
}
return false;
}
RefPtr target = dynamicDowncast<Element>(targetNode);
if (m_quirksData.isOutlook) {
if (target && target->getIdAttribute().startsWith("swatchColorPicker"_s))
return true;
}
if (m_quirksData.isWalmart) {
if (!target || accessibilityRole(*target) != AccessibilityRole::Button)
return false;
RefPtr parent = target->parentElementInComposedTree();
if (!parent || accessibilityRole(*parent) != AccessibilityRole::ListItem)
return false;
}
return true;
}
#endif // PLATFORM(IOS_FAMILY)
// outlook.live.com: rdar://136624720
bool Quirks::needsMozillaFileTypeForDataTransfer() const
{
return needsQuirks() && m_quirksData.needsMozillaFileTypeForDataTransferQuirk;
}
// bing.com rdar://126573838
bool Quirks::needsBingGestureEventQuirk(EventTarget* target) const
{
if (!needsQuirks())
return false;
if (!m_quirksData.needsBingGestureEventQuirk)
return false;
if (RefPtr element = dynamicDowncast<Element>(target)) {
static MainThreadNeverDestroyed<const AtomString> mapClass("atlas-map-canvas"_s);
return element->hasClassName(mapClass.get());
}
return false;
}
// spotify.com rdar://140707449
bool Quirks::shouldAvoidStartingSelectionOnMouseDownOverPointerCursor(const Node& target) const
{
if (!needsQuirks())
return false;
if (!m_quirksData.shouldAvoidStartingSelectionOnMouseDownOverPointerCursor)
return false;
if (CheckedPtr style = target.renderStyle()) {
if (style->cursorType() == CursorType::Pointer)
return true;
}
return false;
}
bool Quirks::shouldReuseLiveRangeForSelectionUpdate() const
{
if (!needsQuirks())
return false;
if (!m_quirksData.needsReuseLiveRangeForSelectionUpdateQuirk)
m_quirksData.needsReuseLiveRangeForSelectionUpdateQuirk = isDomain("scribd.com"_s);
return *m_quirksData.needsReuseLiveRangeForSelectionUpdateQuirk;
}
#if PLATFORM(IOS_FAMILY)
bool Quirks::needsPointerTouchCompatibility(const Element& target) const
{
if (!needsQuirks())
return false;
if (WTF::IOSApplication::isFeedly()) {
RefPtr pageContainer = [&target] -> const HTMLElement* {
for (Ref ancestor : lineageOfType<HTMLElement>(target)) {
if (ancestor->hasClassName("PageContainer"_s))
return ancestor.ptr();
}
return nullptr;
}();
if (pageContainer) {
if (RefPtr article = descendantsOfType<HTMLArticleElement>(*pageContainer).first())
return article->hasClassName("MobileFullEntry"_s);
}
} else if (WTF::IOSApplication::isAmazon()) {
for (Ref ancestor : lineageOfType<HTMLElement>(target)) {
if (ancestor->hasClassName("a-gesture-horizontal"_s))
return true;
}
}
return false;
}
#endif
// facebook.com rdar://141103350
bool Quirks::needsFacebookStoriesCreationFormQuirk(const Element& element, const RenderStyle& computedStyle) const
{
#if PLATFORM(IOS_FAMILY)
if (!needsQuirks())
return false;
if (!m_quirksData.isFacebook)
return false;
if (!topDocumentURL().path().startsWith("/stories/create"_s)) {
m_facebookStoriesCreationFormContainer = { };
return false;
}
Ref document = element.document();
RefPtr loader = document->loader();
if (!loader) [[unlikely]]
return false;
if (loader->metaViewportPolicy() != MetaViewportPolicy::Ignore)
return false;
RefPtr view = document->view();
if (!view) [[unlikely]]
return false;
float width = view->sizeForCSSDefaultViewportUnits().width();
if (width < 800 || width > 900)
return false;
if (m_facebookStoriesCreationFormContainer)
return m_facebookStoriesCreationFormContainer.get() == &element;
if (computedStyle.display() != DisplayType::None)
return false;
if (accessibilityRole(element) != AccessibilityRole::LandmarkNavigation)
return false;
if (!descendantsOfType<HTMLTextAreaElement>(element).first())
return false;
m_facebookStoriesCreationFormContainer = element;
return true;
#else
UNUSED_PARAM(element);
UNUSED_PARAM(computedStyle);
return false;
#endif
}
// hotels.com rdar://126631968
bool Quirks::needsHotelsAnimationQuirk(Element& element, const RenderStyle& style) const
{
if (!needsQuirks() || !m_quirksData.needsHotelsAnimationQuirk)
return false;
if (!style.hasAnimations())
return false;
auto matches = Ref { element }->matches(".uitk-menu-mounted .uitk-menu-container.uitk-menu-container-autoposition.uitk-menu-container-has-intersection-root-el"_s);
return !matches.hasException() && matches.returnValue();
}
bool Quirks::needsLimitedMatroskaSupport() const
{
#if ENABLE(MEDIA_RECORDER) && ENABLE(COCOA_WEBM_PLAYER)
return isDomain("zencastr.com"_s);
#else
return false;
#endif
}
bool Quirks::needsNowPlayingFullscreenSwapQuirk() const
{
return needsQuirks() && m_quirksData.needsNowPlayingFullscreenSwapQuirk;
}
bool Quirks::needsWebKitMediaTextTrackDisplayQuirk() const
{
return needsQuirks() && m_quirksData.needsWebKitMediaTextTrackDisplayQuirk;
}
// rdar://138806698
bool Quirks::shouldSupportHoverMediaQueries() const
{
#if ENABLE(DESKTOP_CONTENT_MODE_QUIRKS)
return needsQuirks() && m_quirksData.shouldSupportHoverMediaQueriesQuirk;
#else
return false;
#endif
}
bool Quirks::shouldRewriteMediaRangeRequestForURL(const URL& url) const
{
return needsQuirks() && m_quirksData.needsMediaRewriteRangeRequestQuirk && RegistrableDomain(url).string() == "bing.com"_s;
}
// rdar://106770785
bool Quirks::shouldPreventKeyframeEffectAcceleration(const KeyframeEffect& effect) const
{
if (!needsQuirks() || !m_quirksData.isEA)
return false;
auto target = Ref { effect }->targetStyleable();
return target && Ref { target->element }->localName() == "ea-network-nav"_s;
}
bool Quirks::shouldEnterNativeFullscreenWhenCallingElementRequestFullscreenQuirk() const
{
return needsQuirks() && m_quirksData.shouldEnterNativeFullscreenWhenCallingElementRequestFullscreen;
}
bool Quirks::shouldDelayReloadWhenRegisteringServiceWorker() const
{
return needsQuirks() && m_quirksData.shouldDelayReloadWhenRegisteringServiceWorker;
}
bool Quirks::shouldDisableDOMAudioSessionQuirk() const
{
return needsQuirks() && m_quirksData.shouldDisableDOMAudioSession;
}
bool Quirks::shouldExposeCredentialsContainerQuirk() const
{
#if ENABLE(WEB_AUTHN)
if (m_document && m_document->settings().webAuthenticationEnabled())
return true;
#endif
return needsQuirks() && m_quirksData.isGoogleAccounts;
}
URL Quirks::topDocumentURL() const
{
if (!m_topDocumentURLForTesting.isEmpty()) [[unlikely]]
return m_topDocumentURLForTesting;
return protectedDocument()->topURL();
}
void Quirks::setTopDocumentURLForTesting(URL&& url)
{
m_topDocumentURLForTesting = WTFMove(url);
determineRelevantQuirks();
}
// FIXME(rdar://141554467): The set of static functions below will be generated from a JSON file in a future patch. For now, we just move the logic
// for deciding if a particular quirk is needed to domain-specific functions below:
#if PLATFORM(IOS) || PLATFORM(VISION)
static void handle365ScoresQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "365scores.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// 365scores.com rdar://116491386
quirksData.shouldSilenceWindowResizeEventsDuringApplicationSnapshotting = true;
}
static void handleNYTimesQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "nytimes.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// nytimes.com: rdar://problem/5976384
quirksData.shouldSilenceWindowResizeEventsDuringApplicationSnapshotting = true;
}
#endif
#if PLATFORM(IOS_FAMILY)
static void handleASQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "as.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// as.com: rdar://121014613
quirksData.shouldDisableElementFullscreen = PAL::currentUserInterfaceIdiomIsSmallScreen();
}
static void handleATTQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "att.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// att.com rdar://55185021
quirksData.shouldUseLegacySelectPopoverDismissalBehaviorInDataActivationQuirk = true;
}
static void handleCBSSportsQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "cbssports.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isCBSSports = true;
// Remove this once rdar://139478801 is resolved.
quirksData.shouldSynthesizeTouchEventsAfterNonSyntheticClickQuirk = true;
}
static void handleSteamQuirks(QuirksData& quirksData, const URL& /* quirksURL */, const String& quirksDomainString, const URL& /* documentURL */)
{
if (quirksDomainString != "steampowered.com"_s)
return;
// Remove this once rdar://142573562 is resolved.
quirksData.shouldTreatAddingMouseOutEventListenerAsContentChange = true;
}
static void handleCNNQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "cnn.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// cnn.com rdar://119640248
quirksData.needsFullscreenObjectFitQuirk = true;
}
static void handleDigitalTrendsQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "digitaltrends.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// digitaltrends.com rdar://121014613
quirksData.shouldDisableElementFullscreen = PAL::currentUserInterfaceIdiomIsSmallScreen();
}
static void handleGizmodoQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "gizmodo.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// gizmodo.com rdar://102227302
quirksData.needsFullscreenDisplayNoneQuirk = true;
}
static void handleInstagramQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "instagram.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// instagram.com rdar://121014613
quirksData.shouldDisableElementFullscreen = true;
}
static void handleMailChimpQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "mailchimp.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// mailchimp.com rdar://47868965
quirksData.shouldDisablePointerEventsQuirk = true;
}
static void handleRalphLaurenQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "ralphlauren.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// ralphlauren.com rdar://55629493
quirksData.shouldIgnoreAriaForFastPathContentObservationCheckQuirk = true;
}
static void handleSkypeQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost != "web.skype.com"_s)
return;
// web.skype.com webkit.org/b/275941
quirksData.needsIPadSkypeOverflowScrollQuirk = true;
}
static void handleSlackQuirks(QuirksData& quirksData, const URL&, const String& quirksDomainString, const URL&)
{
if (quirksDomainString != "slack.com"_s)
return;
UNUSED_PARAM(quirksData);
#if ENABLE(META_VIEWPORT)
// slack.com: rdar://138614711
quirksData.shouldIgnoreViewportArgumentsToAvoidEnlargedViewQuirk = true;
#endif
}
static void handleWalmartQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "walmart.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// walmart.com: rdar://123734840
quirksData.mayNeedToIgnoreContentObservation = true;
quirksData.isWalmart = true;
}
static void handleYahooQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(documentURL);
UNUSED_PARAM(quirksDomainString);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost.startsWith("mail."_s)) {
// mail.yahoo.com rdar://63511613
quirksData.shouldAvoidPastingImagesAsWebContent = true;
}
}
static void handleScriptToEvaluateBeforeRunningScriptFromURLQuirk(QuirksData& quirksData, const URL& quirksURL, const String& topDomain, const URL& documentURL)
{
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
if (topDomain == "thesaurus.com"_s) {
quirksData.isThesaurus = true;
quirksData.needsScriptToEvaluateBeforeRunningScriptFromURLQuirk = true;
}
#if ENABLE(DESKTOP_CONTENT_MODE_QUIRKS)
if (topDomain == "webex.com"_s) {
quirksData.isWebEx = true;
quirksData.needsScriptToEvaluateBeforeRunningScriptFromURLQuirk = true;
}
#endif
}
#endif
#if PLATFORM(IOS_FAMILY) || PLATFORM(MAC)
static void handleICloudQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "icloud.com"_s)
return;
UNUSED_PARAM(documentURL);
#if PLATFORM(IOS_FAMILY)
// icloud.com rdar://131836301
quirksData.shouldSilenceWindowResizeEventsDuringApplicationSnapshotting = quirksURL.path().contains("mail"_s) || quirksURL.fragmentIdentifier().contains("mail"_s);
#endif
#if PLATFORM(MAC)
// icloud.com rdar://26013388
quirksData.isNeverRichlyEditableForTouchBarQuirk = quirksURL.path().contains("notes"_s) || quirksURL.fragmentIdentifier().contains("notes"_s);
#endif
}
#endif
#if PLATFORM(MAC)
static void handleCEACStateGovQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(documentURL);
UNUSED_PARAM(quirksDomainString);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost == "ceac.state.gov"_s || topDocumentHost.endsWith(".ceac.state.gov"_s)) {
// ceac.state.gov https://bugs.webkit.org/show_bug.cgi?id=193478
quirksData.needsFormControlToBeMouseFocusableQuirk = true;
}
}
static void handleTrixEditorQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "trix-editor.org"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// trix-editor.org rdar://28242210
quirksData.isNeverRichlyEditableForTouchBarQuirk = true;
}
static void handleWeatherQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "weather.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// weather.com rdar://139689157
quirksData.needsFormControlToBeMouseFocusableQuirk = true;
}
#endif
#if PLATFORM(IOS_FAMILY)
static void handleDisneyPlusQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "disneyplus.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// disneyplus rdar://137613110
quirksData.shouldHideCoarsePointerCharacteristicsQuirk = true;
#if ENABLE(DESKTOP_CONTENT_MODE_QUIRKS)
// disneyplus rdar://151715964
quirksData.needsZeroMaxTouchPointsQuirk = true;
#endif
}
static void handleGuardianQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
quirksData.shouldHideSoftTopScrollEdgeEffectDuringFocusQuirk = true;
}
#endif // PLATFORM(IOS_FAMILY)
#if ENABLE(DESKTOP_CONTENT_MODE_QUIRKS)
static void handleMaxQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "max.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// max.com: rdar://138424489
quirksData.needsZeroMaxTouchPointsQuirk = true;
// max.com: rdar://138806698
quirksData.shouldSupportHoverMediaQueriesQuirk = true;
}
#endif
#if ENABLE(MEDIA_STREAM)
static void handleBaiduQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost != "www.baidu.com"_s)
return;
// baidu.com rdar://56421276
quirksData.shouldEnableLegacyGetUserMediaQuirk = true;
}
static void handleCodepenQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost != "codepen.io"_s)
return;
quirksData.shouldEnableSpeakerSelectionPermissionsPolicyQuirk = true;
}
static void handleWarbyParkerQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "warbyparker.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// warbyparker.com rdar://72839707
quirksData.shouldEnableLegacyGetUserMediaQuirk = true;
}
static void handleACTestingQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "actesting.org"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// actesting.org rdar://124017544
quirksData.shouldEnableLegacyGetUserMediaQuirk = true;
}
#endif
static void handleDailyMailCoUkQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "dailymail.co.uk"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.shouldUnloadHeavyFrames = true;
}
#if ENABLE(TEXT_AUTOSIZING)
static void handleYCombinatorQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost != "news.ycombinator.com"_s)
return;
// news.ycombinator.com: rdar://127246368
quirksData.shouldIgnoreTextAutoSizingQuirk = true;
}
#endif
#if ENABLE(TOUCH_EVENTS)
static void handleSoylentQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
// soylent.*: rdar://113314067
quirksData.shouldDispatchPointerOutAfterHandlingSyntheticClick = true;
}
#endif
static void handleFacebookQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "facebook.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isFacebook = true;
// facebook.com rdar://100871402
quirksData.needsFacebookRemoveNotSupportedQuirk = true;
#if ENABLE(VIDEO_PRESENTATION_MODE)
// facebook.com rdar://67273166
quirksData.requiresUserGestureToPauseInPictureInPictureQuirk = true;
#endif
}
#if ENABLE(VIDEO_PRESENTATION_MODE)
static void handleForbesQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "forbes.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// forbes.com rdar://67273166
quirksData.requiresUserGestureToPauseInPictureInPictureQuirk = true;
}
static void handleRedditQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "reddit.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// reddit.com: rdar://80550715
quirksData.requiresUserGestureToPauseInPictureInPictureQuirk = true;
}
#endif
static void handleAmazonQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isAmazon = true;
// amazon.com rdar://49124529
quirksData.shouldDispatchedSimulatedMouseEventsAssumeDefaultPreventedQuirk = true;
#if PLATFORM(MAC)
// amazon.com rdar://128962002
quirksData.needsPrimeVideoUserSelectNoneQuirk = true;
#endif
}
static void handleBBCQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
if (quirksDomainString == "bbc.co.uk"_s) {
// bbc.co.uk rdar://126494734
quirksData.returnNullPictureInPictureElementDuringFullscreenChangeQuirk = true;
}
}
static void handleBankOfAmericaQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "bankofamerica.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isBankOfAmerica = true;
// Login issue on bankofamerica.com (rdar://104938789).
quirksData.maybeBypassBackForwardCache = true;
}
static void handleBingQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "bing.com"_s)
return;
UNUSED_PARAM(documentURL);
quirksData.isBing = true;
// bing.com rdar://133223599
quirksData.maybeBypassBackForwardCache = true;
// bing.com rdar://126573838
auto topDocumentHost = quirksURL.host();
quirksData.needsBingGestureEventQuirk = topDocumentHost == "www.bing.com"_s && startsWithLettersIgnoringASCIICase(quirksURL.path(), "/maps"_s);
quirksData.needsMediaRewriteRangeRequestQuirk = true;
}
static void handleBungalowQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "bungalow.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// bungalow.com rdar://61658940
quirksData.shouldBypassAsyncScriptDeferring = true;
}
static void handleDescriptQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "descript.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// descript.com rdar://156024693
quirksData.shouldDisableDOMAudioSession = true;
}
static void handleESPNQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "espn.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isESPN = true;
#if PLATFORM(IOS) || PLATFORM(VISION)
// espn.com rdar://problem/95651814
quirksData.allowLayeredFullscreenVideos = true;
#endif
#if ENABLE(VIDEO_PRESENTATION_MODE)
// espn.com rdar://problem/73227900
quirksData.shouldDisableEndFullscreenEventWhenEnteringPictureInPictureFromFullscreenQuirk = true;
#endif
}
static void handleEAQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "ea.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isEA = true;
}
static void handleGoogleQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
quirksData.isGoogleProperty = true;
auto topDocumentHost = quirksURL.host();
if (startsWithLettersIgnoringASCIICase(quirksURL.path(), "/maps/"_s)) {
quirksData.isGoogleMaps = true;
#if PLATFORM(IOS_FAMILY)
// maps.google.com rdar://152194074
quirksData.mayNeedToIgnoreContentObservation = true;
// maps.google.com rdar://67358928
quirksData.needsGoogleMapsScrollingQuirk = true;
#endif
// maps.google.com https://bugs.webkit.org/show_bug.cgi?id=214945
quirksData.shouldAvoidResizingWhenInputViewBoundsChangeQuirk = true;
}
quirksData.isGoogleDocs = topDocumentHost == "docs.google.com"_s;
quirksData.inputMethodUsesCorrectKeyEventOrder = quirksData.isGoogleDocs;
#if PLATFORM(IOS_FAMILY)
if (quirksData.isGoogleDocs) {
// docs.google.com rdar://49864669
quirksData.shouldSuppressAutocorrectionAndAutocapitalizationInHiddenEditableAreasQuirk = true;
// docs.google.com https://bugs.webkit.org/show_bug.cgi?id=199587
quirksData.needsDeferKeyDownAndKeyPressTimersUntilNextEditingCommandQuirk = startsWithLettersIgnoringASCIICase(quirksURL.path(), "/spreadsheets/"_s);
} else if (topDocumentHost == "mail.google.com"_s) {
// mail.google.com rdar://49403416
quirksData.needsGMailOverflowScrollQuirk =true;
} else if (topDocumentHost == "translate.google.com"_s) {
// translate.google.com rdar://106539018
quirksData.needsGoogleTranslateScrollingQuirk = true;
quirksData.needsScriptToEvaluateBeforeRunningScriptFromURLQuirk = true;
}
#endif
// docs.google.com rdar://59893415
quirksData.maybeBypassBackForwardCache = true;
#if ENABLE(TOUCH_EVENTS)
// sites.google.com rdar://58653069
quirksData.shouldPreventDispatchOfTouchEventQuirk = topDocumentHost == "sites.google.com"_s;
#endif
#if PLATFORM(MAC)
// docs.google.com https://bugs.webkit.org/show_bug.cgi?id=161984
quirksData.isTouchBarUpdateSuppressedForHiddenContentEditableQuirk = quirksData.isGoogleDocs;
#endif
#if ENABLE(MEDIA_STREAM)
quirksData.shouldEnableEnumerateDeviceQuirk = topDocumentHost == "meet.google.com"_s;
#endif
quirksData.isGoogleAccounts = topDocumentHost == "accounts.google.com"_s;
}
static void handleHBOMaxQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "hbomax.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost != "play.hbomax.com"_s)
return;
// play.hbomax.com https://bugs.webkit.org/show_bug.cgi?id=244737
quirksData.shouldEnableFontLoadingAPIQuirk = true;
}
static void handleHotelsQuirks(QuirksData& quirksData, const URL&, const String& quirksDomainString, const URL&)
{
// hotels.com rdar://126631968
quirksData.needsHotelsAnimationQuirk = quirksDomainString == "hotels.com"_s;
}
static void handleHuluQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "hulu.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// hulu.com rdar://100199996
quirksData.needsVideoShouldMaintainAspectRatioQuirk = true;
// hulu.com rdar://126096361
quirksData.implicitMuteWhenVolumeSetToZero = true;
}
static void handleIMDBQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "imdb.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// imdb.com: rdar://137991466
quirksData.needsChromeMediaControlsPseudoElementQuirk = true;
}
static void handleLiveQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "live.com"_s)
return;
UNUSED_PARAM(documentURL);
auto topDocumentHost = quirksURL.host();
quirksData.isOutlook = topDocumentHost == "outlook.live.com"_s;
// outlook.live.com: rdar://136624720
quirksData.needsMozillaFileTypeForDataTransferQuirk = quirksData.isOutlook;
#if PLATFORM(IOS_FAMILY)
// outlook.live.com: rdar://152277211
quirksData.mayNeedToIgnoreContentObservation = quirksData.isOutlook;
#endif
// live.com rdar://52116170
quirksData.shouldAvoidResizingWhenInputViewBoundsChangeQuirk = true;
// Microsoft office online generates data URLs with incorrect padding on Safari only (rdar://114573089).
quirksData.shouldDisableDataURLPaddingValidation = topDocumentHost.endsWith("officeapps.live.com"_s) || topDocumentHost.endsWith("onedrive.live.com"_s);
#if PLATFORM(MAC)
// onedrive.live.com rdar://26013388
quirksData.isNeverRichlyEditableForTouchBarQuirk = topDocumentHost == "onedrive.live.com"_s;
#endif
}
static void handleMarcusQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "marcus.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// Marcus: <rdar://101086391>.
quirksData.shouldExposeShowModalDialog = true;
#if PLATFORM(IOS_FAMILY)
// marcus.com rdar://102959860
quirksData.shouldNavigatorPluginsBeEmpty = true;
#endif
}
static void handleMediumQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "medium.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// medium.com rdar://50457837
quirksData.shouldDispatchSyntheticMouseEventsWhenModifyingSelectionQuirk = true;
}
static void handleMenloSecurityQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost != "safe.menlosecurity.com"_s)
return;
// safe.menlosecurity.com rdar://135114489
quirksData.shouldDisableWritingSuggestionsByDefaultQuirk = true;
}
static void handleNBAQuirks(QuirksData& quirksData, const URL&, const String& quirksDomainString, const URL&)
{
#if PLATFORM(IOS)
if (quirksDomainString != "nba.com"_s)
return;
quirksData.shouldEnterNativeFullscreenWhenCallingElementRequestFullscreen = PAL::currentUserInterfaceIdiomIsSmallScreen();
#else
UNUSED_PARAM(quirksData);
UNUSED_PARAM(quirksDomainString);
#endif
}
static void handleNHLQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "nhl.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.needsWebKitMediaTextTrackDisplayQuirk = true;
}
static void handleNetflixQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "netflix.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isNetflix = true;
// netflix.com https://bugs.webkit.org/show_bug.cgi?id=173030
quirksData.needsSeekingSupportDisabledQuirk = true;
#if PLATFORM(VISION)
quirksData.needsNowPlayingFullscreenSwapQuirk = true;
#endif
}
static void handlePandoraQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "pandora.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// Pandora: <rdar://100243111>.
quirksData.shouldExposeShowModalDialog = true;
}
static void handlePremierLeagueQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "premierleague.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// premierleague.com: rdar://123721211
quirksData.shouldIgnorePlaysInlineRequirementQuirk = true;
// premierleague.com: rdar://68938833
quirksData.shouldDispatchPlayPauseEventsOnResume = true;
// premierleague.com: rdar://136791737
quirksData.shouldAvoidStartingSelectionOnMouseDownOverPointerCursor = true;
}
static void handleSFUSDQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "sfusd.edu"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// sfusd.edu: rdar://116292738
quirksData.shouldBypassAsyncScriptDeferring = true;
}
static void handleSharePointQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "sharepoint.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// sharepoint.com rdar://52116170
quirksData.shouldAvoidResizingWhenInputViewBoundsChangeQuirk = true;
}
static void handleSoundCloudQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "soundcloud.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isSoundCloud = true;
// soundcloud.com rdar://52915981
quirksData.shouldDispatchedSimulatedMouseEventsAssumeDefaultPreventedQuirk = true;
// Soundcloud: rdar://102913500
quirksData.shouldExposeShowModalDialog = true;
}
static void handleSpotifyQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
UNUSED_PARAM(quirksDomainString);
UNUSED_PARAM(documentURL);
auto topDocumentHost = quirksURL.host();
if (topDocumentHost != "open.spotify.com"_s)
return;
// spotify.com rdar://138918575
quirksData.needsBodyScrollbarWidthNoneDisabledQuirk = true;
quirksData.shouldAvoidStartingSelectionOnMouseDownOverPointerCursor = true;
}
static void handleVictoriasSecretQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "victoriassecret.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// Breaks express checkout on victoriassecret.com (rdar://104818312).
quirksData.shouldDisableFetchMetadata = true;
}
static void handleTympanusQuirks(QuirksData& quirksData, const URL&, const String& quirksDomainString, const URL&)
{
if (quirksDomainString != "tympanus.net"_s)
return;
// https://tympanus.net/Tutorials/WebGPUFluid/ does not load (rdar://143839620).
quirksData.shouldBlockFetchWithNewlineAndLessThan = true;
}
static void handleVimeoQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "vimeo.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isVimeo = true;
// vimeo.com rdar://56996057
quirksData.maybeBypassBackForwardCache = true;
#if PLATFORM(IOS_FAMILY)
// vimeo.com rdar://55759025
quirksData.needsPreloadAutoQuirk = true;
// Vimeo.com has incorrect layout on iOS on certain videos with wider
// aspect ratios than the device's screen in landscape mode.
// (Ref: rdar://116531089)
quirksData.shouldDisableElementFullscreen = true;
#endif
#if ENABLE(VIDEO_PRESENTATION_MODE)
// vimeo.com: rdar://problem/73227900
quirksData.shouldDisableEndFullscreenEventWhenEnteringPictureInPictureFromFullscreenQuirk = true;
#endif
#if ENABLE(FULLSCREEN_API) && ENABLE(VIDEO_PRESENTATION_MODE)
// vimeo.com: rdar://107592139
quirksData.blocksEnteringStandardFullscreenFromPictureInPictureQuirk = true;
// vimeo.com: rdar://problem/70788878
quirksData.blocksReturnToFullscreenFromPictureInPictureQuirk = true;
#endif
}
static void handleWeeblyQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "weebly.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// weebly.com rdar://48003980
quirksData.shouldDispatchSyntheticMouseEventsWhenModifyingSelectionQuirk = true;
}
static void handleWikipediaQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "wikipedia.org"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
// wikipedia.org rdar://54856323
quirksData.shouldLayOutAtMinimumWindowWidthWhenIgnoringScalingConstraintsQuirk = true;
#if ENABLE(META_VIEWPORT)
// wikipedia.org https://webkit.org/b/247636
quirksData.shouldIgnoreViewportArgumentsToAvoidExcessiveZoomQuirk = true;
#endif
}
static void handleTwitterXQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "x.com"_s)
return;
UNUSED_PARAM(quirksData);
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
#if PLATFORM(VISION)
// x.com: rdar://132850672
quirksData.shouldDisableFullscreenVideoAspectRatioAdaptiveSizingQuirk = true;
#endif
#if PLATFORM(IOS) || PLATFORM(VISION)
// Twitter.com video embeds have controls that are too tiny and
// show page behind fullscreen.
// (Ref: rdar://121473410)
quirksData.shouldSilenceMediaQueryListChangeEvents = true;
// twitter.com: rdar://problem/58804852 and rdar://problem/61731801
quirksData.shouldSilenceWindowResizeEventsDuringApplicationSnapshotting = true;
#endif
#if ENABLE(VIDEO_PRESENTATION_MODE)
// twitter.com: rdar://73369869
quirksData.requiresUserGestureToLoadInPictureInPictureQuirk = true;
// twitter.com: rdar://73369869
quirksData.requiresUserGestureToPauseInPictureInPictureQuirk = true;
#endif
}
static void handleYouTubeQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "youtube.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isYouTube = true;
// youtube.com https://bugs.webkit.org/show_bug.cgi?id=195598
quirksData.hasBrokenEncryptedMediaAPISupportQuirk = true;
// youtube.com rdar://135886305
quirksData.needsScrollbarWidthThinDisabledQuirk = true;
// youtube.com rdar://66242343
quirksData.needsVP9FullRangeFlagQuirk = true;
#if PLATFORM(IOS_FAMILY)
// YouTube.com does not provide AirPlay controls in fullscreen
// (Ref: rdar://121471373)
quirksData.shouldDisableElementFullscreen = PAL::currentUserInterfaceIdiomIsSmallScreen();
auto topDocumentHost = quirksURL.host();
if (topDocumentHost == "www.youtube.com"_s) {
// www.youtube.com rdar://52361019
quirksData.needsYouTubeMouseOutQuirk = true;
// youtube.com rdar://49582231
quirksData.needsYouTubeOverflowScrollQuirk = true;
}
#endif
#if PLATFORM(IOS) || PLATFORM(VISION)
// youtube.com: rdar://110097836
quirksData.shouldSilenceResizeObservers = true;
#endif
}
static void handleZillowQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "zillow.com"_s)
return;
UNUSED_PARAM(documentURL);
// zillow.com rdar://53103732
auto topDocumentHost = quirksURL.host();
quirksData.shouldAvoidScrollingWhenFocusedContentIsVisibleQuirk = topDocumentHost == "www.zillow.com"_s;
#if PLATFORM(IOS) || PLATFORM(VISION)
// rdar://110097836
quirksData.shouldSilenceResizeObservers = true;
#endif
}
#if PLATFORM(MAC)
static void handleZomatoQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "zomato.com"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.needsZomatoEmailLoginLabelQuirk = true;
}
#endif
static void handleZoomQuirks(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL)
{
if (quirksDomainString != "zoom.us"_s)
return;
UNUSED_PARAM(quirksURL);
UNUSED_PARAM(documentURL);
quirksData.isZoom = true;
// zoom.com https://bugs.webkit.org/show_bug.cgi?id=223180
quirksData.shouldAutoplayWebAudioForArbitraryUserGestureQuirk = true;
#if ENABLE(MEDIA_STREAM)
// zoom.us rdar://118185086
quirksData.shouldDisableImageCaptureQuirk = true;
#endif
}
static void handleCapitalGroupQuirks(QuirksData& quirksData, const URL&, const String& quirksDomainString, const URL&)
{
if (quirksDomainString != "capitalgroup.com"_s)
return;
quirksData.shouldDelayReloadWhenRegisteringServiceWorker = true;
}
void Quirks::determineRelevantQuirks()
{
RELEASE_ASSERT(m_document);
m_quirksData = { };
#if PLATFORM(IOS_FAMILY)
static const bool shouldDisableLazyIframeLoadingQuirk = !linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::NoUNIQLOLazyIframeLoadingQuirk) && WTF::IOSApplication::isUNIQLOApp();
static const bool needsResettingTransitionCancelsRunningTransitionQuirk = !linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::ResettingTransitionCancelsRunningTransitionQuirk) && WTF::IOSApplication::isDOFUSTouch();
m_quirksData.shouldDisableLazyIframeLoadingQuirk = shouldDisableLazyIframeLoadingQuirk;
// DOFUS Touch app (rdar://112679186)
m_quirksData.needsResettingTransitionCancelsRunningTransitionQuirk = needsResettingTransitionCancelsRunningTransitionQuirk;
#endif
#if PLATFORM(MAC)
// Push state file path restrictions break Mimeo Photo Plugin (rdar://112445672).
m_quirksData.shouldDisablePushStateFilePathRestrictions = WTF::MacApplication::isMimeoPhotoProject();
#endif
auto quirksURL = topDocumentURL();
if (quirksURL.isEmpty())
return;
auto quirksDomainString = RegistrableDomain(quirksURL).string();
auto quirkDomainWithoutPSL = PublicSuffixStore::singleton().domainWithoutPublicSuffix(quirksDomainString);
using QuirkHandler = void (*)(QuirksData& quirksData, const URL& quirksURL, const String& quirksDomainString, const URL& documentURL);
using DispatchMap = HashMap<String, QuirkHandler>;
static NeverDestroyed<DispatchMap> dispatchMap = DispatchMap({
#if PLATFORM(IOS) || PLATFORM(VISION)
{ "365scores"_s, &handle365ScoresQuirks },
#endif
#if ENABLE(MEDIA_STREAM)
{ "actesting"_s, &handleACTestingQuirks },
#endif
{ "amazon"_s, &handleAmazonQuirks },
#if PLATFORM(IOS_FAMILY)
{ "as"_s, &handleASQuirks },
{ "att"_s, &handleATTQuirks },
#endif
{ "bbc"_s, &handleBBCQuirks },
#if ENABLE(MEDIA_STREAM)
{ "baidu"_s, &handleBaiduQuirks },
{ "codepen"_s, &handleCodepenQuirks },
#endif
{ "bankofamerica"_s, &handleBankOfAmericaQuirks },
{ "bing"_s, &handleBingQuirks },
{ "bungalow"_s, &handleBungalowQuirks },
{ "capitalgroup"_s, &handleCapitalGroupQuirks },
#if PLATFORM(IOS_FAMILY)
{ "cbssports"_s, &handleCBSSportsQuirks },
{ "cnn"_s, &handleCNNQuirks },
{ "digitaltrends"_s, &handleDigitalTrendsQuirks },
{ "steampowered"_s, &handleSteamQuirks },
#endif
{ "descript"_s, &handleDescriptQuirks },
#if PLATFORM(IOS_FAMILY)
{ "disneyplus"_s, &handleDisneyPlusQuirks },
#endif
{ "ea"_s, &handleEAQuirks },
{ "espn"_s, &handleESPNQuirks },
{ "facebook"_s, &handleFacebookQuirks },
#if ENABLE(VIDEO_PRESENTATION_MODE)
{ "forbes"_s, &handleForbesQuirks },
#endif
#if PLATFORM(IOS_FAMILY)
{ "gizmodo"_s, &handleGizmodoQuirks },
#endif
{ "google"_s, &handleGoogleQuirks },
{ "hbomax"_s, &handleHBOMaxQuirks },
{ "hotels"_s, &handleHotelsQuirks },
{ "hulu"_s, &handleHuluQuirks },
#if PLATFORM(IOS_FAMILY) || PLATFORM(MAC)
{ "icloud"_s, &handleICloudQuirks },
#endif
{ "imdb"_s, &handleIMDBQuirks },
#if PLATFORM(IOS_FAMILY)
{ "instagram"_s, &handleInstagramQuirks },
#endif
{ "live"_s, &handleLiveQuirks },
#if PLATFORM(IOS_FAMILY)
{ "mailchimp"_s, &handleMailChimpQuirks },
#endif
{ "marcus"_s, &handleMarcusQuirks },
#if ENABLE(DESKTOP_CONTENT_MODE_QUIRKS)
{ "max"_s, &handleMaxQuirks },
#endif
{ "medium"_s, &handleMediumQuirks },
{ "menlosecurity"_s, &handleMenloSecurityQuirks },
{ "netflix"_s, &handleNetflixQuirks },
{ "nba"_s, &handleNBAQuirks },
{ "nhl"_s, &handleNHLQuirks },
#if PLATFORM(IOS) || PLATFORM(VISION)
{ "nytimes"_s, &handleNYTimesQuirks },
#endif
{ "pandora"_s, &handlePandoraQuirks },
{ "premierleague"_s, &handlePremierLeagueQuirks },
#if PLATFORM(IOS_FAMILY)
{ "ralphlauren"_s, &handleRalphLaurenQuirks },
#endif
#if ENABLE(VIDEO_PRESENTATION_MODE)
{ "reddit"_s, & handleRedditQuirks },
#endif
{ "sfusd"_s, &handleSFUSDQuirks },
#if PLATFORM(IOS_FAMILY)
{ "slack"_s, &handleSlackQuirks },
#endif
{ "sharepoint"_s, &handleSharePointQuirks },
#if PLATFORM(IOS_FAMILY)
{ "skype"_s, &handleSkypeQuirks },
#endif
{ "soundcloud"_s, &handleSoundCloudQuirks },
#if ENABLE(TOUCH_EVENTS)
{ "soylent"_s, &handleSoylentQuirks },
#endif
{ "spotify"_s, &handleSpotifyQuirks },
#if PLATFORM(MAC)
{ "state"_s, &handleCEACStateGovQuirks },
#endif
#if PLATFORM(IOS_FAMILY)
{ "theguardian"_s, &handleGuardianQuirks },
{ "thesaurus"_s, &handleScriptToEvaluateBeforeRunningScriptFromURLQuirk },
#endif
#if PLATFORM(MAC)
{ "trix-editor"_s, &handleTrixEditorQuirks },
#endif
{ "tympanus"_s, &handleTympanusQuirks },
{ "victoriassecret"_s, &handleVictoriasSecretQuirks },
{ "vimeo"_s, &handleVimeoQuirks },
#if PLATFORM(IOS_FAMILY)
{ "walmart"_s, &handleWalmartQuirks },
#endif
{ "wikipedia"_s, &handleWikipediaQuirks },
#if ENABLE(MEDIA_STREAM)
{ "warbyparker"_s, &handleWarbyParkerQuirks },
#endif
#if PLATFORM(MAC)
{ "weather"_s, &handleWeatherQuirks },
#endif
#if PLATFORM(IOS_FAMILY) && ENABLE(DESKTOP_CONTENT_MODE_QUIRKS)
{ "webex"_s, &handleScriptToEvaluateBeforeRunningScriptFromURLQuirk },
#endif
{ "weebly"_s, &handleWeeblyQuirks },
{ "x"_s, &handleTwitterXQuirks },
#if PLATFORM(IOS_FAMILY)
{ "yahoo"_s, &handleYahooQuirks },
#endif
#if ENABLE(TEXT_AUTOSIZING)
{ "ycombinator"_s, &handleYCombinatorQuirks },
#endif
{ "youtube"_s, &handleYouTubeQuirks },
{ "zillow"_s, &handleZillowQuirks },
#if PLATFORM(MAC)
{ "zomato"_s, &handleZomatoQuirks },
#endif
{ "zoom"_s, &handleZoomQuirks },
{ "dailymail"_s, &handleDailyMailCoUkQuirks }
});
auto findResult = dispatchMap->find(quirkDomainWithoutPSL);
if (findResult != dispatchMap->end())
(findResult->value)(m_quirksData, quirksURL, quirksDomainString, m_document->url());
// Note: `needsDisableDOMPasteAccessQuirk` needs a live document to assess
// Note: `shouldDisableElementFullscreen` needs a live document for embedded sites
// FIXME: The below quirks should be handled more efficiently in a
#if ENABLE(FLIP_SCREEN_DIMENSIONS_QUIRKS)
// rdar://133423460
m_quirksData.shouldFlipScreenDimensionsQuirk = shouldFlipScreenDimensionsInternal(quirksURL);
#endif
// rdar://133423460
m_quirksData.shouldPreventOrientationMediaQueryFromEvaluatingToLandscapeQuirk = shouldPreventOrientationMediaQueryFromEvaluatingToLandscapeInternal(quirksURL);
}
}