44ef943f2c03816c6ba861aed70dfa054925d350
[WebKit-https.git] / Source / WebCore / style / StyleTreeResolver.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Peter Kelly (pmk@post.com)
5  *           (C) 2001 Dirk Mueller (mueller@kde.org)
6  *           (C) 2007 David Smith (catfish.man@gmail.com)
7  * Copyright (C) 2004-2010, 2012-2016 Apple Inc. All rights reserved.
8  *           (C) 2007 Eric Seidel (eric@webkit.org)
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  * Boston, MA 02110-1301, USA.
24  */
25
26 #include "config.h"
27 #include "StyleTreeResolver.h"
28
29 #include "CSSAnimationController.h"
30 #include "CSSFontSelector.h"
31 #include "ComposedTreeAncestorIterator.h"
32 #include "ComposedTreeIterator.h"
33 #include "DocumentTimeline.h"
34 #include "ElementIterator.h"
35 #include "Frame.h"
36 #include "HTMLBodyElement.h"
37 #include "HTMLMeterElement.h"
38 #include "HTMLNames.h"
39 #include "HTMLProgressElement.h"
40 #include "HTMLSlotElement.h"
41 #include "LoaderStrategy.h"
42 #include "NodeRenderStyle.h"
43 #include "Page.h"
44 #include "PlatformStrategies.h"
45 #include "Quirks.h"
46 #include "RenderElement.h"
47 #include "RenderStyle.h"
48 #include "RenderView.h"
49 #include "RuntimeEnabledFeatures.h"
50 #include "Settings.h"
51 #include "ShadowRoot.h"
52 #include "StyleFontSizeFunctions.h"
53 #include "StyleResolver.h"
54 #include "StyleScope.h"
55 #include "Text.h"
56
57 namespace WebCore {
58
59 namespace Style {
60
61 TreeResolver::TreeResolver(Document& document)
62     : m_document(document)
63 {
64 }
65
66 TreeResolver::~TreeResolver() = default;
67
68 TreeResolver::Scope::Scope(Document& document)
69     : styleResolver(document.styleScope().resolver())
70     , sharingResolver(document, styleResolver.ruleSets(), selectorFilter)
71 {
72     document.setIsResolvingTreeStyle(true);
73 }
74
75 TreeResolver::Scope::Scope(ShadowRoot& shadowRoot, Scope& enclosingScope)
76     : styleResolver(shadowRoot.styleScope().resolver())
77     , sharingResolver(shadowRoot.documentScope(), styleResolver.ruleSets(), selectorFilter)
78     , shadowRoot(&shadowRoot)
79     , enclosingScope(&enclosingScope)
80 {
81     styleResolver.setOverrideDocumentElementStyle(enclosingScope.styleResolver.overrideDocumentElementStyle());
82 }
83
84 TreeResolver::Scope::~Scope()
85 {
86     if (!shadowRoot)
87         styleResolver.document().setIsResolvingTreeStyle(false);
88
89     styleResolver.setOverrideDocumentElementStyle(nullptr);
90 }
91
92 TreeResolver::Parent::Parent(Document& document)
93     : element(nullptr)
94     , style(*document.renderStyle())
95 {
96 }
97
98 TreeResolver::Parent::Parent(Element& element, const RenderStyle& style, Change change, DescendantsToResolve descendantsToResolve)
99     : element(&element)
100     , style(style)
101     , change(change)
102     , descendantsToResolve(descendantsToResolve)
103 {
104 }
105
106 void TreeResolver::pushScope(ShadowRoot& shadowRoot)
107 {
108     m_scopeStack.append(adoptRef(*new Scope(shadowRoot, scope())));
109 }
110
111 void TreeResolver::pushEnclosingScope()
112 {
113     ASSERT(scope().enclosingScope);
114     m_scopeStack.append(*scope().enclosingScope);
115 }
116
117 void TreeResolver::popScope()
118 {
119     return m_scopeStack.removeLast();
120 }
121
122 std::unique_ptr<RenderStyle> TreeResolver::styleForElement(Element& element, const RenderStyle& inheritedStyle)
123 {
124     if (element.hasCustomStyleResolveCallbacks()) {
125         RenderStyle* shadowHostStyle = scope().shadowRoot ? m_update->elementStyle(*scope().shadowRoot->host()) : nullptr;
126         if (auto customStyle = element.resolveCustomStyle(inheritedStyle, shadowHostStyle)) {
127             if (customStyle->relations)
128                 commitRelations(WTFMove(customStyle->relations), *m_update);
129
130             return WTFMove(customStyle->renderStyle);
131         }
132     }
133
134     if (auto style = scope().sharingResolver.resolve(element, *m_update))
135         return style;
136
137     auto elementStyle = scope().styleResolver.styleForElement(element, &inheritedStyle, parentBoxStyle(), RuleMatchingBehavior::MatchAllRules, &scope().selectorFilter);
138
139     if (elementStyle.relations)
140         commitRelations(WTFMove(elementStyle.relations), *m_update);
141
142     return WTFMove(elementStyle.renderStyle);
143 }
144
145 static void resetStyleForNonRenderedDescendants(Element& current)
146 {
147     for (auto& child : childrenOfType<Element>(current)) {
148         if (child.needsStyleRecalc()) {
149             child.resetComputedStyle();
150             child.resetStyleRelations();
151             child.setHasValidStyle();
152         }
153
154         if (child.childNeedsStyleRecalc())
155             resetStyleForNonRenderedDescendants(child);
156     }
157     current.clearChildNeedsStyleRecalc();
158 }
159
160 static bool affectsRenderedSubtree(Element& element, const RenderStyle& newStyle)
161 {
162     if (newStyle.display() != DisplayType::None)
163         return true;
164     if (element.renderOrDisplayContentsStyle())
165         return true;
166     if (element.rendererIsNeeded(newStyle))
167         return true;
168     return false;
169 }
170
171 static DescendantsToResolve computeDescendantsToResolve(Change change, Validity validity, DescendantsToResolve parentDescendantsToResolve)
172 {
173     if (parentDescendantsToResolve == DescendantsToResolve::All)
174         return DescendantsToResolve::All;
175     if (validity >= Validity::SubtreeInvalid)
176         return DescendantsToResolve::All;
177     switch (change) {
178     case NoChange:
179         return DescendantsToResolve::None;
180     case NoInherit:
181         return DescendantsToResolve::ChildrenWithExplicitInherit;
182     case Inherit:
183         return DescendantsToResolve::Children;
184     case Detach:
185         return DescendantsToResolve::All;
186     };
187     ASSERT_NOT_REACHED();
188     return DescendantsToResolve::None;
189 };
190
191 ElementUpdates TreeResolver::resolveElement(Element& element)
192 {
193     if (m_didSeePendingStylesheet && !element.renderer() && !m_document.isIgnoringPendingStylesheets()) {
194         m_document.setHasNodesWithMissingStyle();
195         return { };
196     }
197
198     auto newStyle = styleForElement(element, parent().style);
199
200     if (!affectsRenderedSubtree(element, *newStyle))
201         return { };
202
203     auto* existingStyle = element.renderOrDisplayContentsStyle();
204
205     if (m_didSeePendingStylesheet && (!existingStyle || existingStyle->isNotFinal())) {
206         newStyle->setIsNotFinal();
207         m_document.setHasNodesWithNonFinalStyle();
208     }
209
210     auto update = createAnimatedElementUpdate(WTFMove(newStyle), element, parent().change);
211     auto descendantsToResolve = computeDescendantsToResolve(update.change, element.styleValidity(), parent().descendantsToResolve);
212
213     if (&element == m_document.documentElement()) {
214         m_documentElementStyle = RenderStyle::clonePtr(*update.style);
215         scope().styleResolver.setOverrideDocumentElementStyle(m_documentElementStyle.get());
216
217         if (update.change != NoChange && existingStyle && existingStyle->computedFontPixelSize() != update.style->computedFontPixelSize()) {
218             // "rem" units are relative to the document element's font size so we need to recompute everything.
219             // In practice this is rare.
220             scope().styleResolver.invalidateMatchedDeclarationsCache();
221             descendantsToResolve = DescendantsToResolve::All;
222         }
223     }
224
225     // This is needed for resolving color:-webkit-text for subsequent elements.
226     // FIXME: We shouldn't mutate document when resolving style.
227     if (&element == m_document.body())
228         m_document.setTextColor(update.style->visitedDependentColor(CSSPropertyColor));
229
230     // FIXME: These elements should not change renderer based on appearance property.
231     if (element.hasTagName(HTMLNames::meterTag) || is<HTMLProgressElement>(element)) {
232         if (existingStyle && update.style->appearance() != existingStyle->appearance()) {
233             update.change = Detach;
234             descendantsToResolve = DescendantsToResolve::All;
235         }
236     }
237
238     auto beforeUpdate = resolvePseudoStyle(element, update, PseudoId::Before);
239     auto afterUpdate = resolvePseudoStyle(element, update, PseudoId::After);
240
241 #if ENABLE(POINTER_EVENTS) && PLATFORM(IOS_FAMILY)
242     // FIXME: Track this exactly.
243     if (update.style->touchActions() != TouchAction::Auto && !m_document.quirks().shouldDisablePointerEventsQuirk() && RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled())
244         m_document.setMayHaveElementsWithNonAutoTouchAction();
245 #endif
246
247     return { WTFMove(update), descendantsToResolve, WTFMove(beforeUpdate), WTFMove(afterUpdate) };
248 }
249
250 ElementUpdate TreeResolver::resolvePseudoStyle(Element& element, const ElementUpdate& elementUpdate, PseudoId pseudoId)
251 {
252     if (elementUpdate.style->display() == DisplayType::None)
253         return { };
254     if (!elementUpdate.style->hasPseudoStyle(pseudoId))
255         return { };
256
257     auto pseudoStyle = scope().styleResolver.pseudoStyleForElement(element, { pseudoId }, *elementUpdate.style, parentBoxStyleForPseudo(elementUpdate), &scope().selectorFilter);
258     if (!pseudoElementRendererIsNeeded(pseudoStyle.get()))
259         return { };
260
261     PseudoElement* pseudoElement = pseudoId == PseudoId::Before ? element.beforePseudoElement() : element.afterPseudoElement();
262     if (!pseudoElement) {
263         auto newPseudoElement = PseudoElement::create(element, pseudoId);
264         pseudoElement = newPseudoElement.ptr();
265         if (pseudoId == PseudoId::Before)
266             element.setBeforePseudoElement(WTFMove(newPseudoElement));
267         else
268             element.setAfterPseudoElement(WTFMove(newPseudoElement));
269     }
270
271     return createAnimatedElementUpdate(WTFMove(pseudoStyle), *pseudoElement, elementUpdate.change);
272 }
273
274 const RenderStyle* TreeResolver::parentBoxStyle() const
275 {
276     // 'display: contents' doesn't generate boxes.
277     for (auto i = m_parentStack.size(); i--;) {
278         auto& parent = m_parentStack[i];
279         if (parent.style.display() == DisplayType::None)
280             return nullptr;
281         if (parent.style.display() != DisplayType::Contents)
282             return &parent.style;
283     }
284     ASSERT_NOT_REACHED();
285     return nullptr;
286 }
287
288 const RenderStyle* TreeResolver::parentBoxStyleForPseudo(const ElementUpdate& elementUpdate) const
289 {
290     switch (elementUpdate.style->display()) {
291     case DisplayType::None:
292         return nullptr;
293     case DisplayType::Contents:
294         return parentBoxStyle();
295     default:
296         return elementUpdate.style.get();
297     }
298 }
299
300 ElementUpdate TreeResolver::createAnimatedElementUpdate(std::unique_ptr<RenderStyle> newStyle, Element& element, Change parentChange)
301 {
302     auto* oldStyle = element.renderOrDisplayContentsStyle();
303
304     bool shouldRecompositeLayer = false;
305
306     // New code path for CSS Animations and CSS Transitions.
307     if (RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
308         // First, we need to make sure that any new CSS animation occuring on this element has a matching WebAnimation
309         // on the document timeline. Note that we get timeline() on the Document here because we need a timeline created
310         // in case no Web Animations have been created through the JS API.
311         if (element.document().backForwardCacheState() == Document::NotInBackForwardCache && !element.document().renderView()->printing()) {
312             if (oldStyle && (oldStyle->hasTransitions() || newStyle->hasTransitions()))
313                 m_document.timeline().updateCSSTransitionsForElement(element, *oldStyle, *newStyle);
314
315             if ((oldStyle && oldStyle->hasAnimations()) || newStyle->hasAnimations())
316                 m_document.timeline().updateCSSAnimationsForElement(element, oldStyle, *newStyle);
317         }
318     }
319
320     if (auto timeline = m_document.existingTimeline()) {
321         // Now we can update all Web animations, which will include CSS Animations as well
322         // as animations created via the JS API.
323         auto animatedStyle = RenderStyle::clonePtr(*newStyle);
324         shouldRecompositeLayer = timeline->resolveAnimationsForElement(element, *animatedStyle);
325         newStyle = WTFMove(animatedStyle);
326     }
327
328     // Old code path for CSS Animations and CSS Transitions.
329     if (!RuntimeEnabledFeatures::sharedFeatures().webAnimationsCSSIntegrationEnabled()) {
330         auto& animationController = m_document.frame()->animation();
331
332         auto animationUpdate = animationController.updateAnimations(element, *newStyle, oldStyle);
333         shouldRecompositeLayer = animationUpdate.animationChangeRequiresRecomposite;
334
335         if (animationUpdate.style)
336             newStyle = WTFMove(animationUpdate.style);
337     }
338
339     auto change = oldStyle ? determineChange(*oldStyle, *newStyle) : Detach;
340
341     auto validity = element.styleValidity();
342     if (validity >= Validity::SubtreeAndRenderersInvalid || parentChange == Detach)
343         change = Detach;
344
345     shouldRecompositeLayer |= element.styleResolutionShouldRecompositeLayer();
346
347     return { WTFMove(newStyle), change, shouldRecompositeLayer };
348 }
349
350 void TreeResolver::pushParent(Element& element, const RenderStyle& style, Change change, DescendantsToResolve descendantsToResolve)
351 {
352     scope().selectorFilter.pushParent(&element);
353
354     Parent parent(element, style, change, descendantsToResolve);
355
356     if (auto* shadowRoot = element.shadowRoot()) {
357         pushScope(*shadowRoot);
358         parent.didPushScope = true;
359     }
360     else if (is<HTMLSlotElement>(element) && downcast<HTMLSlotElement>(element).assignedNodes()) {
361         pushEnclosingScope();
362         parent.didPushScope = true;
363     }
364
365     m_parentStack.append(WTFMove(parent));
366 }
367
368 void TreeResolver::popParent()
369 {
370     auto& parentElement = *parent().element;
371
372     parentElement.setHasValidStyle();
373     parentElement.clearChildNeedsStyleRecalc();
374
375     if (parent().didPushScope)
376         popScope();
377
378     scope().selectorFilter.popParent();
379
380     m_parentStack.removeLast();
381 }
382
383 void TreeResolver::popParentsToDepth(unsigned depth)
384 {
385     ASSERT(depth);
386     ASSERT(m_parentStack.size() >= depth);
387
388     while (m_parentStack.size() > depth)
389         popParent();
390 }
391
392 static bool shouldResolvePseudoElement(const PseudoElement* pseudoElement)
393 {
394     if (!pseudoElement)
395         return false;
396     return pseudoElement->needsStyleRecalc();
397 }
398
399 static bool shouldResolveElement(const Element& element, DescendantsToResolve parentDescendantsToResolve)
400 {
401     if (element.styleValidity() != Validity::Valid)
402         return true;
403     if (shouldResolvePseudoElement(element.beforePseudoElement()))
404         return true;
405     if (shouldResolvePseudoElement(element.afterPseudoElement()))
406         return true;
407
408     switch (parentDescendantsToResolve) {
409     case DescendantsToResolve::None:
410         return false;
411     case DescendantsToResolve::Children:
412     case DescendantsToResolve::All:
413         return true;
414     case DescendantsToResolve::ChildrenWithExplicitInherit:
415         auto* existingStyle = element.renderOrDisplayContentsStyle();
416         return existingStyle && existingStyle->hasExplicitlyInheritedProperties();
417     };
418     ASSERT_NOT_REACHED();
419     return false;
420 }
421
422 static void clearNeedsStyleResolution(Element& element)
423 {
424     element.setHasValidStyle();
425     if (auto* before = element.beforePseudoElement())
426         before->setHasValidStyle();
427     if (auto* after = element.afterPseudoElement())
428         after->setHasValidStyle();
429 }
430
431 static bool hasLoadingStylesheet(const Style::Scope& styleScope, const Element& element, bool checkDescendants)
432 {
433     if (!styleScope.hasPendingSheetsInBody())
434         return false;
435     if (styleScope.hasPendingSheetInBody(element))
436         return true;
437     if (!checkDescendants)
438         return false;
439     for (auto& descendant : descendantsOfType<Element>(element)) {
440         if (styleScope.hasPendingSheetInBody(descendant))
441             return true;
442     };
443     return false;
444 }
445
446 static std::unique_ptr<RenderStyle> createInheritedDisplayContentsStyleIfNeeded(const RenderStyle& parentElementStyle, const RenderStyle* parentBoxStyle)
447 {
448     if (parentElementStyle.display() != DisplayType::Contents)
449         return nullptr;
450     if (parentBoxStyle && !parentBoxStyle->inheritedNotEqual(&parentElementStyle))
451         return nullptr;
452     // Compute style for imaginary unstyled <span> around the text node.
453     auto style = RenderStyle::createPtr();
454     style->inheritFrom(parentElementStyle);
455     return style;
456 }
457
458 void TreeResolver::resolveComposedTree()
459 {
460     ASSERT(m_parentStack.size() == 1);
461     ASSERT(m_scopeStack.size() == 1);
462
463     auto descendants = composedTreeDescendants(m_document);
464     auto it = descendants.begin();
465     auto end = descendants.end();
466
467     while (it != end) {
468         popParentsToDepth(it.depth());
469
470         auto& node = *it;
471         auto& parent = this->parent();
472
473         ASSERT(node.isConnected());
474         ASSERT(node.containingShadowRoot() == scope().shadowRoot);
475         ASSERT(node.parentElement() == parent.element || is<ShadowRoot>(node.parentNode()) || node.parentElement()->shadowRoot());
476
477         if (is<Text>(node)) {
478             auto& text = downcast<Text>(node);
479             
480             if ((text.styleValidity() >= Validity::SubtreeAndRenderersInvalid && parent.change != Detach) || parent.style.display() == DisplayType::Contents) {
481                 TextUpdate textUpdate;
482                 textUpdate.inheritedDisplayContentsStyle = createInheritedDisplayContentsStyleIfNeeded(parent.style, parentBoxStyle());
483
484                 m_update->addText(text, parent.element, WTFMove(textUpdate));
485             }
486
487             text.setHasValidStyle();
488             it.traverseNextSkippingChildren();
489             continue;
490         }
491
492         auto& element = downcast<Element>(node);
493
494         if (it.depth() > Settings::defaultMaximumRenderTreeDepth) {
495             resetStyleForNonRenderedDescendants(element);
496             it.traverseNextSkippingChildren();
497             continue;
498         }
499
500         auto* style = element.renderOrDisplayContentsStyle();
501         auto change = NoChange;
502         auto descendantsToResolve = DescendantsToResolve::None;
503
504         bool shouldResolve = shouldResolveElement(element, parent.descendantsToResolve);
505         if (shouldResolve) {
506             if (!element.hasDisplayContents())
507                 element.resetComputedStyle();
508             element.resetStyleRelations();
509
510             if (element.hasCustomStyleResolveCallbacks())
511                 element.willRecalcStyle(parent.change);
512
513             auto elementUpdates = resolveElement(element);
514
515             if (element.hasCustomStyleResolveCallbacks())
516                 element.didRecalcStyle(elementUpdates.update.change);
517
518             style = elementUpdates.update.style.get();
519             change = elementUpdates.update.change;
520             descendantsToResolve = elementUpdates.descendantsToResolve;
521
522             if (elementUpdates.update.style)
523                 m_update->addElement(element, parent.element, WTFMove(elementUpdates));
524
525             clearNeedsStyleResolution(element);
526         }
527
528         if (!style)
529             resetStyleForNonRenderedDescendants(element);
530
531         bool shouldIterateChildren = style && (element.childNeedsStyleRecalc() || descendantsToResolve != DescendantsToResolve::None);
532
533         if (!m_didSeePendingStylesheet)
534             m_didSeePendingStylesheet = hasLoadingStylesheet(m_document.styleScope(), element, !shouldIterateChildren);
535
536         if (!shouldIterateChildren) {
537             it.traverseNextSkippingChildren();
538             continue;
539         }
540
541         pushParent(element, *style, change, descendantsToResolve);
542
543         it.traverseNext();
544     }
545
546     popParentsToDepth(1);
547 }
548
549 std::unique_ptr<Update> TreeResolver::resolve()
550 {
551     auto& renderView = *m_document.renderView();
552
553     Element* documentElement = m_document.documentElement();
554     if (!documentElement) {
555         m_document.styleScope().resolver();
556         return nullptr;
557     }
558     if (!documentElement->childNeedsStyleRecalc() && !documentElement->needsStyleRecalc())
559         return nullptr;
560
561     m_didSeePendingStylesheet = m_document.styleScope().hasPendingSheetsBeforeBody();
562
563     m_update = makeUnique<Update>(m_document);
564     m_scopeStack.append(adoptRef(*new Scope(m_document)));
565     m_parentStack.append(Parent(m_document));
566
567     // Pseudo element removal and similar may only work with these flags still set. Reset them after the style recalc.
568     renderView.setUsesFirstLineRules(renderView.usesFirstLineRules() || scope().styleResolver.usesFirstLineRules());
569     renderView.setUsesFirstLetterRules(renderView.usesFirstLetterRules() || scope().styleResolver.usesFirstLetterRules());
570
571     resolveComposedTree();
572
573     renderView.setUsesFirstLineRules(scope().styleResolver.usesFirstLineRules());
574     renderView.setUsesFirstLetterRules(scope().styleResolver.usesFirstLetterRules());
575
576     ASSERT(m_scopeStack.size() == 1);
577     ASSERT(m_parentStack.size() == 1);
578     m_parentStack.clear();
579     popScope();
580
581     if (m_update->roots().isEmpty())
582         return { };
583
584     return WTFMove(m_update);
585 }
586
587 static Vector<Function<void ()>>& postResolutionCallbackQueue()
588 {
589     static NeverDestroyed<Vector<Function<void ()>>> vector;
590     return vector;
591 }
592
593 static Vector<RefPtr<Frame>>& memoryCacheClientCallsResumeQueue()
594 {
595     static NeverDestroyed<Vector<RefPtr<Frame>>> vector;
596     return vector;
597 }
598
599 void queuePostResolutionCallback(Function<void ()>&& callback)
600 {
601     postResolutionCallbackQueue().append(WTFMove(callback));
602 }
603
604 static void suspendMemoryCacheClientCalls(Document& document)
605 {
606     Page* page = document.page();
607     if (!page || !page->areMemoryCacheClientCallsEnabled())
608         return;
609
610     page->setMemoryCacheClientCallsEnabled(false);
611
612     memoryCacheClientCallsResumeQueue().append(&page->mainFrame());
613 }
614
615 static unsigned resolutionNestingDepth;
616
617 PostResolutionCallbackDisabler::PostResolutionCallbackDisabler(Document& document, DrainCallbacks drainCallbacks)
618     : m_drainCallbacks(drainCallbacks)
619 {
620     ++resolutionNestingDepth;
621
622     if (resolutionNestingDepth == 1)
623         platformStrategies()->loaderStrategy()->suspendPendingRequests();
624
625     // FIXME: It's strange to build this into the disabler.
626     suspendMemoryCacheClientCalls(document);
627 }
628
629 PostResolutionCallbackDisabler::~PostResolutionCallbackDisabler()
630 {
631     if (resolutionNestingDepth == 1) {
632         if (m_drainCallbacks == DrainCallbacks::Yes) {
633             // Get size each time through the loop because a callback can add more callbacks to the end of the queue.
634             auto& queue = postResolutionCallbackQueue();
635             for (size_t i = 0; i < queue.size(); ++i)
636                 queue[i]();
637             queue.clear();
638         }
639
640         auto& queue = memoryCacheClientCallsResumeQueue();
641         for (size_t i = 0; i < queue.size(); ++i) {
642             if (auto* page = queue[i]->page())
643                 page->setMemoryCacheClientCallsEnabled(true);
644         }
645         queue.clear();
646
647         platformStrategies()->loaderStrategy()->resumePendingRequests();
648     }
649
650     --resolutionNestingDepth;
651 }
652
653 bool postResolutionCallbacksAreSuspended()
654 {
655     return resolutionNestingDepth;
656 }
657
658 }
659 }