summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCary Clark <cary@android.com>2010-12-16 13:21:01 -0500
committerCary Clark <cary@android.com>2010-12-16 14:05:29 -0500
commit45caa82c86fc13574e7a4c476b92c593e999ebac (patch)
tree89d862ea4292157bf05ec4dae3281317627be839
parent0bdd7f2d73cad03535071e5de0ba3d2f5feb1b00 (diff)
downloadexternal_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.cpp12
-rw-r--r--WebKit/android/nav/CachedLayer.cpp2
-rw-r--r--WebKit/android/nav/SelectText.cpp72
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;