Exemple #1
0
void ScriptElement::executeScriptForScriptRunner(PendingScript& pendingScript)
{
    if (auto* loadableScript = pendingScript.loadableScript())
        executeScriptAndDispatchEvent(*loadableScript);
    else {
        ASSERT(!pendingScript.wasErrored());
        executeScript(ScriptSourceCode(scriptContent(), m_element.document().url(), pendingScript.startingPosition()));
        dispatchLoadEvent();
    }
}
// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script
bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes)
{
    if (m_alreadyStarted)
        return false;

    ScriptLoaderClient* client = this->client();

    bool wasParserInserted;
    if (m_parserInserted) {
        wasParserInserted = true;
        m_parserInserted = false;
    } else {
        wasParserInserted = false;
    }

    if (wasParserInserted && !client->asyncAttributeValue())
        m_forceAsync = true;

    // FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes.
    if (!client->hasSourceAttribute() && !m_element->hasChildren())
        return false;

    if (!m_element->inDocument())
        return false;

    if (!isScriptTypeSupported(supportLegacyTypes))
        return false;

    if (wasParserInserted) {
        m_parserInserted = true;
        m_forceAsync = false;
    }

    m_alreadyStarted = true;

    // FIXME: If script is parser inserted, verify it's still in the original document.
    Document& elementDocument = m_element->document();
    Document* contextDocument = elementDocument.contextDocument().get();

    if (!contextDocument || !contextDocument->allowExecutingScripts(m_element))
        return false;

    if (!isScriptForEventSupported())
        return false;

    if (!client->charsetAttributeValue().isEmpty())
        m_characterEncoding = client->charsetAttributeValue();
    else
        m_characterEncoding = elementDocument.characterSet();

    if (client->hasSourceAttribute()) {
        FetchRequest::DeferOption defer = FetchRequest::NoDefer;
        if (!m_parserInserted || client->asyncAttributeValue() || client->deferAttributeValue())
            defer = FetchRequest::LazyLoad;
        if (!fetchScript(client->sourceAttributeValue(), defer))
            return false;
    }

    if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parserInserted && !client->asyncAttributeValue()) {
        m_willExecuteWhenDocumentFinishedParsing = true;
        m_willBeParserExecuted = true;
    } else if (client->hasSourceAttribute() && m_parserInserted && !client->asyncAttributeValue()) {
        m_willBeParserExecuted = true;
    } else if (!client->hasSourceAttribute() && m_parserInserted && !elementDocument.isRenderingReady()) {
        m_willBeParserExecuted = true;
        m_readyToBeParserExecuted = true;
    } else if (client->hasSourceAttribute() && !client->asyncAttributeValue() && !m_forceAsync) {
        m_willExecuteInOrder = true;
        m_pendingScript = PendingScript(m_element, m_resource.get());
        contextDocument->scriptRunner()->queueScriptForExecution(this, ScriptRunner::IN_ORDER_EXECUTION);
        // Note that watchForLoad can immediately call notifyFinished.
        m_pendingScript.watchForLoad(this);
    } else if (client->hasSourceAttribute()) {
        m_pendingScript = PendingScript(m_element, m_resource.get());
        LocalFrame* frame = m_element->document().frame();
        if (frame) {
            ScriptState* scriptState = ScriptState::forMainWorld(frame);
            if (scriptState->contextIsValid())
                ScriptStreamer::startStreaming(m_pendingScript, PendingScript::Async, frame->settings(), scriptState, frame->frameScheduler()->loadingTaskRunner());
        }
        contextDocument->scriptRunner()->queueScriptForExecution(this, ScriptRunner::ASYNC_EXECUTION);
        // Note that watchForLoad can immediately call notifyFinished.
        m_pendingScript.watchForLoad(this);
    } else {
        // Reset line numbering for nested writes.
        TextPosition position = elementDocument.isInDocumentWrite() ? TextPosition() : scriptStartPosition;
        KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInserted) ? elementDocument.url() : KURL();
        if (!executeScript(ScriptSourceCode(scriptContent(), scriptURL, position))) {
            dispatchErrorEvent();
            return false;
        }
    }

    return true;
}
Exemple #3
0
// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script
bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition,
                                 LegacyTypeSupport supportLegacyTypes) {
    if (m_alreadyStarted)
        return false;

    ScriptLoaderClient* client = this->client();

    bool wasParserInserted;
    if (m_parserInserted) {
        wasParserInserted = true;
        m_parserInserted = false;
    } else {
        wasParserInserted = false;
    }

    if (wasParserInserted && !client->asyncAttributeValue())
        m_forceAsync = true;

    // FIXME: HTML5 spec says we should check that all children are either
    // comments or empty text nodes.
    if (!client->hasSourceAttribute() && !m_element->hasChildren())
        return false;

    if (!m_element->isConnected())
        return false;

    if (!isScriptTypeSupported(supportLegacyTypes))
        return false;

    if (wasParserInserted) {
        m_parserInserted = true;
        m_forceAsync = false;
    }

    m_alreadyStarted = true;

    // FIXME: If script is parser inserted, verify it's still in the original
    // document.
    Document& elementDocument = m_element->document();
    Document* contextDocument = elementDocument.contextDocument();

    if (!contextDocument || !contextDocument->allowExecutingScripts(m_element))
        return false;

    if (!isScriptForEventSupported())
        return false;

    if (!client->charsetAttributeValue().isEmpty())
        m_characterEncoding = client->charsetAttributeValue();
    else
        m_characterEncoding = elementDocument.characterSet();

    if (client->hasSourceAttribute()) {
        FetchRequest::DeferOption defer = FetchRequest::NoDefer;
        if (!m_parserInserted || client->asyncAttributeValue() ||
                client->deferAttributeValue())
            defer = FetchRequest::LazyLoad;
        if (m_documentWriteIntervention ==
                DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle)
            defer = FetchRequest::IdleLoad;
        if (!fetchScript(client->sourceAttributeValue(), defer))
            return false;
    }

    // Since the asynchronous, low priority fetch for doc.written blocked
    // script is not for execution, return early from here. Watch for its
    // completion to be able to remove it from the memory cache.
    if (m_documentWriteIntervention ==
            DocumentWriteIntervention::FetchDocWrittenScriptDeferIdle) {
        m_pendingScript = PendingScript::create(m_element, m_resource.get());
        m_pendingScript->watchForLoad(this);
        return true;
    }

    if (client->hasSourceAttribute() && client->deferAttributeValue() &&
            m_parserInserted && !client->asyncAttributeValue()) {
        m_willExecuteWhenDocumentFinishedParsing = true;
        m_willBeParserExecuted = true;
    } else if (client->hasSourceAttribute() && m_parserInserted &&
               !client->asyncAttributeValue()) {
        m_willBeParserExecuted = true;
    } else if (!client->hasSourceAttribute() && m_parserInserted &&
               !elementDocument.isScriptExecutionReady()) {
        m_willBeParserExecuted = true;
        m_readyToBeParserExecuted = true;
    } else if (client->hasSourceAttribute() && !client->asyncAttributeValue() &&
               !m_forceAsync) {
        m_pendingScript = PendingScript::create(m_element, m_resource.get());
        m_asyncExecType = ScriptRunner::InOrder;
        contextDocument->scriptRunner()->queueScriptForExecution(this,
                m_asyncExecType);
        // Note that watchForLoad can immediately call notifyFinished.
        m_pendingScript->watchForLoad(this);
    } else if (client->hasSourceAttribute()) {
        m_pendingScript = PendingScript::create(m_element, m_resource.get());
        m_asyncExecType = ScriptRunner::Async;
        LocalFrame* frame = m_element->document().frame();
        if (frame) {
            ScriptState* scriptState = ScriptState::forMainWorld(frame);
            if (scriptState)
                ScriptStreamer::startStreaming(
                    m_pendingScript.get(), ScriptStreamer::Async, frame->settings(),
                    scriptState, frame->frameScheduler()->loadingTaskRunner());
        }
        contextDocument->scriptRunner()->queueScriptForExecution(this,
                m_asyncExecType);
        // Note that watchForLoad can immediately call notifyFinished.
        m_pendingScript->watchForLoad(this);
    } else {
        // Reset line numbering for nested writes.
        TextPosition position = elementDocument.isInDocumentWrite()
                                ? TextPosition()
                                : scriptStartPosition;
        KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInserted)
                         ? elementDocument.url()
                         : KURL();
        if (!executeScript(
                    ScriptSourceCode(scriptContent(), scriptURL, position))) {
            dispatchErrorEvent();
            return false;
        }
    }

    return true;
}
Exemple #4
0
// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script
bool ScriptElement::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes)
{
    if (m_alreadyStarted)
        return false;

    bool wasParserInserted;
    if (m_parserInserted) {
        wasParserInserted = true;
        m_parserInserted = false;
    } else
        wasParserInserted = false;

    if (wasParserInserted && !asyncAttributeValue())
        m_forceAsync = true;

    // FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes.
    if (!hasSourceAttribute() && !m_element->firstChild())
        return false;

    if (!m_element->inDocument())
        return false;

    if (!isScriptTypeSupported(supportLegacyTypes))
        return false;

    if (wasParserInserted) {
        m_parserInserted = true;
        m_forceAsync = false;
    }

    m_alreadyStarted = true;

    // FIXME: If script is parser inserted, verify it's still in the original document.
    Document* document = m_element->document();

    // FIXME: Eventually we'd like to evaluate scripts which are inserted into a
    // viewless document but this'll do for now.
    // See http://bugs.webkit.org/show_bug.cgi?id=5727
    if (!document->frame())
        return false;

    if (!document->frame()->script()->canExecuteScripts(AboutToExecuteScript))
        return false;

    if (!isScriptForEventSupported())
        return false;

    if (!charsetAttributeValue().isEmpty())
        m_characterEncoding = charsetAttributeValue();
    else
        m_characterEncoding = document->charset();

    if (hasSourceAttribute())
        if (!requestScript(sourceAttributeValue()))
            return false;

    if (hasSourceAttribute() && deferAttributeValue() && m_parserInserted && !asyncAttributeValue()) {
        m_willExecuteWhenDocumentFinishedParsing = true;
        m_willBeParserExecuted = true;
    } else if (hasSourceAttribute() && m_parserInserted && !asyncAttributeValue())
        m_willBeParserExecuted = true;
    else if (!hasSourceAttribute() && m_parserInserted && !document->haveStylesheetsLoaded()) {
        m_willBeParserExecuted = true;
        m_readyToBeParserExecuted = true;
    } else if (hasSourceAttribute() && !asyncAttributeValue() && !m_forceAsync) {
        m_willExecuteInOrder = true;
        document->scriptRunner()->queueScriptForExecution(this, m_cachedScript, ScriptRunner::IN_ORDER_EXECUTION);
        m_cachedScript->addClient(this);
    } else if (hasSourceAttribute()) {
        m_element->document()->scriptRunner()->queueScriptForExecution(this, m_cachedScript, ScriptRunner::ASYNC_EXECUTION);
        m_cachedScript->addClient(this);
    } else {
        // Reset line numbering for nested writes.
        TextPosition position = document->isInDocumentWrite() ? TextPosition() : scriptStartPosition;
        executeScript(ScriptSourceCode(scriptContent(), document->url(), position));
    }

    return true;
}
Exemple #5
0
nsresult
nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
                               const nsAFlatString& aScript)
{
    nsresult rv = NS_OK;

    // We need a document to evaluate scripts.
    if (!mDocument) {
        return NS_ERROR_FAILURE;
    }

    nsPIDOMWindow *pwin = mDocument->GetInnerWindow();
    if (!pwin || !pwin->IsInnerWindow()) {
        return NS_ERROR_FAILURE;
    }
    nsCOMPtr<nsIScriptGlobalObject> globalObject = do_QueryInterface(pwin);
    NS_ASSERTION(globalObject, "windows must be global objects");

    // Get the script-type to be used by this element.
    nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(aRequest->mElement));
    NS_ASSERTION(scriptContent, "no content - what is default script-type?");
    PRUint32 stid = scriptContent ? scriptContent->GetScriptTypeID() :
                    nsIProgrammingLanguage::JAVASCRIPT;
    // and make sure we are setup for this type of script.
    rv = globalObject->EnsureScriptEnvironment(stid);
    if (NS_FAILED(rv))
        return rv;

    // Make sure context is a strong reference since we access it after
    // we've executed a script, which may cause all other references to
    // the context to go away.
    nsCOMPtr<nsIScriptContext> context = globalObject->GetScriptContext(stid);
    if (!context) {
        return NS_ERROR_FAILURE;
    }

    nsCAutoString url;

    nsIURI* uri = aRequest->mFinalURI ? aRequest->mFinalURI : aRequest->mURI;
    rv = uri->GetSpec(url);
    if (NS_FAILED(rv)) {
        return rv;
    }

    PRBool oldProcessingScriptTag = context->GetProcessingScriptTag();
    context->SetProcessingScriptTag(PR_TRUE);

    // Update our current script.
    nsCOMPtr<nsIScriptElement> oldCurrent = mCurrentScript;
    mCurrentScript = aRequest->mElement;

    PRBool isUndefined;
    rv = context->EvaluateString(aScript,
                                 globalObject->GetScriptGlobal(stid),
                                 mDocument->NodePrincipal(), url.get(),
                                 aRequest->mLineNo, aRequest->mJSVersion, nsnull,
                                 &isUndefined);

    // Put the old script back in case it wants to do anything else.
    mCurrentScript = oldCurrent;

    JSContext *cx = nsnull; // Initialize this to keep GCC happy.
    if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
        cx = (JSContext *)context->GetNativeContext();
        ::JS_BeginRequest(cx);
        ::JS_ReportPendingException(cx);
    }

    context->SetProcessingScriptTag(oldProcessingScriptTag);

    if (stid == nsIProgrammingLanguage::JAVASCRIPT) {
        nsAXPCNativeCallContext *ncc = nsnull;
        nsContentUtils::XPConnect()->
        GetCurrentNativeCallContext(&ncc);

        if (ncc) {
            NS_ASSERTION(!::JS_IsExceptionPending(cx),
                         "JS_ReportPendingException wasn't called");
            ncc->SetExceptionWasThrown(PR_FALSE);
        }
        ::JS_EndRequest(cx);
    }
    return rv;
}
Exemple #6
0
// http://dev.w3.org/html5/spec/Overview.html#prepare-a-script
bool ScriptLoader::prepareScript(const TextPosition& scriptStartPosition, LegacyTypeSupport supportLegacyTypes)
{
    if (m_alreadyStarted)
        return false;

    ScriptLoaderClient* client = this->client();

    bool wasParserInserted;
    if (m_parserInserted) {
        wasParserInserted = true;
        m_parserInserted = false;
    } else {
        wasParserInserted = false;
    }

    if (wasParserInserted && !client->asyncAttributeValue())
        m_forceAsync = true;

    // FIXME: HTML5 spec says we should check that all children are either comments or empty text nodes.
    if (!client->hasSourceAttribute() && !m_element->firstChild())
        return false;

    if (!m_element->inDocument())
        return false;

    if (!isScriptTypeSupported(supportLegacyTypes))
        return false;

    if (wasParserInserted) {
        m_parserInserted = true;
        m_forceAsync = false;
    }

    m_alreadyStarted = true;

    // FIXME: If script is parser inserted, verify it's still in the original document.
    Document& elementDocument = m_element->document();
    Document* contextDocument = elementDocument.contextDocument().get();

    if (!contextDocument || !contextDocument->allowExecutingScripts(m_element))
        return false;

    if (!isScriptForEventSupported())
        return false;

    if (!client->charsetAttributeValue().isEmpty())
        m_characterEncoding = client->charsetAttributeValue();
    else
        m_characterEncoding = elementDocument.charset();

    if (client->hasSourceAttribute()) {
        if (!fetchScript(client->sourceAttributeValue()))
            return false;
    }

    if (client->hasSourceAttribute() && client->deferAttributeValue() && m_parserInserted && !client->asyncAttributeValue()) {
        m_willExecuteWhenDocumentFinishedParsing = true;
        m_willBeParserExecuted = true;
    } else if (client->hasSourceAttribute() && m_parserInserted && !client->asyncAttributeValue()) {
        m_willBeParserExecuted = true;
    } else if (!client->hasSourceAttribute() && m_parserInserted && !elementDocument.isRenderingReady()) {
        m_willBeParserExecuted = true;
        m_readyToBeParserExecuted = true;
    } else if (client->hasSourceAttribute() && !client->asyncAttributeValue() && !m_forceAsync) {
        m_willExecuteInOrder = true;
        contextDocument->scriptRunner()->queueScriptForExecution(this, m_resource, ScriptRunner::IN_ORDER_EXECUTION);
        m_resource->addClient(this);
    } else if (client->hasSourceAttribute()) {
        contextDocument->scriptRunner()->queueScriptForExecution(this, m_resource, ScriptRunner::ASYNC_EXECUTION);
        m_resource->addClient(this);
    } else {
        // Reset line numbering for nested writes.
        TextPosition position = elementDocument.isInDocumentWrite() ? TextPosition() : scriptStartPosition;
        KURL scriptURL = (!elementDocument.isInDocumentWrite() && m_parserInserted) ? elementDocument.url() : KURL();
        executeScript(ScriptSourceCode(scriptContent(), scriptURL, position));
    }

    return true;
}