Home | History | Annotate | Download | only in nav
      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