| Differences between
and this patch
- a/Source/WebCore/ChangeLog +31 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2011-11-30  Shinya Kawanaka  <shinyak@google.com>
2
3
        Asynchronous SpellChecker should consider multiple requests.
4
        https://bugs.webkit.org/show_bug.cgi?id=72939
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Now Spellchecker saves a request when it is processing the previous spellcheck request.
9
        Currently only the latest request is saved.
10
11
        Test: editing/spelling/spellcheck-queue.html
12
13
        * editing/SpellChecker.cpp:
14
        (WebCore::SpellChecker::SpellCheckRequest::SpellCheckRequest):
15
          A structure to have spell check request.
16
        (WebCore::SpellChecker::SpellCheckRequest::sequence):
17
        (WebCore::SpellChecker::SpellCheckRequest::range):
18
        (WebCore::SpellChecker::SpellCheckRequest::text):
19
        (WebCore::SpellChecker::SpellCheckRequest::mask):
20
        (WebCore::SpellChecker::SpellChecker):
21
        (WebCore::SpellChecker::initRequest):
22
        (WebCore::SpellChecker::timerFired):
23
          When timer is fired, queued request is processed if any.
24
        (WebCore::SpellChecker::processQueuedRequest): Sets a timer.
25
        (WebCore::SpellChecker::canCheckAsynchronously):
26
        (WebCore::SpellChecker::isValid):
27
        (WebCore::SpellChecker::doRequestCheckingFor):
28
          When the spellchecker is processing another request, the latest request is queued.
29
        (WebCore::SpellChecker::didCheck):
30
        * editing/SpellChecker.h:
31
1
2011-11-28  Pavel Feldman  <pfeldman@google.com>
32
2011-11-28  Pavel Feldman  <pfeldman@google.com>
2
33
3
        Web Inspector: put inspector agents into a vector in the InspectorController.
34
        Web Inspector: put inspector agents into a vector in the InspectorController.
- a/Source/WebCore/editing/SpellChecker.cpp -26 / +59 lines
Lines 45-53 a/Source/WebCore/editing/SpellChecker.cpp_sec1
45
45
46
namespace WebCore {
46
namespace WebCore {
47
47
48
class SpellChecker::SpellCheckRequest {
49
public:
50
    SpellCheckRequest(int sequence, PassRefPtr<Range> range, const String& text, TextCheckingTypeMask mask)
51
        : m_sequence(sequence)
52
        , m_range(range)
53
        , m_text(text)
54
        , m_mask(mask)
55
    {
56
    }
57
58
    int sequence() const { return m_sequence; }
59
    PassRefPtr<Range> range() const { return m_range; }
60
    const String& text() const { return m_text; }
61
    TextCheckingTypeMask mask() const { return m_mask; }
62
63
private:
64
    int m_sequence;
65
    RefPtr<Range> m_range;
66
    String m_text;
67
    TextCheckingTypeMask m_mask;
68
};
69
48
SpellChecker::SpellChecker(Frame* frame)
70
SpellChecker::SpellChecker(Frame* frame)
49
    : m_frame(frame)
71
    : m_frame(frame)
50
    , m_requestSequence(0)
72
    , m_maxRequestedSequence(0)
73
    , m_timer(this, &SpellChecker::timerFired)
51
{
74
{
52
}
75
}
53
76
Lines 63-87 TextCheckerClient* SpellChecker::client() const a/Source/WebCore/editing/SpellChecker.cpp_sec2
63
    return page->editorClient()->textChecker();
86
    return page->editorClient()->textChecker();
64
}
87
}
65
88
66
bool SpellChecker::initRequest(PassRefPtr<Range> range)
89
PassOwnPtr<SpellChecker::SpellCheckRequest> SpellChecker::initRequest(TextCheckingTypeMask mask, PassRefPtr<Range> range)
67
{
90
{
68
    ASSERT(canCheckAsynchronously(range.get()));
91
    ASSERT(canCheckAsynchronously(range.get()));
69
92
70
    String text = range->text();
93
    String text = range->text();
71
    if (!text.length())
94
    if (!text.length())
72
        return false;
95
        return PassOwnPtr<SpellCheckRequest>();
73
96
74
    m_requestRange = range;
97
    return adoptPtr(new SpellCheckRequest(++m_maxRequestedSequence, range, text, mask));
75
    m_requestText = text;
98
}
76
    m_requestSequence++;
99
100
void SpellChecker::timerFired(Timer<SpellChecker>*)
101
{
102
    if (!m_queuedRequest.get())
103
        return;
77
104
78
    return true;
105
    m_processingRequest = m_queuedRequest.release();
106
    client()->requestCheckingOfString(this, m_processingRequest->sequence(), m_processingRequest->mask(), m_processingRequest->text());
79
}
107
}
80
108
81
void SpellChecker::clearRequest()
109
void SpellChecker::processQueuedRequest()
82
{
110
{
83
    m_requestRange.clear();
111
    m_processingRequest.clear();
84
    m_requestText = String();
112
    if (!m_queuedRequest.get())
113
        return;
114
115
    m_timer.startOneShot(0);
85
}
116
}
86
117
87
bool SpellChecker::isAsynchronousEnabled() const
118
bool SpellChecker::isAsynchronousEnabled() const
Lines 91-107 bool SpellChecker::isAsynchronousEnabled() const a/Source/WebCore/editing/SpellChecker.cpp_sec3
91
122
92
bool SpellChecker::canCheckAsynchronously(Range* range) const
123
bool SpellChecker::canCheckAsynchronously(Range* range) const
93
{
124
{
94
    return client() && isCheckable(range) && isAsynchronousEnabled() && !isBusy();
125
    return client() && isCheckable(range) && isAsynchronousEnabled();
95
}
96
97
bool SpellChecker::isBusy() const
98
{
99
    return m_requestRange.get();
100
}
126
}
101
127
102
bool SpellChecker::isValid(int sequence) const
128
bool SpellChecker::isValid(int sequence) const
103
{
129
{
104
    return m_requestRange.get() && m_requestText.length() && m_requestSequence == sequence;
130
    return m_processingRequest.get() && m_processingRequest->text().length() && m_processingRequest->sequence() == sequence;
105
}
131
}
106
132
107
bool SpellChecker::isCheckable(Range* range) const
133
bool SpellChecker::isCheckable(Range* range) const
Lines 121-129 void SpellChecker::doRequestCheckingFor(TextCheckingTypeMask mask, PassRefPtr<Ra a/Source/WebCore/editing/SpellChecker.cpp_sec4
121
{
147
{
122
    ASSERT(canCheckAsynchronously(range.get()));
148
    ASSERT(canCheckAsynchronously(range.get()));
123
149
124
    if (!initRequest(range))
150
    OwnPtr<SpellCheckRequest> request(initRequest(mask, range));
151
    if (!request.get())
125
        return;
152
        return;
126
    client()->requestCheckingOfString(this, m_requestSequence, mask, m_requestText);
153
154
    if (m_processingRequest.get())
155
        m_queuedRequest = request.release();
156
    else {
157
        client()->requestCheckingOfString(this, request->sequence(), request->mask(), request->text());
158
        m_processingRequest = request.release();
159
    }
127
}
160
}
128
161
129
static bool forwardIterator(PositionIterator& iterator, int distance)
162
static bool forwardIterator(PositionIterator& iterator, int distance)
Lines 162-174 void SpellChecker::didCheck(int sequence, const Vector<TextCheckingResult>& resu a/Source/WebCore/editing/SpellChecker.cpp_sec5
162
    if (!isValid(sequence))
195
    if (!isValid(sequence))
163
        return;
196
        return;
164
197
165
    if (!isCheckable(m_requestRange.get())) {
198
    if (!isCheckable(m_processingRequest->range().get())) {
166
        clearRequest();
199
        processQueuedRequest();
167
        return;
200
        return;
168
    }
201
    }
169
202
170
    int startOffset = 0;
203
    int startOffset = 0;
171
    PositionIterator start = m_requestRange->startPosition();
204
    PositionIterator start = m_processingRequest->range()->startPosition();
172
    for (size_t i = 0; i < results.size(); ++i) {
205
    for (size_t i = 0; i < results.size(); ++i) {
173
        if (results[i].type != TextCheckingTypeSpelling && results[i].type != TextCheckingTypeGrammar)
206
        if (results[i].type != TextCheckingTypeSpelling && results[i].type != TextCheckingTypeGrammar)
174
            continue;
207
            continue;
Lines 186-202 void SpellChecker::didCheck(int sequence, const Vector<TextCheckingResult>& resu a/Source/WebCore/editing/SpellChecker.cpp_sec6
186
        // spellings in the background. To avoid adding markers to the words modified by users or
219
        // spellings in the background. To avoid adding markers to the words modified by users or
187
        // JavaScript applications, retrieve the words in the specified region and compare them with
220
        // JavaScript applications, retrieve the words in the specified region and compare them with
188
        // the original ones.
221
        // the original ones.
189
        RefPtr<Range> range = Range::create(m_requestRange->ownerDocument(), start, end);
222
        RefPtr<Range> range = Range::create(m_processingRequest->range()->ownerDocument(), start, end);
190
        // FIXME: Use textContent() compatible string conversion.
223
        // FIXME: Use textContent() compatible string conversion.
191
        String destination = range->text();
224
        String destination = range->text();
192
        String source = m_requestText.substring(results[i].location, results[i].length);
225
        String source = m_processingRequest->text().substring(results[i].location, results[i].length);
193
        if (destination == source)
226
        if (destination == source)
194
            m_requestRange->ownerDocument()->markers()->addMarker(range.get(), toMarkerType(results[i].type));
227
            m_processingRequest->range()->ownerDocument()->markers()->addMarker(range.get(), toMarkerType(results[i].type));
195
228
196
        startOffset = results[i].location;
229
        startOffset = results[i].location;
197
    }
230
    }
198
231
199
    clearRequest();
232
    processQueuedRequest();
200
}
233
}
201
234
202
235
- a/Source/WebCore/editing/SpellChecker.h -7 / +12 lines
Lines 28-33 a/Source/WebCore/editing/SpellChecker.h_sec1
28
28
29
#include "PlatformString.h"
29
#include "PlatformString.h"
30
#include "TextChecking.h"
30
#include "TextChecking.h"
31
#include "Timer.h"
31
#include <wtf/RefPtr.h>
32
#include <wtf/RefPtr.h>
32
#include <wtf/Noncopyable.h>
33
#include <wtf/Noncopyable.h>
33
#include <wtf/Vector.h>
34
#include <wtf/Vector.h>
Lines 47-70 public: a/Source/WebCore/editing/SpellChecker.h_sec2
47
    ~SpellChecker();
48
    ~SpellChecker();
48
49
49
    bool isAsynchronousEnabled() const;
50
    bool isAsynchronousEnabled() const;
50
    bool canCheckAsynchronously(Range*) const;
51
    bool isBusy() const;
52
    bool isValid(int sequence) const;
51
    bool isValid(int sequence) const;
53
    bool isCheckable(Range*) const;
52
    bool isCheckable(Range*) const;
54
    void requestCheckingFor(TextCheckingTypeMask, PassRefPtr<Range>);
53
    void requestCheckingFor(TextCheckingTypeMask, PassRefPtr<Range>);
55
    void didCheck(int sequence, const Vector<TextCheckingResult>&);
54
    void didCheck(int sequence, const Vector<TextCheckingResult>&);
56
55
57
private:
56
private:
58
    bool initRequest(PassRefPtr<Range>);
57
    class SpellCheckRequest;
59
    void clearRequest();
58
59
    bool canCheckAsynchronously(Range*) const;
60
    PassOwnPtr<SpellCheckRequest> initRequest(TextCheckingTypeMask, PassRefPtr<Range>);
61
    void processQueuedRequest();
60
    void doRequestCheckingFor(TextCheckingTypeMask, PassRefPtr<Range>);
62
    void doRequestCheckingFor(TextCheckingTypeMask, PassRefPtr<Range>);
61
    TextCheckerClient* client() const;
63
    TextCheckerClient* client() const;
64
    void timerFired(Timer<SpellChecker>*);
62
65
63
    Frame* m_frame;
66
    Frame* m_frame;
67
    int m_maxRequestedSequence;
68
69
    Timer<SpellChecker> m_timer;
64
70
65
    RefPtr<Range> m_requestRange;
71
    OwnPtr<SpellCheckRequest> m_processingRequest;
66
    String m_requestText;
72
    OwnPtr<SpellCheckRequest> m_queuedRequest;
67
    int m_requestSequence;
68
};
73
};
69
74
70
} // namespace WebCore
75
} // namespace WebCore
- a/LayoutTests/ChangeLog +14 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2011-11-30  Shinya Kawanaka  <shinyak@google.com>
2
3
        Asynchronous SpellChecker should consider multiple requests.
4
        https://bugs.webkit.org/show_bug.cgi?id=72939
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Tests for multiple spellcheck requests.
9
10
        * editing/spelling/spellcheck-queue-expected.txt: Added.
11
        * editing/spelling/spellcheck-queue.html: Added.
12
        * platform/gtk/Skipped:
13
        * platform/qt/Skipped:
14
1
2011-11-29  Csaba Osztrogonác  <ossy@webkit.org>
15
2011-11-29  Csaba Osztrogonác  <ossy@webkit.org>
2
16
3
        SVG <path> DRT dumps have rounding problems across platforms
17
        SVG <path> DRT dumps have rounding problems across platforms
- a/LayoutTests/editing/spelling/spellcheck-queue-expected.txt +11 lines
Line 0 a/LayoutTests/editing/spelling/spellcheck-queue-expected.txt_sec1
1
For Bug 72939: Asynchronous SpellChecker should consider multiple requests.
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
PASS successfullyParsed is true
7
8
TEST COMPLETE
9
PASS INPUT has a marker on 'foo bar'
10
PASS INPUT has a marker on 'foo bar'
11
- a/LayoutTests/editing/spelling/spellcheck-queue.html +129 lines
Line 0 a/LayoutTests/editing/spelling/spellcheck-queue.html_sec1
1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
2
<html>
3
<head>
4
<script src="../../fast/js/resources/js-test-pre.js"></script>
5
<script src="resources/js-test-selection-shared.js"></script>
6
</head>
7
<body>
8
<p id="description"></p>
9
<div id="console"></div>
10
<script>
11
description('For Bug 72939: Asynchronous SpellChecker should consider multiple requests.');
12
13
if (window.layoutTestController)
14
    layoutTestController.waitUntilDone();
15
16
var testRoot = document.createElement("div");
17
document.body.insertBefore(testRoot, document.body.firstChild);
18
19
var testSourcePlain = document.createElement("div");
20
testSourcePlain.innerHTML = "foo bar";
21
testRoot.appendChild(testSourcePlain);
22
23
var testInput1 = document.createElement("input");
24
testInput1.setAttribute("type", "text");
25
testRoot.appendChild(testInput1);
26
var testInput2 = document.createElement("input");
27
testInput2.setAttribute("type", "text");
28
testRoot.appendChild(testInput2);
29
var testInput3 = document.createElement("input");
30
testInput3.setAttribute("type", "text");
31
testRoot.appendChild(testInput3);
32
33
var sel = window.getSelection();
34
35
// At least, testInput1 and testInput3 should have markers.
36
var tests = [
37
    function() { verify(1, testSourcePlain, testInput1, [[0, 3]]); },
38
    function() { verify(3, testSourcePlain, testInput3, [[0, 3]]); }
39
];
40
41
function done()
42
{
43
    var next = tests.shift();
44
    if (next) {
45
        next();
46
        return;
47
    }
48
49
    testRoot.style.display = "none";
50
    if (window.layoutTestController) {
51
        layoutTestController.setAsynchronousSpellCheckingEnabled(false);
52
        layoutTestController.notifyDone();
53
    }
54
}
55
56
function verifyMarker(node, expectedMarked)
57
{
58
    if (node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement) {
59
        node.focus();
60
    } else {
61
        sel.selectAllChildren(node);
62
    }
63
64
    if (!window.layoutTestController)
65
        return;
66
67
    var ok = true;
68
    for (var i = 0; ok && i < expectedMarked.length; ++i)
69
        ok = ok && layoutTestController.hasSpellingMarker(expectedMarked[i][0], expectedMarked[i][1]);
70
    return ok;
71
}
72
73
function copyAndPaste(source, dest)
74
{
75
    sel.selectAllChildren(source);
76
    document.execCommand("Copy");
77
    if (dest instanceof HTMLInputElement || dest instanceof HTMLTextAreaElement) {
78
        dest.value = "";
79
        dest.focus();
80
    } else {
81
        dest.innerHTML = "";
82
        sel.selectAllChildren(dest);
83
    }
84
    document.execCommand("Paste");
85
}
86
87
function verify(id, source, dest, expectedMarked)
88
{
89
    var nretry = 10;
90
    var nsleep = 1;
91
    function trial() {
92
        var verified = verifyMarker(dest, expectedMarked);
93
        if (verified) {
94
            testPassed(dest.tagName + " has a marker on '" + source.innerHTML + "'");
95
            done();
96
            return;
97
        }
98
99
        nretry--;
100
        if (0 == nretry) {
101
            testFailed(dest.tagName + " should have a marker on for '" + source.innerHTML + "'");
102
            done();
103
            return;
104
        }
105
106
        nsleep *= 2;
107
        window.setTimeout(trial, nsleep);
108
    };
109
    trial();
110
}
111
112
function pasteAndVerify(source, dests, expectedMarked)
113
{
114
    for (var i = 0; i < dests.length; ++i)
115
        copyAndPaste(source, dests[i]);
116
};
117
118
if (window.layoutTestController)
119
    layoutTestController.setAsynchronousSpellCheckingEnabled(true);
120
121
pasteAndVerify(testSourcePlain, [testInput1, testInput2, testInput3], [[0, 3]]);
122
done();
123
124
var successfullyParsed = true;
125
126
</script>
127
<script src="../../fast/js/resources/js-test-post.js"></script>
128
</body>
129
</html>
- a/LayoutTests/platform/gtk/Skipped +1 lines
Lines 1351-1356 media/event-attributes.html a/LayoutTests/platform/gtk/Skipped_sec1
1351
# https://bugs.webkit.org/show_bug.cgi?id=50740
1351
# https://bugs.webkit.org/show_bug.cgi?id=50740
1352
editing/spelling/spelling-backspace-between-lines.html
1352
editing/spelling/spelling-backspace-between-lines.html
1353
editing/spelling/spellcheck-paste.html
1353
editing/spelling/spellcheck-paste.html
1354
editing/spelling/spellcheck-queue.html
1354
1355
1355
# For https://bugs.webkit.org/show_bug.cgi?id=50758
1356
# For https://bugs.webkit.org/show_bug.cgi?id=50758
1356
# These require DRT setSerializeHTTPLoads implementation to be reliable.
1357
# These require DRT setSerializeHTTPLoads implementation to be reliable.
- a/LayoutTests/platform/qt/Skipped +1 lines
Lines 1001-1006 editing/spelling/spelling-attribute-at-child.html a/LayoutTests/platform/qt/Skipped_sec1
1001
1001
1002
# EditorClient::requestCheckingOfString() is not implemented
1002
# EditorClient::requestCheckingOfString() is not implemented
1003
editing/spelling/spellcheck-paste.html
1003
editing/spelling/spellcheck-paste.html
1004
editing/spelling/spellcheck-queue.html
1004
1005
1005
# [Qt][GTK] editing/spelling/spellcheck-async.html fails
1006
# [Qt][GTK] editing/spelling/spellcheck-async.html fails
1006
# https://bugs.webkit.org/show_bug.cgi?id=73003
1007
# https://bugs.webkit.org/show_bug.cgi?id=73003

Return to Bug 72939