summaryrefslogtreecommitdiffstats
path: root/Source/WebKit/android/nav/SelectText.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit/android/nav/SelectText.cpp')
-rw-r--r--Source/WebKit/android/nav/SelectText.cpp1931
1 files changed, 5 insertions, 1926 deletions
diff --git a/Source/WebKit/android/nav/SelectText.cpp b/Source/WebKit/android/nav/SelectText.cpp
index d20c44a..7ce32c3 100644
--- a/Source/WebKit/android/nav/SelectText.cpp
+++ b/Source/WebKit/android/nav/SelectText.cpp
@@ -25,23 +25,20 @@
#define LOG_TAG "webviewglue"
-#include "CachedPrefix.h"
+#include "config.h"
+
#include "BidiResolver.h"
#include "BidiRunList.h"
-#include "CachedRoot.h"
+#include "GLExtras.h"
#include "LayerAndroid.h"
-#include "ParseCanvas.h"
#include "SelectText.h"
#include "SkBitmap.h"
#include "SkBounder.h"
-#include "SkGradientShader.h"
-#include "SkMatrix.h"
+#include "SkCanvas.h"
#include "SkPicture.h"
-#include "SkPixelXorXfermode.h"
#include "SkPoint.h"
#include "SkRect.h"
#include "SkRegion.h"
-#include "SkUtils.h"
#include "TextRun.h"
#ifdef DEBUG_NAV_UI
@@ -52,7 +49,7 @@
// #define EXTRA_NOISY_LOGGING 1
#define DEBUG_TOUCH_HANDLES 0
#if DEBUG_TOUCH_HANDLES
-#define DBG_HANDLE_LOG(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
+#define DBG_HANDLE_LOG(format, ...) ALOGD("%s " format, __FUNCTION__, __VA_ARGS__)
#else
#define DBG_HANDLE_LOG(...)
#endif
@@ -147,1921 +144,3 @@ void ReverseBidi(UChar* chars, int len) {
}
-namespace android {
-
-#define HYPHEN_MINUS 0x2D // ASCII hyphen
-#define SOLIDUS 0x2F // ASCII slash
-#define REVERSE_SOLIDUS 0x5C // ASCII backslash
-#define HYPHEN 0x2010 // unicode hyphen, first in range of dashes
-#define HORZ_BAR 0x2015 // unicode horizontal bar, last in range of dashes
-#define TOUCH_SLOP 10 // additional distance from character rect when hit
-
-class CommonCheck : public SkBounder {
-public:
- CommonCheck(const SkIRect& area)
- : mArea(area)
- , mLastUni(0)
- {
- mLastGlyph.fGlyphID = static_cast<uint16_t>(-1);
- mLastCandidate.fGlyphID = static_cast<uint16_t>(-1);
- mMatrix.reset();
- reset();
- }
-
- /* called only while the picture is parsed */
- int base() {
- if (mBase == INT_MAX) {
- SkPoint result;
- mMatrix.mapXY(0, mY, &result);
- mBase = SkScalarFloor(result.fY);
- }
- return mBase;
- }
-
- /* called only while the picture is parsed */
- int bottom() {
- if (mBottom == INT_MAX) {
- SkPoint result;
- SkPaint::FontMetrics metrics;
- mPaint.getFontMetrics(&metrics);
- mMatrix.mapXY(0, metrics.fDescent + mY, &result);
- mBottom = SkScalarCeil(result.fY);
- }
- return mBottom;
- }
-
-#if DEBUG_NAV_UI
- // make current (possibily uncomputed) value visible for debugging
- int bottomDebug() const
- {
- return mBottom;
- }
-#endif
-
- bool addNewLine(const SkBounder::GlyphRec& rec)
- {
- SkFixed lineSpacing = SkFixedAbs(mLastGlyph.fLSB.fY - rec.fLSB.fY);
- SkFixed lineHeight = SkIntToFixed(bottom() - top());
- return lineSpacing >= lineHeight + (lineHeight >> 1); // 1.5
- }
-
- bool addSpace(const SkBounder::GlyphRec& rec)
- {
- bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
- if (((mLastUni >= HYPHEN && mLastUni <= HORZ_BAR)
- || mLastUni == HYPHEN_MINUS || mLastUni == SOLIDUS
- || mLastUni == REVERSE_SOLIDUS) && newBaseLine)
- {
- return false;
- }
- return isSpace(rec);
- }
-
- void finishGlyph()
- {
- mLastGlyph = mLastCandidate;
- mLastUni = mLastUniCandidate;
- mLastPaint = mLastPaintCandidate;
- }
-
- const SkIRect& getArea() const {
- return mArea;
- }
-
- /* called only while the picture is parsed */
- SkUnichar getUniChar(const SkBounder::GlyphRec& rec)
- {
- SkUnichar unichar;
- SkPaint::TextEncoding save = mPaint.getTextEncoding();
- mPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- mPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar);
- mPaint.setTextEncoding(save);
- return unichar;
- }
-
- bool isSpace(const SkBounder::GlyphRec& rec)
- {
- if (mLastGlyph.fGlyphID == static_cast<uint16_t>(-1))
- return true;
- DBG_NAV_LOGD("mLastGlyph=((%g, %g),(%g, %g), %d)"
- " rec=((%g, %g),(%g, %g), %d) mLastUni=0x%04x '%c'",
- SkFixedToScalar(mLastGlyph.fLSB.fX),
- SkFixedToScalar(mLastGlyph.fLSB.fY),
- SkFixedToScalar(mLastGlyph.fRSB.fX),
- SkFixedToScalar(mLastGlyph.fRSB.fY), mLastGlyph.fGlyphID,
- SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fLSB.fY),
- SkFixedToScalar(rec.fRSB.fX), SkFixedToScalar(rec.fRSB.fY),
- rec.fGlyphID,
- mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
- bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
- if (newBaseLine)
- return true;
- SkFixed gapOne = mLastGlyph.fLSB.fX - rec.fRSB.fX;
- SkFixed gapTwo = rec.fLSB.fX - mLastGlyph.fRSB.fX;
- if (gapOne < 0 && gapTwo < 0)
- return false; // overlaps
- const SkBounder::GlyphRec& first = mLastGlyph.fLSB.fX < rec.fLSB.fX
- ? mLastGlyph : rec;
- const SkBounder::GlyphRec& second = mLastGlyph.fLSB.fX < rec.fLSB.fX
- ? rec : mLastGlyph;
- uint16_t firstGlyph = first.fGlyphID;
- SkScalar firstWidth = mLastPaint.measureText(&firstGlyph, sizeof(firstGlyph));
- SkFixed ceilWidth = SkIntToFixed(SkScalarCeil(firstWidth));
- SkFixed posNoSpace = first.fLSB.fX + ceilWidth;
- SkFixed ceilSpace = SkIntToFixed(SkFixedCeil(minSpaceWidth(mLastPaint)));
- SkFixed posWithSpace = posNoSpace + ceilSpace;
- SkFixed diffNoSpace = SkFixedAbs(second.fLSB.fX - posNoSpace);
- SkFixed diffWithSpace = SkFixedAbs(second.fLSB.fX - posWithSpace);
- DBG_NAV_LOGD("second=%g width=%g (%g) noSpace=%g (%g) withSpace=%g (%g)"
- " fontSize=%g",
- SkFixedToScalar(second.fLSB.fX),
- firstWidth, SkFixedToScalar(ceilWidth),
- SkFixedToScalar(posNoSpace), SkFixedToScalar(diffNoSpace),
- SkFixedToScalar(posWithSpace), SkFixedToScalar(diffWithSpace),
- mLastPaint.getTextSize());
- return diffWithSpace <= diffNoSpace;
- }
-
- SkFixed minSpaceWidth(SkPaint& paint)
- {
- if (mMinSpaceWidth == SK_FixedMax) {
- SkPaint::TextEncoding save = paint.getTextEncoding();
- paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
- SkScalar width = paint.measureText(" ", 1);
- mMinSpaceWidth = SkScalarToFixed(width * mMatrix.getScaleX());
- paint.setTextEncoding(save);
- DBG_NAV_LOGV("width=%g matrix sx/sy=(%g, %g) tx/ty=(%g, %g)"
- " mMinSpaceWidth=%g", width,
- mMatrix.getScaleX(), mMatrix.getScaleY(),
- mMatrix.getTranslateX(), mMatrix.getTranslateY(),
- SkFixedToScalar(mMinSpaceWidth));
- }
- return mMinSpaceWidth;
- }
-
- void recordGlyph(const SkBounder::GlyphRec& rec)
- {
- mLastCandidate = rec;
- mLastUniCandidate = getUniChar(rec);
- mLastPaintCandidate = mPaint;
- }
-
- void reset()
- {
- mMinSpaceWidth = SK_FixedMax; // mark as uninitialized
- mBase = mBottom = mTop = INT_MAX; // mark as uninitialized
- }
-
- void set(CommonCheck& check)
- {
- mLastGlyph = check.mLastGlyph;
- mLastUni = check.mLastUni;
- mMatrix = check.mMatrix;
- mLastPaint = check.mLastPaint;
- reset();
- }
-
- void setGlyph(CommonCheck& check)
- {
- mLastGlyph = check.mLastGlyph;
- mLastUni = check.mLastUni;
- mLastPaint = check.mLastPaint;
- }
-
- void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y,
- const void* text)
- {
- mMatrix = matrix;
- mPaint = paint;
- mText = static_cast<const uint16_t*>(text);
- mY = y;
- reset();
- }
-
- /* called only while the picture is parsed */
- int top() {
- if (mTop == INT_MAX) {
- SkPoint result;
- SkPaint::FontMetrics metrics;
- mPaint.getFontMetrics(&metrics);
- mMatrix.mapXY(0, metrics.fAscent + mY, &result);
- mTop = SkScalarFloor(result.fY);
- }
- return mTop;
- }
-
-#if DEBUG_NAV_UI
- // make current (possibily uncomputed) value visible for debugging
- int topDebug() const
- {
- return mTop;
- }
-#endif
-
-protected:
- SkIRect mArea;
- SkBounder::GlyphRec mLastCandidate;
- SkBounder::GlyphRec mLastGlyph;
- SkPaint mLastPaint; // available after picture has been parsed
- SkPaint mLastPaintCandidate; // associated with candidate glyph
- SkUnichar mLastUni;
- SkUnichar mLastUniCandidate;
- SkMatrix mMatrix;
- SkPaint mPaint; // only set up while the picture is parsed
- const uint16_t* mText;
- SkScalar mY;
-private:
- int mBase;
- int mBottom;
- SkFixed mMinSpaceWidth;
- int mTop;
- friend class EdgeCheck;
-};
-
-// generate the limit area for the new selection
-class LineCheck : public CommonCheck {
-public:
- LineCheck(int x, int y, const SkIRect& area)
- : INHERITED(area)
- , mX(x)
- , mY(y)
- , mInBetween(false)
- {
- mLast.setEmpty();
- }
-
- void finish(const SkRegion& selectedRgn)
- {
- if (!mParagraphs.count() && mLast.isEmpty())
- return;
- processLine();
- bool above = false;
- bool below = false;
- bool selected = false;
- SkRegion localRgn(selectedRgn);
- localRgn.translate(-mArea.fLeft, -mArea.fTop, &localRgn);
- DBG_NAV_LOGD("localRgn=(%d,%d,%d,%d)",
- localRgn.getBounds().fLeft, localRgn.getBounds().fTop,
- localRgn.getBounds().fRight, localRgn.getBounds().fBottom);
- for (int index = 0; index < mParagraphs.count(); index++) {
- const SkIRect& rect = mParagraphs[index];
- bool localSelected = localRgn.intersects(rect);
- DBG_NAV_LOGD("[%d] rect=(%d,%d,%d,%d)", index, rect.fLeft, rect.fTop,
- rect.fRight, rect.fBottom);
- if (localSelected) {
- DBG_NAV_LOGD("[%d] localSelected=true", index);
- *mSelected.append() = rect;
- }
- if (rect.fRight <= mX || rect.fLeft >= mX)
- continue;
- if (mY > rect.fBottom) {
- below = true;
- selected |= localSelected;
- DBG_NAV_LOGD("[%d] below=true localSelected=%s", index,
- localSelected ? "true" : "false");
- }
- if (mY < rect.fTop) {
- above = true;
- selected |= localSelected;
- DBG_NAV_LOGD("[%d] above=true localSelected=%s", index,
- localSelected ? "true" : "false");
- }
- }
- DBG_NAV_LOGD("mX=%d mY=%d above=%s below=%s selected=%s",
- mX, mY, above ? "true" : "false", below ? "true" : "false",
- selected ? "true" : "false");
- mInBetween = above && below && selected;
- }
-
- bool inBetween() const
- {
- return mInBetween;
- }
-
- bool inColumn(const SkIRect& test) const
- {
- for (int index = 0; index < mSelected.count(); index++) {
- const SkIRect& rect = mSelected[index];
- if (rect.fRight > test.fLeft && rect.fLeft < test.fRight)
- return true;
- }
- return false;
- }
-
- bool inColumn(int x, int y) const
- {
- for (int index = 0; index < mSelected.count(); index++) {
- const SkIRect& rect = mSelected[index];
- if (rect.contains(x, y))
- return true;
- }
- return false;
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- SkIRect bounds;
- bounds.set(rect.fLeft, top(), rect.fRight, bottom());
- // assume that characters must be consecutive to describe spaces
- // (i.e., don't join rects drawn at different times)
- if (bounds.fTop != mLast.fTop || bounds.fBottom != mLast.fBottom
- || bounds.fLeft > mLast.fRight + minSpaceWidth(mPaint)
- || bounds.fLeft < mLast.fLeft) {
- processLine();
- mLast = bounds;
- } else
- mLast.join(bounds);
- return false;
- }
-
- void processLine()
- {
- // assume line spacing of 1.5
- int lineHeight = bottom() - top();
- mLast.inset(0, -lineHeight >> 1);
- // collect arrays of rectangles making up glyphs below or above this one
- for (int index = 0; index < mParagraphs.count(); index++) {
- SkIRect& rect = mParagraphs[index];
- if (SkIRect::Intersects(rect, mLast)) {
- rect.join(mLast);
- return;
- }
- }
- *mParagraphs.append() = mLast;
- }
-
-protected:
- int mX;
- int mY;
- SkIRect mLast;
- SkTDArray<SkIRect> mParagraphs;
- SkTDArray<SkIRect> mSelected;
- bool mInBetween;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class SelectText::FirstCheck : public CommonCheck {
-public:
- FirstCheck(int x, int y, const SkIRect& area)
- : INHERITED(area)
- , mLineCheck(0)
- , mFocusX(x - area.fLeft)
- , mFocusY(y - area.fTop)
- , mBestInColumn(false)
- , mRecordGlyph(false)
- {
- reset();
- }
-
- const SkIRect& adjustedBounds(int* base)
- {
- *base = mBestBase + mArea.fTop;
- mBestBounds.offset(mArea.fLeft, mArea.fTop);
- DBG_NAV_LOGD("FirstCheck mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d",
- mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight,
- mBestBounds.fBottom, topDebug(), bottomDebug());
- return mBestBounds;
- }
-
- int focusX() const { return mFocusX; }
- int focusY() const { return mFocusY; }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- /* compute distance from rectangle center.
- * centerX = (rect.L + rect.R) / 2
- * multiply centerX and comparison x by 2 to retain better precision
- */
- SkIRect testBounds = {rect.fLeft, top(), rect.fRight, bottom()};
- // dx and dy are the distances from the tested edge
- // The edge distance is paramount if the test point is far away
- int dx = std::max(0, std::max(testBounds.fLeft - mFocusX,
- mFocusX - testBounds.fRight));
- int dy = std::max(0, std::max(testBounds.fTop - mFocusY,
- mFocusY - testBounds.fBottom));
- bool testInColumn = false;
- bool inBetween = false;
- bool inFocus = false;
- if (mLineCheck) {
- testInColumn = mLineCheck->inColumn(testBounds);
- inBetween = mLineCheck->inBetween();
- inFocus = mLineCheck->inColumn(mFocusX, mFocusY);
- }
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) {
- SkUnichar ch = getUniChar(rec);
- DBG_NAV_LOGD("FC dx/y=%d,%d mDx/y=%d,%d test=%d,%d,%d,%d"
- " best=%d,%d,%d,%d bestIn=%s tween=%s testIn=%s focus=%s ch=%c",
- dx, dy, mDx, mDy,
- testBounds.fLeft, testBounds.fTop, testBounds.fRight,
- testBounds.fBottom, mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom,
- mBestInColumn ? "true" : "false", inBetween ? "true" : "false",
- testInColumn ? "true" : "false", inFocus ? "true" : "false",
- ch < 0x7f ? ch : '?');
- }
-#endif
- if ((mBestInColumn || inBetween) && !testInColumn) {
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) DBG_NAV_LOG("FirstCheck reject column");
-#endif
- return false;
- }
- bool ignoreColumn = mBestInColumn == testInColumn || !inFocus;
- if (ignoreColumn && dy > 0 && (mDy < dy
- || (mDy == dy && dx > 0 && mDx <= dx))) {
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) DBG_NAV_LOG("FirstCheck reject edge");
-#endif
- return false;
- }
- // cx and cy are the distances from the tested center
- // The center distance is used when the test point is over the text
- int cx = std::abs(((testBounds.fLeft + testBounds.fRight) >> 1)
- - mFocusX);
- int cy = std::abs(((testBounds.fTop + testBounds.fBottom) >> 1)
- - mFocusY);
- if (ignoreColumn && dy == 0 && mDy == 0) {
- if (mCy < cy) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject cy=%d mCy=%d", cy, mCy);
-#endif
- return false;
- }
- if (mCy == cy) {
- if (dx == 0 && mDx == 0) {
- if (mCx < cx) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject cx=%d mCx=%d", cx, mCx);
-#endif
- return false;
- }
- } else if (dx > 0 && mDx <= dx) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject dx=%d mDx=%d", dx, mDx);
-#endif
- return false;
- }
- }
- }
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) {
- DBG_NAV_LOGD("FirstCheck cx/y=(%d,%d)", cx, cy);
- }
-#endif
- mBestBase = base();
- mBestBounds = testBounds;
- mBestInColumn = testInColumn;
-#ifndef EXTRA_NOISY_LOGGING
- if (dy < 10 && dx < 10)
-#endif
- {
-#if DEBUG_NAV_UI
- SkUnichar ch = getUniChar(rec);
-#endif
- DBG_NAV_LOGD("FirstCheck dx/y=(%d,%d) mFocus=(%d,%d)"
- " mBestBounds={%d,%d,r=%d,b=%d} inColumn=%s ch=%c",
- dx, dy, mFocusX, mFocusY,
- mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom,
- mBestInColumn ? "true" : "false", ch < 0x7f ? ch : '?');
- }
- mCx = cx;
- mCy = cy;
- mDx = dx;
- mDy = dy;
- if (mRecordGlyph)
- recordGlyph(rec);
- return false;
- }
-
- void reset()
- {
- mBestBounds.setEmpty();
- mDx = mDy = mCx = mCy = INT_MAX;
- }
-
- void setLines(const LineCheck* lineCheck) { mLineCheck = lineCheck; }
- void setRecordGlyph() { mRecordGlyph = true; }
-
-protected:
- const LineCheck* mLineCheck;
- int mBestBase;
- SkIRect mBestBounds;
- int mCx;
- int mCy;
- int mDx;
- int mDy;
- int mFocusX;
- int mFocusY;
- bool mBestInColumn;
- bool mRecordGlyph;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class SelectText::EdgeCheck : public SelectText::FirstCheck {
-public:
- EdgeCheck(int x, int y, const SkIRect& area, CommonCheck& last, bool left)
- : INHERITED(x, y, area)
- , mLast(area)
- , mLeft(left)
- {
- mLast.set(last); // CommonCheck::set()
- setGlyph(last);
- }
-
- bool adjacent()
- {
- return !mLast.isSpace(mLastGlyph);
- }
-
- const SkIRect& bestBounds(int* base)
- {
- *base = mBestBase;
- return mBestBounds;
- }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- int dx = mLeft ? mFocusX - rect.fRight : rect.fLeft - mFocusX;
- int dy = ((top() + bottom()) >> 1) - mFocusY;
- dx = abs(dx);
- dy = abs(dy);
- if (mLeft ? mFocusX <= rect.fLeft : mFocusX >= rect.fRight) {
- if (dx <= 10 && dy <= 10) {
- DBG_NAV_LOGD("EdgeCheck fLeft=%d fRight=%d mFocusX=%d dx=%d dy=%d",
- rect.fLeft, rect.fRight, mFocusX, dx, dy);
- }
- return false;
- }
- if (mDy > dy || (mDy == dy && mDx > dx)) {
- if (rec.fLSB == mLastGlyph.fLSB && rec.fRSB == mLastGlyph.fRSB) {
- DBG_NAV_LOGD("dup rec.fLSB.fX=%g rec.fRSB.fX=%g",
- SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fRSB.fX));
- return false;
- }
- recordGlyph(rec);
- mDx = dx;
- mDy = dy;
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- if (dx <= 10 && dy <= 10) {
- DBG_NAV_LOGD("EdgeCheck mBestBounds={%d,%d,r=%d,b=%d} dx/y=(%d, %d)",
- mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom, dx, dy);
- }
- }
- return false;
- }
-
- void shiftStart(SkIRect bounds)
- {
- DBG_NAV_LOGD("EdgeCheck mFocusX=%d mLeft=%s bounds.fLeft=%d bounds.fRight=%d",
- mFocusX, mLeft ? "true" : "false", bounds.fLeft, bounds.fRight);
- reset();
- mFocusX = mLeft ? bounds.fLeft : bounds.fRight;
- mLast.set(*this); // CommonCheck::set()
- }
-
-protected:
- CommonCheck mLast;
- bool mLeft;
-private:
- typedef SelectText::FirstCheck INHERITED;
-};
-
-class FindFirst : public CommonCheck {
-public:
- FindFirst(const SkIRect& area)
- : INHERITED(area)
- {
- mBestBounds.set(area.width(), area.height(), area.width(), area.height());
- }
-
- const SkIRect& bestBounds(int* base)
- {
- *base = mBestBase;
- return mBestBounds;
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- if (mBestBounds.isEmpty()) {
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- }
- return false;
- }
-
-protected:
- int mBestBase;
- SkIRect mBestBounds;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class FindLast : public FindFirst {
-public:
- FindLast(const SkIRect& area)
- : INHERITED(area)
- {
- mBestBounds.setEmpty();
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- return false;
- }
-
-private:
- typedef FindFirst INHERITED;
-};
-
-static bool baseLinesAgree(const SkIRect& rectA, int baseA,
- const SkIRect& rectB, int baseB)
-{
- return (rectA.fTop < baseB && rectA.fBottom >= baseB)
- || (rectB.fTop < baseA && rectB.fBottom >= baseA);
-}
-
-class BuilderCheck : public CommonCheck {
-protected:
- enum IntersectionType {
- NO_INTERSECTION, // debugging printf expects this to equal zero
- LAST_INTERSECTION, // debugging printf expects this to equal one
- WAIT_FOR_INTERSECTION
- };
-
- BuilderCheck(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area)
- : INHERITED(area)
- , mCapture(false)
- , mEnd(end)
- , mEndBase(endBase)
- , mStart(start)
- , mStartBase(startBase)
- {
- mEnd.offset(-area.fLeft, -area.fTop);
- mEndBase -= area.fTop;
- mEndExtra.setEmpty();
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mSelectRect.setEmpty();
- mStart.offset(-area.fLeft, -area.fTop);
- mStartBase -= area.fTop;
- mStartExtra.setEmpty();
- DBG_NAV_LOGD(" mStart=(%d,%d,r=%d,b=%d) mStartBase=%d"
- " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d",
- mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase,
- mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase);
- }
-
- int checkFlipRect(const SkIRect& full, int fullBase) {
- mCollectFull = false;
- // is the text to collect between the selection top and bottom?
- if (fullBase < mStart.fTop || fullBase > mEnd.fBottom) {
- if (VERBOSE_LOGGING && !mLast.isEmpty()) DBG_NAV_LOGD("%s 1"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase);
- return mLastIntersects;
- }
- // is the text to the left of the selection start?
- if (baseLinesAgree(mStart, mStartBase, full, fullBase)
- && full.fLeft < mStart.fLeft) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 2"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mStart=(%d,%d,r=%d,b=%d) mStartBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase);
- mStartExtra.join(full);
- return mLastIntersects;
- }
- // is the text to the right of the selection end?
- if (baseLinesAgree(mEnd, mEndBase, full, fullBase)
- && full.fRight > mEnd.fRight) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 3"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase);
- mEndExtra.join(full);
- return mLastIntersects;
- }
- int spaceGap = SkFixedRound(minSpaceWidth(mPaint) * 3);
- // should text to the left of the start be added to the selection bounds?
- if (!mStartExtra.isEmpty()) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)"
- " mStartExtra=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom);
- if (mStartExtra.fRight + spaceGap >= mStart.fLeft)
- mSelectRect.join(mStartExtra);
- mStartExtra.setEmpty();
- }
- // should text to the right of the end be added to the selection bounds?
- if (!mEndExtra.isEmpty()) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)"
- " mEndExtra=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom);
- if (mEndExtra.fLeft - spaceGap <= mEnd.fRight)
- mSelectRect.join(mEndExtra);
- mEndExtra.setEmpty();
- }
- bool sameBaseLine = baseLinesAgree(mLast, mLastBase, full, fullBase);
- bool adjacent = (full.fLeft - mLast.fRight) < spaceGap;
- // is this the first, or are there more characters on the same line?
- if (mLast.isEmpty() || (sameBaseLine && adjacent)) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("WAIT_FOR_INTERSECTION"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mSelectRect=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
- mLast.join(full);
- mLastIntersects = SkIRect::Intersects(mLast, mSelectRect);
- return WAIT_FOR_INTERSECTION;
- }
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 4"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mSelectRect=(%d,%d,r=%d,b=%d)"
- " mStartExtra=(%d,%d,r=%d,b=%d)"
- " mEndExtra=(%d,%d,r=%d,b=%d)",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom,
- mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom);
- // after the caller determines what to do with the last collection,
- // start the collection over with full and fullBase.
- mCollectFull = true;
- return mLastIntersects;
- }
-
- bool resetLast(const SkIRect& full, int fullBase)
- {
- if (mCollectFull) {
- mLast = full;
- mLastBase = fullBase;
- mLastIntersects = SkIRect::Intersects(mLast, mSelectRect);
- } else {
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mLastIntersects = false;
- }
- return mCollectFull;
- }
-
- void setFlippedState()
- {
- mSelectRect = mStart;
- mSelectRect.join(mEnd);
- DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mLastIntersects = NO_INTERSECTION;
- }
-
- bool mCapture;
- bool mCollectFull;
- SkIRect mEnd;
- int mEndBase;
- SkIRect mEndExtra;
- bool mFlipped;
- SkIRect mLast;
- int mLastBase;
- int mLastIntersects;
- SkIRect mSelectRect;
- SkIRect mStart;
- SkIRect mStartExtra;
- int mStartBase;
-private:
- typedef CommonCheck INHERITED;
-
-};
-
-class MultilineBuilder : public BuilderCheck {
-public:
- MultilineBuilder(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area, SkRegion* region)
- : INHERITED(start, startBase, end, endBase, area)
- , mSelectRegion(region)
- {
- mFlipped = false;
- }
-
- void addLastToRegion() {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD(" mLast=(%d,%d,r=%d,b=%d)",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
- mSelectRegion->op(mLast, SkRegion::kUnion_Op);
- }
-
- void finish() {
- if (!mFlipped || !mLastIntersects)
- return;
- addLastToRegion();
- }
-
- // return true if capture end was not found after capture begin
- bool flipped() {
- DBG_NAV_LOGD("flipped=%s", mCapture ? "true" : "false");
- if (!mCapture)
- return false;
- mFlipped = true;
- setFlippedState();
- mSelectRegion->setEmpty();
- return true;
- }
-
- virtual bool onIRect(const SkIRect& rect) {
- SkIRect full;
- full.set(rect.fLeft, top(), rect.fRight, bottom());
- int fullBase = base();
- if (mFlipped) {
- int intersectType = checkFlipRect(full, fullBase);
- if (intersectType == LAST_INTERSECTION)
- addLastToRegion();
- if (intersectType != WAIT_FOR_INTERSECTION)
- resetLast(full, fullBase);
- return false;
- }
- if (full == mStart) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mStart full=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom);
- mCapture = true;
- }
- if (mCapture) {
- bool sameLines = baseLinesAgree(mLast, mLastBase, full, fullBase);
- if (sameLines)
- mLast.join(full);
- if (!sameLines || full == mEnd) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("finish mLast=(%d,%d,r=%d,b=%d)",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
- addLastToRegion();
- mLast = full;
- mLastBase = fullBase;
- }
- }
- if (full == mEnd) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mEnd full=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom);
- mCapture = false;
- if (full == mStart)
- addLastToRegion();
- }
- return false;
- }
-
-protected:
- SkRegion* mSelectRegion;
-private:
- typedef BuilderCheck INHERITED;
-};
-
-static inline bool compareBounds(const SkIRect* first, const SkIRect* second)
-{
- return first->fTop < second->fTop;
-}
-
-class TextExtractor : public BuilderCheck {
-public:
- TextExtractor(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area, bool flipped)
- : INHERITED(start, startBase, end, endBase, area)
- , mSelectStartIndex(-1)
- , mSkipFirstSpace(true) // don't start with a space
- {
- mFlipped = flipped;
- if (flipped)
- setFlippedState();
- }
-
- void addCharacter(const SkBounder::GlyphRec& rec)
- {
- if (mSelectStartIndex < 0)
- mSelectStartIndex = mSelectText.count();
- if (!mSkipFirstSpace) {
- if (addNewLine(rec)) {
- DBG_NAV_LOG("write new line");
- *mSelectText.append() = '\n';
- *mSelectText.append() = '\n';
- } else if (addSpace(rec)) {
- DBG_NAV_LOG("write space");
- *mSelectText.append() = ' ';
- }
- } else
- mSkipFirstSpace = false;
- recordGlyph(rec);
- finishGlyph();
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("glyphID=%d uni=%d '%c'", rec.fGlyphID,
- mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
- if (mLastUni) {
- uint16_t chars[2];
- size_t count = SkUTF16_FromUnichar(mLastUni, chars);
- *mSelectText.append() = chars[0];
- if (count == 2)
- *mSelectText.append() = chars[1];
- }
- }
-
- void addLast()
- {
- *mSelectBounds.append() = mLast;
- *mSelectStart.append() = mSelectStartIndex;
- *mSelectEnd.append() = mSelectText.count();
- }
-
- /* Text characters are collected before it's been determined that the
- characters are part of the selection. The bounds describe valid parts
- of the selection, but the bounds are out of order.
-
- This sorts the characters by sorting the bounds, then copying the
- characters that were captured.
- */
- void finish()
- {
- if (mLastIntersects)
- addLast();
- Vector<SkIRect*> sortedBounds;
- SkTDArray<uint16_t> temp;
- int index;
- DBG_NAV_LOGD("mSelectBounds.count=%d text=%d", mSelectBounds.count(),
- mSelectText.count());
- for (index = 0; index < mSelectBounds.count(); index++)
- sortedBounds.append(&mSelectBounds[index]);
- std::sort(sortedBounds.begin(), sortedBounds.end(), compareBounds);
- int lastEnd = -1;
- for (index = 0; index < mSelectBounds.count(); index++) {
- int order = sortedBounds[index] - &mSelectBounds[0];
- int start = mSelectStart[order];
- int end = mSelectEnd[order];
- DBG_NAV_LOGD("order=%d start=%d end=%d top=%d", order, start, end,
- mSelectBounds[order].fTop);
- int count = temp.count();
- if (count > 0 && temp[count - 1] != '\n' && start != lastEnd) {
- // always separate paragraphs when original text is out of order
- DBG_NAV_LOG("write new line");
- *temp.append() = '\n';
- *temp.append() = '\n';
- }
- temp.append(end - start, &mSelectText[start]);
- lastEnd = end;
- }
- mSelectText.swap(temp);
- }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- SkIRect full;
- full.set(rect.fLeft, top(), rect.fRight, bottom());
- int fullBase = base();
- if (mFlipped) {
- int intersectType = checkFlipRect(full, fullBase);
- if (WAIT_FOR_INTERSECTION == intersectType)
- addCharacter(rec); // may not be copied
- else {
- if (LAST_INTERSECTION == intersectType)
- addLast();
- else
- mSkipFirstSpace = true;
- mSelectStartIndex = -1;
- if (resetLast(full, fullBase))
- addCharacter(rec); // may not be copied
- }
- return false;
- }
- if (full == mStart)
- mCapture = true;
- if (mCapture)
- addCharacter(rec);
- else
- mSkipFirstSpace = true;
- if (full == mEnd)
- mCapture = false;
- return false;
- }
-
- WTF::String text() {
- if (mFlipped)
- finish();
- // the text has been copied in visual order. Reverse as needed if
- // result contains right-to-left characters.
- const uint16_t* start = mSelectText.begin();
- const uint16_t* end = mSelectText.end();
- while (start < end) {
- SkUnichar ch = SkUTF16_NextUnichar(&start);
- WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch);
- if (WTF::Unicode::RightToLeftArabic == charDirection
- || WTF::Unicode::RightToLeft == charDirection) {
- WebCore::ReverseBidi(mSelectText.begin(), mSelectText.count());
- break;
- }
- }
- return WTF::String(mSelectText.begin(), mSelectText.count());
- }
-
-protected:
- SkIRect mEmpty;
- SkTDArray<SkIRect> mSelectBounds;
- SkTDArray<int> mSelectEnd;
- SkTDArray<int> mSelectStart;
- int mSelectStartIndex;
- SkTDArray<uint16_t> mSelectText;
- bool mSkipFirstSpace;
-private:
- typedef BuilderCheck INHERITED;
-};
-
-class TextCanvas : public ParseCanvas {
-public:
-
- TextCanvas(CommonCheck* bounder)
- : mBounder(*bounder) {
- setBounder(bounder);
- SkBitmap bitmap;
- const SkIRect& area = bounder->getArea();
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, area.width(),
- area.height());
- setBitmapDevice(bitmap);
- translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop));
-#ifdef DEBUG_NAV_UI
- const SkIRect& clip = getTotalClip().getBounds();
- const SkMatrix& matrix = getTotalMatrix();
- DBG_NAV_LOGD("bitmap=(%d,%d) clip=(%d,%d,%d,%d) matrix=(%g,%g)",
- bitmap.width(), bitmap.height(), clip.fLeft, clip.fTop,
- clip.fRight, clip.fBottom, matrix.getTranslateX(), matrix.getTranslateY());
-#endif
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- }
-
- virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
- }
-
- virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
- }
-
- virtual void drawPath(const SkPath& path, const SkPaint& paint) {
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
- const SkMatrix& matrix, const SkPaint& paint) {
- }
-
- virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL) {
- }
-
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- mBounder.setUp(paint, getTotalMatrix(), y, text);
- INHERITED::drawText(text, byteLength, x, y, paint);
- }
-
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- mBounder.setUp(paint, getTotalMatrix(), constY, text);
- INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
- }
-
- virtual void drawVertices(VertexMode vmode, int vertexCount,
- const SkPoint vertices[], const SkPoint texs[],
- const SkColor colors[], SkXfermode* xmode,
- const uint16_t indices[], int indexCount,
- const SkPaint& paint) {
- }
-
- CommonCheck& mBounder;
-private:
- typedef ParseCanvas INHERITED;
-};
-
-static bool buildSelection(const SkPicture& picture, const SkIRect& area,
- const SkIRect& selStart, int startBase,
- const SkIRect& selEnd, int endBase, SkRegion* region)
-{
- DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)"
- " selEnd=(%d, %d, %d, %d)",
- area.fLeft, area.fTop, area.fRight, area.fBottom,
- selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom,
- selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom);
- MultilineBuilder builder(selStart, startBase, selEnd, endBase, area, region);
- TextCanvas checker(&builder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- bool flipped = builder.flipped();
- if (flipped) {
- TextCanvas checker(&builder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- }
- builder.finish();
- region->translate(area.fLeft, area.fTop);
- return flipped;
-}
-
-static SkIRect findFirst(const SkPicture& picture, int* base)
-{
- SkIRect area;
- area.set(0, 0, picture.width(), picture.height());
- FindFirst finder(area);
- TextCanvas checker(&finder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return finder.bestBounds(base);
-}
-
-static SkIRect findLast(const SkPicture& picture, int* base)
-{
- SkIRect area;
- area.set(0, 0, picture.width(), picture.height());
- FindLast finder(area);
- TextCanvas checker(&finder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return finder.bestBounds(base);
-}
-
-static WTF::String text(const SkPicture& picture, const SkIRect& area,
- const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, bool flipped)
-{
- TextExtractor extractor(start, startBase, end, endBase, area, flipped);
- TextCanvas checker(&extractor);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return extractor.text();
-}
-
-#define CONTROL_NOTCH 16
-// TODO: Now that java is the one actually drawing these, get the real values
-// from the drawable itself
-#define CONTROL_HEIGHT 47
-#define CONTROL_WIDTH 26
-#define CONTROL_SLOP 5
-#define STROKE_WIDTH 1.0f
-#define STROKE_OUTSET 3.5f
-#define STROKE_I_OUTSET 4 // (int) ceil(STROKE_OUTSET)
-#define STROKE_COLOR 0x66000000
-#define OUTER_COLOR 0x33000000
-#define INNER_COLOR 0xe6aae300
-
-SelectText::SelectText()
- : m_controlWidth(CONTROL_WIDTH)
- , m_controlHeight(CONTROL_HEIGHT)
- , m_controlSlop(CONTROL_SLOP)
-{
- m_picture = 0;
- reset();
- SkPaint paint;
- SkRect oval;
-
- SkPath startOuterPath;
- oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET,
- -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 180, 45, true);
- oval.set(-STROKE_OUTSET, -STROKE_OUTSET, STROKE_OUTSET, STROKE_OUTSET);
- startOuterPath.arcTo(oval, 180 + 45, 135, false);
- oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 0, 90, false);
- oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 90, 90, false);
- startOuterPath.close();
- SkPath startInnerPath;
- startInnerPath.moveTo(-CONTROL_WIDTH, CONTROL_NOTCH);
- startInnerPath.lineTo(-CONTROL_WIDTH, CONTROL_HEIGHT);
- startInnerPath.lineTo(0, CONTROL_HEIGHT);
- startInnerPath.lineTo(0, 0);
- startInnerPath.close();
- startOuterPath.addPath(startInnerPath, 0, 0);
-
- SkCanvas* canvas = m_startControl.beginRecording(
- CONTROL_WIDTH + STROKE_OUTSET * 2,
- CONTROL_HEIGHT + STROKE_OUTSET * 2);
- paint.setAntiAlias(true);
- paint.setColor(INNER_COLOR);
- paint.setStyle(SkPaint::kFill_Style);
- canvas->drawPath(startInnerPath, paint);
- paint.setColor(OUTER_COLOR);
- canvas->drawPath(startOuterPath, paint);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(STROKE_COLOR);
- paint.setStrokeWidth(STROKE_WIDTH);
- canvas->drawPath(startInnerPath, paint);
- m_startControl.endRecording();
-
- SkPath endOuterPath;
- oval.set(-STROKE_OUTSET, -STROKE_OUTSET, STROKE_OUTSET, STROKE_OUTSET);
- endOuterPath.arcTo(oval, 180, 135, true);
- oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET,
- CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 360 - 45, 45, false);
- oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 0, 90, false);
- oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 90, 90, false);
- startOuterPath.close();
- SkPath endInnerPath;
- endInnerPath.moveTo(0, 0);
- endInnerPath.lineTo(0, CONTROL_HEIGHT);
- endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_HEIGHT);
- endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_NOTCH);
- endInnerPath.close();
- endOuterPath.addPath(endInnerPath, 0, 0);
-
- canvas = m_endControl.beginRecording(CONTROL_WIDTH + STROKE_OUTSET * 2,
- CONTROL_HEIGHT + STROKE_OUTSET * 2);
- paint.setColor(INNER_COLOR);
- paint.setStyle(SkPaint::kFill_Style);
- canvas->drawPath(endInnerPath, paint);
- paint.setColor(OUTER_COLOR);
- canvas->drawPath(endOuterPath, paint);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(STROKE_COLOR);
- paint.setStrokeWidth(STROKE_WIDTH);
- canvas->drawPath(endInnerPath, paint);
- m_endControl.endRecording();
-}
-
-SelectText::~SelectText()
-{
- SkSafeUnref(m_picture);
-}
-
-void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval)
-{
- if (m_layerId != layer->uniqueId())
- return;
- // reset m_picture to match m_layerId
- SkSafeUnref(m_picture);
- m_picture = layer->picture();
- SkSafeRef(m_picture);
- DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d layer [%d]",
- m_extendSelection, m_drawPointer, layer->uniqueId());
- if (m_extendSelection)
- drawSelectionRegion(canvas, inval);
- if (m_drawPointer)
- drawSelectionPointer(canvas, inval);
-}
-
-static void addInval(IntRect* inval, const SkCanvas* canvas,
- const SkRect& bounds) {
- const SkMatrix& matrix = canvas->getTotalMatrix();
- SkRect transformed;
- matrix.mapRect(&transformed, bounds);
- SkIRect iTrans;
- transformed.round(&iTrans);
- inval->unite(iTrans);
-}
-
-void SelectText::drawSelectionPointer(SkCanvas* canvas, IntRect* inval)
-{
- SkPath path;
- if (m_extendSelection)
- getSelectionCaret(&path);
- else
- getSelectionArrow(&path);
- SkPixelXorXfermode xorMode(SK_ColorWHITE);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(SK_ColorBLACK);
- if (m_extendSelection)
- paint.setXfermode(&xorMode);
- else
- paint.setStrokeWidth(SK_Scalar1 * 2);
- int sc = canvas->save();
- canvas->scale(m_inverseScale, m_inverseScale);
- canvas->translate(m_selectX, m_selectY);
- canvas->drawPath(path, paint);
- if (!m_extendSelection) {
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(SK_ColorWHITE);
- canvas->drawPath(path, paint);
- }
- SkRect bounds = path.getBounds();
- bounds.inset(-SK_Scalar1 * 2, -SK_Scalar1 * 2); // stroke width
- addInval(inval, canvas, bounds);
- canvas->restoreToCount(sc);
-}
-
-static void addStart(SkRegion* diff, const SkIRect& rect)
-{
- SkIRect bounds;
- bounds.set(rect.fLeft - CONTROL_WIDTH - STROKE_I_OUTSET,
- rect.fBottom - STROKE_I_OUTSET, rect.fLeft + STROKE_I_OUTSET,
- rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET);
- diff->op(bounds, SkRegion::kUnion_Op);
-}
-
-static void addEnd(SkRegion* diff, const SkIRect& rect)
-{
- SkIRect bounds;
- bounds.set(rect.fRight - STROKE_I_OUTSET, rect.fBottom - STROKE_I_OUTSET,
- rect.fRight + CONTROL_WIDTH + STROKE_I_OUTSET,
- rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET);
- diff->op(bounds, SkRegion::kUnion_Op);
-}
-
-void SelectText::getSelectionRegion(const IntRect& vis, SkRegion *region,
- LayerAndroid* root)
-{
- SkIRect ivisBounds = vis;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- region->setEmpty();
- buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, region);
- if (root && m_layerId) {
- Layer* layer = root->findById(m_layerId);
- while (layer) {
- const SkPoint& pos = layer->getPosition();
- region->translate(pos.fX, pos.fY);
- layer = layer->getParent();
- }
- }
-}
-
-void SelectText::drawSelectionRegion(SkCanvas* canvas, IntRect* inval)
-{
- if (!m_picture)
- return;
- SkIRect ivisBounds = m_visibleRect;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)"
- " ivisBounds=(%d,%d,r=%d,b=%d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
- ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
- if (m_lastSelRegion != m_selRegion)
- m_lastSelRegion.set(m_selRegion);
- SkRegion diff(m_lastSelRegion);
- m_selRegion.setEmpty();
- m_flipped = buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, &m_selRegion);
- SkPath path;
- m_selRegion.getBoundaryPath(&path);
- path.setFillType(SkPath::kEvenOdd_FillType);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SkColorSetARGB(0x80, 0x83, 0xCC, 0x39));
- canvas->drawPath(path, paint);
- // experiment to draw touchable controls that resize the selection
- float scale = m_controlHeight / (float)CONTROL_HEIGHT;
- canvas->save();
- canvas->translate(m_selStart.fLeft, m_selStart.fBottom);
- canvas->scale(scale, scale);
- canvas->drawPicture(m_startControl);
- canvas->restore();
- canvas->save();
- canvas->translate(m_selEnd.fRight, m_selEnd.fBottom);
- canvas->scale(scale, scale);
- canvas->drawPicture(m_endControl);
- canvas->restore();
-
-#if DEBUG_TOUCH_HANDLES
- SkRect touchHandleRect;
- paint.setColor(SkColorSetARGB(0x60, 0xFF, 0x00, 0x00));
- touchHandleRect.set(0, m_selStart.fBottom, m_selStart.fLeft, 0);
- touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight;
- touchHandleRect.fLeft = touchHandleRect.fRight - m_controlWidth;
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.inset(-m_controlSlop, -m_controlSlop);
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.set(m_selEnd.fRight, m_selEnd.fBottom, 0, 0);
- touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight;
- touchHandleRect.fRight = touchHandleRect.fLeft + m_controlWidth;
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.inset(-m_controlSlop, -m_controlSlop);
- canvas->drawRect(touchHandleRect, paint);
-#endif
-
- SkIRect a = diff.getBounds();
- SkIRect b = m_selRegion.getBounds();
- diff.op(m_selRegion, SkRegion::kXOR_Op);
- SkIRect c = diff.getBounds();
- DBG_NAV_LOGD("old=(%d,%d,r=%d,b=%d) new=(%d,%d,r=%d,b=%d) diff=(%d,%d,r=%d,b=%d)",
- a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom,
- c.fLeft, c.fTop, c.fRight, c.fBottom);
- DBG_NAV_LOGD("lastStart=(%d,%d,r=%d,b=%d) m_lastEnd=(%d,%d,r=%d,b=%d)",
- m_lastStart.fLeft, m_lastStart.fTop, m_lastStart.fRight, m_lastStart.fBottom,
- m_lastEnd.fLeft, m_lastEnd.fTop, m_lastEnd.fRight, m_lastEnd.fBottom);
- if (!m_lastDrawnStart.isEmpty())
- addStart(&diff, m_lastDrawnStart);
- if (m_lastStart != m_selStart) {
- m_lastDrawnStart = m_lastStart;
- m_lastStart = m_selStart;
- }
- addStart(&diff, m_selStart);
- if (!m_lastDrawnEnd.isEmpty())
- addEnd(&diff, m_lastDrawnEnd);
- if (m_lastEnd != m_selEnd) {
- m_lastDrawnEnd = m_lastEnd;
- m_lastEnd = m_selEnd;
- }
- addEnd(&diff, m_selEnd);
- SkIRect iBounds = diff.getBounds();
- DBG_NAV_LOGD("diff=(%d,%d,r=%d,b=%d)",
- iBounds.fLeft, iBounds.fTop, iBounds.fRight, iBounds.fBottom);
- SkRect bounds;
- bounds.set(iBounds);
- addInval(inval, canvas, bounds);
-}
-
-void SelectText::extendSelection(const IntRect& vis, int x, int y)
-{
- if (!m_picture)
- return;
- setVisibleRect(vis);
- SkIRect clipRect = m_visibleRect;
- int base;
- DBG_NAV_LOGD("extend x/y=%d,%d m_startOffset=%d,%d", x, y,
- m_startOffset.fX, m_startOffset.fY);
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- if (m_startSelection) {
- if (!clipRect.contains(x, y)
- || !clipRect.contains(m_original.fX, m_original.fY)) {
- clipRect.set(m_original.fX, m_original.fY, x, y);
- clipRect.sort();
- clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
- }
- FirstCheck center(m_original.fX, m_original.fY, clipRect);
- m_selStart = m_selEnd = findClosest(center, *m_picture, &base);
- if (m_selStart.isEmpty())
- return;
- DBG_NAV_LOGD("selStart clip=(%d,%d,%d,%d) m_original=%d,%d"
- " m_selStart=(%d,%d,%d,%d)", clipRect.fLeft, clipRect.fTop,
- clipRect.fRight, clipRect.fBottom, m_original.fX, m_original.fY,
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom);
- m_startBase = m_endBase = base;
- m_startSelection = false;
- m_extendSelection = true;
- m_original.fX = m_original.fY = 0;
- }
- DBG_NAV_LOGD("extend x/y=%d,%d m_original=%d,%d", x, y,
- m_original.fX, m_original.fY);
- x -= m_original.fX;
- y -= m_original.fY;
- if (!clipRect.contains(x, y) || !clipRect.contains(m_selStart)) {
- clipRect.set(m_selStart.fLeft, m_selStart.fTop, x, y);
- clipRect.sort();
- clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
- }
- DBG_NAV_LOGD("extend clip=(%d,%d,%d,%d) x/y=%d,%d wordSel=%s outsideWord=%s",
- clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, x, y,
- m_wordSelection ? "true" : "false", m_outsideWord ? "true" : "false");
- FirstCheck extension(x, y, clipRect);
- SkIRect found = findClosest(extension, *m_picture, &base);
- if (m_wordSelection) {
- SkIRect wordBounds = m_wordBounds;
- if (!m_outsideWord)
- wordBounds.inset(-TOUCH_SLOP, -TOUCH_SLOP);
- DBG_NAV_LOGD("x=%d y=%d wordBounds=(%d,%d,r=%d,b=%d)"
- " found=(%d,%d,r=%d,b=%d)", x, y, wordBounds.fLeft, wordBounds.fTop,
- wordBounds.fRight, wordBounds.fBottom, found.fLeft, found.fTop,
- found.fRight, found.fBottom);
- if (wordBounds.contains(x, y)) {
- DBG_NAV_LOG("wordBounds.contains=true");
- m_outsideWord = false;
- return;
- }
- m_outsideWord = true;
- if (found.fBottom <= wordBounds.fTop)
- m_hitTopLeft = true;
- else if (found.fTop >= wordBounds.fBottom)
- m_hitTopLeft = false;
- else
- m_hitTopLeft = (found.fLeft + found.fRight)
- < (wordBounds.fLeft + wordBounds.fRight);
- }
- DBG_NAV_LOGD("x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)"
- " m_extendSelection=%s",
- x, y, m_startSelection ? "true" : "false",
- m_hitTopLeft ? "m_selStart" : "m_selEnd",
- found.fLeft, found.fTop, found.fRight, found.fBottom,
- m_extendSelection ? "true" : "false");
- if (m_hitTopLeft) {
- m_startBase = base;
- m_selStart = found;
- } else {
- m_endBase = base;
- m_selEnd = found;
- }
- swapAsNeeded();
-}
-
-SkIRect SelectText::findClosest(FirstCheck& check, const SkPicture& picture,
- int* base)
-{
- LineCheck lineCheck(check.focusX(), check.focusY(), check.getArea());
- TextCanvas lineChecker(&lineCheck);
- lineChecker.drawPicture(const_cast<SkPicture&>(picture));
- lineCheck.finish(m_selRegion);
- check.setLines(&lineCheck);
- TextCanvas checker(&check);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- check.finishGlyph();
- return check.adjustedBounds(base);
-}
-
-SkIRect SelectText::findEdge(const SkPicture& picture, const SkIRect& area,
- int x, int y, bool left, int* base)
-{
- SkIRect result;
- result.setEmpty();
- FirstCheck center(x, y, area);
- center.setRecordGlyph();
- int closestBase;
- SkIRect closest = findClosest(center, picture, &closestBase);
- SkIRect sloppy = closest;
- sloppy.inset(-TOUCH_SLOP, -TOUCH_SLOP);
- if (!sloppy.contains(x, y)) {
- DBG_NAV_LOGD("sloppy=(%d, %d, %d, %d) area=(%d, %d, %d, %d) x/y=%d,%d",
- sloppy.fLeft, sloppy.fTop, sloppy.fRight, sloppy.fBottom,
- area.fLeft, area.fTop, area.fRight, area.fBottom, x, y);
- return result;
- }
- EdgeCheck edge(x, y, area, center, left);
- do { // detect left or right until there's a gap
- DBG_NAV_LOGD("edge=%p picture=%p area=%d,%d,%d,%d",
- &edge, &picture, area.fLeft, area.fTop, area.fRight, area.fBottom);
- TextCanvas checker(&edge);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- edge.finishGlyph();
- if (!edge.adjacent()) {
- if (result.isEmpty()) {
- *base = closestBase;
- DBG_NAV_LOGD("closest=%d,%d,%d,%d", closest.fLeft,
- closest.fTop, closest.fRight, closest.fBottom);
- return closest;
- }
- DBG_NAV_LOG("adjacent break");
- break;
- }
- int nextBase;
- const SkIRect& next = edge.bestBounds(&nextBase);
- if (next.isEmpty()) {
- DBG_NAV_LOG("empty");
- break;
- }
- if (result == next) {
- DBG_NAV_LOG("result == next");
- break;
- }
- *base = nextBase;
- result = next;
- edge.shiftStart(result);
- } while (true);
- if (!result.isEmpty()) {
- *base += area.fTop;
- result.offset(area.fLeft, area.fTop);
- }
- return result;
-}
-
-SkIRect SelectText::findLeft(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base)
-{
- return findEdge(picture, area, x, y, true, base);
-}
-
-SkIRect SelectText::findRight(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base)
-{
- return findEdge(picture, area, x, y, false, base);
-}
-
-const String SelectText::getSelection()
-{
- if (!m_picture)
- return String();
- SkIRect clipRect;
- clipRect.set(0, 0, m_picture->width(), m_picture->height());
- String result = text(*m_picture, clipRect, m_selStart, m_startBase,
- m_selEnd, m_endBase, m_flipped);
- DBG_NAV_LOGD("clip=(%d,%d,%d,%d)"
- " m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
- clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom,
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
- DBG_NAV_LOGD("text=%s", result.latin1().data()); // uses CString
- return result;
-}
-
-void SelectText::getSelectionArrow(SkPath* path)
-{
- const int arrow[] = {
- 0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
- };
- for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
- path->lineTo(arrow[index], arrow[index + 1]);
- path->close();
-}
-
-void SelectText::getSelectionCaret(SkPath* path)
-{
- SkScalar height = m_selStart.fBottom - m_selStart.fTop;
- SkScalar dist = height / 4;
- path->moveTo(0, -height / 2);
- path->rLineTo(0, height);
- path->rLineTo(-dist, dist);
- path->rMoveTo(0, -0.5f);
- path->rLineTo(dist * 2, 0);
- path->rMoveTo(0, 0.5f);
- path->rLineTo(-dist, -dist);
-}
-
-bool SelectText::hitCorner(int cx, int cy, int x, int y) const
-{
- SkIRect test;
- test.set(cx, cy, cx + m_controlWidth, cy + m_controlHeight);
- test.inset(-m_controlSlop, -m_controlSlop);
- DBG_HANDLE_LOG("checking if %dx%d,%d-%d contains %dx%d",
- cx, cy, m_controlWidth, m_controlHeight, x, y);
- return test.contains(x, y);
-}
-
-bool SelectText::hitStartHandle(int x, int y) const
-{
- int left = m_selStart.fLeft - m_controlWidth;
- return hitCorner(left, m_selStart.fBottom, x, y);
-}
-
-bool SelectText::hitEndHandle(int x, int y) const
-{
- int left = m_selEnd.fRight;
- return hitCorner(left, m_selEnd.fBottom, x, y);
-}
-
-bool SelectText::hitSelection(int x, int y) const
-{
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- if (hitStartHandle(x, y))
- return true;
- if (hitEndHandle(x, y))
- return true;
- return m_selRegion.contains(x, y);
-}
-
-void SelectText::getSelectionHandles(int* handles, LayerAndroid* root)
-{
- handles[0] = m_selStart.fLeft;
- handles[1] = m_selStart.fBottom;
- handles[2] = m_selEnd.fRight;
- handles[3] = m_selEnd.fBottom;
- if (root && m_layerId) {
- Layer* layer = root->findById(m_layerId);
- while (layer) {
- const SkPoint& pos = layer->getPosition();
- handles[0] += pos.fX;
- handles[2] += pos.fX;
- handles[1] += pos.fY;
- handles[3] += pos.fY;
- layer = layer->getParent();
- }
- }
-}
-
-void SelectText::moveSelection(const IntRect& vis, int x, int y)
-{
- if (!m_picture)
- return;
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- setVisibleRect(vis);
- SkIRect clipRect = m_visibleRect;
- clipRect.join(m_selStart);
- clipRect.join(m_selEnd);
- FirstCheck center(x, y, clipRect);
- int base;
- SkIRect found = findClosest(center, *m_picture, &base);
- if (m_hitTopLeft || !m_extendSelection) {
- m_startBase = base;
- m_selStart = found;
- }
- if (!m_hitTopLeft || !m_extendSelection) {
- m_endBase = base;
- m_selEnd = found;
- }
- swapAsNeeded();
- DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
- " m_selEnd=(%d, %d, %d, %d)", x, y, m_extendSelection ? "true" : "false",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
-}
-
-void SelectText::reset()
-{
- DBG_NAV_LOG("m_extendSelection=false");
- m_selStart.setEmpty();
- m_lastStart.setEmpty();
- m_lastDrawnStart.setEmpty();
- m_selEnd.setEmpty();
- m_lastEnd.setEmpty();
- m_lastDrawnEnd.setEmpty();
- m_extendSelection = false;
- m_startSelection = false;
- SkSafeUnref(m_picture);
- m_picture = 0;
- m_layerId = 0;
-}
-
-IntPoint SelectText::selectableText(const CachedRoot* root)
-{
- int x = 0;
- int y = 0;
- SkPicture* picture = root->pictureAt(&x, &y, &m_layerId);
- if (!picture) {
- DBG_NAV_LOG("picture==0");
- return IntPoint(0, 0);
- }
- int width = picture->width();
- int height = picture->height();
- IntRect vis(0, 0, width, height);
- FirstCheck center(width >> 1, height >> 1, vis);
- int base;
- const SkIRect& closest = findClosest(center, *picture, &base);
- return IntPoint((closest.fLeft + closest.fRight) >> 1,
- (closest.fTop + closest.fBottom) >> 1);
-}
-
-void SelectText::selectAll()
-{
- if (!m_picture)
- return;
- m_selStart = findFirst(*m_picture, &m_startBase);
- m_selEnd = findLast(*m_picture, &m_endBase);
- m_extendSelection = true;
-}
-
-int SelectText::selectionX() const
-{
- return (m_hitTopLeft ? m_selStart.fLeft : m_selEnd.fRight) + m_startOffset.fX;
-}
-
-int SelectText::selectionY() const
-{
- const SkIRect& rect = m_hitTopLeft ? m_selStart : m_selEnd;
- return ((rect.fTop + rect.fBottom) >> 1) + m_startOffset.fY;
-}
-
-void SelectText::setVisibleRect(const IntRect& vis)
-{
- DBG_NAV_LOGD("vis=(%d,%d,w=%d,h=%d) offset=(%d,%d)",
- vis.x(), vis.y(), vis.width(), vis.height(), m_startOffset.fX,
- m_startOffset.fY);
- m_visibleRect = vis;
- m_visibleRect.offset(-m_startOffset.fX, -m_startOffset.fY);
-}
-
-bool SelectText::startSelection(const CachedRoot* root, const IntRect& vis,
- int x, int y)
-{
- m_wordSelection = false;
- m_startOffset.set(x, y);
- DBG_NAV_LOGD("x/y=(%d,%d)", x, y);
- SkSafeUnref(m_picture);
- m_picture = root->pictureAt(&x, &y, &m_layerId);
- DBG_NAV_LOGD("m_picture=%p m_layerId=%d x/y=(%d,%d)", m_picture, m_layerId,
- x, y);
- if (!m_picture) {
- DBG_NAV_LOG("picture==0");
- return false;
- }
- m_picture->ref();
- m_startOffset.fX -= x;
- m_startOffset.fY -= y;
- m_original.fX = x;
- m_original.fY = y;
- setVisibleRect(vis);
- if (m_selStart.isEmpty()) {
- DBG_NAV_LOGD("empty start picture=(%d,%d) x=%d y=%d",
- m_picture->width(), m_picture->height(), x, y);
- m_startSelection = true;
- return true;
- }
- m_hitTopLeft = hitStartHandle(x, y);
- bool hitBottomRight = hitEndHandle(x, y);
- DBG_NAV_LOGD("picture=(%d,%d) left=%d top=%d right=%d bottom=%d x=%d y=%d",
- m_picture->width(), m_picture->height(),left, top, right, bottom, x, y);
- if (m_hitTopLeft) {
- DBG_NAV_LOG("hit top left");
- m_original.fX -= m_selStart.fLeft;
- m_original.fY -= (m_selStart.fTop + m_selStart.fBottom) >> 1;
- } else if (hitBottomRight) {
- DBG_NAV_LOG("hit bottom right");
- m_original.fX -= m_selEnd.fRight;
- m_original.fY -= (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
- }
- return m_hitTopLeft || hitBottomRight;
-}
-
-void SelectText::updateHandleScale(float handleScale)
-{
- m_controlHeight = CONTROL_HEIGHT * handleScale;
- m_controlWidth = CONTROL_WIDTH * handleScale;
- m_controlSlop = CONTROL_SLOP * handleScale;
-}
-
-/* selects the word at (x, y)
-* a word is normally delimited by spaces
-* a string of digits (even with inside spaces) is a word (for phone numbers)
-* FIXME: digit find isn't implemented yet
-* returns true if a word was selected
-*/
-bool SelectText::wordSelection(const CachedRoot* root, const IntRect& vis,
- int x, int y)
-{
- IntRect tapArea = IntRect(x - TOUCH_SLOP, y - TOUCH_SLOP, TOUCH_SLOP * 2,
- TOUCH_SLOP * 2);
- if (!startSelection(root, tapArea, x, y))
- return false;
- extendSelection(tapArea, x, y);
- if (m_selStart.isEmpty())
- return false;
- setDrawPointer(false);
- setVisibleRect(vis);
- SkIRect ivisBounds = m_visibleRect;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)"
- " ivisBounds=(%d,%d,r=%d,b=%d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
- ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
- m_selRegion.setEmpty();
- buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, &m_selRegion);
- x = m_selStart.fLeft;
- y = (m_selStart.fTop + m_selStart.fBottom) >> 1;
- SkIRect clipRect = m_visibleRect;
- clipRect.fLeft -= m_visibleRect.width() >> 1;
- clipRect.fLeft = std::max(clipRect.fLeft, 0);
- int base;
- SkIRect left = findLeft(*m_picture, clipRect, x, y, &base);
- if (!left.isEmpty()) {
- m_startBase = base;
- m_selStart = left;
- }
- x = m_selEnd.fRight;
- y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
- clipRect = m_visibleRect;
- clipRect.fRight += m_visibleRect.width() >> 1;
- SkIRect right = findRight(*m_picture, clipRect, x, y, &base);
- if (!right.isEmpty()) {
- m_endBase = base;
- m_selEnd = right;
- }
- DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
- if (!left.isEmpty() || !right.isEmpty()) {
- m_wordBounds = m_selStart;
- m_wordBounds.join(m_selEnd);
- m_extendSelection = m_wordSelection = true;
- m_outsideWord = false;
- return true;
- }
- return false;
-}
-
-void SelectText::swapAsNeeded()
-{
- if (m_selStart.fTop >= (m_selEnd.fTop + m_selEnd.fBottom) >> 1
- || (m_selEnd.fTop < (m_selStart.fTop + m_selStart.fBottom) >> 1
- && m_selStart.fRight > m_selEnd.fLeft))
- {
- SkTSwap(m_startBase, m_endBase);
- SkTSwap(m_selStart, m_selEnd);
- m_hitTopLeft ^= true;
- DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false");
- }
-}
-
-}