1 /* 2 * Copyright 2008, The Android Open Source Project 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifndef Find_Canvas_h 27 #define Find_Canvas_h 28 29 #include "DrawExtra.h" 30 #include "IntRect.h" 31 #include "SkBounder.h" 32 #include "SkCanvas.h" 33 #include "SkPicture.h" 34 #include "SkRect.h" 35 #include "SkRegion.h" 36 #include "SkTDArray.h" 37 38 #include <unicode/umachine.h> 39 #include <wtf/Vector.h> 40 41 namespace android { 42 43 // Stores both region information and an SkPicture of the match, so that the 44 // region can be drawn, followed by drawing the matching text on top of it. 45 // This class owns its SkPicture 46 class MatchInfo { 47 public: 48 MatchInfo(); 49 ~MatchInfo(); 50 MatchInfo(const MatchInfo& src); 51 const SkRegion& getLocation() const { return m_location; } 52 // Return a pointer to our picture, representing the matching text. Does 53 // not transfer ownership of the picture. 54 SkPicture* getPicture() const { return m_picture; } 55 // This will make a copy of the region, and increase the ref count on the 56 // SkPicture. If this MatchInfo already had one, unref it. 57 void set(const SkRegion& region, SkPicture* pic, int layerId); 58 bool isInLayer() const { return m_layerId >= 0; } 59 int layerId() const { return m_layerId; } 60 private: 61 MatchInfo& operator=(MatchInfo& src); 62 SkRegion m_location; 63 SkPicture* m_picture; 64 int m_layerId; 65 }; 66 67 // A class containing a typeface for reference, the length in glyphs, and 68 // the upper and lower case representations of the search string. 69 class GlyphSet { 70 public: 71 GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper, 72 size_t byteLength); 73 ~GlyphSet(); 74 GlyphSet& operator=(GlyphSet& src); 75 76 // Return true iff c matches one of our glyph arrays at index 77 bool characterMatches(uint16_t c, int index); 78 79 int getCount() const { return mCount; } 80 81 const SkTypeface* getTypeface() const { return mTypeface; } 82 83 private: 84 // Disallow copy constructor 85 GlyphSet(GlyphSet& src) { } 86 87 // mTypeface is used for comparison only 88 const SkTypeface* mTypeface; 89 // mLowerGlyphs points to all of our storage space: the lower set followed 90 // by the upper set. mUpperGlyphs is purely a convenience pointer to the 91 // start of the upper case glyphs. 92 uint16_t* mLowerGlyphs; 93 uint16_t* mUpperGlyphs; 94 // mCount is the number of glyphs of the search string. Must be the same 95 // for both the lower case set and the upper case set. 96 int mCount; 97 98 // Arbitrarily chose the maximum storage to use in the GlyphSet. This is 99 // based on the length of the word being searched. If users are always 100 // searching for 3 letter words (for example), an ideal number would be 3. 101 // Each time the user searches for a word longer than (in this case, 3) that 102 // will result in calling new/delete. 103 enum Storage { 104 MAX_STORAGE_COUNT = 16 105 }; 106 // In order to eliminate new/deletes, create storage that will be enough 107 // most of the time 108 uint16_t mStorage[2*MAX_STORAGE_COUNT]; 109 }; 110 111 class FindBounder : public SkBounder { 112 public: 113 FindBounder() {} 114 ~FindBounder() {} 115 protected: 116 virtual bool onIRect(const SkIRect&) { return false; } 117 }; 118 119 class FindCanvas : public SkCanvas { 120 public: 121 FindCanvas(int width, int height, const UChar* , const UChar*, 122 size_t byteLength); 123 124 virtual ~FindCanvas(); 125 126 virtual void drawText(const void* text, size_t byteLength, SkScalar x, 127 SkScalar y, const SkPaint& paint); 128 129 /* FIXME: This path has not been tested. */ 130 virtual void drawPosText(const void* text, size_t byteLength, 131 const SkPoint pos[], const SkPaint& paint); 132 133 /* Also untested */ 134 virtual void drawPosTextH(const void* text, size_t byteLength, 135 const SkScalar xpos[], SkScalar constY, 136 const SkPaint& paint); 137 138 /* Not sure what to do here or for drawTextOnPathHV */ 139 virtual void drawTextOnPath(const void* text, size_t byteLength, 140 const SkPath& path, const SkMatrix* matrix, 141 const SkPaint& paint) { 142 } 143 144 void drawLayers(LayerAndroid*); 145 int found() const { return mNumFound; } 146 void setLayerId(int layerId) { mLayerId = layerId; } 147 148 // This method detaches our array of matches and passes ownership to 149 // the caller, who is then responsible for deleting them. 150 WTF::Vector<MatchInfo>* detachMatches() { 151 WTF::Vector<MatchInfo>* array = mMatches; 152 mMatches = NULL; 153 return array; 154 } 155 156 private: 157 // These calls are made by findHelper to store information about each match 158 // that is found. They return a rectangle which is used to highlight the 159 // match. They also add to our SkPicture (which can be accessed with 160 // getDrawnMatches) a draw of each match. This way it can be drawn after 161 // the rectangle. The rect that is returned is in device coordinates. 162 SkRect addMatchNormal(int index, 163 const SkPaint& paint, int count, const uint16_t* glyphs, 164 const SkScalar pos[], SkScalar y); 165 166 SkRect addMatchPos(int index, 167 const SkPaint& paint, int count, const uint16_t* glyphs, 168 const SkScalar xPos[], SkScalar /* y */); 169 170 SkRect addMatchPosH(int index, 171 const SkPaint& paint, int count, const uint16_t* glyphs, 172 const SkScalar position[], SkScalar constY); 173 174 // Helper for each of our draw calls 175 void findHelper(const void* text, size_t byteLength, const SkPaint& paint, 176 const SkScalar xPos[], SkScalar y, 177 SkRect (FindCanvas::*addMatch)(int index, 178 const SkPaint& paint, int count, const uint16_t* glyphs, 179 const SkScalar pos[], SkScalar y)); 180 181 // If we already have a working canvas, grab it. Otherwise, create a new 182 // one. 183 SkCanvas* getWorkingCanvas(); 184 185 // Return the set of glyphs and its count for the text being searched for 186 // and the parameter paint. If one has already been created and cached 187 // for this paint, use it. If not, create a new one and cache it. 188 GlyphSet* getGlyphs(const SkPaint& paint); 189 190 // Store all the accumulated info about a match in our vector. 191 void insertMatchInfo(const SkRegion& region); 192 193 // Throw away our cumulative information about our working SkCanvas. After 194 // this call, next call to getWorkingCanvas will create a new one. 195 void resetWorkingCanvas(); 196 197 // Since we may transfer ownership of this array (see detachRects()), we 198 // hold a pointer to the array instead of just the array itself. 199 WTF::Vector<MatchInfo>* mMatches; 200 const UChar* mLowerText; 201 const UChar* mUpperText; 202 Vector<UChar> mLowerReversed; 203 Vector<UChar> mUpperReversed; 204 size_t mLength; 205 FindBounder mBounder; 206 int mNumFound; 207 SkScalar mOutset; 208 SkTDArray<GlyphSet> mGlyphSets; 209 210 SkPicture* mWorkingPicture; 211 SkCanvas* mWorkingCanvas; 212 SkRegion mWorkingRegion; 213 int mWorkingIndex; 214 int mLayerId; 215 }; 216 217 class FindOnPage : public DrawExtra { 218 public: 219 FindOnPage() { 220 m_matches = 0; 221 m_hasCurrentLocation = false; 222 m_isFindPaintSetUp = false; 223 m_lastBounds.setEmpty(); 224 } 225 virtual ~FindOnPage() { if (m_matches) delete m_matches; } 226 void clearCurrentLocation() { m_hasCurrentLocation = false; } 227 IntRect currentMatchBounds() const; 228 int currentMatchIndex() const { return m_findIndex; } 229 bool currentMatchIsInLayer() const; 230 // This requires the current match to be in a layer. See 231 // currentMatchIsInLayer(). 232 int currentMatchLayerId() const; 233 virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); 234 void findNext(bool forward); 235 bool isCurrentLocationValid() { return m_hasCurrentLocation; } 236 void setMatches(WTF::Vector<MatchInfo>* matches); 237 WTF::Vector<MatchInfo>* matches() { return m_matches; } 238 private: 239 void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused); 240 void setUpFindPaint(); 241 void storeCurrentMatchLocation(); 242 WTF::Vector<MatchInfo>* m_matches; 243 // Stores the location of the current match. 244 SkIPoint m_currentMatchLocation; 245 // Tells whether the value in m_currentMatchLocation is valid. 246 bool m_hasCurrentLocation; 247 // Tells whether we have done the setup to draw the Find matches. 248 bool m_isFindPaintSetUp; 249 // Paint used to draw our Find matches. 250 SkPaint m_findPaint; 251 // Paint used for the background of our Find matches. 252 SkPaint m_findBlurPaint; 253 unsigned m_findIndex; 254 SkIRect m_lastBounds; 255 }; 256 257 } 258 259 #endif // Find_Canvas_h 260