[iOS] Implement idempotent mode for text autosizing
[WebKit-https.git] / Source / WebCore / page / SettingsBase.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009, 2011, 2012 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "SettingsBase.h"
28
29 #include "AudioSession.h"
30 #include "BackForwardController.h"
31 #include "CachedResourceLoader.h"
32 #include "CookieStorage.h"
33 #include "DOMTimer.h"
34 #include "Database.h"
35 #include "Document.h"
36 #include "FontCascade.h"
37 #include "FontGenericFamilies.h"
38 #include "Frame.h"
39 #include "FrameTree.h"
40 #include "FrameView.h"
41 #include "HistoryItem.h"
42 #include "Page.h"
43 #include "PageCache.h"
44 #include "RenderWidget.h"
45 #include "RuntimeApplicationChecks.h"
46 #include "Settings.h"
47 #include "StorageMap.h"
48 #include <limits>
49 #include <wtf/StdLibExtras.h>
50
51 #if ENABLE(MEDIA_STREAM)
52 #include "MockRealtimeMediaSourceCenter.h"
53 #endif
54
55 namespace WebCore {
56
57 static void invalidateAfterGenericFamilyChange(Page* page)
58 {
59     invalidateFontCascadeCache();
60     if (page)
61         page->setNeedsRecalcStyleInAllFrames();
62 }
63
64 // This amount of time must have elapsed before we will even consider scheduling a layout without a delay.
65 // FIXME: For faster machines this value can really be lowered to 200. 250 is adequate, but a little high
66 // for dual G5s. :)
67 static const Seconds layoutScheduleThreshold = 250_ms;
68
69 SettingsBase::SettingsBase(Page* page)
70     : m_page(nullptr)
71     , m_fontGenericFamilies(std::make_unique<FontGenericFamilies>())
72     , m_layoutInterval(layoutScheduleThreshold)
73     , m_minimumDOMTimerInterval(DOMTimer::defaultMinimumInterval())
74     , m_setImageLoadingSettingsTimer(*this, &SettingsBase::imageLoadingSettingsTimerFired)
75 {
76     // A Frame may not have been created yet, so we initialize the AtomicString
77     // hash before trying to use it.
78     AtomicString::init();
79     initializeDefaultFontFamilies();
80     m_page = page; // Page is not yet fully initialized when constructing Settings, so keeping m_page null over initializeDefaultFontFamilies() call.
81 }
82
83 SettingsBase::~SettingsBase() = default;
84
85 float SettingsBase::defaultMinimumZoomFontSize()
86 {
87 #if PLATFORM(WATCHOS)
88     return 30;
89 #else
90     return 15;
91 #endif
92 }
93
94 #if !PLATFORM(IOS_FAMILY)
95 bool SettingsBase::defaultTextAutosizingEnabled()
96 {
97     return false;
98 }
99
100 bool SettingsBase::defaultTextAutosizingUsesIdempotentMode()
101 {
102     return false;
103 }
104 #endif
105
106 bool SettingsBase::defaultDownloadableBinaryFontsEnabled()
107 {
108 #if PLATFORM(WATCHOS)
109     return false;
110 #else
111     return true;
112 #endif
113 }
114
115 bool SettingsBase::defaultContentChangeObserverEnabled()
116 {
117 #if PLATFORM(IOS_FAMILY) && !PLATFORM(IOSMAC)
118     return true;
119 #else
120     return false;
121 #endif
122 }
123
124 #if !PLATFORM(COCOA)
125 const String& SettingsBase::defaultMediaContentTypesRequiringHardwareSupport()
126 {
127     return emptyString();
128 }
129 #endif
130
131 #if !PLATFORM(COCOA)
132 void SettingsBase::initializeDefaultFontFamilies()
133 {
134     // Other platforms can set up fonts from a client, but on Mac, we want it in WebCore to share code between WebKit1 and WebKit2.
135 }
136 #endif
137
138 #if ENABLE(MEDIA_SOURCE) && !PLATFORM(COCOA)
139 bool SettingsBase::platformDefaultMediaSourceEnabled()
140 {
141     return true;
142 }
143 #endif
144
145 const AtomicString& SettingsBase::standardFontFamily(UScriptCode script) const
146 {
147     return m_fontGenericFamilies->standardFontFamily(script);
148 }
149
150 void SettingsBase::setStandardFontFamily(const AtomicString& family, UScriptCode script)
151 {
152     bool changes = m_fontGenericFamilies->setStandardFontFamily(family, script);
153     if (changes)
154         invalidateAfterGenericFamilyChange(m_page);
155 }
156
157 const AtomicString& SettingsBase::fixedFontFamily(UScriptCode script) const
158 {
159     return m_fontGenericFamilies->fixedFontFamily(script);
160 }
161
162 void SettingsBase::setFixedFontFamily(const AtomicString& family, UScriptCode script)
163 {
164     bool changes = m_fontGenericFamilies->setFixedFontFamily(family, script);
165     if (changes)
166         invalidateAfterGenericFamilyChange(m_page);
167 }
168
169 const AtomicString& SettingsBase::serifFontFamily(UScriptCode script) const
170 {
171     return m_fontGenericFamilies->serifFontFamily(script);
172 }
173
174 void SettingsBase::setSerifFontFamily(const AtomicString& family, UScriptCode script)
175 {
176     bool changes = m_fontGenericFamilies->setSerifFontFamily(family, script);
177     if (changes)
178         invalidateAfterGenericFamilyChange(m_page);
179 }
180
181 const AtomicString& SettingsBase::sansSerifFontFamily(UScriptCode script) const
182 {
183     return m_fontGenericFamilies->sansSerifFontFamily(script);
184 }
185
186 void SettingsBase::setSansSerifFontFamily(const AtomicString& family, UScriptCode script)
187 {
188     bool changes = m_fontGenericFamilies->setSansSerifFontFamily(family, script);
189     if (changes)
190         invalidateAfterGenericFamilyChange(m_page);
191 }
192
193 const AtomicString& SettingsBase::cursiveFontFamily(UScriptCode script) const
194 {
195     return m_fontGenericFamilies->cursiveFontFamily(script);
196 }
197
198 void SettingsBase::setCursiveFontFamily(const AtomicString& family, UScriptCode script)
199 {
200     bool changes = m_fontGenericFamilies->setCursiveFontFamily(family, script);
201     if (changes)
202         invalidateAfterGenericFamilyChange(m_page);
203 }
204
205 const AtomicString& SettingsBase::fantasyFontFamily(UScriptCode script) const
206 {
207     return m_fontGenericFamilies->fantasyFontFamily(script);
208 }
209
210 void SettingsBase::setFantasyFontFamily(const AtomicString& family, UScriptCode script)
211 {
212     bool changes = m_fontGenericFamilies->setFantasyFontFamily(family, script);
213     if (changes)
214         invalidateAfterGenericFamilyChange(m_page);
215 }
216
217 const AtomicString& SettingsBase::pictographFontFamily(UScriptCode script) const
218 {
219     return m_fontGenericFamilies->pictographFontFamily(script);
220 }
221
222 void SettingsBase::setPictographFontFamily(const AtomicString& family, UScriptCode script)
223 {
224     bool changes = m_fontGenericFamilies->setPictographFontFamily(family, script);
225     if (changes)
226         invalidateAfterGenericFamilyChange(m_page);
227 }
228
229 void SettingsBase::setMinimumDOMTimerInterval(Seconds interval)
230 {
231     auto oldTimerInterval = std::exchange(m_minimumDOMTimerInterval, interval);
232
233     if (!m_page)
234         return;
235
236     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
237         if (frame->document())
238             frame->document()->adjustMinimumDOMTimerInterval(oldTimerInterval);
239     }
240 }
241
242 void SettingsBase::setLayoutInterval(Seconds layoutInterval)
243 {
244     // FIXME: It seems weird that this function may disregard the specified layout interval.
245     // We should either expose layoutScheduleThreshold or better communicate this invariant.
246     m_layoutInterval = std::max(layoutInterval, layoutScheduleThreshold);
247 }
248
249 void SettingsBase::setMediaContentTypesRequiringHardwareSupport(const String& contentTypes)
250 {
251     m_mediaContentTypesRequiringHardwareSupport.shrink(0);
252     for (auto type : StringView(contentTypes).split(':'))
253         m_mediaContentTypesRequiringHardwareSupport.append(ContentType { type.toString() });
254 }
255
256 void SettingsBase::setMediaContentTypesRequiringHardwareSupport(const Vector<ContentType>& contentTypes)
257 {
258     m_mediaContentTypesRequiringHardwareSupport = contentTypes;
259 }
260
261
262
263 // MARK - onChange handlers
264
265 void SettingsBase::setNeedsRecalcStyleInAllFrames()
266 {
267     if (m_page)
268         m_page->setNeedsRecalcStyleInAllFrames();
269 }
270
271 void SettingsBase::setNeedsRelayoutAllFrames()
272 {
273     if (!m_page)
274         return;
275
276     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
277         if (!frame->ownerRenderer())
278             continue;
279         frame->ownerRenderer()->setNeedsLayoutAndPrefWidthsRecalc();
280     }
281 }
282
283 void SettingsBase::mediaTypeOverrideChanged()
284 {
285     if (!m_page)
286         return;
287
288     FrameView* view = m_page->mainFrame().view();
289     if (view)
290         view->setMediaType(m_page->settings().mediaTypeOverride());
291
292     m_page->setNeedsRecalcStyleInAllFrames();
293 }
294
295 void SettingsBase::imagesEnabledChanged()
296 {
297     // Changing this setting to true might immediately start new loads for images that had previously had loading disabled.
298     // If this happens while a WebView is being dealloc'ed, and we don't know the WebView is being dealloc'ed, these new loads
299     // can cause crashes downstream when the WebView memory has actually been free'd.
300     // One example where this can happen is in Mac apps that subclass WebView then do work in their overridden dealloc methods.
301     // Starting these loads synchronously is not important. By putting it on a 0-delay, properly closing the Page cancels them
302     // before they have a chance to really start.
303     // See http://webkit.org/b/60572 for more discussion.
304     m_setImageLoadingSettingsTimer.startOneShot(0_s);
305 }
306
307 void SettingsBase::imageLoadingSettingsTimerFired()
308 {
309     if (!m_page)
310         return;
311
312     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
313         if (!frame->document())
314             continue;
315         frame->document()->cachedResourceLoader().setImagesEnabled(m_page->settings().areImagesEnabled());
316         frame->document()->cachedResourceLoader().setAutoLoadImages(m_page->settings().loadsImagesAutomatically());
317     }
318 }
319
320 void SettingsBase::pluginsEnabledChanged()
321 {
322     Page::refreshPlugins(false);
323 }
324
325 void SettingsBase::iceCandidateFilteringEnabledChanged()
326 {
327     if (!m_page)
328         return;
329
330     if (m_page->settings().iceCandidateFilteringEnabled())
331         m_page->enableICECandidateFiltering();
332     else
333         m_page->disableICECandidateFiltering();
334 }
335
336 #if ENABLE(TEXT_AUTOSIZING)
337
338 void SettingsBase::shouldEnableTextAutosizingBoostChanged()
339 {
340     if (!m_page)
341         return;
342
343     bool boostAutosizing = m_page->settings().shouldEnableTextAutosizingBoost();
344     m_oneLineTextMultiplierCoefficient = boostAutosizing ? boostedOneLineTextMultiplierCoefficient : defaultOneLineTextMultiplierCoefficient;
345     m_multiLineTextMultiplierCoefficient = boostAutosizing ? boostedMultiLineTextMultiplierCoefficient : defaultMultiLineTextMultiplierCoefficient;
346     m_maxTextAutosizingScaleIncrease = boostAutosizing ? boostedMaxTextAutosizingScaleIncrease : defaultMaxTextAutosizingScaleIncrease;
347
348     setNeedsRecalcStyleInAllFrames();
349 }
350
351 #endif
352
353 #if ENABLE(MEDIA_STREAM)
354 void SettingsBase::mockCaptureDevicesEnabledChanged()
355 {
356     bool enabled = false;
357     if (m_page)
358         enabled = m_page->settings().mockCaptureDevicesEnabled();
359
360     MockRealtimeMediaSourceCenter::setMockRealtimeMediaSourceCenterEnabled(enabled);
361 }
362 #endif
363
364 void SettingsBase::userStyleSheetLocationChanged()
365 {
366     if (m_page)
367         m_page->userStyleSheetLocationChanged();
368 }
369
370 void SettingsBase::usesPageCacheChanged()
371 {
372     if (!m_page)
373         return;
374
375     if (!m_page->settings().usesPageCache())
376         PageCache::singleton().pruneToSizeNow(0, PruningReason::None);
377 }
378
379 void SettingsBase::dnsPrefetchingEnabledChanged()
380 {
381     if (m_page)
382         m_page->dnsPrefetchingStateChanged();
383 }
384
385 void SettingsBase::storageBlockingPolicyChanged()
386 {
387     if (m_page)
388         m_page->storageBlockingStateChanged();
389 }
390
391 void SettingsBase::backgroundShouldExtendBeyondPageChanged()
392 {
393     if (m_page)
394         m_page->mainFrame().view()->updateExtendBackgroundIfNecessary();
395 }
396
397 void SettingsBase::scrollingPerformanceLoggingEnabledChanged()
398 {
399     if (m_page && m_page->mainFrame().view())
400         m_page->mainFrame().view()->setScrollingPerformanceLoggingEnabled(m_page->settings().scrollingPerformanceLoggingEnabled());
401 }
402
403 void SettingsBase::hiddenPageDOMTimerThrottlingStateChanged()
404 {
405     if (m_page)
406         m_page->hiddenPageDOMTimerThrottlingStateChanged();
407 }
408
409 void SettingsBase::hiddenPageCSSAnimationSuspensionEnabledChanged()
410 {
411     if (m_page)
412         m_page->hiddenPageCSSAnimationSuspensionStateChanged();
413 }
414
415 void SettingsBase::resourceUsageOverlayVisibleChanged()
416 {
417 #if ENABLE(RESOURCE_USAGE)
418     if (m_page)
419         m_page->setResourceUsageOverlayVisible(m_page->settings().resourceUsageOverlayVisible());
420 #endif
421 }
422
423 } // namespace WebCore