diff options
author | Cary Clark <cary@android.com> | 2010-12-16 13:21:01 -0500 |
---|---|---|
committer | Cary Clark <cary@android.com> | 2010-12-16 14:05:29 -0500 |
commit | 45caa82c86fc13574e7a4c476b92c593e999ebac (patch) | |
tree | 89d862ea4292157bf05ec4dae3281317627be839 | |
parent | 0bdd7f2d73cad03535071e5de0ba3d2f5feb1b00 (diff) | |
download | external_webkit-45caa82c86fc13574e7a4c476b92c593e999ebac.zip external_webkit-45caa82c86fc13574e7a4c476b92c593e999ebac.tar.gz external_webkit-45caa82c86fc13574e7a4c476b92c593e999ebac.tar.bz2 |
improve text selection in scrollable divs
Detect which layer is hit by looking for scrollable layers.
In this case it isn't necessary to see what is drawn or where,
because the layer has already been prescreened by the parent clip.
Adjust the x/y hit by the layer's position. This corrects the
position when the layer scrolls.
Fix CachedLayer's debug output to be in sync with LayerAndroid.h
SelectText edge cases are corrected when there is not text to hit.
To find the closest character, first look at the edge of the
text line. If the hit is inside the line of text, measure from the
center of the character. This helps when textlines overlap.
bug:3275625
bug:3191699
Change-Id: I924cc0432f6dace32e0a7444fe69ef15dca2e77f
-rw-r--r-- | WebCore/platform/graphics/android/LayerAndroid.cpp | 12 | ||||
-rw-r--r-- | WebKit/android/nav/CachedLayer.cpp | 2 | ||||
-rw-r--r-- | WebKit/android/nav/SelectText.cpp | 72 |
3 files changed, 66 insertions, 20 deletions
diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp index b71f525..15b992a 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -316,10 +316,10 @@ public: bool drewText() { return m_findCheck.drewText(); } - void setBest(const LayerAndroid* best) { + void setBest(const LayerAndroid* best, int x, int y) { m_best = best; - m_bestX = m_x; - m_bestY = m_y; + m_bestX = x; + m_bestY = y; } int x() const { return m_x; } int y() const { return m_y; } @@ -354,12 +354,14 @@ void LayerAndroid::findInner(LayerAndroid::FindState& state) const for (int i = 0; i < countChildren(); i++) getChild(i)->findInner(state); // Move back into the parent coordinates. + int testX = state.x(); + int testY = state.y(); state.setLocation(x + localBounds.fLeft, y + localBounds.fTop); if (!m_recordingPicture) return; - if (!state.drew(m_recordingPicture, localBounds)) + if (!contentIsScrollable() && !state.drew(m_recordingPicture, localBounds)) return; - state.setBest(this); // set last match (presumably on top) + state.setBest(this, testX, testY); // set last match (presumably on top) } const LayerAndroid* LayerAndroid::find(int* xPtr, int* yPtr, SkPicture* root) const diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp index 0c53da2..7780250 100644 --- a/WebKit/android/nav/CachedLayer.cpp +++ b/WebKit/android/nav/CachedLayer.cpp @@ -202,7 +202,7 @@ void CachedLayer::Debug::printLayerAndroid(const LayerAndroid* layer) spaces, " ", layer, layer->uniqueId(), bounds.fLeft, bounds.fTop, bounds.width(), bounds.height(), layer->getPosition().fX, layer->getPosition().fY, - layer->translation().fX, layer->translation().fY, + layer->translation().x(), layer->translation().y(), layer->getAnchorPoint().fX, layer->getAnchorPoint().fY, layer->getMatrix().getTranslateX(), layer->getMatrix().getTranslateY(), layer->getChildrenMatrix().getTranslateX(), diff --git a/WebKit/android/nav/SelectText.cpp b/WebKit/android/nav/SelectText.cpp index 6a22c73..53eac2c 100644 --- a/WebKit/android/nav/SelectText.cpp +++ b/WebKit/android/nav/SelectText.cpp @@ -189,6 +189,7 @@ public: , mPaint(0) { mLastGlyph.fGlyphID = static_cast<uint16_t>(-1); + mLastCandidate.fGlyphID = static_cast<uint16_t>(-1); reset(); } @@ -260,6 +261,8 @@ public: 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)" " mMinSpaceWidth=%g mLastUni=0x%04x '%c'", @@ -319,7 +322,7 @@ public: charPaint.setTextEncoding(SkPaint::kUTF8_TextEncoding); SkScalar width = charPaint.measureText(" ", 1); mMinSpaceWidth = SkScalarToFixed(width * mMatrix->getScaleX()); - DBG_NAV_LOGD("width=%g matrix sx/sy=(%g, %g) tx/ty=(%g, %g)" + 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(), @@ -416,6 +419,8 @@ public: void finish(const SkRegion& selectedRgn) { + if (!mParagraphs.count() && mLast.isEmpty()) + return; processLine(); bool above = false; bool below = false; @@ -548,28 +553,60 @@ public: * 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 overlaps = testBounds.fTop < mBestBounds.fBottom - && testBounds.fBottom > mBestBounds.fTop; #ifdef EXTRA_NOISY_LOGGING if (dy < 10) { SkUnichar ch = getUniChar(rec); DBG_NAV_LOGD("FirstCheck dx/y=(%d,%d) mDx/y=(%d,%d)" " testBounds=(%d,%d,r=%d,b=%d) mBestBounds=(%d,%d,r=%d,b=%d)" - " overlaps=%s ch=%c", dx, dy, mDx, mDy, + " ch=%c", dx, dy, mDx, mDy, testBounds.fLeft, testBounds.fTop, testBounds.fRight, testBounds.fBottom, mBestBounds.fLeft, mBestBounds.fTop, - mBestBounds.fRight, mBestBounds.fBottom, - overlaps ? "true" : "false", ch < 0x7f ? ch : '?'); + mBestBounds.fRight, mBestBounds.fBottom, ch < 0x7f ? ch : '?'); } #endif - if ((mDy <= dy || overlaps) - && ((mDy != dy && !overlaps) || mDx <= dx)) { + if (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 = INT_MAX; + int cy = INT_MAX; + if (dy == 0) { + cy = std::abs(((testBounds.fTop + testBounds.fBottom) >> 1) + - mFocusY); + 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) { + cx = std::abs(((testBounds.fLeft + testBounds.fRight) >> 1) + - mFocusX); + 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; + } + } + } bool testInColumn = false; bool inBetween = false; if (mLineCheck) { @@ -578,9 +615,9 @@ public: } #ifdef EXTRA_NOISY_LOGGING if (dy < 10) { - DBG_NAV_LOGD("FirstCheck bestIn=%s testIn=%s focusIn=%s", - mBestInColumn ? "true" : "false", testInColumn ? "true" : "false", - inBetween ? "true" : "false"); + DBG_NAV_LOGD("FirstCheck cx/y=(%d,%d) bestIn=%s testIn=%s focusIn=%s", + cx, cy, mBestInColumn ? "true" : "false", + testInColumn ? "true" : "false", inBetween ? "true" : "false"); } #endif if ((mBestInColumn || inBetween) && !testInColumn) @@ -592,13 +629,18 @@ public: 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", + " 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"); + mBestInColumn ? "true" : "false", ch < 0x7f ? ch : '?'); } + mCx = cx; + mCy = cy; mDx = dx; mDy = dy; if (mRecordGlyph) @@ -609,7 +651,7 @@ public: void reset() { mBestBounds.setEmpty(); - mDx = mDy = INT_MAX; + mDx = mDy = mCx = mCy = INT_MAX; } void setLines(const LineCheck* lineCheck) { mLineCheck = lineCheck; } @@ -619,6 +661,8 @@ protected: const LineCheck* mLineCheck; int mBestBase; SkIRect mBestBounds; + int mCx; + int mCy; int mDx; int mDy; int mFocusX; |