blob: 0fa095c93ccbe5ef8924bb1e18a93b5669bfc2cf [file] [log] [blame]
/*
* 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.
void set(const SkRegion& region, SkPicture* pic, int layerId);
bool isInLayer() const { return m_layerId >= 0; }
int layerId() const { return m_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() { if (m_matches) delete m_matches; }
void clearCurrentLocation() { m_hasCurrentLocation = false; }
IntRect currentMatchBounds() const;
int currentMatchIndex() const { return m_findIndex; }
bool currentMatchIsInLayer() const;
// This requires the current match to be in a layer. See
// currentMatchIsInLayer().
int currentMatchLayerId() const;
virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
void findNext(bool forward);
bool isCurrentLocationValid() { return m_hasCurrentLocation; }
void setMatches(WTF::Vector<MatchInfo>* matches);
WTF::Vector<MatchInfo>* matches() { return m_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