summaryrefslogtreecommitdiffstats
path: root/WebKit/android/nav/FindCanvas.h
blob: 76ee1e2a64055b2d8c4bf95b0fa4a7ebd74db106 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/*
 * Copyright 2008, The Android Open Source Project
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef Find_Canvas_h
#define Find_Canvas_h

#include "DrawExtra.h"
#include "IntRect.h"
#include "SkBounder.h"
#include "SkCanvas.h"
#include "SkPicture.h"
#include "SkRect.h"
#include "SkRegion.h"
#include "SkTDArray.h"

#include <unicode/umachine.h>
#include <wtf/Vector.h>

namespace android {

// Stores both region information and an SkPicture of the match, so that the
// region can be drawn, followed by drawing the matching text on top of it.
// This class owns its SkPicture
class MatchInfo {
public:
    MatchInfo();
    ~MatchInfo();
    MatchInfo(const MatchInfo& src);
    const SkRegion& getLocation() const { return m_location; }
    // Return a pointer to our picture, representing the matching text.  Does
    // not transfer ownership of the picture.
    SkPicture* getPicture() const { return m_picture; }
    // This will make a copy of the region, and increase the ref count on the
    // SkPicture.  If this MatchInfo already had one, unref it.
    bool isInLayer() const { return m_layerId >= 0; }
    int layerId() const { return m_layerId; }
    void set(const SkRegion& region, SkPicture* pic, int layerId);
private:
    MatchInfo& operator=(MatchInfo& src);
    SkRegion    m_location;
    SkPicture*  m_picture;
    int         m_layerId;
};

// A class containing a typeface for reference, the length in glyphs, and
// the upper and lower case representations of the search string.
class GlyphSet {
public:
    GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper,
            size_t byteLength);
    ~GlyphSet();
    GlyphSet& operator=(GlyphSet& src);

    // Return true iff c matches one of our glyph arrays at index
    bool characterMatches(uint16_t c, int index);
    
    int getCount() const { return mCount; }

    const SkTypeface* getTypeface() const { return mTypeface; }

private:
    // Disallow copy constructor
    GlyphSet(GlyphSet& src) { }

    // mTypeface is used for comparison only
    const SkTypeface* mTypeface;
    // mLowerGlyphs points to all of our storage space: the lower set followed
    // by the upper set.  mUpperGlyphs is purely a convenience pointer to the
    // start of the upper case glyphs.
    uint16_t*   mLowerGlyphs;
    uint16_t*   mUpperGlyphs;
    // mCount is the number of glyphs of the search string.  Must be the same
    // for both the lower case set and the upper case set.
    int         mCount;

    // Arbitrarily chose the maximum storage to use in the GlyphSet.  This is
    // based on the length of the word being searched.  If users are always
    // searching for 3 letter words (for example), an ideal number would be 3.
    // Each time the user searches for a word longer than (in this case, 3) that
    // will result in calling new/delete.
    enum Storage {
        MAX_STORAGE_COUNT = 16
    };
    // In order to eliminate new/deletes, create storage that will be enough
    // most of the time
    uint16_t    mStorage[2*MAX_STORAGE_COUNT];
};

class FindBounder : public SkBounder {
public:
    FindBounder() {}
    ~FindBounder() {}
protected:
    virtual bool onIRect(const SkIRect&) { return false; }
};

class FindCanvas : public SkCanvas {
public:
    FindCanvas(int width, int height, const UChar* , const UChar*,
            size_t byteLength);

    virtual ~FindCanvas();

    virtual void drawText(const void* text, size_t byteLength, SkScalar x,
                          SkScalar y, const SkPaint& paint);

    /* FIXME: This path has not been tested. */
    virtual void drawPosText(const void* text, size_t byteLength,
                             const SkPoint pos[], const SkPaint& paint);

    /* Also untested */
    virtual void drawPosTextH(const void* text, size_t byteLength,
                              const SkScalar xpos[], SkScalar constY,
                              const SkPaint& paint);

    /* Not sure what to do here or for drawTextOnPathHV */
    virtual void drawTextOnPath(const void* text, size_t byteLength,
                                const SkPath& path, const SkMatrix* matrix,
                                const SkPaint& paint) {
    }

    void drawLayers(LayerAndroid* );
    int found() const { return mNumFound; }
    void setLayerId(int layerId) { mLayerId = layerId; }

    // This method detaches our array of matches and passes ownership to
    // the caller, who is then responsible for deleting them.
    WTF::Vector<MatchInfo>* detachMatches() {
        WTF::Vector<MatchInfo>* array = mMatches;
        mMatches = NULL;
        return array;
    }

private:
    // These calls are made by findHelper to store information about each match
    // that is found.  They return a rectangle which is used to highlight the
    // match.  They also add to our SkPicture (which can be accessed with
    // getDrawnMatches) a draw of each match.  This way it can be drawn after
    // the rectangle.  The rect that is returned is in device coordinates.
    SkRect addMatchNormal(int index,
        const SkPaint& paint, int count, const uint16_t* glyphs,
        const SkScalar pos[], SkScalar y);

    SkRect addMatchPos(int index,
        const SkPaint& paint, int count, const uint16_t* glyphs,
        const SkScalar xPos[], SkScalar /* y */);

    SkRect addMatchPosH(int index,
        const SkPaint& paint, int count, const uint16_t* glyphs,
        const SkScalar position[], SkScalar constY);

    // Helper for each of our draw calls
    void findHelper(const void* text, size_t byteLength, const SkPaint& paint,
                    const SkScalar xPos[], SkScalar y,
                    SkRect (FindCanvas::*addMatch)(int index,
                    const SkPaint& paint, int count, const uint16_t* glyphs,
                    const SkScalar pos[], SkScalar y));

    // If we already have a working canvas, grab it.  Otherwise, create a new
    // one.
    SkCanvas* getWorkingCanvas();

    // Return the set of glyphs and its count for the text being searched for
    // and the parameter paint.  If one has already been created and cached
    // for this paint, use it.  If not, create a new one and cache it.
    GlyphSet* getGlyphs(const SkPaint& paint);

    // Store all the accumulated info about a match in our vector.
    void insertMatchInfo(const SkRegion& region);

    // Throw away our cumulative information about our working SkCanvas.  After
    // this call, next call to getWorkingCanvas will create a new one.
    void resetWorkingCanvas();

    // Since we may transfer ownership of this array (see detachRects()), we
    // hold a pointer to the array instead of just the array itself.
    WTF::Vector<MatchInfo>* mMatches;
    const UChar*            mLowerText;
    const UChar*            mUpperText;
    Vector<UChar>           mLowerReversed;
    Vector<UChar>           mUpperReversed;
    size_t                  mLength;
    FindBounder             mBounder;
    int                     mNumFound;
    SkScalar                mOutset;
    SkTDArray<GlyphSet>     mGlyphSets;

    SkPicture*              mWorkingPicture;
    SkCanvas*               mWorkingCanvas;
    SkRegion                mWorkingRegion;
    int                     mWorkingIndex;
    int                     mLayerId;
};

class FindOnPage : public DrawExtra {
public:
    FindOnPage() {
        m_matches = 0;
        m_hasCurrentLocation = false;
        m_isFindPaintSetUp = false;
        m_lastBounds.setEmpty();
    }
    virtual ~FindOnPage() { delete m_matches; }
    void clearCurrentLocation() { m_hasCurrentLocation = false; }
    IntRect currentMatchBounds() const;
    int currentMatchIndex() const { return m_findIndex; }
    bool currentMatchIsInLayer() const;
    virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
    void findNext(bool forward);
    bool isCurrentLocationValid() { return m_hasCurrentLocation; }
    void setMatches(WTF::Vector<MatchInfo>* matches);
private:
    void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused);
    void setUpFindPaint();
    void storeCurrentMatchLocation();
    WTF::Vector<MatchInfo>* m_matches;
    // Stores the location of the current match.
    SkIPoint m_currentMatchLocation;
    // Tells whether the value in m_currentMatchLocation is valid.
    bool m_hasCurrentLocation;
    // Tells whether we have done the setup to draw the Find matches.
    bool m_isFindPaintSetUp;
    // Paint used to draw our Find matches.
    SkPaint m_findPaint;
    // Paint used for the background of our Find matches.
    SkPaint m_findBlurPaint;
    unsigned m_findIndex;
    SkIRect m_lastBounds;
};

}

#endif  // Find_Canvas_h