Changeset 212614 in webkit
- Timestamp:
- Feb 19, 2017 4:12:07 AM (7 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r212610 r212614 1 2017-02-19 Antti Koivisto <antti@apple.com> 2 3 Execute pending scripts asynchronously after stylesheet loads complete 4 https://bugs.webkit.org/show_bug.cgi?id=168367 5 rdar://problem/30561379 6 7 Reviewed by Andreas Kling. 8 9 The current synchronous execution is fragile and creates various problems. 10 11 * css/StyleSheetContents.cpp: 12 (WebCore::StyleSheetContents::checkLoaded): 13 * dom/ContainerNode.cpp: 14 (WebCore::ContainerNode::takeAllChildrenFrom): 15 (WebCore::ContainerNode::notifyChildInserted): 16 (WebCore::ContainerNode::removeChild): 17 (WebCore::ContainerNode::parserRemoveChild): 18 (WebCore::ContainerNode::removeChildren): 19 20 Remove various places where we would trigger delayed synchronous execution. 21 22 * dom/Document.cpp: 23 (WebCore::Document::Document): 24 (WebCore::Document::recalcStyle): 25 26 Trigger scroll to anchor at the end of style resolution instead of when style sheet load completes. 27 28 (WebCore::Document::didRemoveAllPendingStylesheet): 29 30 Call asynchronous script execution function. 31 32 * dom/Document.h: 33 (WebCore::Document::setNeedsNotifyRemoveAllPendingStylesheet): Deleted. 34 (WebCore::Document::notifyRemovePendingSheetIfNeeded): Deleted. 35 * dom/ScriptableDocumentParser.cpp: 36 (WebCore::ScriptableDocumentParser::ScriptableDocumentParser): 37 (WebCore::ScriptableDocumentParser::executeScriptsWaitingForStylesheetsSoon): 38 (WebCore::ScriptableDocumentParser::scriptsWaitingForStylesheetsExecutionTimerFired): 39 40 Add a timer for executing pending scripts. 41 42 (WebCore::ScriptableDocumentParser::detach): 43 * dom/ScriptableDocumentParser.h: 44 (WebCore::ScriptableDocumentParser::executeScriptsWaitingForStylesheets): 45 * html/HTMLLinkElement.cpp: 46 (WebCore::HTMLLinkElement::removedFrom): 47 (WebCore::HTMLLinkElement::removePendingSheet): 48 * html/HTMLLinkElement.h: 49 * html/parser/HTMLDocumentParser.cpp: 50 (WebCore::HTMLDocumentParser::detach): 51 * loader/DocumentLoader.cpp: 52 (WebCore::DocumentLoader::isLoadingInAPISense): 53 54 Stay in loading state if we have a pending script. This matches existing behavior. 55 56 * style/StyleScope.cpp: 57 (WebCore::Style::Scope::removePendingSheet): 58 * style/StyleScope.h: 59 1 60 2017-02-18 Chris Dumez <cdumez@apple.com> 2 61 -
trunk/Source/WebCore/css/StyleSheetContents.cpp
r212556 r212614 365 365 return; 366 366 367 // Avoid |this| being deleted by scripts that run via368 // ScriptableDocumentParser::executeScriptsWaitingForStylesheets().369 // See <rdar://problem/6622300>.370 367 Ref<StyleSheetContents> protectedThis(*this); 371 368 StyleSheetContents* parentSheet = parentStyleSheet(); -
trunk/Source/WebCore/dom/ContainerNode.cpp
r212556 r212614 146 146 } 147 147 148 document().notifyRemovePendingSheetIfNeeded();149 150 148 // FIXME: assert that we don't dispatch events here since this container node is still disconnected. 151 149 for (auto& child : children) { … … 365 363 childrenChanged(change); 366 364 367 // Some call sites may have deleted child nodes. Calling it earlier results in bugs like webkit.org/b/168069.368 document().notifyRemovePendingSheetIfNeeded();369 370 365 for (auto& target : postInsertionNotificationTargets) 371 366 target->finishedInsertingSubtree(); … … 555 550 } 556 551 557 document().notifyRemovePendingSheetIfNeeded();558 552 rebuildSVGExtensionsElementsIfNecessary(); 559 553 dispatchSubtreeModifiedEvent(); … … 616 610 617 611 notifyChildRemoved(oldChild, prev, next, ChildChangeSourceParser); 618 document().notifyRemovePendingSheetIfNeeded();619 612 } 620 613 … … 710 703 } 711 704 712 document().notifyRemovePendingSheetIfNeeded();713 705 rebuildSVGExtensionsElementsIfNecessary(); 714 706 dispatchSubtreeModifiedEvent(); -
trunk/Source/WebCore/dom/Document.cpp
r212556 r212614 444 444 , m_settings(frame ? Ref<Settings>(frame->settings()) : Settings::create(nullptr)) 445 445 , m_hasNodesWithPlaceholderStyle(false) 446 , m_needsNotifyRemoveAllPendingStylesheet(false)447 446 , m_ignorePendingStylesheets(false) 448 447 , m_pendingSheetLayout(NoLayoutWithPendingSheets) … … 1847 1846 if (m_hoveredElement && !m_hoveredElement->renderer()) 1848 1847 frameView.frame().mainFrame().eventHandler().dispatchFakeMouseMoveEventSoon(); 1848 1849 if (m_gotoAnchorNeededAfterStylesheetsLoad && !styleScope().hasPendingSheets()) 1850 frameView.scrollToFragment(m_url); 1849 1851 } 1850 1852 … … 2624 2626 } 2625 2627 2626 m_frame->loader().checkCompleted();2628 checkCompleted(); 2627 2629 } 2628 2630 … … 3074 3076 void Document::didRemoveAllPendingStylesheet() 3075 3077 { 3076 m_needsNotifyRemoveAllPendingStylesheet = false;3077 3078 3078 if (m_pendingSheetLayout == DidLayoutWithPendingSheets) { 3079 // Painting is disabled when doing layouts with pending sheets to avoid FOUC. 3080 // We need to force paint when coming out from this state. 3081 // FIXME: This is not very elegant. 3079 3082 m_pendingSheetLayout = IgnoreLayoutWithPendingSheets; 3080 3083 if (renderView()) … … 3082 3085 } 3083 3086 3084 if (ScriptableDocumentParser* parser = scriptableDocumentParser()) 3085 parser->executeScriptsWaitingForStylesheets(); 3086 3087 if (m_gotoAnchorNeededAfterStylesheetsLoad && view()) 3088 view()->scrollToFragment(m_url); 3087 if (auto* parser = scriptableDocumentParser()) 3088 parser->executeScriptsWaitingForStylesheetsSoon(); 3089 3089 } 3090 3090 … … 6039 6039 void Document::loadEventDelayTimerFired() 6040 6040 { 6041 if (frame()) 6042 frame()->loader().checkCompleted(); 6041 checkCompleted(); 6042 } 6043 6044 void Document::checkCompleted() 6045 { 6046 if (auto* frame = this->frame()) 6047 frame->loader().checkCompleted(); 6043 6048 } 6044 6049 -
trunk/Source/WebCore/dom/Document.h
r212556 r212614 487 487 CSSFontSelector& fontSelector() { return m_fontSelector; } 488 488 489 void notifyRemovePendingSheetIfNeeded();490 491 489 WEBCORE_EXPORT bool haveStylesheetsLoaded() const; 492 490 … … 1117 1115 void decrementLoadEventDelayCount(); 1118 1116 bool isDelayingLoadEvent() const { return m_loadEventDelayCount; } 1117 void checkCompleted(); 1119 1118 1120 1119 #if ENABLE(IOS_TOUCH_EVENTS) … … 1207 1206 1208 1207 void didRemoveAllPendingStylesheet(); 1209 void setNeedsNotifyRemoveAllPendingStylesheet() { m_needsNotifyRemoveAllPendingStylesheet = true; }1210 1208 void didClearStyleResolver(); 1211 1209 … … 1392 1390 std::unique_ptr<StyleResolver> m_userAgentShadowTreeStyleResolver; 1393 1391 bool m_hasNodesWithPlaceholderStyle; 1394 bool m_needsNotifyRemoveAllPendingStylesheet;1395 1392 // But sometimes you need to ignore pending stylesheet count to 1396 1393 // force an immediate layout when requested by JS. … … 1758 1755 Element* eventTargetElementForDocument(Document*); 1759 1756 1760 inline void Document::notifyRemovePendingSheetIfNeeded()1761 {1762 if (m_needsNotifyRemoveAllPendingStylesheet)1763 didRemoveAllPendingStylesheet();1764 }1765 1766 1757 inline TextEncoding Document::textEncoding() const 1767 1758 { -
trunk/Source/WebCore/dom/ScriptableDocumentParser.cpp
r212556 r212614 29 29 #include "Document.h" 30 30 #include "Settings.h" 31 #include "StyleScope.h" 31 32 32 33 namespace WebCore { … … 36 37 , m_wasCreatedByScript(false) 37 38 , m_parserContentPolicy(parserContentPolicy) 39 , m_scriptsWaitingForStylesheetsExecutionTimer(*this, &ScriptableDocumentParser::scriptsWaitingForStylesheetsExecutionTimerFired) 38 40 { 39 41 if (!pluginContentIsAllowed(m_parserContentPolicy)) … … 44 46 } 45 47 48 void ScriptableDocumentParser::executeScriptsWaitingForStylesheetsSoon() 49 { 50 ASSERT(!document()->styleScope().hasPendingSheets()); 51 52 if (m_scriptsWaitingForStylesheetsExecutionTimer.isActive()) 53 return; 54 if (!hasScriptsWaitingForStylesheets()) 55 return; 56 57 m_scriptsWaitingForStylesheetsExecutionTimer.startOneShot(0); 58 } 59 60 void ScriptableDocumentParser::scriptsWaitingForStylesheetsExecutionTimerFired() 61 { 62 ASSERT(!isDetached()); 63 64 Ref<ScriptableDocumentParser> protectedThis(*this); 65 66 if (!document()->styleScope().hasPendingSheets()) 67 executeScriptsWaitingForStylesheets(); 68 69 if (!isDetached()) 70 document()->checkCompleted(); 71 } 72 73 void ScriptableDocumentParser::detach() 74 { 75 m_scriptsWaitingForStylesheetsExecutionTimer.stop(); 76 77 DecodedDataDocumentParser::detach(); 78 } 79 46 80 }; -
trunk/Source/WebCore/dom/ScriptableDocumentParser.h
r212556 r212614 28 28 #include "DecodedDataDocumentParser.h" 29 29 #include "FragmentScriptingPermission.h" 30 #include "Timer.h" 30 31 #include <wtf/text/TextPosition.h> 31 32 … … 38 39 virtual bool isExecutingScript() const { return false; } 39 40 40 // FIXME: Only the HTMLDocumentParser ever blocks script execution on41 // stylesheet load, which is likely a bug in the XMLDocumentParser.42 virtual void executeScriptsWaitingForStylesheets() { }43 44 41 virtual bool isWaitingForScripts() const = 0; 45 42 46 43 virtual TextPosition textPosition() const = 0; 44 45 virtual bool hasScriptsWaitingForStylesheets() const { return false; } 46 47 void executeScriptsWaitingForStylesheetsSoon(); 47 48 48 49 // Returns true if the parser didn't yield or pause or synchronously execute a script, … … 58 59 explicit ScriptableDocumentParser(Document&, ParserContentPolicy = AllowScriptingContent); 59 60 61 virtual void executeScriptsWaitingForStylesheets() { } 62 63 void detach() override; 64 60 65 private: 61 66 ScriptableDocumentParser* asScriptableDocumentParser() final { return this; } 67 68 void scriptsWaitingForStylesheetsExecutionTimerFired(); 62 69 63 70 // http://www.whatwg.org/specs/web-apps/current-work/#script-created-parser 64 71 bool m_wasCreatedByScript; 65 72 ParserContentPolicy m_parserContentPolicy; 73 Timer m_scriptsWaitingForStylesheetsExecutionTimer; 66 74 }; 67 75 -
trunk/Source/WebCore/html/HTMLLinkElement.cpp
r212556 r212614 328 328 329 329 if (styleSheetIsLoading()) 330 removePendingSheet( RemovePendingSheetNotifyLater);330 removePendingSheet(); 331 331 332 332 if (m_styleScope) { … … 555 555 } 556 556 557 void HTMLLinkElement::removePendingSheet( RemovePendingSheetNotificationType notification)557 void HTMLLinkElement::removePendingSheet() 558 558 { 559 559 PendingSheetType type = m_pendingSheetType; … … 570 570 } 571 571 572 m_styleScope->removePendingSheet( 573 notification == RemovePendingSheetNotifyImmediately 574 ? Style::Scope::RemovePendingSheetNotifyImmediately 575 : Style::Scope::RemovePendingSheetNotifyLater); 572 m_styleScope->removePendingSheet(); 576 573 } 577 574 -
trunk/Source/WebCore/html/HTMLLinkElement.h
r212556 r212614 112 112 void addPendingSheet(PendingSheetType); 113 113 114 enum RemovePendingSheetNotificationType { 115 RemovePendingSheetNotifyImmediately, 116 RemovePendingSheetNotifyLater 117 }; 118 119 void removePendingSheet(RemovePendingSheetNotificationType = RemovePendingSheetNotifyImmediately); 114 void removePendingSheet(); 120 115 121 116 LinkLoader m_linkLoader; -
trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp
r212556 r212614 88 88 void HTMLDocumentParser::detach() 89 89 { 90 DocumentParser::detach();90 ScriptableDocumentParser::detach(); 91 91 92 92 if (m_scriptRunner) … … 539 539 } 540 540 541 bool HTMLDocumentParser::hasScriptsWaitingForStylesheets() const 542 { 543 return m_scriptRunner && m_scriptRunner->hasScriptsWaitingForStylesheets(); 544 } 545 541 546 void HTMLDocumentParser::executeScriptsWaitingForStylesheets() 542 547 { -
trunk/Source/WebCore/html/parser/HTMLDocumentParser.h
r212556 r212614 84 84 bool isWaitingForScripts() const override; 85 85 bool isExecutingScript() const final; 86 bool hasScriptsWaitingForStylesheets() const final; 86 87 void executeScriptsWaitingForStylesheets() final; 87 88 void suspendScheduledTasks() final; -
trunk/Source/WebCore/loader/DocumentLoader.cpp
r212556 r212614 69 69 #include "ResourceLoadObserver.h" 70 70 #include "SchemeRegistry.h" 71 #include "ScriptableDocumentParser.h" 71 72 #include "SecurityPolicy.h" 72 73 #include "Settings.h" … … 1058 1059 if (document.hasActiveParser()) 1059 1060 return true; 1061 auto* scriptableParser = document.scriptableDocumentParser(); 1062 if (scriptableParser && scriptableParser->hasScriptsWaitingForStylesheets()) 1063 return true; 1060 1064 } 1061 1065 return frameLoader()->subframeIsLoading(); -
trunk/Source/WebCore/loader/FrameLoader.cpp
r212556 r212614 788 788 return; 789 789 790 auto* scriptableParser = m_frame.document()->scriptableDocumentParser(); 791 if (scriptableParser && scriptableParser->hasScriptsWaitingForStylesheets()) 792 return; 793 790 794 // Any frame that hasn't completed yet? 791 795 if (!allChildrenAreComplete()) -
trunk/Source/WebCore/style/StyleScope.cpp
r212556 r212614 171 171 172 172 // This method is called whenever a top-level stylesheet has finished loading. 173 void Scope::removePendingSheet( RemovePendingSheetNotificationType notification)173 void Scope::removePendingSheet() 174 174 { 175 175 // Make sure we knew this sheet was pending, and that our count isn't out of sync. … … 179 179 if (m_pendingStyleSheetCount) 180 180 return; 181 182 if (notification == RemovePendingSheetNotifyLater) {183 m_document.setNeedsNotifyRemoveAllPendingStylesheet();184 return;185 }186 181 187 182 didChangeActiveStyleSheetCandidates(); -
trunk/Source/WebCore/style/StyleScope.h
r212556 r212614 83 83 84 84 void addPendingSheet() { m_pendingStyleSheetCount++; } 85 enum RemovePendingSheetNotificationType { 86 RemovePendingSheetNotifyImmediately, 87 RemovePendingSheetNotifyLater 88 }; 89 void removePendingSheet(RemovePendingSheetNotificationType = RemovePendingSheetNotifyImmediately); 85 void removePendingSheet(); 90 86 91 87 bool hasPendingSheets() const { return m_pendingStyleSheetCount > 0; }
Note: See TracChangeset
for help on using the changeset viewer.