Unreviewed restoration of non-unified build.
[WebKit-https.git] / Source / WebCore / page / Quirks.cpp
1 /*
2  * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "Quirks.h"
28
29 #include "Document.h"
30 #include "DocumentLoader.h"
31 #include "HTMLMetaElement.h"
32 #include "HTMLObjectElement.h"
33 #include "LayoutUnit.h"
34 #include "Settings.h"
35
36 namespace WebCore {
37
38 static inline OptionSet<AutoplayQuirk> allowedAutoplayQuirks(Document& document)
39 {
40     auto* loader = document.loader();
41     if (!loader)
42         return { };
43
44     return loader->allowedAutoplayQuirks();
45 }
46
47 Quirks::Quirks(Document& document)
48     : m_document(makeWeakPtr(document))
49 {
50 }
51
52 Quirks::~Quirks() = default;
53
54 inline bool Quirks::needsQuirks() const
55 {
56     return m_document && m_document->settings().needsSiteSpecificQuirks();
57 }
58
59 bool Quirks::shouldIgnoreShrinkToFitContent() const
60 {
61 #if PLATFORM(IOS_FAMILY)
62     if (!needsQuirks())
63         return false;
64
65     auto host = m_document->topDocument().url().host();
66     if (equalLettersIgnoringASCIICase(host, "outlook.live.com"))
67         return true;
68 #endif
69     return false;
70 }
71
72 Optional<LayoutUnit> Quirks::overriddenViewLayoutWidth(LayoutUnit currentViewLayoutWidth) const
73 {
74 #if PLATFORM(IOS_FAMILY)
75     if (!needsQuirks())
76         return { };
77
78     auto host = m_document->topDocument().url().host();
79     if (equalLettersIgnoringASCIICase(host, "outlook.live.com")) {
80         if (currentViewLayoutWidth <= 989 || currentViewLayoutWidth >= 1132)
81             return { };
82         return { 989 };
83     }
84 #else
85     UNUSED_PARAM(currentViewLayoutWidth);
86 #endif
87     return { };
88 }
89
90 bool Quirks::shouldIgnoreInvalidSignal() const
91 {
92     if (!needsQuirks())
93         return false;
94
95     auto host = m_document->topDocument().url().host();
96     return equalLettersIgnoringASCIICase(host, "www.thrivepatientportal.com");
97 }
98
99 bool Quirks::needsFormControlToBeMouseFocusable() const
100 {
101 #if PLATFORM(MAC)
102     if (!needsQuirks())
103         return false;
104
105     auto host = m_document->url().host();
106     return equalLettersIgnoringASCIICase(host, "ceac.state.gov") || host.endsWithIgnoringASCIICase(".ceac.state.gov");
107 #else
108     return false;
109 #endif
110 }
111
112 bool Quirks::needsAutoplayPlayPauseEvents() const
113 {
114     if (!needsQuirks())
115         return false;
116
117     if (allowedAutoplayQuirks(*m_document).contains(AutoplayQuirk::SynthesizedPauseEvents))
118         return true;
119
120     return allowedAutoplayQuirks(m_document->topDocument()).contains(AutoplayQuirk::SynthesizedPauseEvents);
121 }
122
123 bool Quirks::needsSeekingSupportDisabled() const
124 {
125     if (!needsQuirks())
126         return false;
127
128     auto host = m_document->topDocument().url().host();
129     return equalLettersIgnoringASCIICase(host, "netflix.com") || host.endsWithIgnoringASCIICase(".netflix.com");
130 }
131
132 bool Quirks::needsPerDocumentAutoplayBehavior() const
133 {
134 #if PLATFORM(MAC)
135     ASSERT(m_document == &m_document->topDocument());
136     return needsQuirks() && allowedAutoplayQuirks(*m_document).contains(AutoplayQuirk::PerDocumentAutoplayBehavior);
137 #else
138     return false;
139 #endif
140 }
141
142 bool Quirks::shouldAutoplayForArbitraryUserGesture() const
143 {
144 #if PLATFORM(MAC)
145     return needsQuirks() && allowedAutoplayQuirks(*m_document).contains(AutoplayQuirk::ArbitraryUserGestures);
146 #else
147     return false;
148 #endif
149 }
150
151 bool Quirks::hasBrokenEncryptedMediaAPISupportQuirk() const
152 {
153     if (!needsQuirks())
154         return false;
155
156     if (m_hasBrokenEncryptedMediaAPISupportQuirk)
157         return m_hasBrokenEncryptedMediaAPISupportQuirk.value();
158
159     auto domain = m_document->securityOrigin().domain().convertToASCIILowercase();
160
161     m_hasBrokenEncryptedMediaAPISupportQuirk = domain == "starz.com"
162         || domain.endsWith(".starz.com")
163         || domain == "youtube.com"
164         || domain.endsWith(".youtube.com")
165         || domain == "hulu.com"
166         || domain.endsWith("hulu.com");
167
168     return m_hasBrokenEncryptedMediaAPISupportQuirk.value();
169 }
170
171 bool Quirks::hasWebSQLSupportQuirk() const
172 {
173     if (!needsQuirks())
174         return false;
175     
176     if (m_hasWebSQLSupportQuirk)
177         return m_hasWebSQLSupportQuirk.value();
178     
179     auto domain = m_document->securityOrigin().domain().convertToASCIILowercase();
180     
181     m_hasWebSQLSupportQuirk = domain == "bostonglobe.com"
182         || domain.endsWith(".bostonglobe.com")
183         || domain == "latimes.com"
184         || domain.endsWith(".latimes.com");
185     
186     return m_hasWebSQLSupportQuirk.value();
187 }
188
189 bool Quirks::isTouchBarUpdateSupressedForHiddenContentEditable() const
190 {
191 #if PLATFORM(MAC)
192     if (!needsQuirks())
193         return false;
194
195     auto host = m_document->topDocument().url().host();
196     return equalLettersIgnoringASCIICase(host, "docs.google.com");
197 #else
198     return false;
199 #endif
200 }
201
202 bool Quirks::isNeverRichlyEditableForTouchBar() const
203 {
204 #if PLATFORM(MAC)
205     if (!needsQuirks())
206         return false;
207
208     auto& url = m_document->topDocument().url();
209     auto host = url.host();
210
211     if (equalLettersIgnoringASCIICase(host, "twitter.com"))
212         return true;
213
214     if (equalLettersIgnoringASCIICase(host, "onedrive.live.com"))
215         return true;
216
217     if (equalLettersIgnoringASCIICase(host, "trix-editor.org"))
218         return true;
219
220     if (equalLettersIgnoringASCIICase(host, "www.icloud.com")) {
221         auto path = url.path();
222         if (path.contains("notes") || url.fragmentIdentifier().contains("notes"))
223             return true;
224     }
225 #endif
226
227     return false;
228 }
229
230 #if USE(APPLE_INTERNAL_SDK)
231 #import <WebKitAdditions/QuirksAdditions.cpp>
232 #else
233
234 static bool shouldSuppressAutocorrectionAndAutocaptializationInHiddenEditableAreasForHost(const StringView&)
235 {
236     return false;
237 }
238
239 static bool shouldEmulateUndoRedoInHiddenEditableAreasForHost(const StringView&)
240 {
241     return false;
242 }
243
244 #endif
245
246 bool Quirks::shouldDispatchSyntheticMouseEventsWhenModifyingSelection() const
247 {
248     if (m_document->settings().shouldDispatchSyntheticMouseEventsWhenModifyingSelection())
249         return true;
250
251     if (!needsQuirks())
252         return false;
253
254     auto host = m_document->topDocument().url().host();
255     if (equalLettersIgnoringASCIICase(host, "medium.com") || host.endsWithIgnoringASCIICase(".medium.com"))
256         return true;
257
258     if (equalLettersIgnoringASCIICase(host, "weebly.com") || host.endsWithIgnoringASCIICase(".weebly.com"))
259         return true;
260
261     return false;
262 }
263
264 bool Quirks::shouldEmulateUndoRedoInHiddenEditableAreas() const
265 {
266     if (!needsQuirks())
267         return false;
268
269     return shouldEmulateUndoRedoInHiddenEditableAreasForHost(m_document->topDocument().url().host());
270 }
271
272 bool Quirks::shouldSuppressAutocorrectionAndAutocaptializationInHiddenEditableAreas() const
273 {
274     if (!needsQuirks())
275         return false;
276
277     return shouldSuppressAutocorrectionAndAutocaptializationInHiddenEditableAreasForHost(m_document->topDocument().url().host());
278 }
279
280 bool Quirks::shouldDispatchSimulatedMouseEvents() const
281 {
282 #if PLATFORM(IOS_FAMILY)
283     if (!needsQuirks())
284         return false;
285
286     auto* loader = m_document->loader();
287     if (!loader || loader->simulatedMouseEventsDispatchPolicy() != SimulatedMouseEventsDispatchPolicy::Allow)
288         return false;
289
290     auto& url = m_document->topDocument().url();
291     auto host = url.host();
292
293     if (equalLettersIgnoringASCIICase(host, "amazon.com") || host.endsWithIgnoringASCIICase(".amazon.com"))
294         return true;
295     if (equalLettersIgnoringASCIICase(host, "wix.com") || host.endsWithIgnoringASCIICase(".wix.com"))
296         return true;
297     if ((equalLettersIgnoringASCIICase(host, "desmos.com") || host.endsWithIgnoringASCIICase(".desmos.com")) && url.path().startsWithIgnoringASCIICase("/calculator/"))
298         return true;
299     if (equalLettersIgnoringASCIICase(host, "figma.com") || host.endsWithIgnoringASCIICase(".figma.com"))
300         return true;
301     if (equalLettersIgnoringASCIICase(host, "trello.com") || host.endsWithIgnoringASCIICase(".trello.com"))
302         return true;
303     if (equalLettersIgnoringASCIICase(host, "airtable.com") || host.endsWithIgnoringASCIICase(".airtable.com"))
304         return true;
305     if (equalLettersIgnoringASCIICase(host, "msn.com") || host.endsWithIgnoringASCIICase(".msn.com"))
306         return true;
307     if (equalLettersIgnoringASCIICase(host, "flipkart.com") || host.endsWithIgnoringASCIICase(".flipkart.com"))
308         return true;
309     if (equalLettersIgnoringASCIICase(host, "www.google.com") && url.path().startsWithIgnoringASCIICase("/maps/"))
310         return true;
311     if (equalLettersIgnoringASCIICase(host, "trailers.apple.com"))
312         return true;
313 #endif
314     return false;
315 }
316
317 bool Quirks::shouldDisablePointerEventsQuirk() const
318 {
319 #if PLATFORM(IOS_FAMILY)
320     if (!needsQuirks())
321         return false;
322
323     auto& url = m_document->topDocument().url();
324     auto host = url.host();
325     if (equalLettersIgnoringASCIICase(host, "mailchimp.com") || host.endsWithIgnoringASCIICase(".mailchimp.com"))
326         return true;
327 #endif
328     return false;
329 }
330
331 // FIXME(<rdar://problem/50394969>): Remove after desmos.com adopts inputmode="none".
332 bool Quirks::needsInputModeNoneImplicitly(const HTMLElement& element) const
333 {
334 #if PLATFORM(IOS_FAMILY)
335     if (!needsQuirks())
336         return false;
337
338     if (!element.hasTagName(HTMLNames::textareaTag))
339         return false;
340
341     auto& url = m_document->url();
342     auto host = url.host();
343     if (!host.endsWithIgnoringASCIICase(".desmos.com"))
344         return false;
345
346     return element.parentElement() && element.parentElement()->classNames().contains("dcg-mq-textarea");
347 #else
348     UNUSED_PARAM(element);
349     return false;
350 #endif
351 }
352
353 // FIXME: Remove after the site is fixed, <rdar://problem/50374200>
354 bool Quirks::needsGMailOverflowScrollQuirk() const
355 {
356 #if PLATFORM(IOS_FAMILY)
357     if (!needsQuirks())
358         return false;
359
360     if (!m_needsGMailOverflowScrollQuirk)
361         m_needsGMailOverflowScrollQuirk = equalLettersIgnoringASCIICase(m_document->url().host(), "mail.google.com");
362
363     return *m_needsGMailOverflowScrollQuirk;
364 #else
365     return false;
366 #endif
367 }
368
369 // FIXME: Remove after the site is fixed, <rdar://problem/50374311>
370 bool Quirks::needsYouTubeOverflowScrollQuirk() const
371 {
372 #if PLATFORM(IOS_FAMILY)
373     if (!needsQuirks())
374         return false;
375
376     if (!m_needsYouTubeOverflowScrollQuirk)
377         m_needsYouTubeOverflowScrollQuirk = equalLettersIgnoringASCIICase(m_document->url().host(), "www.youtube.com");
378
379     return *m_needsYouTubeOverflowScrollQuirk;
380 #else
381     return false;
382 #endif
383 }
384
385
386 }