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 #define LOG_TAG "webviewglue"
     27 
     28 #include "CachedPrefix.h"
     29 #include "BidiResolver.h"
     30 #include "BidiRunList.h"
     31 #include "CachedRoot.h"
     32 #include "LayerAndroid.h"
     33 #include "ParseCanvas.h"
     34 #include "SelectText.h"
     35 #include "SkBitmap.h"
     36 #include "SkBounder.h"
     37 #include "SkGradientShader.h"
     38 #include "SkMatrix.h"
     39 #include "SkPicture.h"
     40 #include "SkPixelXorXfermode.h"
     41 #include "SkPoint.h"
     42 #include "SkRect.h"
     43 #include "SkRegion.h"
     44 #include "SkUtils.h"
     45 #include "TextRun.h"
     46 
     47 #ifdef DEBUG_NAV_UI
     48 #include <wtf/text/CString.h>
     49 #endif
     50 
     51 #define VERBOSE_LOGGING 0
     52 // #define EXTRA_NOISY_LOGGING 1
     53 #define DEBUG_TOUCH_HANDLES 0
     54 #if DEBUG_TOUCH_HANDLES
     55 #define DBG_HANDLE_LOG(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
     56 #else
     57 #define DBG_HANDLE_LOG(...)
     58 #endif
     59 
     60 // TextRunIterator has been copied verbatim from GraphicsContext.cpp
     61 namespace WebCore {
     62 
     63 class TextRunIterator {
     64 public:
     65     TextRunIterator()
     66         : m_textRun(0)
     67         , m_offset(0)
     68     {
     69     }
     70 
     71     TextRunIterator(const TextRun* textRun, unsigned offset)
     72         : m_textRun(textRun)
     73         , m_offset(offset)
     74     {
     75     }
     76 
     77     TextRunIterator(const TextRunIterator& other)
     78         : m_textRun(other.m_textRun)
     79         , m_offset(other.m_offset)
     80     {
     81     }
     82 
     83     unsigned offset() const { return m_offset; }
     84     void increment() { m_offset++; }
     85     bool atEnd() const { return !m_textRun || m_offset >= m_textRun->length(); }
     86     UChar current() const { return (*m_textRun)[m_offset]; }
     87     WTF::Unicode::Direction direction() const { return atEnd() ? WTF::Unicode::OtherNeutral : WTF::Unicode::direction(current()); }
     88 
     89     bool operator==(const TextRunIterator& other)
     90     {
     91         return m_offset == other.m_offset && m_textRun == other.m_textRun;
     92     }
     93 
     94     bool operator!=(const TextRunIterator& other) { return !operator==(other); }
     95 
     96 private:
     97     const TextRun* m_textRun;
     98     int m_offset;
     99 };
    100 
    101 // ReverseBidi is a trimmed-down version of GraphicsContext::drawBidiText()
    102 void ReverseBidi(UChar* chars, int len) {
    103     using namespace WTF::Unicode;
    104     WTF::Vector<UChar> result;
    105     result.reserveCapacity(len);
    106     TextRun run(chars, len);
    107     BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
    108     BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
    109     bidiResolver.setStatus(BidiStatus(LeftToRight, LeftToRight, LeftToRight,
    110         BidiContext::create(0, LeftToRight, false)));
    111     bidiResolver.setPosition(TextRunIterator(&run, 0));
    112     bidiResolver.createBidiRunsForLine(TextRunIterator(&run, len));
    113     if (!bidiRuns.runCount())
    114         return;
    115     BidiCharacterRun* bidiRun = bidiRuns.firstRun();
    116     while (bidiRun) {
    117         int bidiStart = bidiRun->start();
    118         int bidiStop = bidiRun->stop();
    119         int size = result.size();
    120         int bidiCount = bidiStop - bidiStart;
    121         result.append(chars + bidiStart, bidiCount);
    122         if (bidiRun->level() % 2) {
    123             UChar* start = &result[size];
    124             UChar* end = start + bidiCount;
    125             // reverse the order of any RTL substrings
    126             while (start < end) {
    127                 UChar temp = *start;
    128                 *start++ = *--end;
    129                 *end = temp;
    130             }
    131             start = &result[size];
    132             end = start + bidiCount - 1;
    133             // if the RTL substring had a surrogate pair, restore its order
    134             while (start < end) {
    135                 UChar trail = *start++;
    136                 if (!U16_IS_SURROGATE(trail))
    137                     continue;
    138                 start[-1] = *start; // lead
    139                 *start++ = trail;
    140             }
    141         }
    142         bidiRun = bidiRun->next();
    143     }
    144     bidiRuns.deleteRuns();
    145     memcpy(chars, &result[0], len * sizeof(UChar));
    146 }
    147 
    148 }
    149 
    150 namespace android {
    151 
    152 #define HYPHEN_MINUS 0x2D // ASCII hyphen
    153 #define SOLIDUS 0x2F // ASCII slash
    154 #define REVERSE_SOLIDUS 0x5C // ASCII backslash
    155 #define HYPHEN 0x2010 // unicode hyphen, first in range of dashes
    156 #define HORZ_BAR 0x2015 // unicode horizontal bar, last in range of dashes
    157 #define TOUCH_SLOP 10 // additional distance from character rect when hit
    158 
    159 class CommonCheck : public SkBounder {
    160 public:
    161     CommonCheck(const SkIRect& area)
    162         : mArea(area)
    163         , mLastUni(0)
    164     {
    165         mLastGlyph.fGlyphID = static_cast<uint16_t>(-1);
    166         mLastCandidate.fGlyphID = static_cast<uint16_t>(-1);
    167         mMatrix.reset();
    168         reset();
    169     }
    170 
    171     /* called only while the picture is parsed */
    172     int base() {
    173         if (mBase == INT_MAX) {
    174             SkPoint result;
    175             mMatrix.mapXY(0, mY, &result);
    176             mBase = SkScalarFloor(result.fY);
    177         }
    178         return mBase;
    179     }
    180 
    181     /* called only while the picture is parsed */
    182      int bottom() {
    183         if (mBottom == INT_MAX) {
    184             SkPoint result;
    185             SkPaint::FontMetrics metrics;
    186             mPaint.getFontMetrics(&metrics);
    187             mMatrix.mapXY(0, metrics.fDescent + mY, &result);
    188             mBottom = SkScalarCeil(result.fY);
    189         }
    190         return mBottom;
    191     }
    192 
    193 #if DEBUG_NAV_UI
    194     // make current (possibily uncomputed) value visible for debugging
    195     int bottomDebug() const
    196     {
    197         return mBottom;
    198     }
    199 #endif
    200 
    201     bool addNewLine(const SkBounder::GlyphRec& rec)
    202     {
    203         SkFixed lineSpacing = SkFixedAbs(mLastGlyph.fLSB.fY - rec.fLSB.fY);
    204         SkFixed lineHeight = SkIntToFixed(bottom() - top());
    205         return lineSpacing >= lineHeight + (lineHeight >> 1); // 1.5
    206     }
    207 
    208     bool addSpace(const SkBounder::GlyphRec& rec)
    209     {
    210         bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
    211         if (((mLastUni >= HYPHEN && mLastUni <= HORZ_BAR)
    212             || mLastUni == HYPHEN_MINUS || mLastUni == SOLIDUS
    213             || mLastUni == REVERSE_SOLIDUS) && newBaseLine)
    214         {
    215             return false;
    216         }
    217         return isSpace(rec);
    218     }
    219 
    220     void finishGlyph()
    221     {
    222         mLastGlyph = mLastCandidate;
    223         mLastUni = mLastUniCandidate;
    224         mLastPaint = mLastPaintCandidate;
    225     }
    226 
    227     const SkIRect& getArea() const {
    228         return mArea;
    229     }
    230 
    231     /* called only while the picture is parsed */
    232     SkUnichar getUniChar(const SkBounder::GlyphRec& rec)
    233     {
    234         SkUnichar unichar;
    235         SkPaint::TextEncoding save = mPaint.getTextEncoding();
    236         mPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
    237         mPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar);
    238         mPaint.setTextEncoding(save);
    239         return unichar;
    240     }
    241 
    242     bool isSpace(const SkBounder::GlyphRec& rec)
    243     {
    244         if (mLastGlyph.fGlyphID == static_cast<uint16_t>(-1))
    245             return true;
    246         DBG_NAV_LOGD("mLastGlyph=((%g, %g),(%g, %g), %d)"
    247             " rec=((%g, %g),(%g, %g), %d) mLastUni=0x%04x '%c'",
    248             SkFixedToScalar(mLastGlyph.fLSB.fX),
    249             SkFixedToScalar(mLastGlyph.fLSB.fY),
    250             SkFixedToScalar(mLastGlyph.fRSB.fX),
    251             SkFixedToScalar(mLastGlyph.fRSB.fY), mLastGlyph.fGlyphID,
    252             SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fLSB.fY),
    253             SkFixedToScalar(rec.fRSB.fX), SkFixedToScalar(rec.fRSB.fY),
    254             rec.fGlyphID,
    255             mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
    256         bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
    257         if (newBaseLine)
    258             return true;
    259         SkFixed gapOne = mLastGlyph.fLSB.fX - rec.fRSB.fX;
    260         SkFixed gapTwo = rec.fLSB.fX - mLastGlyph.fRSB.fX;
    261         if (gapOne < 0 && gapTwo < 0)
    262             return false; // overlaps
    263         const SkBounder::GlyphRec& first = mLastGlyph.fLSB.fX < rec.fLSB.fX
    264             ? mLastGlyph : rec;
    265         const SkBounder::GlyphRec& second = mLastGlyph.fLSB.fX < rec.fLSB.fX
    266             ? rec : mLastGlyph;
    267         uint16_t firstGlyph = first.fGlyphID;
    268         SkScalar firstWidth = mLastPaint.measureText(&firstGlyph, sizeof(firstGlyph));
    269         SkFixed ceilWidth = SkIntToFixed(SkScalarCeil(firstWidth));
    270         SkFixed posNoSpace = first.fLSB.fX + ceilWidth;
    271         SkFixed ceilSpace = SkIntToFixed(SkFixedCeil(minSpaceWidth(mLastPaint)));
    272         SkFixed posWithSpace = posNoSpace + ceilSpace;
    273         SkFixed diffNoSpace = SkFixedAbs(second.fLSB.fX - posNoSpace);
    274         SkFixed diffWithSpace = SkFixedAbs(second.fLSB.fX - posWithSpace);
    275         DBG_NAV_LOGD("second=%g width=%g (%g) noSpace=%g (%g) withSpace=%g (%g)"
    276             " fontSize=%g",
    277             SkFixedToScalar(second.fLSB.fX),
    278             firstWidth, SkFixedToScalar(ceilWidth),
    279             SkFixedToScalar(posNoSpace), SkFixedToScalar(diffNoSpace),
    280             SkFixedToScalar(posWithSpace), SkFixedToScalar(diffWithSpace),
    281             mLastPaint.getTextSize());
    282         return diffWithSpace <= diffNoSpace;
    283     }
    284 
    285     SkFixed minSpaceWidth(SkPaint& paint)
    286     {
    287         if (mMinSpaceWidth == SK_FixedMax) {
    288             SkPaint::TextEncoding save = paint.getTextEncoding();
    289             paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
    290             SkScalar width = paint.measureText(" ", 1);
    291             mMinSpaceWidth = SkScalarToFixed(width * mMatrix.getScaleX());
    292             paint.setTextEncoding(save);
    293             DBG_NAV_LOGV("width=%g matrix sx/sy=(%g, %g) tx/ty=(%g, %g)"
    294                 " mMinSpaceWidth=%g", width,
    295                 mMatrix.getScaleX(), mMatrix.getScaleY(),
    296                 mMatrix.getTranslateX(), mMatrix.getTranslateY(),
    297                 SkFixedToScalar(mMinSpaceWidth));
    298         }
    299         return mMinSpaceWidth;
    300     }
    301 
    302     void recordGlyph(const SkBounder::GlyphRec& rec)
    303     {
    304         mLastCandidate = rec;
    305         mLastUniCandidate = getUniChar(rec);
    306         mLastPaintCandidate = mPaint;
    307     }
    308 
    309     void reset()
    310     {
    311         mMinSpaceWidth = SK_FixedMax; // mark as uninitialized
    312         mBase = mBottom = mTop = INT_MAX; // mark as uninitialized
    313     }
    314 
    315     void set(CommonCheck& check)
    316     {
    317         mLastGlyph = check.mLastGlyph;
    318         mLastUni = check.mLastUni;
    319         mMatrix = check.mMatrix;
    320         mLastPaint = check.mLastPaint;
    321         reset();
    322     }
    323 
    324     void setGlyph(CommonCheck& check)
    325     {
    326         mLastGlyph = check.mLastGlyph;
    327         mLastUni = check.mLastUni;
    328         mLastPaint = check.mLastPaint;
    329     }
    330 
    331     void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y,
    332             const void* text)
    333     {
    334         mMatrix = matrix;
    335         mPaint = paint;
    336         mText = static_cast<const uint16_t*>(text);
    337         mY = y;
    338         reset();
    339     }
    340 
    341     /* called only while the picture is parsed */
    342     int top() {
    343         if (mTop == INT_MAX) {
    344             SkPoint result;
    345             SkPaint::FontMetrics metrics;
    346             mPaint.getFontMetrics(&metrics);
    347             mMatrix.mapXY(0, metrics.fAscent + mY, &result);
    348             mTop = SkScalarFloor(result.fY);
    349         }
    350         return mTop;
    351     }
    352 
    353 #if DEBUG_NAV_UI
    354     // make current (possibily uncomputed) value visible for debugging
    355     int topDebug() const
    356     {
    357         return mTop;
    358     }
    359 #endif
    360 
    361 protected:
    362     SkIRect mArea;
    363     SkBounder::GlyphRec mLastCandidate;
    364     SkBounder::GlyphRec mLastGlyph;
    365     SkPaint mLastPaint; // available after picture has been parsed
    366     SkPaint mLastPaintCandidate; // associated with candidate glyph
    367     SkUnichar mLastUni;
    368     SkUnichar mLastUniCandidate;
    369     SkMatrix mMatrix;
    370     SkPaint mPaint; // only set up while the picture is parsed
    371     const uint16_t* mText;
    372     SkScalar mY;
    373 private:
    374     int mBase;
    375     int mBottom;
    376     SkFixed mMinSpaceWidth;
    377     int mTop;
    378     friend class EdgeCheck;
    379 };
    380 
    381 // generate the limit area for the new selection
    382 class LineCheck : public CommonCheck {
    383 public:
    384     LineCheck(int x, int y, const SkIRect& area)
    385         : INHERITED(area)
    386         , mX(x)
    387         , mY(y)
    388         , mInBetween(false)
    389     {
    390         mLast.setEmpty();
    391     }
    392 
    393     void finish(const SkRegion& selectedRgn)
    394     {
    395         if (!mParagraphs.count() && mLast.isEmpty())
    396             return;
    397         processLine();
    398         bool above = false;
    399         bool below = false;
    400         bool selected = false;
    401         SkRegion localRgn(selectedRgn);
    402         localRgn.translate(-mArea.fLeft, -mArea.fTop, &localRgn);
    403         DBG_NAV_LOGD("localRgn=(%d,%d,%d,%d)",
    404             localRgn.getBounds().fLeft, localRgn.getBounds().fTop,
    405             localRgn.getBounds().fRight, localRgn.getBounds().fBottom);
    406         for (int index = 0; index < mParagraphs.count(); index++) {
    407             const SkIRect& rect = mParagraphs[index];
    408             bool localSelected = localRgn.intersects(rect);
    409             DBG_NAV_LOGD("[%d] rect=(%d,%d,%d,%d)", index, rect.fLeft, rect.fTop,
    410                 rect.fRight, rect.fBottom);
    411             if (localSelected) {
    412                 DBG_NAV_LOGD("[%d] localSelected=true", index);
    413                 *mSelected.append() = rect;
    414             }
    415             if (rect.fRight <= mX || rect.fLeft >= mX)
    416                 continue;
    417             if (mY > rect.fBottom) {
    418                 below = true;
    419                 selected |= localSelected;
    420                 DBG_NAV_LOGD("[%d] below=true localSelected=%s", index,
    421                     localSelected ? "true" : "false");
    422            }
    423             if (mY < rect.fTop) {
    424                 above = true;
    425                 selected |= localSelected;
    426                 DBG_NAV_LOGD("[%d] above=true localSelected=%s", index,
    427                     localSelected ? "true" : "false");
    428             }
    429         }
    430         DBG_NAV_LOGD("mX=%d mY=%d above=%s below=%s selected=%s",
    431             mX, mY, above ? "true" : "false", below ? "true" : "false",
    432             selected ? "true" : "false");
    433         mInBetween = above && below && selected;
    434     }
    435 
    436     bool inBetween() const
    437     {
    438         return mInBetween;
    439     }
    440 
    441     bool inColumn(const SkIRect& test) const
    442     {
    443         for (int index = 0; index < mSelected.count(); index++) {
    444             const SkIRect& rect = mSelected[index];
    445             if (rect.fRight > test.fLeft && rect.fLeft < test.fRight)
    446                 return true;
    447         }
    448         return false;
    449     }
    450 
    451     bool inColumn(int x, int y) const
    452     {
    453         for (int index = 0; index < mSelected.count(); index++) {
    454             const SkIRect& rect = mSelected[index];
    455             if (rect.contains(x, y))
    456                 return true;
    457         }
    458         return false;
    459     }
    460 
    461     virtual bool onIRect(const SkIRect& rect)
    462     {
    463         SkIRect bounds;
    464         bounds.set(rect.fLeft, top(), rect.fRight, bottom());
    465         // assume that characters must be consecutive to describe spaces
    466         // (i.e., don't join rects drawn at different times)
    467         if (bounds.fTop != mLast.fTop || bounds.fBottom != mLast.fBottom
    468             || bounds.fLeft > mLast.fRight + minSpaceWidth(mPaint)
    469             || bounds.fLeft < mLast.fLeft) {
    470             processLine();
    471             mLast = bounds;
    472         } else
    473             mLast.join(bounds);
    474         return false;
    475     }
    476 
    477     void processLine()
    478     {
    479         // assume line spacing of 1.5
    480         int lineHeight = bottom() - top();
    481         mLast.inset(0, -lineHeight >> 1);
    482         // collect arrays of rectangles making up glyphs below or above this one
    483         for (int index = 0; index < mParagraphs.count(); index++) {
    484             SkIRect& rect = mParagraphs[index];
    485             if (SkIRect::Intersects(rect, mLast)) {
    486                 rect.join(mLast);
    487                 return;
    488             }
    489         }
    490         *mParagraphs.append() = mLast;
    491     }
    492 
    493 protected:
    494     int mX;
    495     int mY;
    496     SkIRect mLast;
    497     SkTDArray<SkIRect> mParagraphs;
    498     SkTDArray<SkIRect> mSelected;
    499     bool mInBetween;
    500 private:
    501     typedef CommonCheck INHERITED;
    502 };
    503 
    504 class SelectText::FirstCheck : public CommonCheck {
    505 public:
    506     FirstCheck(int x, int y, const SkIRect& area)
    507         : INHERITED(area)
    508         , mLineCheck(0)
    509         , mFocusX(x - area.fLeft)
    510         , mFocusY(y - area.fTop)
    511         , mBestInColumn(false)
    512         , mRecordGlyph(false)
    513     {
    514         reset();
    515     }
    516 
    517     const SkIRect& adjustedBounds(int* base)
    518     {
    519         *base = mBestBase + mArea.fTop;
    520         mBestBounds.offset(mArea.fLeft, mArea.fTop);
    521         DBG_NAV_LOGD("FirstCheck mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d",
    522             mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight,
    523             mBestBounds.fBottom, topDebug(), bottomDebug());
    524         return mBestBounds;
    525     }
    526 
    527     int focusX() const { return mFocusX; }
    528     int focusY() const { return mFocusY; }
    529 
    530     virtual bool onIRectGlyph(const SkIRect& rect,
    531         const SkBounder::GlyphRec& rec)
    532     {
    533         /* compute distance from rectangle center.
    534          * centerX = (rect.L + rect.R) / 2
    535          * multiply centerX and comparison x by 2 to retain better precision
    536          */
    537         SkIRect testBounds = {rect.fLeft, top(), rect.fRight, bottom()};
    538         // dx and dy are the distances from the tested edge
    539         // The edge distance is paramount if the test point is far away
    540         int dx = std::max(0, std::max(testBounds.fLeft - mFocusX,
    541             mFocusX - testBounds.fRight));
    542         int dy = std::max(0, std::max(testBounds.fTop - mFocusY,
    543             mFocusY - testBounds.fBottom));
    544         bool testInColumn = false;
    545         bool inBetween = false;
    546         bool inFocus = false;
    547         if (mLineCheck) {
    548             testInColumn = mLineCheck->inColumn(testBounds);
    549             inBetween = mLineCheck->inBetween();
    550             inFocus = mLineCheck->inColumn(mFocusX, mFocusY);
    551         }
    552 #ifdef EXTRA_NOISY_LOGGING
    553         if (dy < 10) {
    554             SkUnichar ch = getUniChar(rec);
    555             DBG_NAV_LOGD("FC dx/y=%d,%d mDx/y=%d,%d test=%d,%d,%d,%d"
    556                 " best=%d,%d,%d,%d bestIn=%s tween=%s testIn=%s focus=%s ch=%c",
    557                 dx, dy, mDx, mDy,
    558                 testBounds.fLeft, testBounds.fTop, testBounds.fRight,
    559                 testBounds.fBottom, mBestBounds.fLeft, mBestBounds.fTop,
    560                 mBestBounds.fRight, mBestBounds.fBottom,
    561                 mBestInColumn ? "true" : "false", inBetween ? "true" : "false",
    562                 testInColumn ? "true" : "false", inFocus ? "true" : "false",
    563                 ch < 0x7f ? ch : '?');
    564         }
    565 #endif
    566         if ((mBestInColumn || inBetween) && !testInColumn) {
    567 #ifdef EXTRA_NOISY_LOGGING
    568             if (dy < 10) DBG_NAV_LOG("FirstCheck reject column");
    569 #endif
    570             return false;
    571         }
    572         bool ignoreColumn = mBestInColumn == testInColumn || !inFocus;
    573         if (ignoreColumn && dy > 0 && (mDy < dy
    574             || (mDy == dy && dx > 0 && mDx <= dx))) {
    575 #ifdef EXTRA_NOISY_LOGGING
    576             if (dy < 10) DBG_NAV_LOG("FirstCheck reject edge");
    577 #endif
    578             return false;
    579         }
    580         // cx and cy are the distances from the tested center
    581         // The center distance is used when the test point is over the text
    582         int cx = std::abs(((testBounds.fLeft + testBounds.fRight) >> 1)
    583                 - mFocusX);
    584         int cy = std::abs(((testBounds.fTop + testBounds.fBottom) >> 1)
    585                 - mFocusY);
    586         if (ignoreColumn && dy == 0 && mDy == 0) {
    587             if (mCy < cy) {
    588 #ifdef EXTRA_NOISY_LOGGING
    589                 DBG_NAV_LOGD("FirstCheck reject cy=%d mCy=%d", cy, mCy);
    590 #endif
    591                 return false;
    592             }
    593             if (mCy == cy) {
    594                 if (dx == 0 && mDx == 0) {
    595                     if (mCx < cx) {
    596 #ifdef EXTRA_NOISY_LOGGING
    597                         DBG_NAV_LOGD("FirstCheck reject cx=%d mCx=%d", cx, mCx);
    598 #endif
    599                         return false;
    600                     }
    601                 } else if (dx > 0 && mDx <= dx) {
    602 #ifdef EXTRA_NOISY_LOGGING
    603                     DBG_NAV_LOGD("FirstCheck reject dx=%d mDx=%d", dx, mDx);
    604 #endif
    605                     return false;
    606                 }
    607             }
    608         }
    609 #ifdef EXTRA_NOISY_LOGGING
    610         if (dy < 10) {
    611             DBG_NAV_LOGD("FirstCheck cx/y=(%d,%d)", cx, cy);
    612         }
    613 #endif
    614         mBestBase = base();
    615         mBestBounds = testBounds;
    616         mBestInColumn = testInColumn;
    617 #ifndef EXTRA_NOISY_LOGGING
    618         if (dy < 10 && dx < 10)
    619 #endif
    620         {
    621 #if DEBUG_NAV_UI
    622             SkUnichar ch = getUniChar(rec);
    623 #endif
    624             DBG_NAV_LOGD("FirstCheck dx/y=(%d,%d) mFocus=(%d,%d)"
    625                 " mBestBounds={%d,%d,r=%d,b=%d} inColumn=%s ch=%c",
    626                 dx, dy, mFocusX, mFocusY,
    627                 mBestBounds.fLeft, mBestBounds.fTop,
    628                 mBestBounds.fRight, mBestBounds.fBottom,
    629                 mBestInColumn ? "true" : "false", ch < 0x7f ? ch : '?');
    630         }
    631         mCx = cx;
    632         mCy = cy;
    633         mDx = dx;
    634         mDy = dy;
    635         if (mRecordGlyph)
    636             recordGlyph(rec);
    637         return false;
    638     }
    639 
    640     void reset()
    641     {
    642         mBestBounds.setEmpty();
    643         mDx = mDy = mCx = mCy = INT_MAX;
    644     }
    645 
    646     void setLines(const LineCheck* lineCheck) { mLineCheck = lineCheck; }
    647     void setRecordGlyph() { mRecordGlyph = true; }
    648 
    649 protected:
    650     const LineCheck* mLineCheck;
    651     int mBestBase;
    652     SkIRect mBestBounds;
    653     int mCx;
    654     int mCy;
    655     int mDx;
    656     int mDy;
    657     int mFocusX;
    658     int mFocusY;
    659     bool mBestInColumn;
    660     bool mRecordGlyph;
    661 private:
    662     typedef CommonCheck INHERITED;
    663 };
    664 
    665 class SelectText::EdgeCheck : public SelectText::FirstCheck {
    666 public:
    667     EdgeCheck(int x, int y, const SkIRect& area, CommonCheck& last, bool left)
    668         : INHERITED(x, y, area)
    669         , mLast(area)
    670         , mLeft(left)
    671     {
    672         mLast.set(last); // CommonCheck::set()
    673         setGlyph(last);
    674     }
    675 
    676     bool adjacent()
    677     {
    678         return !mLast.isSpace(mLastGlyph);
    679     }
    680 
    681     const SkIRect& bestBounds(int* base)
    682     {
    683         *base = mBestBase;
    684         return mBestBounds;
    685     }
    686 
    687     virtual bool onIRectGlyph(const SkIRect& rect,
    688         const SkBounder::GlyphRec& rec)
    689     {
    690         int dx = mLeft ? mFocusX - rect.fRight : rect.fLeft - mFocusX;
    691         int dy = ((top() + bottom()) >> 1) - mFocusY;
    692         dx = abs(dx);
    693         dy = abs(dy);
    694         if (mLeft ? mFocusX <= rect.fLeft : mFocusX >= rect.fRight) {
    695             if (dx <= 10 && dy <= 10) {
    696                 DBG_NAV_LOGD("EdgeCheck fLeft=%d fRight=%d mFocusX=%d dx=%d dy=%d",
    697                     rect.fLeft, rect.fRight, mFocusX, dx, dy);
    698             }
    699             return false;
    700         }
    701         if (mDy > dy || (mDy == dy && mDx > dx)) {
    702             if (rec.fLSB == mLastGlyph.fLSB && rec.fRSB == mLastGlyph.fRSB) {
    703                 DBG_NAV_LOGD("dup rec.fLSB.fX=%g rec.fRSB.fX=%g",
    704                 SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fRSB.fX));
    705                 return false;
    706             }
    707             recordGlyph(rec);
    708             mDx = dx;
    709             mDy = dy;
    710             mBestBase = base();
    711             mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
    712             if (dx <= 10 && dy <= 10) {
    713                 DBG_NAV_LOGD("EdgeCheck mBestBounds={%d,%d,r=%d,b=%d} dx/y=(%d, %d)",
    714                     mBestBounds.fLeft, mBestBounds.fTop,
    715                     mBestBounds.fRight, mBestBounds.fBottom, dx, dy);
    716             }
    717         }
    718         return false;
    719     }
    720 
    721     void shiftStart(SkIRect bounds)
    722     {
    723         DBG_NAV_LOGD("EdgeCheck mFocusX=%d mLeft=%s bounds.fLeft=%d bounds.fRight=%d",
    724             mFocusX, mLeft ? "true" : "false", bounds.fLeft, bounds.fRight);
    725         reset();
    726         mFocusX = mLeft ? bounds.fLeft : bounds.fRight;
    727         mLast.set(*this); // CommonCheck::set()
    728     }
    729 
    730 protected:
    731     CommonCheck mLast;
    732     bool mLeft;
    733 private:
    734     typedef SelectText::FirstCheck INHERITED;
    735 };
    736 
    737 class FindFirst : public CommonCheck {
    738 public:
    739     FindFirst(const SkIRect& area)
    740         : INHERITED(area)
    741     {
    742         mBestBounds.set(area.width(), area.height(), area.width(), area.height());
    743     }
    744 
    745     const SkIRect& bestBounds(int* base)
    746     {
    747         *base = mBestBase;
    748         return mBestBounds;
    749     }
    750 
    751     virtual bool onIRect(const SkIRect& rect)
    752     {
    753         if (mBestBounds.isEmpty()) {
    754             mBestBase = base();
    755             mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
    756         }
    757         return false;
    758     }
    759 
    760 protected:
    761     int mBestBase;
    762     SkIRect mBestBounds;
    763 private:
    764     typedef CommonCheck INHERITED;
    765 };
    766 
    767 class FindLast : public FindFirst {
    768 public:
    769     FindLast(const SkIRect& area)
    770         : INHERITED(area)
    771     {
    772         mBestBounds.setEmpty();
    773     }
    774 
    775     virtual bool onIRect(const SkIRect& rect)
    776     {
    777         mBestBase = base();
    778         mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
    779         return false;
    780     }
    781 
    782 private:
    783     typedef FindFirst INHERITED;
    784 };
    785 
    786 static bool baseLinesAgree(const SkIRect& rectA, int baseA,
    787     const SkIRect& rectB, int baseB)
    788 {
    789     return (rectA.fTop < baseB && rectA.fBottom >= baseB)
    790         || (rectB.fTop < baseA && rectB.fBottom >= baseA);
    791 }
    792 
    793 class BuilderCheck : public CommonCheck {
    794 protected:
    795     enum IntersectionType {
    796         NO_INTERSECTION, // debugging printf expects this to equal zero
    797         LAST_INTERSECTION, // debugging printf expects this to equal one
    798         WAIT_FOR_INTERSECTION
    799     };
    800 
    801     BuilderCheck(const SkIRect& start, int startBase, const SkIRect& end,
    802         int endBase, const SkIRect& area)
    803         : INHERITED(area)
    804         , mCapture(false)
    805         , mEnd(end)
    806         , mEndBase(endBase)
    807         , mStart(start)
    808         , mStartBase(startBase)
    809     {
    810         mEnd.offset(-area.fLeft, -area.fTop);
    811         mEndBase -= area.fTop;
    812         mEndExtra.setEmpty();
    813         mLast.setEmpty();
    814         mLastBase = INT_MAX;
    815         mSelectRect.setEmpty();
    816         mStart.offset(-area.fLeft, -area.fTop);
    817         mStartBase -= area.fTop;
    818         mStartExtra.setEmpty();
    819         DBG_NAV_LOGD(" mStart=(%d,%d,r=%d,b=%d) mStartBase=%d"
    820             " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d",
    821             mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase,
    822             mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase);
    823     }
    824 
    825     int checkFlipRect(const SkIRect& full, int fullBase) {
    826         mCollectFull = false;
    827         // is the text to collect between the selection top and bottom?
    828         if (fullBase < mStart.fTop || fullBase > mEnd.fBottom) {
    829             if (VERBOSE_LOGGING && !mLast.isEmpty()) DBG_NAV_LOGD("%s 1"
    830                 " full=(%d,%d,r=%d,b=%d) fullBase=%d"
    831                 " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d",
    832                 mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
    833                 full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
    834                 mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase);
    835             return mLastIntersects;
    836         }
    837         // is the text to the left of the selection start?
    838         if (baseLinesAgree(mStart, mStartBase, full, fullBase)
    839             && full.fLeft < mStart.fLeft) {
    840             if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 2"
    841                 " full=(%d,%d,r=%d,b=%d) fullBase=%d"
    842                 " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
    843                 " mStart=(%d,%d,r=%d,b=%d) mStartBase=%d",
    844                 mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
    845                 full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
    846                 mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
    847                 mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase);
    848             mStartExtra.join(full);
    849             return mLastIntersects;
    850         }
    851         // is the text to the right of the selection end?
    852         if (baseLinesAgree(mEnd, mEndBase, full, fullBase)
    853             && full.fRight > mEnd.fRight) {
    854             if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 3"
    855                 " full=(%d,%d,r=%d,b=%d) fullBase=%d"
    856                 " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
    857                 " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d",
    858                 mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
    859                 full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
    860                 mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
    861                 mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase);
    862             mEndExtra.join(full);
    863             return mLastIntersects;
    864         }
    865         int spaceGap = SkFixedRound(minSpaceWidth(mPaint) * 3);
    866         // should text to the left of the start be added to the selection bounds?
    867         if (!mStartExtra.isEmpty()) {
    868             if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)"
    869                 " mStartExtra=(%d,%d,r=%d,b=%d)",
    870                 mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
    871                 mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom);
    872             if (mStartExtra.fRight + spaceGap >= mStart.fLeft)
    873                 mSelectRect.join(mStartExtra);
    874             mStartExtra.setEmpty();
    875         }
    876         // should text to the right of the end be added to the selection bounds?
    877         if (!mEndExtra.isEmpty()) {
    878             if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)"
    879                 " mEndExtra=(%d,%d,r=%d,b=%d)",
    880                 mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
    881                 mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom);
    882             if (mEndExtra.fLeft - spaceGap <= mEnd.fRight)
    883                 mSelectRect.join(mEndExtra);
    884             mEndExtra.setEmpty();
    885         }
    886         bool sameBaseLine = baseLinesAgree(mLast, mLastBase, full, fullBase);
    887         bool adjacent = (full.fLeft - mLast.fRight) < spaceGap;
    888         // is this the first, or are there more characters on the same line?
    889         if (mLast.isEmpty() || (sameBaseLine && adjacent)) {
    890             if (VERBOSE_LOGGING) DBG_NAV_LOGD("WAIT_FOR_INTERSECTION"
    891                 " full=(%d,%d,r=%d,b=%d) fullBase=%d"
    892                 " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
    893                 " mSelectRect=(%d,%d,r=%d,b=%d)",
    894                 full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
    895                 mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
    896                 mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
    897             mLast.join(full);
    898             mLastIntersects = SkIRect::Intersects(mLast, mSelectRect);
    899             return WAIT_FOR_INTERSECTION;
    900         }
    901         if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 4"
    902             " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
    903             " full=(%d,%d,r=%d,b=%d) fullBase=%d"
    904             " mSelectRect=(%d,%d,r=%d,b=%d)"
    905             " mStartExtra=(%d,%d,r=%d,b=%d)"
    906             " mEndExtra=(%d,%d,r=%d,b=%d)",
    907             mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
    908             mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
    909             full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
    910             mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
    911             mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom,
    912             mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom);
    913         // after the caller determines what to do with the last collection,
    914         // start the collection over with full and fullBase.
    915         mCollectFull = true;
    916         return mLastIntersects;
    917     }
    918 
    919     bool resetLast(const SkIRect& full, int fullBase)
    920     {
    921         if (mCollectFull) {
    922             mLast = full;
    923             mLastBase = fullBase;
    924             mLastIntersects = SkIRect::Intersects(mLast, mSelectRect);
    925         } else {
    926             mLast.setEmpty();
    927             mLastBase = INT_MAX;
    928             mLastIntersects = false;
    929         }
    930         return mCollectFull;
    931     }
    932 
    933     void setFlippedState()
    934     {
    935         mSelectRect = mStart;
    936         mSelectRect.join(mEnd);
    937         DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)",
    938             mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
    939         mLast.setEmpty();
    940         mLastBase = INT_MAX;
    941         mLastIntersects = NO_INTERSECTION;
    942     }
    943 
    944     bool mCapture;
    945     bool mCollectFull;
    946     SkIRect mEnd;
    947     int mEndBase;
    948     SkIRect mEndExtra;
    949     bool mFlipped;
    950     SkIRect mLast;
    951     int mLastBase;
    952     int mLastIntersects;
    953     SkIRect mSelectRect;
    954     SkIRect mStart;
    955     SkIRect mStartExtra;
    956     int mStartBase;
    957 private:
    958     typedef CommonCheck INHERITED;
    959 
    960 };
    961 
    962 class MultilineBuilder : public BuilderCheck {
    963 public:
    964     MultilineBuilder(const SkIRect& start, int startBase, const SkIRect& end,
    965             int endBase, const SkIRect& area, SkRegion* region)
    966         : INHERITED(start, startBase, end, endBase, area)
    967         , mSelectRegion(region)
    968     {
    969         mFlipped = false;
    970     }
    971 
    972     void addLastToRegion() {
    973         if (VERBOSE_LOGGING) DBG_NAV_LOGD(" mLast=(%d,%d,r=%d,b=%d)",
    974             mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
    975         mSelectRegion->op(mLast, SkRegion::kUnion_Op);
    976     }
    977 
    978     void finish() {
    979         if (!mFlipped || !mLastIntersects)
    980             return;
    981         addLastToRegion();
    982     }
    983 
    984     // return true if capture end was not found after capture begin
    985     bool flipped() {
    986         DBG_NAV_LOGD("flipped=%s", mCapture ? "true" : "false");
    987         if (!mCapture)
    988             return false;
    989         mFlipped = true;
    990         setFlippedState();
    991         mSelectRegion->setEmpty();
    992         return true;
    993     }
    994 
    995     virtual bool onIRect(const SkIRect& rect) {
    996         SkIRect full;
    997         full.set(rect.fLeft, top(), rect.fRight, bottom());
    998         int fullBase = base();
    999         if (mFlipped) {
   1000             int intersectType = checkFlipRect(full, fullBase);
   1001             if (intersectType == LAST_INTERSECTION)
   1002                 addLastToRegion();
   1003             if (intersectType != WAIT_FOR_INTERSECTION)
   1004                 resetLast(full, fullBase);
   1005             return false;
   1006         }
   1007         if (full == mStart) {
   1008             if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mStart full=(%d,%d,r=%d,b=%d)",
   1009                 full.fLeft, full.fTop, full.fRight, full.fBottom);
   1010             mCapture = true;
   1011         }
   1012         if (mCapture) {
   1013             bool sameLines = baseLinesAgree(mLast, mLastBase, full, fullBase);
   1014             if (sameLines)
   1015                 mLast.join(full);
   1016             if (!sameLines || full == mEnd) {
   1017                 if (VERBOSE_LOGGING) DBG_NAV_LOGD("finish mLast=(%d,%d,r=%d,b=%d)",
   1018                     mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
   1019                 addLastToRegion();
   1020                 mLast = full;
   1021                 mLastBase = fullBase;
   1022             }
   1023         }
   1024         if (full == mEnd) {
   1025             if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mEnd full=(%d,%d,r=%d,b=%d)",
   1026                 full.fLeft, full.fTop, full.fRight, full.fBottom);
   1027             mCapture = false;
   1028             if (full == mStart)
   1029                 addLastToRegion();
   1030         }
   1031         return false;
   1032     }
   1033 
   1034 protected:
   1035     SkRegion* mSelectRegion;
   1036 private:
   1037     typedef BuilderCheck INHERITED;
   1038 };
   1039 
   1040 static inline bool compareBounds(const SkIRect* first, const SkIRect* second)
   1041 {
   1042     return first->fTop < second->fTop;
   1043 }
   1044 
   1045 class TextExtractor : public BuilderCheck {
   1046 public:
   1047     TextExtractor(const SkIRect& start, int startBase, const SkIRect& end,
   1048         int endBase, const SkIRect& area, bool flipped)
   1049         : INHERITED(start, startBase, end, endBase, area)
   1050         , mSelectStartIndex(-1)
   1051         , mSkipFirstSpace(true) // don't start with a space
   1052     {
   1053         mFlipped = flipped;
   1054         if (flipped)
   1055             setFlippedState();
   1056     }
   1057 
   1058     void addCharacter(const SkBounder::GlyphRec& rec)
   1059     {
   1060         if (mSelectStartIndex < 0)
   1061             mSelectStartIndex = mSelectText.count();
   1062         if (!mSkipFirstSpace) {
   1063             if (addNewLine(rec)) {
   1064                 DBG_NAV_LOG("write new line");
   1065                 *mSelectText.append() = '\n';
   1066                 *mSelectText.append() = '\n';
   1067             } else if (addSpace(rec)) {
   1068                 DBG_NAV_LOG("write space");
   1069                 *mSelectText.append() = ' ';
   1070             }
   1071         } else
   1072             mSkipFirstSpace = false;
   1073         recordGlyph(rec);
   1074         finishGlyph();
   1075         if (VERBOSE_LOGGING) DBG_NAV_LOGD("glyphID=%d uni=%d '%c'", rec.fGlyphID,
   1076             mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
   1077         if (mLastUni) {
   1078             uint16_t chars[2];
   1079             size_t count = SkUTF16_FromUnichar(mLastUni, chars);
   1080             *mSelectText.append() = chars[0];
   1081             if (count == 2)
   1082                 *mSelectText.append() = chars[1];
   1083         }
   1084     }
   1085 
   1086     void addLast()
   1087     {
   1088         *mSelectBounds.append() = mLast;
   1089         *mSelectStart.append() = mSelectStartIndex;
   1090         *mSelectEnd.append() = mSelectText.count();
   1091     }
   1092 
   1093     /* Text characters are collected before it's been determined that the
   1094        characters are part of the selection. The bounds describe valid parts
   1095        of the selection, but the bounds are out of order.
   1096 
   1097        This sorts the characters by sorting the bounds, then copying the
   1098        characters that were captured.
   1099      */
   1100     void finish()
   1101     {
   1102         if (mLastIntersects)
   1103             addLast();
   1104         Vector<SkIRect*> sortedBounds;
   1105         SkTDArray<uint16_t> temp;
   1106         int index;
   1107         DBG_NAV_LOGD("mSelectBounds.count=%d text=%d", mSelectBounds.count(),
   1108             mSelectText.count());
   1109         for (index = 0; index < mSelectBounds.count(); index++)
   1110             sortedBounds.append(&mSelectBounds[index]);
   1111         std::sort(sortedBounds.begin(), sortedBounds.end(), compareBounds);
   1112         int lastEnd = -1;
   1113         for (index = 0; index < mSelectBounds.count(); index++) {
   1114             int order = sortedBounds[index] - &mSelectBounds[0];
   1115             int start = mSelectStart[order];
   1116             int end = mSelectEnd[order];
   1117             DBG_NAV_LOGD("order=%d start=%d end=%d top=%d", order, start, end,
   1118                 mSelectBounds[order].fTop);
   1119             int count = temp.count();
   1120             if (count > 0 && temp[count - 1] != '\n' && start != lastEnd) {
   1121                 // always separate paragraphs when original text is out of order
   1122                 DBG_NAV_LOG("write new line");
   1123                 *temp.append() = '\n';
   1124                 *temp.append() = '\n';
   1125             }
   1126             temp.append(end - start, &mSelectText[start]);
   1127             lastEnd = end;
   1128         }
   1129         mSelectText.swap(temp);
   1130     }
   1131 
   1132     virtual bool onIRectGlyph(const SkIRect& rect,
   1133         const SkBounder::GlyphRec& rec)
   1134     {
   1135         SkIRect full;
   1136         full.set(rect.fLeft, top(), rect.fRight, bottom());
   1137         int fullBase = base();
   1138         if (mFlipped) {
   1139             int intersectType = checkFlipRect(full, fullBase);
   1140             if (WAIT_FOR_INTERSECTION == intersectType)
   1141                 addCharacter(rec); // may not be copied
   1142             else {
   1143                 if (LAST_INTERSECTION == intersectType)
   1144                     addLast();
   1145                 else
   1146                     mSkipFirstSpace = true;
   1147                 mSelectStartIndex = -1;
   1148                 if (resetLast(full, fullBase))
   1149                     addCharacter(rec); // may not be copied
   1150             }
   1151             return false;
   1152         }
   1153         if (full == mStart)
   1154             mCapture = true;
   1155         if (mCapture)
   1156             addCharacter(rec);
   1157         else
   1158             mSkipFirstSpace = true;
   1159         if (full == mEnd)
   1160             mCapture = false;
   1161         return false;
   1162     }
   1163 
   1164     WTF::String text() {
   1165         if (mFlipped)
   1166             finish();
   1167         // the text has been copied in visual order. Reverse as needed if
   1168         // result contains right-to-left characters.
   1169         const uint16_t* start = mSelectText.begin();
   1170         const uint16_t* end = mSelectText.end();
   1171         while (start < end) {
   1172             SkUnichar ch = SkUTF16_NextUnichar(&start);
   1173             WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch);
   1174             if (WTF::Unicode::RightToLeftArabic == charDirection
   1175                     || WTF::Unicode::RightToLeft == charDirection) {
   1176                 WebCore::ReverseBidi(mSelectText.begin(), mSelectText.count());
   1177                 break;
   1178             }
   1179         }
   1180         return WTF::String(mSelectText.begin(), mSelectText.count());
   1181     }
   1182 
   1183 protected:
   1184     SkIRect mEmpty;
   1185     SkTDArray<SkIRect> mSelectBounds;
   1186     SkTDArray<int> mSelectEnd;
   1187     SkTDArray<int> mSelectStart;
   1188     int mSelectStartIndex;
   1189     SkTDArray<uint16_t> mSelectText;
   1190     bool mSkipFirstSpace;
   1191 private:
   1192     typedef BuilderCheck INHERITED;
   1193 };
   1194 
   1195 class TextCanvas : public ParseCanvas {
   1196 public:
   1197 
   1198     TextCanvas(CommonCheck* bounder)
   1199             : mBounder(*bounder) {
   1200         setBounder(bounder);
   1201         SkBitmap bitmap;
   1202         const SkIRect& area = bounder->getArea();
   1203         bitmap.setConfig(SkBitmap::kARGB_8888_Config, area.width(),
   1204             area.height());
   1205         setBitmapDevice(bitmap);
   1206         translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop));
   1207 #ifdef DEBUG_NAV_UI
   1208         const SkIRect& clip = getTotalClip().getBounds();
   1209         const SkMatrix& matrix = getTotalMatrix();
   1210         DBG_NAV_LOGD("bitmap=(%d,%d) clip=(%d,%d,%d,%d) matrix=(%g,%g)",
   1211             bitmap.width(), bitmap.height(), clip.fLeft, clip.fTop,
   1212             clip.fRight, clip.fBottom, matrix.getTranslateX(), matrix.getTranslateY());
   1213 #endif
   1214     }
   1215 
   1216     virtual void drawPaint(const SkPaint& paint) {
   1217     }
   1218 
   1219     virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
   1220                             const SkPaint& paint) {
   1221     }
   1222 
   1223     virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
   1224     }
   1225 
   1226     virtual void drawPath(const SkPath& path, const SkPaint& paint) {
   1227     }
   1228 
   1229     virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
   1230                               const SkMatrix& matrix, const SkPaint& paint) {
   1231     }
   1232 
   1233     virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
   1234                             const SkPaint* paint = NULL) {
   1235     }
   1236 
   1237     virtual void drawText(const void* text, size_t byteLength, SkScalar x,
   1238                           SkScalar y, const SkPaint& paint) {
   1239         mBounder.setUp(paint, getTotalMatrix(), y, text);
   1240         INHERITED::drawText(text, byteLength, x, y, paint);
   1241     }
   1242 
   1243     virtual void drawPosTextH(const void* text, size_t byteLength,
   1244                               const SkScalar xpos[], SkScalar constY,
   1245                               const SkPaint& paint) {
   1246         mBounder.setUp(paint, getTotalMatrix(), constY, text);
   1247         INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
   1248     }
   1249 
   1250     virtual void drawVertices(VertexMode vmode, int vertexCount,
   1251                               const SkPoint vertices[], const SkPoint texs[],
   1252                               const SkColor colors[], SkXfermode* xmode,
   1253                               const uint16_t indices[], int indexCount,
   1254                               const SkPaint& paint) {
   1255     }
   1256 
   1257     CommonCheck& mBounder;
   1258 private:
   1259     typedef ParseCanvas INHERITED;
   1260 };
   1261 
   1262 static bool buildSelection(const SkPicture& picture, const SkIRect& area,
   1263         const SkIRect& selStart, int startBase,
   1264         const SkIRect& selEnd, int endBase, SkRegion* region)
   1265 {
   1266     DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)"
   1267         " selEnd=(%d, %d, %d, %d)",
   1268         area.fLeft, area.fTop, area.fRight, area.fBottom,
   1269         selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom,
   1270         selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom);
   1271     MultilineBuilder builder(selStart, startBase, selEnd, endBase, area, region);
   1272     TextCanvas checker(&builder);
   1273     checker.drawPicture(const_cast<SkPicture&>(picture));
   1274     bool flipped = builder.flipped();
   1275     if (flipped) {
   1276         TextCanvas checker(&builder);
   1277         checker.drawPicture(const_cast<SkPicture&>(picture));
   1278     }
   1279     builder.finish();
   1280     region->translate(area.fLeft, area.fTop);
   1281     return flipped;
   1282 }
   1283 
   1284 static SkIRect findFirst(const SkPicture& picture, int* base)
   1285 {
   1286     SkIRect area;
   1287     area.set(0, 0, picture.width(), picture.height());
   1288     FindFirst finder(area);
   1289     TextCanvas checker(&finder);
   1290     checker.drawPicture(const_cast<SkPicture&>(picture));
   1291     return finder.bestBounds(base);
   1292 }
   1293 
   1294 static SkIRect findLast(const SkPicture& picture, int* base)
   1295 {
   1296     SkIRect area;
   1297     area.set(0, 0, picture.width(), picture.height());
   1298     FindLast finder(area);
   1299     TextCanvas checker(&finder);
   1300     checker.drawPicture(const_cast<SkPicture&>(picture));
   1301     return finder.bestBounds(base);
   1302 }
   1303 
   1304 static WTF::String text(const SkPicture& picture, const SkIRect& area,
   1305         const SkIRect& start, int startBase, const SkIRect& end,
   1306         int endBase, bool flipped)
   1307 {
   1308     TextExtractor extractor(start, startBase, end, endBase, area, flipped);
   1309     TextCanvas checker(&extractor);
   1310     checker.drawPicture(const_cast<SkPicture&>(picture));
   1311     return extractor.text();
   1312 }
   1313 
   1314 #define CONTROL_NOTCH 16
   1315 // TODO: Now that java is the one actually drawing these, get the real values
   1316 // from the drawable itself
   1317 #define CONTROL_HEIGHT 47
   1318 #define CONTROL_WIDTH 26
   1319 #define CONTROL_SLOP 5
   1320 #define STROKE_WIDTH 1.0f
   1321 #define STROKE_OUTSET 3.5f
   1322 #define STROKE_I_OUTSET 4 // (int) ceil(STROKE_OUTSET)
   1323 #define STROKE_COLOR 0x66000000
   1324 #define OUTER_COLOR 0x33000000
   1325 #define INNER_COLOR 0xe6aae300
   1326 
   1327 SelectText::SelectText()
   1328     : m_controlWidth(CONTROL_WIDTH)
   1329     , m_controlHeight(CONTROL_HEIGHT)
   1330     , m_controlSlop(CONTROL_SLOP)
   1331 {
   1332     m_picture = 0;
   1333     reset();
   1334     SkPaint paint;
   1335     SkRect oval;
   1336 
   1337     SkPath startOuterPath;
   1338     oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET,
   1339         -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET);
   1340     startOuterPath.arcTo(oval, 180, 45, true);
   1341     oval.set(-STROKE_OUTSET, -STROKE_OUTSET,  STROKE_OUTSET, STROKE_OUTSET);
   1342     startOuterPath.arcTo(oval, 180 + 45, 135, false);
   1343     oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
   1344         STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
   1345     startOuterPath.arcTo(oval, 0, 90, false);
   1346     oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
   1347         -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
   1348     startOuterPath.arcTo(oval, 90, 90, false);
   1349     startOuterPath.close();
   1350     SkPath startInnerPath;
   1351     startInnerPath.moveTo(-CONTROL_WIDTH, CONTROL_NOTCH);
   1352     startInnerPath.lineTo(-CONTROL_WIDTH, CONTROL_HEIGHT);
   1353     startInnerPath.lineTo(0, CONTROL_HEIGHT);
   1354     startInnerPath.lineTo(0, 0);
   1355     startInnerPath.close();
   1356     startOuterPath.addPath(startInnerPath, 0, 0);
   1357 
   1358     SkCanvas* canvas = m_startControl.beginRecording(
   1359         CONTROL_WIDTH + STROKE_OUTSET * 2,
   1360         CONTROL_HEIGHT + STROKE_OUTSET * 2);
   1361     paint.setAntiAlias(true);
   1362     paint.setColor(INNER_COLOR);
   1363     paint.setStyle(SkPaint::kFill_Style);
   1364     canvas->drawPath(startInnerPath, paint);
   1365     paint.setColor(OUTER_COLOR);
   1366     canvas->drawPath(startOuterPath, paint);
   1367     paint.setStyle(SkPaint::kStroke_Style);
   1368     paint.setColor(STROKE_COLOR);
   1369     paint.setStrokeWidth(STROKE_WIDTH);
   1370     canvas->drawPath(startInnerPath, paint);
   1371     m_startControl.endRecording();
   1372 
   1373     SkPath endOuterPath;
   1374     oval.set(-STROKE_OUTSET, -STROKE_OUTSET,  STROKE_OUTSET, STROKE_OUTSET);
   1375     endOuterPath.arcTo(oval, 180, 135, true);
   1376     oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET,
   1377         CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET);
   1378     endOuterPath.arcTo(oval, 360 - 45, 45, false);
   1379     oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
   1380         CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
   1381     endOuterPath.arcTo(oval, 0, 90, false);
   1382     oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
   1383         STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
   1384     endOuterPath.arcTo(oval, 90, 90, false);
   1385     startOuterPath.close();
   1386     SkPath endInnerPath;
   1387     endInnerPath.moveTo(0, 0);
   1388     endInnerPath.lineTo(0, CONTROL_HEIGHT);
   1389     endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_HEIGHT);
   1390     endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_NOTCH);
   1391     endInnerPath.close();
   1392     endOuterPath.addPath(endInnerPath, 0, 0);
   1393 
   1394     canvas = m_endControl.beginRecording(CONTROL_WIDTH + STROKE_OUTSET * 2,
   1395         CONTROL_HEIGHT + STROKE_OUTSET * 2);
   1396     paint.setColor(INNER_COLOR);
   1397     paint.setStyle(SkPaint::kFill_Style);
   1398     canvas->drawPath(endInnerPath, paint);
   1399     paint.setColor(OUTER_COLOR);
   1400     canvas->drawPath(endOuterPath, paint);
   1401     paint.setStyle(SkPaint::kStroke_Style);
   1402     paint.setColor(STROKE_COLOR);
   1403     paint.setStrokeWidth(STROKE_WIDTH);
   1404     canvas->drawPath(endInnerPath, paint);
   1405     m_endControl.endRecording();
   1406 }
   1407 
   1408 SelectText::~SelectText()
   1409 {
   1410     SkSafeUnref(m_picture);
   1411 }
   1412 
   1413 void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval)
   1414 {
   1415     if (m_layerId != layer->uniqueId())
   1416         return;
   1417     // reset m_picture to match m_layerId
   1418     SkSafeUnref(m_picture);
   1419     m_picture = layer->picture();
   1420     SkSafeRef(m_picture);
   1421     DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d layer [%d]",
   1422         m_extendSelection, m_drawPointer, layer->uniqueId());
   1423     if (m_extendSelection)
   1424         drawSelectionRegion(canvas, inval);
   1425     if (m_drawPointer)
   1426         drawSelectionPointer(canvas, inval);
   1427 }
   1428 
   1429 static void addInval(IntRect* inval, const SkCanvas* canvas,
   1430         const SkRect& bounds) {
   1431     const SkMatrix& matrix = canvas->getTotalMatrix();
   1432     SkRect transformed;
   1433     matrix.mapRect(&transformed, bounds);
   1434     SkIRect iTrans;
   1435     transformed.round(&iTrans);
   1436     inval->unite(iTrans);
   1437 }
   1438 
   1439 void SelectText::drawSelectionPointer(SkCanvas* canvas, IntRect* inval)
   1440 {
   1441     SkPath path;
   1442     if (m_extendSelection)
   1443         getSelectionCaret(&path);
   1444     else
   1445         getSelectionArrow(&path);
   1446     SkPixelXorXfermode xorMode(SK_ColorWHITE);
   1447     SkPaint paint;
   1448     paint.setAntiAlias(true);
   1449     paint.setStyle(SkPaint::kStroke_Style);
   1450     paint.setColor(SK_ColorBLACK);
   1451     if (m_extendSelection)
   1452         paint.setXfermode(&xorMode);
   1453     else
   1454         paint.setStrokeWidth(SK_Scalar1 * 2);
   1455     int sc = canvas->save();
   1456     canvas->scale(m_inverseScale, m_inverseScale);
   1457     canvas->translate(m_selectX, m_selectY);
   1458     canvas->drawPath(path, paint);
   1459     if (!m_extendSelection) {
   1460         paint.setStyle(SkPaint::kFill_Style);
   1461         paint.setColor(SK_ColorWHITE);
   1462         canvas->drawPath(path, paint);
   1463     }
   1464     SkRect bounds = path.getBounds();
   1465     bounds.inset(-SK_Scalar1 * 2, -SK_Scalar1 * 2); // stroke width
   1466     addInval(inval, canvas, bounds);
   1467     canvas->restoreToCount(sc);
   1468 }
   1469 
   1470 static void addStart(SkRegion* diff, const SkIRect& rect)
   1471 {
   1472     SkIRect bounds;
   1473     bounds.set(rect.fLeft - CONTROL_WIDTH - STROKE_I_OUTSET,
   1474         rect.fBottom - STROKE_I_OUTSET, rect.fLeft + STROKE_I_OUTSET,
   1475         rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET);
   1476     diff->op(bounds, SkRegion::kUnion_Op);
   1477 }
   1478 
   1479 static void addEnd(SkRegion* diff, const SkIRect& rect)
   1480 {
   1481     SkIRect bounds;
   1482     bounds.set(rect.fRight - STROKE_I_OUTSET, rect.fBottom - STROKE_I_OUTSET,
   1483         rect.fRight + CONTROL_WIDTH + STROKE_I_OUTSET,
   1484         rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET);
   1485     diff->op(bounds, SkRegion::kUnion_Op);
   1486 }
   1487 
   1488 void SelectText::getSelectionRegion(const IntRect& vis, SkRegion *region,
   1489                                     LayerAndroid* root)
   1490 {
   1491     SkIRect ivisBounds = vis;
   1492     ivisBounds.join(m_selStart);
   1493     ivisBounds.join(m_selEnd);
   1494     region->setEmpty();
   1495     buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
   1496         m_selEnd, m_endBase, region);
   1497     if (root && m_layerId) {
   1498         Layer* layer = root->findById(m_layerId);
   1499         while (layer) {
   1500             const SkPoint& pos = layer->getPosition();
   1501             region->translate(pos.fX, pos.fY);
   1502             layer = layer->getParent();
   1503         }
   1504     }
   1505 }
   1506 
   1507 void SelectText::drawSelectionRegion(SkCanvas* canvas, IntRect* inval)
   1508 {
   1509     if (!m_picture)
   1510         return;
   1511     SkIRect ivisBounds = m_visibleRect;
   1512     ivisBounds.join(m_selStart);
   1513     ivisBounds.join(m_selEnd);
   1514     DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)"
   1515         " ivisBounds=(%d,%d,r=%d,b=%d)",
   1516         m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
   1517         m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
   1518         ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
   1519     if (m_lastSelRegion != m_selRegion)
   1520         m_lastSelRegion.set(m_selRegion);
   1521     SkRegion diff(m_lastSelRegion);
   1522     m_selRegion.setEmpty();
   1523     m_flipped = buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
   1524         m_selEnd, m_endBase, &m_selRegion);
   1525     SkPath path;
   1526     m_selRegion.getBoundaryPath(&path);
   1527     path.setFillType(SkPath::kEvenOdd_FillType);
   1528 
   1529     SkPaint paint;
   1530     paint.setAntiAlias(true);
   1531     paint.setColor(SkColorSetARGB(0x80, 0x83, 0xCC, 0x39));
   1532     canvas->drawPath(path, paint);
   1533     // experiment to draw touchable controls that resize the selection
   1534     float scale = m_controlHeight / (float)CONTROL_HEIGHT;
   1535     canvas->save();
   1536     canvas->translate(m_selStart.fLeft, m_selStart.fBottom);
   1537     canvas->scale(scale, scale);
   1538     canvas->drawPicture(m_startControl);
   1539     canvas->restore();
   1540     canvas->save();
   1541     canvas->translate(m_selEnd.fRight, m_selEnd.fBottom);
   1542     canvas->scale(scale, scale);
   1543     canvas->drawPicture(m_endControl);
   1544     canvas->restore();
   1545 
   1546 #if DEBUG_TOUCH_HANDLES
   1547     SkRect touchHandleRect;
   1548     paint.setColor(SkColorSetARGB(0x60, 0xFF, 0x00, 0x00));
   1549     touchHandleRect.set(0, m_selStart.fBottom, m_selStart.fLeft, 0);
   1550     touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight;
   1551     touchHandleRect.fLeft = touchHandleRect.fRight - m_controlWidth;
   1552     canvas->drawRect(touchHandleRect, paint);
   1553     touchHandleRect.inset(-m_controlSlop, -m_controlSlop);
   1554     canvas->drawRect(touchHandleRect, paint);
   1555     touchHandleRect.set(m_selEnd.fRight, m_selEnd.fBottom, 0, 0);
   1556     touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight;
   1557     touchHandleRect.fRight = touchHandleRect.fLeft + m_controlWidth;
   1558     canvas->drawRect(touchHandleRect, paint);
   1559     touchHandleRect.inset(-m_controlSlop, -m_controlSlop);
   1560     canvas->drawRect(touchHandleRect, paint);
   1561 #endif
   1562 
   1563     SkIRect a = diff.getBounds();
   1564     SkIRect b = m_selRegion.getBounds();
   1565     diff.op(m_selRegion, SkRegion::kXOR_Op);
   1566     SkIRect c = diff.getBounds();
   1567     DBG_NAV_LOGD("old=(%d,%d,r=%d,b=%d) new=(%d,%d,r=%d,b=%d) diff=(%d,%d,r=%d,b=%d)",
   1568         a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom,
   1569         c.fLeft, c.fTop, c.fRight, c.fBottom);
   1570     DBG_NAV_LOGD("lastStart=(%d,%d,r=%d,b=%d) m_lastEnd=(%d,%d,r=%d,b=%d)",
   1571         m_lastStart.fLeft, m_lastStart.fTop, m_lastStart.fRight, m_lastStart.fBottom,
   1572         m_lastEnd.fLeft, m_lastEnd.fTop, m_lastEnd.fRight, m_lastEnd.fBottom);
   1573     if (!m_lastDrawnStart.isEmpty())
   1574         addStart(&diff, m_lastDrawnStart);
   1575     if (m_lastStart != m_selStart) {
   1576         m_lastDrawnStart = m_lastStart;
   1577         m_lastStart = m_selStart;
   1578     }
   1579     addStart(&diff, m_selStart);
   1580     if (!m_lastDrawnEnd.isEmpty())
   1581         addEnd(&diff, m_lastDrawnEnd);
   1582     if (m_lastEnd != m_selEnd) {
   1583         m_lastDrawnEnd = m_lastEnd;
   1584         m_lastEnd = m_selEnd;
   1585     }
   1586     addEnd(&diff, m_selEnd);
   1587     SkIRect iBounds = diff.getBounds();
   1588     DBG_NAV_LOGD("diff=(%d,%d,r=%d,b=%d)",
   1589         iBounds.fLeft, iBounds.fTop, iBounds.fRight, iBounds.fBottom);
   1590     SkRect bounds;
   1591     bounds.set(iBounds);
   1592     addInval(inval, canvas, bounds);
   1593 }
   1594 
   1595 void SelectText::extendSelection(const IntRect& vis, int x, int y)
   1596 {
   1597     if (!m_picture)
   1598         return;
   1599     setVisibleRect(vis);
   1600     SkIRect clipRect = m_visibleRect;
   1601     int base;
   1602     DBG_NAV_LOGD("extend x/y=%d,%d m_startOffset=%d,%d", x, y,
   1603         m_startOffset.fX, m_startOffset.fY);
   1604     x -= m_startOffset.fX;
   1605     y -= m_startOffset.fY;
   1606     if (m_startSelection) {
   1607         if (!clipRect.contains(x, y)
   1608                 || !clipRect.contains(m_original.fX, m_original.fY)) {
   1609             clipRect.set(m_original.fX, m_original.fY, x, y);
   1610             clipRect.sort();
   1611             clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
   1612         }
   1613         FirstCheck center(m_original.fX, m_original.fY, clipRect);
   1614         m_selStart = m_selEnd = findClosest(center, *m_picture, &base);
   1615         if (m_selStart.isEmpty())
   1616             return;
   1617         DBG_NAV_LOGD("selStart clip=(%d,%d,%d,%d) m_original=%d,%d"
   1618             " m_selStart=(%d,%d,%d,%d)", clipRect.fLeft, clipRect.fTop,
   1619             clipRect.fRight, clipRect.fBottom, m_original.fX, m_original.fY,
   1620             m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom);
   1621         m_startBase = m_endBase = base;
   1622         m_startSelection = false;
   1623         m_extendSelection = true;
   1624         m_original.fX = m_original.fY = 0;
   1625     }
   1626     DBG_NAV_LOGD("extend x/y=%d,%d m_original=%d,%d", x, y,
   1627         m_original.fX, m_original.fY);
   1628     x -= m_original.fX;
   1629     y -= m_original.fY;
   1630     if (!clipRect.contains(x, y) || !clipRect.contains(m_selStart)) {
   1631         clipRect.set(m_selStart.fLeft, m_selStart.fTop, x, y);
   1632         clipRect.sort();
   1633         clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
   1634     }
   1635     DBG_NAV_LOGD("extend clip=(%d,%d,%d,%d) x/y=%d,%d wordSel=%s outsideWord=%s",
   1636         clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, x, y,
   1637         m_wordSelection ? "true" : "false", m_outsideWord ? "true" : "false");
   1638     FirstCheck extension(x, y, clipRect);
   1639     SkIRect found = findClosest(extension, *m_picture, &base);
   1640     if (m_wordSelection) {
   1641         SkIRect wordBounds = m_wordBounds;
   1642         if (!m_outsideWord)
   1643             wordBounds.inset(-TOUCH_SLOP, -TOUCH_SLOP);
   1644         DBG_NAV_LOGD("x=%d y=%d wordBounds=(%d,%d,r=%d,b=%d)"
   1645             " found=(%d,%d,r=%d,b=%d)", x, y, wordBounds.fLeft, wordBounds.fTop,
   1646             wordBounds.fRight, wordBounds.fBottom, found.fLeft, found.fTop,
   1647             found.fRight, found.fBottom);
   1648         if (wordBounds.contains(x, y)) {
   1649             DBG_NAV_LOG("wordBounds.contains=true");
   1650             m_outsideWord = false;
   1651             return;
   1652         }
   1653         m_outsideWord = true;
   1654         if (found.fBottom <= wordBounds.fTop)
   1655             m_hitTopLeft = true;
   1656         else if (found.fTop >= wordBounds.fBottom)
   1657             m_hitTopLeft = false;
   1658         else
   1659             m_hitTopLeft = (found.fLeft + found.fRight)
   1660                 < (wordBounds.fLeft + wordBounds.fRight);
   1661     }
   1662     DBG_NAV_LOGD("x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)"
   1663         " m_extendSelection=%s",
   1664         x, y, m_startSelection ? "true" : "false",
   1665         m_hitTopLeft ? "m_selStart" : "m_selEnd",
   1666         found.fLeft, found.fTop, found.fRight, found.fBottom,
   1667         m_extendSelection ? "true" : "false");
   1668     if (m_hitTopLeft) {
   1669         m_startBase = base;
   1670         m_selStart = found;
   1671     } else {
   1672         m_endBase = base;
   1673         m_selEnd = found;
   1674     }
   1675     swapAsNeeded();
   1676 }
   1677 
   1678 SkIRect SelectText::findClosest(FirstCheck& check, const SkPicture& picture,
   1679         int* base)
   1680 {
   1681     LineCheck lineCheck(check.focusX(), check.focusY(), check.getArea());
   1682     TextCanvas lineChecker(&lineCheck);
   1683     lineChecker.drawPicture(const_cast<SkPicture&>(picture));
   1684     lineCheck.finish(m_selRegion);
   1685     check.setLines(&lineCheck);
   1686     TextCanvas checker(&check);
   1687     checker.drawPicture(const_cast<SkPicture&>(picture));
   1688     check.finishGlyph();
   1689     return check.adjustedBounds(base);
   1690 }
   1691 
   1692 SkIRect SelectText::findEdge(const SkPicture& picture, const SkIRect& area,
   1693         int x, int y, bool left, int* base)
   1694 {
   1695     SkIRect result;
   1696     result.setEmpty();
   1697     FirstCheck center(x, y, area);
   1698     center.setRecordGlyph();
   1699     int closestBase;
   1700     SkIRect closest = findClosest(center, picture, &closestBase);
   1701     SkIRect sloppy = closest;
   1702     sloppy.inset(-TOUCH_SLOP, -TOUCH_SLOP);
   1703     if (!sloppy.contains(x, y)) {
   1704         DBG_NAV_LOGD("sloppy=(%d, %d, %d, %d) area=(%d, %d, %d, %d) x/y=%d,%d",
   1705             sloppy.fLeft, sloppy.fTop, sloppy.fRight, sloppy.fBottom,
   1706             area.fLeft, area.fTop, area.fRight, area.fBottom, x, y);
   1707         return result;
   1708     }
   1709     EdgeCheck edge(x, y, area, center, left);
   1710     do { // detect left or right until there's a gap
   1711         DBG_NAV_LOGD("edge=%p picture=%p area=%d,%d,%d,%d",
   1712             &edge, &picture, area.fLeft, area.fTop, area.fRight, area.fBottom);
   1713         TextCanvas checker(&edge);
   1714         checker.drawPicture(const_cast<SkPicture&>(picture));
   1715         edge.finishGlyph();
   1716         if (!edge.adjacent()) {
   1717             if (result.isEmpty()) {
   1718                 *base = closestBase;
   1719                 DBG_NAV_LOGD("closest=%d,%d,%d,%d", closest.fLeft,
   1720                     closest.fTop, closest.fRight, closest.fBottom);
   1721                 return closest;
   1722             }
   1723             DBG_NAV_LOG("adjacent break");
   1724             break;
   1725         }
   1726         int nextBase;
   1727         const SkIRect& next = edge.bestBounds(&nextBase);
   1728         if (next.isEmpty()) {
   1729             DBG_NAV_LOG("empty");
   1730             break;
   1731         }
   1732         if (result == next) {
   1733             DBG_NAV_LOG("result == next");
   1734             break;
   1735         }
   1736         *base = nextBase;
   1737         result = next;
   1738         edge.shiftStart(result);
   1739     } while (true);
   1740     if (!result.isEmpty()) {
   1741         *base += area.fTop;
   1742         result.offset(area.fLeft, area.fTop);
   1743     }
   1744     return result;
   1745 }
   1746 
   1747 SkIRect SelectText::findLeft(const SkPicture& picture, const SkIRect& area,
   1748         int x, int y, int* base)
   1749 {
   1750     return findEdge(picture, area, x, y, true, base);
   1751 }
   1752 
   1753 SkIRect SelectText::findRight(const SkPicture& picture, const SkIRect& area,
   1754         int x, int y, int* base)
   1755 {
   1756     return findEdge(picture, area, x, y, false, base);
   1757 }
   1758 
   1759 const String SelectText::getSelection()
   1760 {
   1761     if (!m_picture)
   1762         return String();
   1763     SkIRect clipRect;
   1764     clipRect.set(0, 0, m_picture->width(), m_picture->height());
   1765     String result = text(*m_picture, clipRect, m_selStart, m_startBase,
   1766         m_selEnd, m_endBase, m_flipped);
   1767     DBG_NAV_LOGD("clip=(%d,%d,%d,%d)"
   1768         " m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
   1769         clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom,
   1770         m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
   1771         m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
   1772     DBG_NAV_LOGD("text=%s", result.latin1().data()); // uses CString
   1773     return result;
   1774 }
   1775 
   1776 void SelectText::getSelectionArrow(SkPath* path)
   1777 {
   1778     const int arrow[] = {
   1779         0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
   1780     };
   1781     for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
   1782         path->lineTo(arrow[index], arrow[index + 1]);
   1783     path->close();
   1784 }
   1785 
   1786 void SelectText::getSelectionCaret(SkPath* path)
   1787 {
   1788     SkScalar height = m_selStart.fBottom - m_selStart.fTop;
   1789     SkScalar dist = height / 4;
   1790     path->moveTo(0, -height / 2);
   1791     path->rLineTo(0, height);
   1792     path->rLineTo(-dist, dist);
   1793     path->rMoveTo(0, -0.5f);
   1794     path->rLineTo(dist * 2, 0);
   1795     path->rMoveTo(0, 0.5f);
   1796     path->rLineTo(-dist, -dist);
   1797 }
   1798 
   1799 bool SelectText::hitCorner(int cx, int cy, int x, int y) const
   1800 {
   1801     SkIRect test;
   1802     test.set(cx, cy, cx + m_controlWidth, cy + m_controlHeight);
   1803     test.inset(-m_controlSlop, -m_controlSlop);
   1804     DBG_HANDLE_LOG("checking if %dx%d,%d-%d contains %dx%d",
   1805                    cx, cy, m_controlWidth, m_controlHeight, x,  y);
   1806     return test.contains(x, y);
   1807 }
   1808 
   1809 bool SelectText::hitStartHandle(int x, int y) const
   1810 {
   1811     int left = m_selStart.fLeft - m_controlWidth;
   1812     return hitCorner(left, m_selStart.fBottom, x, y);
   1813 }
   1814 
   1815 bool SelectText::hitEndHandle(int x, int y) const
   1816 {
   1817     int left = m_selEnd.fRight;
   1818     return hitCorner(left, m_selEnd.fBottom, x, y);
   1819 }
   1820 
   1821 bool SelectText::hitSelection(int x, int y) const
   1822 {
   1823     x -= m_startOffset.fX;
   1824     y -= m_startOffset.fY;
   1825     if (hitStartHandle(x, y))
   1826         return true;
   1827     if (hitEndHandle(x, y))
   1828         return true;
   1829     return m_selRegion.contains(x, y);
   1830 }
   1831 
   1832 void SelectText::getSelectionHandles(int* handles, LayerAndroid* root)
   1833 {
   1834     handles[0] = m_selStart.fLeft;
   1835     handles[1] = m_selStart.fBottom;
   1836     handles[2] = m_selEnd.fRight;
   1837     handles[3] = m_selEnd.fBottom;
   1838     if (root && m_layerId) {
   1839         Layer* layer = root->findById(m_layerId);
   1840         while (layer) {
   1841             const SkPoint& pos = layer->getPosition();
   1842             handles[0] += pos.fX;
   1843             handles[2] += pos.fX;
   1844             handles[1] += pos.fY;
   1845             handles[3] += pos.fY;
   1846             layer = layer->getParent();
   1847         }
   1848     }
   1849 }
   1850 
   1851 void SelectText::moveSelection(const IntRect& vis, int x, int y)
   1852 {
   1853     if (!m_picture)
   1854         return;
   1855     x -= m_startOffset.fX;
   1856     y -= m_startOffset.fY;
   1857     setVisibleRect(vis);
   1858     SkIRect clipRect = m_visibleRect;
   1859     clipRect.join(m_selStart);
   1860     clipRect.join(m_selEnd);
   1861     FirstCheck center(x, y, clipRect);
   1862     int base;
   1863     SkIRect found = findClosest(center, *m_picture, &base);
   1864     if (m_hitTopLeft || !m_extendSelection) {
   1865         m_startBase = base;
   1866         m_selStart = found;
   1867     }
   1868     if (!m_hitTopLeft || !m_extendSelection) {
   1869         m_endBase = base;
   1870         m_selEnd = found;
   1871     }
   1872     swapAsNeeded();
   1873     DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
   1874         " m_selEnd=(%d, %d, %d, %d)", x, y, m_extendSelection ? "true" : "false",
   1875         m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
   1876         m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
   1877 }
   1878 
   1879 void SelectText::reset()
   1880 {
   1881     DBG_NAV_LOG("m_extendSelection=false");
   1882     m_selStart.setEmpty();
   1883     m_lastStart.setEmpty();
   1884     m_lastDrawnStart.setEmpty();
   1885     m_selEnd.setEmpty();
   1886     m_lastEnd.setEmpty();
   1887     m_lastDrawnEnd.setEmpty();
   1888     m_extendSelection = false;
   1889     m_startSelection = false;
   1890     SkSafeUnref(m_picture);
   1891     m_picture = 0;
   1892     m_layerId = 0;
   1893 }
   1894 
   1895 IntPoint SelectText::selectableText(const CachedRoot* root)
   1896 {
   1897     int x = 0;
   1898     int y = 0;
   1899     SkPicture* picture = root->pictureAt(&x, &y, &m_layerId);
   1900     if (!picture) {
   1901         DBG_NAV_LOG("picture==0");
   1902         return IntPoint(0, 0);
   1903     }
   1904     int width = picture->width();
   1905     int height = picture->height();
   1906     IntRect vis(0, 0, width, height);
   1907     FirstCheck center(width >> 1, height >> 1, vis);
   1908     int base;
   1909     const SkIRect& closest = findClosest(center, *picture, &base);
   1910     return IntPoint((closest.fLeft + closest.fRight) >> 1,
   1911         (closest.fTop + closest.fBottom) >> 1);
   1912 }
   1913 
   1914 void SelectText::selectAll()
   1915 {
   1916     if (!m_picture)
   1917         return;
   1918     m_selStart = findFirst(*m_picture, &m_startBase);
   1919     m_selEnd = findLast(*m_picture, &m_endBase);
   1920     m_extendSelection = true;
   1921 }
   1922 
   1923 int SelectText::selectionX() const
   1924 {
   1925     return (m_hitTopLeft ? m_selStart.fLeft : m_selEnd.fRight) + m_startOffset.fX;
   1926 }
   1927 
   1928 int SelectText::selectionY() const
   1929 {
   1930     const SkIRect& rect = m_hitTopLeft ? m_selStart : m_selEnd;
   1931     return ((rect.fTop + rect.fBottom) >> 1) + m_startOffset.fY;
   1932 }
   1933 
   1934 void SelectText::setVisibleRect(const IntRect& vis)
   1935 {
   1936     DBG_NAV_LOGD("vis=(%d,%d,w=%d,h=%d) offset=(%d,%d)",
   1937         vis.x(), vis.y(), vis.width(), vis.height(), m_startOffset.fX,
   1938         m_startOffset.fY);
   1939     m_visibleRect = vis;
   1940     m_visibleRect.offset(-m_startOffset.fX, -m_startOffset.fY);
   1941 }
   1942 
   1943 bool SelectText::startSelection(const CachedRoot* root, const IntRect& vis,
   1944     int x, int y)
   1945 {
   1946     m_wordSelection = false;
   1947     m_startOffset.set(x, y);
   1948     DBG_NAV_LOGD("x/y=(%d,%d)", x, y);
   1949     SkSafeUnref(m_picture);
   1950     m_picture = root->pictureAt(&x, &y, &m_layerId);
   1951     DBG_NAV_LOGD("m_picture=%p m_layerId=%d x/y=(%d,%d)", m_picture, m_layerId,
   1952         x, y);
   1953     if (!m_picture) {
   1954         DBG_NAV_LOG("picture==0");
   1955         return false;
   1956     }
   1957     m_picture->ref();
   1958     m_startOffset.fX -= x;
   1959     m_startOffset.fY -= y;
   1960     m_original.fX = x;
   1961     m_original.fY = y;
   1962     setVisibleRect(vis);
   1963     if (m_selStart.isEmpty()) {
   1964         DBG_NAV_LOGD("empty start picture=(%d,%d) x=%d y=%d",
   1965              m_picture->width(), m_picture->height(), x, y);
   1966         m_startSelection = true;
   1967         return true;
   1968     }
   1969     m_hitTopLeft = hitStartHandle(x, y);
   1970     bool hitBottomRight = hitEndHandle(x, y);
   1971     DBG_NAV_LOGD("picture=(%d,%d) left=%d top=%d right=%d bottom=%d x=%d y=%d",
   1972         m_picture->width(), m_picture->height(),left, top, right, bottom, x, y);
   1973     if (m_hitTopLeft) {
   1974         DBG_NAV_LOG("hit top left");
   1975         m_original.fX -= m_selStart.fLeft;
   1976         m_original.fY -= (m_selStart.fTop + m_selStart.fBottom) >> 1;
   1977     } else if (hitBottomRight) {
   1978         DBG_NAV_LOG("hit bottom right");
   1979         m_original.fX -= m_selEnd.fRight;
   1980         m_original.fY -= (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
   1981     }
   1982     return m_hitTopLeft || hitBottomRight;
   1983 }
   1984 
   1985 void SelectText::updateHandleScale(float handleScale)
   1986 {
   1987     m_controlHeight = CONTROL_HEIGHT * handleScale;
   1988     m_controlWidth = CONTROL_WIDTH * handleScale;
   1989     m_controlSlop = CONTROL_SLOP * handleScale;
   1990 }
   1991 
   1992 /* selects the word at (x, y)
   1993 * a word is normally delimited by spaces
   1994 * a string of digits (even with inside spaces) is a word (for phone numbers)
   1995 * FIXME: digit find isn't implemented yet
   1996 * returns true if a word was selected
   1997 */
   1998 bool SelectText::wordSelection(const CachedRoot* root, const IntRect& vis,
   1999     int x, int y)
   2000 {
   2001     IntRect tapArea = IntRect(x - TOUCH_SLOP, y - TOUCH_SLOP, TOUCH_SLOP * 2,
   2002         TOUCH_SLOP * 2);
   2003     if (!startSelection(root, tapArea, x, y))
   2004         return false;
   2005     extendSelection(tapArea, x, y);
   2006     if (m_selStart.isEmpty())
   2007         return false;
   2008     setDrawPointer(false);
   2009     setVisibleRect(vis);
   2010     SkIRect ivisBounds = m_visibleRect;
   2011     ivisBounds.join(m_selStart);
   2012     ivisBounds.join(m_selEnd);
   2013     DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)"
   2014         " ivisBounds=(%d,%d,r=%d,b=%d)",
   2015         m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
   2016         m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
   2017         ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
   2018     m_selRegion.setEmpty();
   2019     buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
   2020         m_selEnd, m_endBase, &m_selRegion);
   2021     x = m_selStart.fLeft;
   2022     y = (m_selStart.fTop + m_selStart.fBottom) >> 1;
   2023     SkIRect clipRect = m_visibleRect;
   2024     clipRect.fLeft -= m_visibleRect.width() >> 1;
   2025     clipRect.fLeft = std::max(clipRect.fLeft, 0);
   2026     int base;
   2027     SkIRect left = findLeft(*m_picture, clipRect, x, y, &base);
   2028     if (!left.isEmpty()) {
   2029         m_startBase = base;
   2030         m_selStart = left;
   2031     }
   2032     x = m_selEnd.fRight;
   2033     y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
   2034     clipRect = m_visibleRect;
   2035     clipRect.fRight += m_visibleRect.width() >> 1;
   2036     SkIRect right = findRight(*m_picture, clipRect, x, y, &base);
   2037     if (!right.isEmpty()) {
   2038         m_endBase = base;
   2039         m_selEnd = right;
   2040     }
   2041     DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
   2042         m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
   2043         m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
   2044     if (!left.isEmpty() || !right.isEmpty()) {
   2045         m_wordBounds = m_selStart;
   2046         m_wordBounds.join(m_selEnd);
   2047         m_extendSelection = m_wordSelection = true;
   2048         m_outsideWord = false;
   2049         return true;
   2050     }
   2051     return false;
   2052 }
   2053 
   2054 void SelectText::swapAsNeeded()
   2055 {
   2056     if (m_selStart.fTop >= (m_selEnd.fTop + m_selEnd.fBottom) >> 1
   2057             || (m_selEnd.fTop < (m_selStart.fTop + m_selStart.fBottom) >> 1
   2058             && m_selStart.fRight > m_selEnd.fLeft))
   2059     {
   2060         SkTSwap(m_startBase, m_endBase);
   2061         SkTSwap(m_selStart, m_selEnd);
   2062         m_hitTopLeft ^= true;
   2063         DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false");
   2064     }
   2065 }
   2066 
   2067 }
   2068