diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog index d8ed20bc380c..e1eccf8f0f99 100644 --- a/Source/WebCore/ChangeLog +++ b/Source/WebCore/ChangeLog @@ -1,3 +1,39 @@ +2017-10-25 Ryosuke Niwa + + Style::Scope::flushPendingUpdate() can replace the entire document in XSLTProcessor::createDocumentFromSource + https://bugs.webkit.org/show_bug.cgi?id=178715 + + + Reviewed by Brent Fulgham. + + Apply XLS tranforms when a 0s timer fires or the document finishes parsing or loading whichever comes first + instead of in the middle of collecting a list of stylesheets. + + * dom/Document.cpp: + (WebCore::Document::Document): Initialize the newly added timer. + (WebCore::Document::implicitClose): Apply any pending XSLT before we fire load events since some of the event + handlers may be expecting to see the document after XSLT had been applied. + (WebCore::Document::scheduleToApplyXSLTransforms): Added. + (WebCore::Document::applyPendingXSLTransformsNowIfScheduled): Added. + (WebCore::Document::applyPendingXSLTransformsTimerFired): Added. Moved the logic to apply XSL transforms from + Style::Scope::collectActiveStyleSheets, and merged applyXSLTransform into this function. + (WebCore::Document::applyXSLTransform): Deleted. + (WebCore::Document::finishedParsing): Apply XSLT right before updating the style. This is where used to apply + inline XSLT and it happens much earlier than implicitClose. + * dom/Document.h: + * dom/ProcessingInstruction.cpp: + (WebCore::ProcessingInstruction::checkStyleSheet): Schedule XSLT in the document instead of flushing pending + stylesheets, which would have synchronously applied XSLT. We can't apply XSLT synchronously here because this + function can be called from a non-script-resilient call stack. + (WebCore::ProcessingInstruction::sheetLoaded): Ditto. + * style/StyleScope.cpp: + (WebCore::Style::Scope::collectXSLTransforms): Added. + (WebCore::Style::Scope::collectActiveStyleSheets): Removed the code to apply XSLT. Skip ProcessingInstructions + that applies XSLT. Also use RefPtr instead of a raw pointer to store StyleSheet. + * style/StyleScope.h: + * xml/parser/XMLDocumentParserLibxml2.cpp: + (WebCore::XMLDocumentParser::doEnd): Apply any pending XSLTs synchronously here as the comment suggests. + 2017-10-24 Miguel Gomez [GTK][X11] Windy.com shows always straight wind lines diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp index a9485aad95b4..9a380341d6d8 100644 --- a/Source/WebCore/dom/Document.cpp +++ b/Source/WebCore/dom/Document.cpp @@ -465,6 +465,7 @@ Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsig , m_documentCreationTime(MonotonicTime::now()) , m_scriptRunner(std::make_unique(*this)) , m_moduleLoader(std::make_unique(*this)) + , m_applyPendingXSLTransformsTimer(*this, &Document::applyPendingXSLTransformsTimerFired) , m_xmlVersion(ASCIILiteral("1.0")) , m_constantPropertyMap(std::make_unique(*this)) , m_documentClasses(documentClasses) @@ -2717,6 +2718,9 @@ void Document::implicitClose() // ramifications, and we need to decide what is the Right Thing To Do(tm) Frame* f = frame(); if (f) { + // Apply XSL transforms before load events so that event handlers can access the transformed DOM tree. + applyPendingXSLTransformsNowIfScheduled(); + if (auto* documentLoader = loader()) documentLoader->startIconLoading(); @@ -5010,18 +5014,43 @@ void Document::popCurrentScript() #if ENABLE(XSLT) -void Document::applyXSLTransform(ProcessingInstruction* pi) +void Document::scheduleToApplyXSLTransforms() { - RefPtr processor = XSLTProcessor::create(); - processor->setXSLStyleSheet(downcast(pi->sheet())); - String resultMIMEType; - String newSource; - String resultEncoding; - if (!processor->transformToString(*this, resultMIMEType, newSource, resultEncoding)) + if (!m_applyPendingXSLTransformsTimer.isActive()) + m_applyPendingXSLTransformsTimer.startOneShot(0_s); +} + +void Document::applyPendingXSLTransformsNowIfScheduled() +{ + if (!m_applyPendingXSLTransformsTimer.isActive()) return; - // FIXME: If the transform failed we should probably report an error (like Mozilla does). - Frame* ownerFrame = frame(); - processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, ownerFrame); + m_applyPendingXSLTransformsTimer.stop(); + applyPendingXSLTransformsTimerFired(); +} + +void Document::applyPendingXSLTransformsTimerFired() +{ + if (parsing()) + return; + + ASSERT(NoEventDispatchAssertion::isEventAllowedInMainThread()); + for (auto& processingInstruction : styleScope().collectXSLTransforms()) { + ASSERT(processingInstruction->isXSL()); + + // Don't apply XSL transforms to already transformed documents -- + if (transformSourceDocument() || !processingInstruction->sheet()) + return; + + auto processor = XSLTProcessor::create(); + processor->setXSLStyleSheet(downcast(processingInstruction->sheet())); + String resultMIMEType; + String newSource; + String resultEncoding; + if (!processor->transformToString(*this, resultMIMEType, newSource, resultEncoding)) + continue; + // FIXME: If the transform failed we should probably report an error (like Mozilla does). + processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame()); + } } void Document::setTransformSource(std::unique_ptr source) @@ -5203,6 +5232,8 @@ void Document::finishedParsing() ASSERT(!scriptableDocumentParser() || m_readyState != Loading); setParsing(false); + Ref protectedThis(*this); + if (!m_documentTiming.domContentLoadedEventStart) m_documentTiming.domContentLoadedEventStart = MonotonicTime::now(); @@ -5212,6 +5243,8 @@ void Document::finishedParsing() m_documentTiming.domContentLoadedEventEnd = MonotonicTime::now(); if (RefPtr frame = this->frame()) { + applyPendingXSLTransformsNowIfScheduled(); + // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all // resource loads are complete. HTMLObjectElements can start loading their resources from // post attach callbacks triggered by resolveStyle(). This means if we parse out an diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h index ff2dd69f8dbd..48ab79eb422e 100644 --- a/Source/WebCore/dom/Document.h +++ b/Source/WebCore/dom/Document.h @@ -943,7 +943,8 @@ class Document void popCurrentScript(); #if ENABLE(XSLT) - void applyXSLTransform(ProcessingInstruction* pi); + void scheduleToApplyXSLTransforms(); + void applyPendingXSLTransformsNowIfScheduled(); RefPtr transformSourceDocument() { return m_transformSourceDocument; } void setTransformSourceDocument(Document* doc) { m_transformSourceDocument = doc; } @@ -1549,8 +1550,11 @@ class Document Vector> m_currentScriptStack; #if ENABLE(XSLT) + void applyPendingXSLTransformsTimerFired(); + std::unique_ptr m_transformSource; RefPtr m_transformSourceDocument; + Timer m_applyPendingXSLTransformsTimer; #endif String m_xmlEncoding; diff --git a/Source/WebCore/dom/ProcessingInstruction.cpp b/Source/WebCore/dom/ProcessingInstruction.cpp index 7456026ee93f..da952c7ed5b2 100644 --- a/Source/WebCore/dom/ProcessingInstruction.cpp +++ b/Source/WebCore/dom/ProcessingInstruction.cpp @@ -126,6 +126,7 @@ void ProcessingInstruction::checkStyleSheet() URL finalURL(ParsedURLString, m_localHref); m_sheet = XSLStyleSheet::createEmbedded(this, finalURL); m_loading = false; + document().scheduleToApplyXSLTransforms(); } #endif } else { @@ -179,7 +180,7 @@ void ProcessingInstruction::checkStyleSheet() document().styleScope().removePendingSheet(*this); #if ENABLE(XSLT) if (m_isXSL) - document().styleScope().flushPendingUpdate(); + document().scheduleToApplyXSLTransforms(); #endif } } @@ -202,7 +203,7 @@ bool ProcessingInstruction::sheetLoaded() document().styleScope().removePendingSheet(*this); #if ENABLE(XSLT) if (m_isXSL) - document().styleScope().flushPendingUpdate(); + document().scheduleToApplyXSLTransforms(); #endif return true; } diff --git a/Source/WebCore/style/StyleScope.cpp b/Source/WebCore/style/StyleScope.cpp index 17690ccd6777..c031d32c7dd0 100644 --- a/Source/WebCore/style/StyleScope.cpp +++ b/Source/WebCore/style/StyleScope.cpp @@ -290,27 +290,31 @@ void Scope::removeStyleSheetCandidateNode(Node& node) didChangeActiveStyleSheetCandidates(); } +#if ENABLE(XSLT) +// FIXME: Remove XSLT relaed code from Style::Scope. +Vector> Scope::collectXSLTransforms() +{ + Vector> processingInstructions; + for (auto& node : m_styleSheetCandidateNodes) { + if (is(*node) && downcast(*node).isXSL()) + processingInstructions.append(downcast(*node)); + } + return processingInstructions; +} +#endif + void Scope::collectActiveStyleSheets(Vector>& sheets) { if (!m_document.settings().authorAndUserStylesEnabled()) return; for (auto& node : m_styleSheetCandidateNodes) { - StyleSheet* sheet = nullptr; + RefPtr sheet; if (is(*node)) { - // Processing instruction (XML documents only). + if (!downcast(*node).isCSS()) + continue; // We don't support linking to embedded CSS stylesheets, see for discussion. - ProcessingInstruction& pi = downcast(*node); - sheet = pi.sheet(); -#if ENABLE(XSLT) - // Don't apply XSL transforms to already transformed documents -- - if (pi.isXSL() && !m_document.transformSourceDocument()) { - // Don't apply XSL transforms until loading is finished. - if (!m_document.parsing()) - m_document.applyXSLTransform(&pi); - return; - } -#endif + sheet = downcast(*node).sheet(); } else if (is(*node) || is(*node) || is(*node)) { Element& element = downcast(*node); AtomicString title = element.attributeWithoutSynchronization(titleAttr); @@ -364,7 +368,7 @@ void Scope::collectActiveStyleSheets(Vector>& sheets) sheet = nullptr; } if (sheet) - sheets.append(sheet); + sheets.append(WTFMove(sheet)); } } diff --git a/Source/WebCore/style/StyleScope.h b/Source/WebCore/style/StyleScope.h index a408d8cea49c..0ebfd1b80b54 100644 --- a/Source/WebCore/style/StyleScope.h +++ b/Source/WebCore/style/StyleScope.h @@ -108,6 +108,10 @@ class Scope { bool hasPendingUpdate() const { return m_pendingUpdate || m_hasDescendantWithPendingUpdate; } void flushPendingUpdate(); +#if ENABLE(XSLT) + Vector> collectXSLTransforms(); +#endif + StyleResolver& resolver(); StyleResolver* resolverIfExists(); void clearResolver(); diff --git a/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp b/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp index dd73c0c27a9b..b784e4d2474f 100644 --- a/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp +++ b/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp @@ -1333,7 +1333,7 @@ void XMLDocumentParser::doEnd() document()->setTransformSource(std::make_unique(doc)); document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets. - document()->styleScope().didChangeActiveStyleSheetCandidates(); + document()->applyPendingXSLTransformsNowIfScheduled(); // styleResolverChanged() call can detach the parser and null out its document. // In that case, we just bail out.