JSValue JSInspectorFrontendHost::search(ExecState* exec, const ArgList& args)
{
    if (args.size() < 2)
        return jsUndefined();

    Node* node = toNode(args.at(0));
    if (!node)
        return jsUndefined();

    String target = args.at(1).toString(exec);
    if (exec->hadException())
        return jsUndefined();

    MarkedArgumentBuffer result;
    RefPtr<Range> searchRange(rangeOfContents(node));

    ExceptionCode ec = 0;
    do {
        RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
        if (resultRange->collapsed(ec))
            break;

        // A non-collapsed result range can in some funky whitespace cases still not
        // advance the range's start position (4509328). Break to avoid infinite loop.
        VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
        if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
            break;

        result.append(toJS(exec, resultRange.get()));

        setStart(searchRange.get(), newStart);
    } while (true);

    return constructArray(exec, result);
}
static JSValueRef search(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/)
{
    InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject));
    if (!controller)
        return JSValueMakeUndefined(ctx);

    if (argumentCount < 2 || !JSValueIsString(ctx, arguments[1]))
        return JSValueMakeUndefined(ctx);

    Node* node = toNode(toJS(arguments[0]));
    if (!node)
        return JSValueMakeUndefined(ctx);

    JSStringRef string = JSValueToStringCopy(ctx, arguments[1], 0);
    String target(JSStringGetCharactersPtr(string), JSStringGetLength(string));
    JSStringRelease(string);

    JSObjectRef globalObject = JSContextGetGlobalObject(ctx);
    JSStringRef constructorString = JSStringCreateWithUTF8CString("Array");
    JSObjectRef arrayConstructor = JSValueToObject(ctx, JSObjectGetProperty(ctx, globalObject, constructorString, 0), 0);
    JSStringRelease(constructorString);
    JSObjectRef array = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, 0);

    JSStringRef pushString = JSStringCreateWithUTF8CString("push");
    JSValueRef pushValue = JSObjectGetProperty(ctx, array, pushString, 0);
    JSStringRelease(pushString);
    JSObjectRef push = JSValueToObject(ctx, pushValue, 0);

    RefPtr<Range> searchRange(rangeOfContents(node));

    int exception = 0;
    do {
        RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
        if (resultRange->collapsed(exception))
            break;

        // A non-collapsed result range can in some funky whitespace cases still not
        // advance the range's start position (4509328). Break to avoid infinite loop.
        VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
        if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
            break;

        KJS::JSLock lock;
        JSValueRef arg0 = toRef(toJS(toJS(ctx), resultRange.get()));
        JSObjectCallAsFunction(ctx, push, array, 1, &arg0, 0);

        setStart(searchRange.get(), newStart);
    } while (true);

    return array;
}
示例#3
0
void InPageSearchManager::scopeStringMatches(const String& text, bool reset, bool locateActiveMatchOnly, Frame* scopingFrame)
{
    if (reset) {
        if (!locateActiveMatchOnly) {
            m_activeMatchCount = 0;
            m_scopingComplete = false;
        }
        m_resumeScopingFromRange = 0;
        m_locatingActiveMatch = true;
        m_activeMatchIndex = 0;
        // New search should always start from mainFrame.
        scopeStringMatchesSoon(m_webPage->mainFrame(), text, false /* reset */, locateActiveMatchOnly);
        return;
    }

    if (m_resumeScopingFromRange && scopingFrame != m_resumeScopingFromRange->ownerDocument().frame())
        m_resumeScopingFromRange = 0;

    RefPtr<Range> searchRange(rangeOfContents(scopingFrame->document()));
    Node* originalEndContainer = searchRange->endContainer();
    int originalEndOffset = searchRange->endOffset();
    ExceptionCode ec = 0, ec2 = 0;
    if (m_resumeScopingFromRange) {
        searchRange->setStart(m_resumeScopingFromRange->startContainer(), m_resumeScopingFromRange->startOffset(ec2) + 1, ec);
        if (ec || ec2) {
            m_scopingComplete = true; // We should stop scoping because of some stale data.
            return;
        }
    }

    int matchCount = 0;
    bool timeout = false;
    double startTime = currentTime();
    do {
        RefPtr<Range> resultRange(findPlainText(searchRange.get(), text, m_scopingCaseInsensitive ? CaseInsensitive : 0));
        if (resultRange->collapsed(ec)) {
            if (!resultRange->startContainer()->isInShadowTree())
                break;
            searchRange->setStartAfter(resultRange->startContainer()->deprecatedShadowAncestorNode(), ec);
            searchRange->setEnd(originalEndContainer, originalEndOffset, ec);
            continue;
        }

        ++matchCount;
        bool foundActiveMatch = false;
        if (m_locatingActiveMatch && areRangesEqual(resultRange.get(), m_activeMatch.get())) {
            foundActiveMatch = true;
            m_locatingActiveMatch = false;
            if (locateActiveMatchOnly) {
                m_activeMatchIndex += matchCount;
                m_webPage->m_client->updateFindStringResult(m_activeMatchCount, m_activeMatchIndex);
                return;
            }
            m_activeMatchIndex = m_activeMatchCount + matchCount;
        }
        if (!locateActiveMatchOnly && m_highlightAllMatches)
            resultRange->ownerDocument().markers().addTextMatchMarker(resultRange.get(), foundActiveMatch);

        searchRange->setStart(resultRange->endContainer(ec), resultRange->endOffset(ec), ec);
        ShadowRoot* shadowTreeRoot = searchRange->shadowRoot();
        if (searchRange->collapsed(ec) && shadowTreeRoot)
            searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
        m_resumeScopingFromRange = resultRange;
        timeout = (currentTime() - startTime) >= MaxScopingDuration;
    } while (!timeout);

    if (matchCount > 0) {
        if (locateActiveMatchOnly) {
            // We have not found it yet.
            // m_activeMatchIndex now temporarily remember where we left over in this time slot.
            m_activeMatchIndex += matchCount;
        } else {
            if (m_highlightAllMatches)
                scopingFrame->editor().setMarkedTextMatchesAreHighlighted(true /* highlight */);
            m_activeMatchCount += matchCount;
            m_webPage->m_client->updateFindStringResult(m_activeMatchCount, m_activeMatchIndex);
        }
    }

    if (timeout)
        scopeStringMatchesSoon(scopingFrame, text, false /* reset */, locateActiveMatchOnly);
    else {
        // Scoping is done for this frame.
        Frame* nextFrame = DOMSupport::incrementFrame(scopingFrame, true /* forward */, false /* wrapFlag */);
        if (!nextFrame) {
            m_scopingComplete = true;
            return; // Scoping is done for all frames;
        }
        scopeStringMatchesSoon(nextFrame, text, false /* reset */, locateActiveMatchOnly);
    }
}
示例#4
0
void InPageSearchManager::scopeStringMatches(const String& text, bool reset, Frame* scopingFrame)
{
    if (reset) {
        m_activeMatchCount = 0;
        m_resumeScopingFromRange = 0;
        m_scopingComplete = false;
        m_locatingActiveMatch = true;
        // New search should always start from mainFrame.
        scopeStringMatchesSoon(m_webPage->mainFrame(), text, false /* reset */);
        return;
    }

    if (m_resumeScopingFromRange && scopingFrame != m_resumeScopingFromRange->ownerDocument()->frame())
        m_resumeScopingFromRange = 0;

    RefPtr<Range> searchRange(rangeOfContents(scopingFrame->document()));
    Node* originalEndContainer = searchRange->endContainer();
    int originalEndOffset = searchRange->endOffset();
    ExceptionCode ec = 0, ec2 = 0;
    if (m_resumeScopingFromRange) {
        searchRange->setStart(m_resumeScopingFromRange->startContainer(), m_resumeScopingFromRange->startOffset(ec2) + 1, ec);
        if (ec || ec2) {
            m_scopingComplete = true; // We should stop scoping because of some stale data.
            return;
        }
    }

    int matchCount = 0;
    bool timeout = false;
    double startTime = currentTime();
    do {
        RefPtr<Range> resultRange(findPlainText(searchRange.get(), text, CaseInsensitive));
        if (resultRange->collapsed(ec)) {
            if (!resultRange->startContainer()->isInShadowTree())
                break;
            searchRange->setStartAfter(resultRange->startContainer()->shadowAncestorNode(), ec);
            searchRange->setEnd(originalEndContainer, originalEndOffset, ec);
            continue;
        }

        if (scopingFrame->editor()->insideVisibleArea(resultRange.get())) {
            ++matchCount;
            bool foundActiveMatch = false;
            if (m_locatingActiveMatch && areRangesEqual(resultRange.get(), m_activeMatch.get())) {
                foundActiveMatch = true;
                m_locatingActiveMatch = false;
                m_activeMatchIndex = m_activeMatchCount + matchCount;
                // FIXME: We need to notify client with m_activeMatchIndex.
            }
            resultRange->ownerDocument()->markers()->addTextMatchMarker(resultRange.get(), foundActiveMatch);
        }
        searchRange->setStart(resultRange->endContainer(ec), resultRange->endOffset(ec), ec);
        Node* shadowTreeRoot = searchRange->shadowTreeRootNode();
        if (searchRange->collapsed(ec) && shadowTreeRoot)
            searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
        m_resumeScopingFromRange = resultRange;
        timeout = (currentTime() - startTime) >= MaxScopingDuration;
    } while (!timeout);

    if (matchCount > 0) {
        scopingFrame->editor()->setMarkedTextMatchesAreHighlighted(true /* highlight */);
        m_activeMatchCount += matchCount;
    }

    if (timeout)
        scopeStringMatchesSoon(scopingFrame, text, false /* reset */);
    else {
        // Scoping is done for this frame.
        Frame* nextFrame = DOMSupport::incrementFrame(scopingFrame, true /* forward */, false /* wrapFlag */);
        if (!nextFrame) {
            m_scopingComplete = true;
            return; // Scoping is done for all frames;
        }
        scopeStringMatchesSoon(nextFrame, text, false /* reset */);
    }
}