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 "SkRegion.h" 35 #include "SkTDArray.h" 36 #include "icu/unicode/umachine.h" 37 #include "wtf/Vector.h" 38 39 namespace android { 40 41 // Stores both region information and an SkPicture of the match, so that the 42 // region can be drawn, followed by drawing the matching text on top of it. 43 // This class owns its SkPicture 44 class MatchInfo { 45 public: 46 MatchInfo(); 47 ~MatchInfo(); 48 MatchInfo(const MatchInfo& src); getLocation()49 const SkRegion& getLocation() const { return m_location; } 50 // Return a pointer to our picture, representing the matching text. Does 51 // not transfer ownership of the picture. getPicture()52 SkPicture* getPicture() const { return m_picture; } 53 // This will make a copy of the region, and increase the ref count on the 54 // SkPicture. If this MatchInfo already had one, unref it. isInLayer()55 bool isInLayer() const { return m_layerId >= 0; } layerId()56 int layerId() const { return m_layerId; } 57 void set(const SkRegion& region, SkPicture* pic, int layerId); 58 private: 59 MatchInfo& operator=(MatchInfo& src); 60 SkRegion m_location; 61 SkPicture* m_picture; 62 int m_layerId; 63 }; 64 65 // A class containing a typeface for reference, the length in glyphs, and 66 // the upper and lower case representations of the search string. 67 class GlyphSet { 68 public: 69 GlyphSet(const SkPaint& paint, const UChar* lower, const UChar* upper, 70 size_t byteLength); 71 ~GlyphSet(); 72 GlyphSet& operator=(GlyphSet& src); 73 74 // Return true iff c matches one of our glyph arrays at index 75 bool characterMatches(uint16_t c, int index); 76 getCount()77 int getCount() const { return mCount; } 78 getTypeface()79 const SkTypeface* getTypeface() const { return mTypeface; } 80 81 private: 82 // Disallow copy constructor GlyphSet(GlyphSet & src)83 GlyphSet(GlyphSet& src) { } 84 85 // mTypeface is used for comparison only 86 const SkTypeface* mTypeface; 87 // mLowerGlyphs points to all of our storage space: the lower set followed 88 // by the upper set. mUpperGlyphs is purely a convenience pointer to the 89 // start of the upper case glyphs. 90 uint16_t* mLowerGlyphs; 91 uint16_t* mUpperGlyphs; 92 // mCount is the number of glyphs of the search string. Must be the same 93 // for both the lower case set and the upper case set. 94 int mCount; 95 96 // Arbitrarily chose the maximum storage to use in the GlyphSet. This is 97 // based on the length of the word being searched. If users are always 98 // searching for 3 letter words (for example), an ideal number would be 3. 99 // Each time the user searches for a word longer than (in this case, 3) that 100 // will result in calling new/delete. 101 enum Storage { 102 MAX_STORAGE_COUNT = 16 103 }; 104 // In order to eliminate new/deletes, create storage that will be enough 105 // most of the time 106 uint16_t mStorage[2*MAX_STORAGE_COUNT]; 107 }; 108 109 class FindBounder : public SkBounder { 110 public: FindBounder()111 FindBounder() {} ~FindBounder()112 ~FindBounder() {} 113 protected: onIRect(const SkIRect &)114 virtual bool onIRect(const SkIRect&) { return false; } 115 }; 116 117 class FindCanvas : public SkCanvas { 118 public: 119 FindCanvas(int width, int height, const UChar* , const UChar*, 120 size_t byteLength); 121 122 virtual ~FindCanvas(); 123 124 virtual void drawText(const void* text, size_t byteLength, SkScalar x, 125 SkScalar y, const SkPaint& paint); 126 127 /* FIXME: This path has not been tested. */ 128 virtual void drawPosText(const void* text, size_t byteLength, 129 const SkPoint pos[], const SkPaint& paint); 130 131 /* Also untested */ 132 virtual void drawPosTextH(const void* text, size_t byteLength, 133 const SkScalar xpos[], SkScalar constY, 134 const SkPaint& paint); 135 136 /* Not sure what to do here or for drawTextOnPathHV */ drawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)137 virtual void drawTextOnPath(const void* text, size_t byteLength, 138 const SkPath& path, const SkMatrix* matrix, 139 const SkPaint& paint) { 140 } 141 142 void drawLayers(LayerAndroid* ); found()143 int found() const { return mNumFound; } setLayerId(int layerId)144 void setLayerId(int layerId) { mLayerId = layerId; } 145 146 // This method detaches our array of matches and passes ownership to 147 // the caller, who is then responsible for deleting them. detachMatches()148 WTF::Vector<MatchInfo>* detachMatches() { 149 WTF::Vector<MatchInfo>* array = mMatches; 150 mMatches = NULL; 151 return array; 152 } 153 154 private: 155 // These calls are made by findHelper to store information about each match 156 // that is found. They return a rectangle which is used to highlight the 157 // match. They also add to our SkPicture (which can be accessed with 158 // getDrawnMatches) a draw of each match. This way it can be drawn after 159 // the rectangle. The rect that is returned is in device coordinates. 160 SkRect addMatchNormal(int index, 161 const SkPaint& paint, int count, const uint16_t* glyphs, 162 const SkScalar pos[], SkScalar y); 163 164 SkRect addMatchPos(int index, 165 const SkPaint& paint, int count, const uint16_t* glyphs, 166 const SkScalar xPos[], SkScalar /* y */); 167 168 SkRect addMatchPosH(int index, 169 const SkPaint& paint, int count, const uint16_t* glyphs, 170 const SkScalar position[], SkScalar constY); 171 172 // Helper for each of our draw calls 173 void findHelper(const void* text, size_t byteLength, const SkPaint& paint, 174 const SkScalar xPos[], SkScalar y, 175 SkRect (FindCanvas::*addMatch)(int index, 176 const SkPaint& paint, int count, const uint16_t* glyphs, 177 const SkScalar pos[], SkScalar y)); 178 179 // If we already have a working canvas, grab it. Otherwise, create a new 180 // one. 181 SkCanvas* getWorkingCanvas(); 182 183 // Return the set of glyphs and its count for the text being searched for 184 // and the parameter paint. If one has already been created and cached 185 // for this paint, use it. If not, create a new one and cache it. 186 GlyphSet* getGlyphs(const SkPaint& paint); 187 188 // Store all the accumulated info about a match in our vector. 189 void insertMatchInfo(const SkRegion& region); 190 191 // Throw away our cumulative information about our working SkCanvas. After 192 // this call, next call to getWorkingCanvas will create a new one. 193 void resetWorkingCanvas(); 194 195 // Since we may transfer ownership of this array (see detachRects()), we 196 // hold a pointer to the array instead of just the array itself. 197 WTF::Vector<MatchInfo>* mMatches; 198 const UChar* mLowerText; 199 const UChar* mUpperText; 200 size_t mLength; 201 FindBounder mBounder; 202 int mNumFound; 203 SkScalar mOutset; 204 SkTDArray<GlyphSet> mGlyphSets; 205 206 SkPicture* mWorkingPicture; 207 SkCanvas* mWorkingCanvas; 208 SkRegion mWorkingRegion; 209 int mWorkingIndex; 210 int mLayerId; 211 }; 212 213 class FindOnPage : public DrawExtra { 214 public: FindOnPage()215 FindOnPage() { 216 m_matches = 0; 217 m_hasCurrentLocation = false; 218 m_isFindPaintSetUp = false; 219 } ~FindOnPage()220 virtual ~FindOnPage() { delete m_matches; } clearCurrentLocation()221 void clearCurrentLocation() { m_hasCurrentLocation = false; } 222 IntRect currentMatchBounds() const; currentMatchIndex()223 int currentMatchIndex() const { return m_findIndex; } 224 bool currentMatchIsInLayer() const; 225 virtual void draw(SkCanvas* , LayerAndroid* ); 226 void findNext(bool forward); 227 void setMatches(WTF::Vector<MatchInfo>* matches); 228 private: 229 void drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused); 230 void setUpFindPaint(); 231 void storeCurrentMatchLocation(); 232 WTF::Vector<MatchInfo>* m_matches; 233 // Stores the location of the current match. 234 SkIPoint m_currentMatchLocation; 235 // Tells whether the value in m_currentMatchLocation is valid. 236 bool m_hasCurrentLocation; 237 // Tells whether we have done the setup to draw the Find matches. 238 bool m_isFindPaintSetUp; 239 // Paint used to draw our Find matches. 240 SkPaint m_findPaint; 241 // Paint used for the background of our Find matches. 242 SkPaint m_findBlurPaint; 243 unsigned m_findIndex; 244 }; 245 246 } 247 248 #endif // Find_Canvas_h 249