Vector<Action> ContentExtensionsBackend::actionsForResourceLoad(const ResourceLoadInfo& resourceLoadInfo) const
{
#if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
    double addedTimeStart = monotonicallyIncreasingTime();
#endif
    if (resourceLoadInfo.resourceURL.protocolIsData())
        return Vector<Action>();

    const String& urlString = resourceLoadInfo.resourceURL.string();
    ASSERT_WITH_MESSAGE(urlString.containsOnlyASCII(), "A decoded URL should only contain ASCII characters. The matching algorithm assumes the input is ASCII.");
    const CString& urlCString = urlString.utf8();

    Vector<Action> finalActions;
    ResourceFlags flags = resourceLoadInfo.getResourceFlags();
    for (auto& contentExtension : m_contentExtensions.values()) {
        RELEASE_ASSERT(contentExtension);
        const CompiledContentExtension& compiledExtension = contentExtension->compiledExtension();
        
        DFABytecodeInterpreter withoutDomainsInterpreter(compiledExtension.filtersWithoutDomainsBytecode(), compiledExtension.filtersWithoutDomainsBytecodeLength());
        DFABytecodeInterpreter::Actions withoutDomainsActions = withoutDomainsInterpreter.interpret(urlCString, flags);
        
        String domain = resourceLoadInfo.mainDocumentURL.host();
        DFABytecodeInterpreter withDomainsInterpreter(compiledExtension.filtersWithDomainsBytecode(), compiledExtension.filtersWithDomainsBytecodeLength());
        DFABytecodeInterpreter::Actions withDomainsActions = withDomainsInterpreter.interpretWithDomains(urlCString, flags, contentExtension->cachedDomainActions(domain));
        
        const SerializedActionByte* actions = compiledExtension.actions();
        const unsigned actionsLength = compiledExtension.actionsLength();
        
        bool sawIgnorePreviousRules = false;
        const Vector<uint32_t>& universalWithDomains = contentExtension->universalActionsWithDomains(domain);
        const Vector<uint32_t>& universalWithoutDomains = contentExtension->universalActionsWithoutDomains();
        if (!withoutDomainsActions.isEmpty() || !withDomainsActions.isEmpty() || !universalWithDomains.isEmpty() || !universalWithoutDomains.isEmpty()) {
            Vector<uint32_t> actionLocations;
            actionLocations.reserveInitialCapacity(withoutDomainsActions.size() + withDomainsActions.size() + universalWithoutDomains.size() + universalWithDomains.size());
            for (uint64_t actionLocation : withoutDomainsActions)
                actionLocations.uncheckedAppend(static_cast<uint32_t>(actionLocation));
            for (uint64_t actionLocation : withDomainsActions)
                actionLocations.uncheckedAppend(static_cast<uint32_t>(actionLocation));
            for (uint32_t actionLocation : universalWithoutDomains)
                actionLocations.uncheckedAppend(actionLocation);
            for (uint32_t actionLocation : universalWithDomains)
                actionLocations.uncheckedAppend(actionLocation);
            std::sort(actionLocations.begin(), actionLocations.end());

            // Add actions in reverse order to properly deal with IgnorePreviousRules.
            for (unsigned i = actionLocations.size(); i; i--) {
                Action action = Action::deserialize(actions, actionsLength, actionLocations[i - 1]);
                action.setExtensionIdentifier(contentExtension->identifier());
                if (action.type() == ActionType::IgnorePreviousRules) {
                    sawIgnorePreviousRules = true;
                    break;
                }
                finalActions.append(action);
            }
        }
        if (!sawIgnorePreviousRules) {
            finalActions.append(Action(ActionType::CSSDisplayNoneStyleSheet, contentExtension->identifier()));
            finalActions.last().setExtensionIdentifier(contentExtension->identifier());
        }
    }
#if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
    double addedTimeEnd = monotonicallyIncreasingTime();
    dataLogF("Time added: %f microseconds %s \n", (addedTimeEnd - addedTimeStart) * 1.0e6, resourceLoadInfo.resourceURL.string().utf8().data());
#endif
    return finalActions;
}
Vector<Action> ContentExtensionsBackend::actionsForResourceLoad(const ResourceLoadInfo& resourceLoadInfo) const
{
#if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
    double addedTimeStart = monotonicallyIncreasingTime();
#endif
    if (resourceLoadInfo.resourceURL.protocolIsData())
        return Vector<Action>();

    const String& urlString = resourceLoadInfo.resourceURL.string();
    ASSERT_WITH_MESSAGE(urlString.containsOnlyASCII(), "A decoded URL should only contain ASCII characters. The matching algorithm assumes the input is ASCII.");
    const CString& urlCString = urlString.utf8();

    Vector<Action> finalActions;
    ResourceFlags flags = resourceLoadInfo.getResourceFlags();
    for (auto& contentExtension : m_contentExtensions.values()) {
        RELEASE_ASSERT(contentExtension);
        const CompiledContentExtension& compiledExtension = contentExtension->compiledExtension();
        
        // FIXME: These should use a different Vector<bool> to keep track of which memory pages are used when doing memory reporting. Or just remove the memory reporting completely.
        DFABytecodeInterpreter withoutDomainsInterpreter(compiledExtension.filtersWithoutDomainsBytecode(), compiledExtension.filtersWithoutDomainsBytecodeLength(), contentExtension->m_pagesUsed);
        DFABytecodeInterpreter::Actions triggeredActions = withoutDomainsInterpreter.interpret(urlCString, flags);
        
        // Check to see if there are any actions triggered with if- or unless-domain and check the domain if there are.
        DFABytecodeInterpreter withDomainsInterpreter(compiledExtension.filtersWithDomainsBytecode(), compiledExtension.filtersWithDomainsBytecodeLength(), contentExtension->m_pagesUsed);
        
        DFABytecodeInterpreter::Actions withDomainsPossibleActions = withDomainsInterpreter.interpret(urlCString, flags);
        if (!withDomainsPossibleActions.isEmpty()) {
            DFABytecodeInterpreter domainsInterpreter(compiledExtension.domainFiltersBytecode(), compiledExtension.domainFiltersBytecodeLength(), contentExtension->m_pagesUsed);
            DFABytecodeInterpreter::Actions domainsActions = domainsInterpreter.interpret(resourceLoadInfo.mainDocumentURL.host().utf8(), flags);
            
            DFABytecodeInterpreter::Actions ifDomainActions;
            DFABytecodeInterpreter::Actions unlessDomainActions;
            for (uint64_t action : domainsActions) {
                if (action & IfDomainFlag)
                    ifDomainActions.add(action);
                else
                    unlessDomainActions.add(action);
            }
            
            for (uint64_t action : withDomainsPossibleActions) {
                if (ifDomainActions.contains(action)) {
                    // If an if-domain trigger matches, add the action.
                    ASSERT(action & IfDomainFlag);
                    triggeredActions.add(action & ~IfDomainFlag);
                } else if (!(action & IfDomainFlag) && !unlessDomainActions.contains(action)) {
                    // If this action did not need an if-domain, it must have been an unless-domain rule.
                    // Add the action unless it matched an unless-domain trigger.
                    triggeredActions.add(action);
                }
            }
        }
        
        const SerializedActionByte* actions = compiledExtension.actions();
        const unsigned actionsLength = compiledExtension.actionsLength();
        
        bool sawIgnorePreviousRules = false;
        if (!triggeredActions.isEmpty()) {
            Vector<unsigned> actionLocations;
            actionLocations.reserveInitialCapacity(triggeredActions.size());
            for (auto actionLocation : triggeredActions)
                actionLocations.append(static_cast<unsigned>(actionLocation));
            std::sort(actionLocations.begin(), actionLocations.end());

            // Add actions in reverse order to properly deal with IgnorePreviousRules.
            for (unsigned i = actionLocations.size(); i; i--) {
                Action action = Action::deserialize(actions, actionsLength, actionLocations[i - 1]);
                action.setExtensionIdentifier(contentExtension->identifier());
                if (action.type() == ActionType::IgnorePreviousRules) {
                    sawIgnorePreviousRules = true;
                    break;
                }
                finalActions.append(action);
            }
        }
        if (!sawIgnorePreviousRules) {
            finalActions.append(Action(ActionType::CSSDisplayNoneStyleSheet, contentExtension->identifier()));
            finalActions.last().setExtensionIdentifier(contentExtension->identifier());
        }
    }
#if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
    double addedTimeEnd = monotonicallyIncreasingTime();
    WTFLogAlways("Time added: %f microseconds %s", (addedTimeEnd - addedTimeStart) * 1.0e6, resourceLoadInfo.resourceURL.string().utf8().data());
#endif
    return finalActions;
}
Vector<Action> ContentExtensionsBackend::actionsForResourceLoad(const ResourceLoadInfo& resourceLoadInfo) const
{
#if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
    double addedTimeStart = monotonicallyIncreasingTime();
#endif
    if (resourceLoadInfo.resourceURL.protocolIsData())
        return Vector<Action>();

    const String& urlString = resourceLoadInfo.resourceURL.string();
    ASSERT_WITH_MESSAGE(urlString.containsOnlyASCII(), "A decoded URL should only contain ASCII characters. The matching algorithm assumes the input is ASCII.");
    const CString& urlCString = urlString.utf8();

    Vector<Action> finalActions;
    ResourceFlags flags = resourceLoadInfo.getResourceFlags();
    for (auto& contentExtension : m_contentExtensions.values()) {
        RELEASE_ASSERT(contentExtension);
        const CompiledContentExtension& compiledExtension = contentExtension->compiledExtension();
        DFABytecodeInterpreter interpreter(compiledExtension.bytecode(), compiledExtension.bytecodeLength(), contentExtension->m_pagesUsed);
        DFABytecodeInterpreter::Actions triggeredActions = interpreter.interpret(urlCString, flags);
        
        const SerializedActionByte* actions = compiledExtension.actions();
        const unsigned actionsLength = compiledExtension.actionsLength();
        
        bool sawIgnorePreviousRules = false;
        if (!triggeredActions.isEmpty()) {
            Vector<unsigned> actionLocations;
            actionLocations.reserveInitialCapacity(triggeredActions.size());
            for (auto actionLocation : triggeredActions)
                actionLocations.append(static_cast<unsigned>(actionLocation));
            std::sort(actionLocations.begin(), actionLocations.end());

            // Add actions in reverse order to properly deal with IgnorePreviousRules.
            for (unsigned i = actionLocations.size(); i; i--) {
                Action action = Action::deserialize(actions, actionsLength, actionLocations[i - 1]);
                action.setExtensionIdentifier(contentExtension->identifier());
                if (action.type() == ActionType::IgnorePreviousRules) {
                    sawIgnorePreviousRules = true;
                    break;
                }
                finalActions.append(action);
            }
        }
        if (!sawIgnorePreviousRules) {
            DFABytecodeInterpreter::Actions universalActions = interpreter.actionsFromDFARoot();
            for (auto actionLocation : universalActions) {
                Action action = Action::deserialize(actions, actionsLength, static_cast<unsigned>(actionLocation));
                action.setExtensionIdentifier(contentExtension->identifier());

                // CSS selectors were already compiled into a stylesheet using globalDisplayNoneSelectors.
                if (action.type() != ActionType::CSSDisplayNoneSelector)
                    finalActions.append(action);
            }
            finalActions.append(Action(ActionType::CSSDisplayNoneStyleSheet, contentExtension->identifier()));
            finalActions.last().setExtensionIdentifier(contentExtension->identifier());
        }
    }
#if CONTENT_EXTENSIONS_PERFORMANCE_REPORTING
    double addedTimeEnd = monotonicallyIncreasingTime();
    WTFLogAlways("Time added: %f microseconds %s", (addedTimeEnd - addedTimeStart) * 1.0e6, resourceLoadInfo.resourceURL.string().utf8().data());
#endif
    return finalActions;
}