Changeset 224146 in webkit


Ignore:
Timestamp:
Oct 28, 2017 2:17:59 AM (7 years ago)
Author:
rniwa@webkit.org
Message:

Style::Scope::flushPendingUpdate() can replace the entire document in XSLTProcessor::createDocumentFromSource
https://bugs.webkit.org/show_bug.cgi?id=178715
<rdar://problem/35144665>

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.
(WebCore::Document::suspendScheduledTasks): Suspend the XSLT timer.
(WebCore::Document::resumeScheduledTasks): Reschedule the XSLT timer if m_hasPendingXSLTransforms is set.

  • 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<StyleSheet> 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.

Location:
trunk/Source/WebCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r224142 r224146  
     12017-10-28  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        Style::Scope::flushPendingUpdate() can replace the entire document in XSLTProcessor::createDocumentFromSource
     4        https://bugs.webkit.org/show_bug.cgi?id=178715
     5        <rdar://problem/35144665>
     6
     7        Reviewed by Brent Fulgham.
     8
     9        Apply XLS tranforms when a 0s timer fires or the document finishes parsing or loading whichever comes first
     10        instead of in the middle of collecting a list of stylesheets.
     11
     12        * dom/Document.cpp:
     13        (WebCore::Document::Document): Initialize the newly added timer.
     14        (WebCore::Document::implicitClose): Apply any pending XSLT before we fire load events since some of the event
     15        handlers may be expecting to see the document after XSLT had been applied.
     16        (WebCore::Document::scheduleToApplyXSLTransforms): Added.
     17        (WebCore::Document::applyPendingXSLTransformsNowIfScheduled): Added.
     18        (WebCore::Document::applyPendingXSLTransformsTimerFired): Added. Moved the logic to apply XSL transforms from
     19        Style::Scope::collectActiveStyleSheets, and merged applyXSLTransform into this function.
     20        (WebCore::Document::applyXSLTransform): Deleted.
     21        (WebCore::Document::finishedParsing): Apply XSLT right before updating the style. This is where used to apply
     22        inline XSLT and it happens much earlier than implicitClose.
     23        (WebCore::Document::suspendScheduledTasks): Suspend the XSLT timer.
     24        (WebCore::Document::resumeScheduledTasks): Reschedule the XSLT timer if m_hasPendingXSLTransforms is set.
     25        * dom/Document.h:
     26        * dom/ProcessingInstruction.cpp:
     27        (WebCore::ProcessingInstruction::checkStyleSheet): Schedule XSLT in the document instead of flushing pending
     28        stylesheets, which would have synchronously applied XSLT. We can't apply XSLT synchronously here because this
     29        function can be called from a non-script-resilient call stack.
     30        (WebCore::ProcessingInstruction::sheetLoaded): Ditto.
     31        * style/StyleScope.cpp:
     32        (WebCore::Style::Scope::collectXSLTransforms): Added.
     33        (WebCore::Style::Scope::collectActiveStyleSheets): Removed the code to apply XSLT. Skip ProcessingInstructions
     34        that applies XSLT. Also use RefPtr<StyleSheet> instead of a raw pointer to store StyleSheet.
     35        * style/StyleScope.h:
     36        * xml/parser/XMLDocumentParserLibxml2.cpp:
     37        (WebCore::XMLDocumentParser::doEnd): Apply any pending XSLTs synchronously here as the comment suggests.
     38
    1392017-10-27  Devin Rousso  <webkit@devinrousso.com>
    240
  • trunk/Source/WebCore/dom/Document.cpp

    r224131 r224146  
    481481    , m_scriptRunner(std::make_unique<ScriptRunner>(*this))
    482482    , m_moduleLoader(std::make_unique<ScriptModuleLoader>(*this))
     483#if ENABLE(XSLT)
     484    , m_applyPendingXSLTransformsTimer(*this, &Document::applyPendingXSLTransformsTimerFired)
     485#endif
    483486    , m_xmlVersion(ASCIILiteral("1.0"))
    484487    , m_constantPropertyMap(std::make_unique<ConstantPropertyMap>(*this))
     
    27402743    RefPtr<Frame> f = frame();
    27412744    if (f) {
     2745#if ENABLE(XSLT)
     2746        // Apply XSL transforms before load events so that event handlers can access the transformed DOM tree.
     2747        applyPendingXSLTransformsNowIfScheduled();
     2748#endif
     2749
    27422750        if (auto* documentLoader = loader())
    27432751            documentLoader->startIconLoading();
     
    50665074#if ENABLE(XSLT)
    50675075
    5068 void Document::applyXSLTransform(ProcessingInstruction* pi)
    5069 {
    5070     RefPtr<XSLTProcessor> processor = XSLTProcessor::create();
    5071     processor->setXSLStyleSheet(downcast<XSLStyleSheet>(pi->sheet()));
    5072     String resultMIMEType;
    5073     String newSource;
    5074     String resultEncoding;
    5075     if (!processor->transformToString(*this, resultMIMEType, newSource, resultEncoding))
    5076         return;
    5077     // FIXME: If the transform failed we should probably report an error (like Mozilla does).
    5078     Frame* ownerFrame = frame();
    5079     processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, ownerFrame);
     5076void Document::scheduleToApplyXSLTransforms()
     5077{
     5078    m_hasPendingXSLTransforms = true;
     5079    if (!m_applyPendingXSLTransformsTimer.isActive())
     5080        m_applyPendingXSLTransformsTimer.startOneShot(0_s);
     5081}
     5082
     5083void Document::applyPendingXSLTransformsNowIfScheduled()
     5084{
     5085    if (!m_hasPendingXSLTransforms)
     5086        return;
     5087    m_applyPendingXSLTransformsTimer.stop();
     5088    applyPendingXSLTransformsTimerFired();
     5089}
     5090
     5091void Document::applyPendingXSLTransformsTimerFired()
     5092{
     5093    if (parsing())
     5094        return;
     5095
     5096    m_hasPendingXSLTransforms = false;
     5097    ASSERT(NoEventDispatchAssertion::isEventAllowedInMainThread());
     5098    for (auto& processingInstruction : styleScope().collectXSLTransforms()) {
     5099        ASSERT(processingInstruction->isXSL());
     5100
     5101        // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
     5102        if (transformSourceDocument() || !processingInstruction->sheet())
     5103            return;
     5104
     5105        auto processor = XSLTProcessor::create();
     5106        processor->setXSLStyleSheet(downcast<XSLStyleSheet>(processingInstruction->sheet()));
     5107        String resultMIMEType;
     5108        String newSource;
     5109        String resultEncoding;
     5110        if (!processor->transformToString(*this, resultMIMEType, newSource, resultEncoding))
     5111            continue;
     5112        // FIXME: If the transform failed we should probably report an error (like Mozilla does).
     5113        processor->createDocumentFromSource(newSource, resultEncoding, resultMIMEType, this, frame());
     5114    }
    50805115}
    50815116
     
    52595294    setParsing(false);
    52605295
     5296    Ref<Document> protectedThis(*this);
     5297
    52615298    if (!m_documentTiming.domContentLoadedEventStart)
    52625299        m_documentTiming.domContentLoadedEventStart = MonotonicTime::now();
     
    52685305
    52695306    if (RefPtr<Frame> frame = this->frame()) {
     5307#if ENABLE(XSLT)
     5308        applyPendingXSLTransformsNowIfScheduled();
     5309#endif
     5310
    52705311        // FrameLoader::finishedParsing() might end up calling Document::implicitClose() if all
    52715312        // resource loads are complete. HTMLObjectElements can start loading their resources from
     
    57085749    m_pendingTasksTimer.stop();
    57095750
     5751#if ENABLE(XSLT)
     5752    m_applyPendingXSLTransformsTimer.stop();
     5753#endif
     5754
    57105755    // Deferring loading and suspending parser is necessary when we need to prevent re-entrant JavaScript execution
    57115756    // (e.g. while displaying an alert).
     
    57275772    if (reason == ActiveDOMObject::WillDeferLoading && m_parser)
    57285773        m_parser->resumeScheduledTasks();
     5774
     5775#if ENABLE(XSLT)
     5776    if (m_hasPendingXSLTransforms)
     5777        m_applyPendingXSLTransformsTimer.startOneShot(0_s);
     5778#endif
     5779
    57295780    if (!m_pendingTasks.isEmpty())
    57305781        m_pendingTasksTimer.startOneShot(0_s);
  • trunk/Source/WebCore/dom/Document.h

    r224116 r224146  
    953953
    954954#if ENABLE(XSLT)
    955     void applyXSLTransform(ProcessingInstruction* pi);
     955    void scheduleToApplyXSLTransforms();
     956    void applyPendingXSLTransformsNowIfScheduled();
    956957    RefPtr<Document> transformSourceDocument() { return m_transformSourceDocument; }
    957958    void setTransformSourceDocument(Document* doc) { m_transformSourceDocument = doc; }
     
    15681569
    15691570#if ENABLE(XSLT)
     1571    void applyPendingXSLTransformsTimerFired();
     1572
    15701573    std::unique_ptr<TransformSource> m_transformSource;
    15711574    RefPtr<Document> m_transformSourceDocument;
     1575    Timer m_applyPendingXSLTransformsTimer;
     1576    bool m_hasPendingXSLTransforms { false };
    15721577#endif
    15731578
  • trunk/Source/WebCore/dom/ProcessingInstruction.cpp

    r224116 r224146  
    127127                m_sheet = XSLStyleSheet::createEmbedded(this, finalURL);
    128128                m_loading = false;
     129                document().scheduleToApplyXSLTransforms();
    129130            }
    130131#endif
     
    180181#if ENABLE(XSLT)
    181182                if (m_isXSL)
    182                     document().styleScope().flushPendingUpdate();
     183                    document().scheduleToApplyXSLTransforms();
    183184#endif
    184185            }
     
    203204#if ENABLE(XSLT)
    204205        if (m_isXSL)
    205             document().styleScope().flushPendingUpdate();
     206            document().scheduleToApplyXSLTransforms();
    206207#endif
    207208        return true;
  • trunk/Source/WebCore/style/StyleScope.cpp

    r224116 r224146  
    291291}
    292292
     293#if ENABLE(XSLT)
     294// FIXME: <https://webkit.org/b/178830> Remove XSLT relaed code from Style::Scope.
     295Vector<Ref<ProcessingInstruction>> Scope::collectXSLTransforms()
     296{
     297    Vector<Ref<ProcessingInstruction>> processingInstructions;
     298    for (auto& node : m_styleSheetCandidateNodes) {
     299        if (is<ProcessingInstruction>(*node) && downcast<ProcessingInstruction>(*node).isXSL())
     300            processingInstructions.append(downcast<ProcessingInstruction>(*node));
     301    }
     302    return processingInstructions;
     303}
     304#endif
     305
    293306void Scope::collectActiveStyleSheets(Vector<RefPtr<StyleSheet>>& sheets)
    294307{
     
    297310
    298311    for (auto& node : m_styleSheetCandidateNodes) {
    299         StyleSheet* sheet = nullptr;
     312        RefPtr<StyleSheet> sheet;
    300313        if (is<ProcessingInstruction>(*node)) {
    301             // Processing instruction (XML documents only).
     314            if (!downcast<ProcessingInstruction>(*node).isCSS())
     315                continue;
    302316            // We don't support linking to embedded CSS stylesheets, see <https://bugs.webkit.org/show_bug.cgi?id=49281> for discussion.
    303             ProcessingInstruction& pi = downcast<ProcessingInstruction>(*node);
    304             sheet = pi.sheet();
    305 #if ENABLE(XSLT)
    306             // Don't apply XSL transforms to already transformed documents -- <rdar://problem/4132806>
    307             if (pi.isXSL() && !m_document.transformSourceDocument()) {
    308                 // Don't apply XSL transforms until loading is finished.
    309                 if (!m_document.parsing())
    310                     m_document.applyXSLTransform(&pi);
    311                 return;
    312             }
    313 #endif
     317            sheet = downcast<ProcessingInstruction>(*node).sheet();
    314318        } else if (is<HTMLLinkElement>(*node) || is<HTMLStyleElement>(*node) || is<SVGStyleElement>(*node)) {
    315319            Element& element = downcast<Element>(*node);
     
    365369        }
    366370        if (sheet)
    367             sheets.append(sheet);
     371            sheets.append(WTFMove(sheet));
    368372    }
    369373}
  • trunk/Source/WebCore/style/StyleScope.h

    r224116 r224146  
    109109    void flushPendingUpdate();
    110110
     111#if ENABLE(XSLT)
     112    Vector<Ref<ProcessingInstruction>> collectXSLTransforms();
     113#endif
     114
    111115    StyleResolver& resolver();
    112116    StyleResolver* resolverIfExists();
  • trunk/Source/WebCore/xml/parser/XMLDocumentParserLibxml2.cpp

    r224116 r224146  
    13341334
    13351335        document()->setParsing(false); // Make the document think it's done, so it will apply XSL stylesheets.
    1336         document()->styleScope().didChangeActiveStyleSheetCandidates();
     1336        document()->applyPendingXSLTransformsNowIfScheduled();
    13371337
    13381338        // styleResolverChanged() call can detach the parser and null out its document.
Note: See TracChangeset for help on using the changeset viewer.