summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/WebCore/editing/SelectionController.cpp4
-rw-r--r--Source/WebCore/platform/graphics/android/BaseRenderer.cpp20
-rw-r--r--Source/WebCore/platform/graphics/android/BaseTile.cpp89
-rw-r--r--Source/WebCore/platform/graphics/android/BaseTileTexture.h1
-rw-r--r--Source/WebCore/platform/graphics/android/GLExtras.cpp50
-rw-r--r--Source/WebCore/platform/graphics/android/GLExtras.h13
-rw-r--r--Source/WebCore/platform/graphics/android/GLUtils.cpp38
-rw-r--r--Source/WebCore/platform/graphics/android/GLUtils.h4
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h2
-rw-r--r--Source/WebCore/platform/graphics/android/Layer.cpp8
-rw-r--r--Source/WebCore/platform/graphics/android/Layer.h8
-rw-r--r--Source/WebCore/platform/graphics/android/LayerAndroid.cpp6
-rw-r--r--Source/WebCore/platform/graphics/android/LayerAndroid.h3
-rw-r--r--Source/WebCore/platform/graphics/android/RasterRenderer.cpp10
-rw-r--r--Source/WebCore/platform/graphics/android/TransferQueue.cpp70
-rw-r--r--Source/WebCore/platform/graphics/android/TransferQueue.h5
-rw-r--r--Source/WebCore/platform/graphics/android/android_graphics.cpp2
-rw-r--r--Source/WebCore/platform/graphics/android/android_graphics.h2
-rw-r--r--Source/WebKit/Android.mk1
-rw-r--r--Source/WebKit/android/jni/AndroidHitTestResult.cpp39
-rw-r--r--Source/WebKit/android/jni/WebCoreJni.cpp23
-rw-r--r--Source/WebKit/android/jni/WebCoreJni.h3
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp323
-rw-r--r--Source/WebKit/android/jni/WebViewCore.h17
-rw-r--r--Source/WebKit/android/nav/DrawExtra.cpp96
-rw-r--r--Source/WebKit/android/nav/DrawExtra.h39
-rw-r--r--Source/WebKit/android/nav/FindCanvas.cpp2
-rw-r--r--Source/WebKit/android/nav/FindCanvas.h2
-rw-r--r--Source/WebKit/android/nav/SelectText.cpp1928
-rw-r--r--Source/WebKit/android/nav/SelectText.h102
-rw-r--r--Source/WebKit/android/nav/WebView.cpp406
31 files changed, 840 insertions, 2476 deletions
diff --git a/Source/WebCore/editing/SelectionController.cpp b/Source/WebCore/editing/SelectionController.cpp
index c5a33d3..e9bdd6a 100644
--- a/Source/WebCore/editing/SelectionController.cpp
+++ b/Source/WebCore/editing/SelectionController.cpp
@@ -1592,6 +1592,10 @@ void SelectionController::updateAppearance()
// We need to update style in case the node containing the selection is made display:none.
m_frame->document()->updateStyleIfNeeded();
+#if PLATFORM(ANDROID)
+ return;
+#endif
+
RenderView* view = m_frame->contentRenderer();
if (!view)
return;
diff --git a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp
index 57baee8..b708ad1 100644
--- a/Source/WebCore/platform/graphics/android/BaseRenderer.cpp
+++ b/Source/WebCore/platform/graphics/android/BaseRenderer.cpp
@@ -141,7 +141,13 @@ int BaseRenderer::renderTiledContent(const TileRenderInfo& renderInfo)
// only color the invalidated area
SkPaint invalPaint;
invalPaint.setARGB(color, 0, 255, 0);
- canvas.drawIRect(*renderInfo.invalRect, invalPaint);
+ if (renderInfo.invalRect)
+ canvas.drawIRect(*renderInfo.invalRect, invalPaint);
+ else {
+ SkIRect rect;
+ rect.set(0, 0, tileSize.width(), tileSize.height());
+ canvas.drawIRect(rect, invalPaint);
+ }
// paint the tile boundaries
SkPaint paint;
@@ -154,6 +160,18 @@ int BaseRenderer::renderTiledContent(const TileRenderInfo& renderInfo)
canvas.drawLine(0, 0, tileSize.width(), 0, paint);
canvas.drawLine(tileSize.width(), 0, tileSize.width(), tileSize.height(), paint);
+ if (renderInfo.invalRect) {
+ // if partial inval...
+ int x = renderInfo.invalRect->fLeft;
+ int y = renderInfo.invalRect->fTop;
+ int w = renderInfo.invalRect->width();
+ int h = renderInfo.invalRect->height();
+
+ paint.setARGB(128, 255, 255, 0);
+ canvas.drawLine(x, y, x + w, y + h, paint);
+ canvas.drawLine(x, y + h, x + w, y, paint);
+ }
+
if (renderInfo.measurePerf)
drawTileInfo(&canvas, renderInfo, pictureCount);
}
diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp
index 76ee1e7..42d02a5 100644
--- a/Source/WebCore/platform/graphics/android/BaseTile.cpp
+++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp
@@ -54,6 +54,13 @@
#endif // DEBUG
+// If the dirty portion of a tile exceeds this ratio, fully repaint.
+// Lower values give fewer partial repaints, thus fewer front-to-back
+// texture copies (cost will vary by device). It's a tradeoff between
+// the rasterization cost and the FBO texture recopy cost when using
+// GPU for the transfer queue.
+#define MAX_INVAL_AREA 0.6
+
namespace WebCore {
BaseTile::BaseTile(bool isLayerTile)
@@ -369,55 +376,65 @@ void BaseTile::paintBitmap()
fullRepaint = true;
}
- // With SurfaceTexture, just repaint the entire tile if we intersect.
- // TODO: Implement the partial invalidate in Surface Texture Mode.
- // Such that the code of partial invalidation below is preserved.
+ // For now, only do full repaint
fullRepaint = true;
- while (!fullRepaint && !cliperator.done()) {
- SkRect realTileRect;
- SkRect dirtyRect;
- dirtyRect.set(cliperator.rect());
- bool intersect = intersectWithRect(x, y, tileWidth, tileHeight,
- scale, dirtyRect, realTileRect);
-
- if (intersect) {
- // initialize finalRealRect to the rounded values of realTileRect
- SkIRect finalRealRect;
- realTileRect.roundOut(&finalRealRect);
-
- // stash the int values of the current width and height
- const int iWidth = finalRealRect.width();
- const int iHeight = finalRealRect.height();
-
- if (iWidth == tileWidth || iHeight == tileHeight) {
- fullRepaint = true;
- break;
+ if (!fullRepaint) {
+ // compute the partial inval area
+ SkIRect totalRect;
+ totalRect.set(0, 0, 0, 0);
+ float tileSurface = tileWidth * tileHeight;
+ float tileSurfaceCap = MAX_INVAL_AREA * tileSurface;
+
+ // We join all the invals in the same tile for now
+ while (!fullRepaint && !cliperator.done()) {
+ SkRect realTileRect;
+ SkRect dirtyRect;
+ dirtyRect.set(cliperator.rect());
+ bool intersect = intersectWithRect(x, y, tileWidth, tileHeight,
+ scale, dirtyRect, realTileRect);
+ if (intersect) {
+ // initialize finalRealRect to the rounded values of realTileRect
+ SkIRect finalRealRect;
+ realTileRect.roundOut(&finalRealRect);
+
+ // stash the int values of the current width and height
+ const int iWidth = finalRealRect.width();
+ const int iHeight = finalRealRect.height();
+
+ if (iWidth == tileWidth || iHeight == tileHeight) {
+ fullRepaint = true;
+ break;
+ }
+
+ // translate the rect into tile space coordinates
+ finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth);
+ finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight);
+ finalRealRect.fRight = finalRealRect.fLeft + iWidth;
+ finalRealRect.fBottom = finalRealRect.fTop + iHeight;
+ totalRect.join(finalRealRect);
+ float repaintSurface = totalRect.width() * totalRect.height();
+
+ if (repaintSurface > tileSurfaceCap) {
+ fullRepaint = true;
+ break;
+ }
}
- // translate the rect into tile space coordinates
- finalRealRect.fLeft = finalRealRect.fLeft % static_cast<int>(tileWidth);
- finalRealRect.fTop = finalRealRect.fTop % static_cast<int>(tileHeight);
- finalRealRect.fRight = finalRealRect.fLeft + iWidth;
- finalRealRect.fBottom = finalRealRect.fTop + iHeight;
+ cliperator.next();
+ }
- renderInfo.invalRect = &finalRealRect;
+ if (!fullRepaint) {
+ renderInfo.invalRect = &totalRect;
renderInfo.measurePerf = false;
-
pictureCount = m_renderer->renderTiledContent(renderInfo);
}
-
- cliperator.next();
}
// Do a full repaint if needed
if (fullRepaint) {
- SkIRect rect;
- rect.set(0, 0, tileWidth, tileHeight);
-
- renderInfo.invalRect = &rect;
+ renderInfo.invalRect = 0;
renderInfo.measurePerf = TilesManager::instance()->getShowVisualIndicator();
-
pictureCount = m_renderer->renderTiledContent(renderInfo);
}
diff --git a/Source/WebCore/platform/graphics/android/BaseTileTexture.h b/Source/WebCore/platform/graphics/android/BaseTileTexture.h
index 55314c7..67eeeb9 100644
--- a/Source/WebCore/platform/graphics/android/BaseTileTexture.h
+++ b/Source/WebCore/platform/graphics/android/BaseTileTexture.h
@@ -60,6 +60,7 @@ public:
TilePainter* m_painter;
unsigned int m_picture;
bool m_inverted;
+ IntRect m_inval;
};
class BaseTileTexture {
diff --git a/Source/WebCore/platform/graphics/android/GLExtras.cpp b/Source/WebCore/platform/graphics/android/GLExtras.cpp
index 9ad369a..b872951 100644
--- a/Source/WebCore/platform/graphics/android/GLExtras.cpp
+++ b/Source/WebCore/platform/graphics/android/GLExtras.cpp
@@ -52,10 +52,6 @@
// Touch ring border width. This is doubled if the ring is not pressed
#define RING_BORDER_WIDTH 1
-// Color of the ring is 0x6633b5e5 (copied from framework's holo_light)
-#define COLOR_HOLO_LIGHT &m_lightRingTexture, 0x33, 0xb5, 0xe5, 0.4f
-// Color of the ring is 0x660099cc (copied from framework's holo_dark)
-#define COLOR_HOLO_DARK &m_darkRingTexture, 0x00, 0x99, 0xcc, 0.6f
// Put a cap on the number of matches to draw. If the current page has more
// matches than this, only draw the focused match. This both prevents clutter
// on the page and keeps the performance happy
@@ -65,8 +61,6 @@ GLExtras::GLExtras()
: m_findOnPage(0)
, m_ring(0)
, m_drawExtra(0)
- , m_lightRingTexture(-1)
- , m_darkRingTexture(-1)
, m_viewport()
{
}
@@ -75,27 +69,28 @@ GLExtras::~GLExtras()
{
}
-void GLExtras::drawRing(SkRect& srcRect, int* texture, int r, int g, int b, float a,
- const TransformationMatrix* drawMat)
+void GLExtras::drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat)
{
- if (*texture == -1)
- *texture = GLUtils::createSampleColorTexture(r, g, b);
-
if (srcRect.fRight <= srcRect.fLeft || srcRect.fBottom <= srcRect.fTop) {
// Invalid rect, reject it
return;
}
XLOG("drawQuad [%fx%f, %f, %f]", srcRect.fLeft, srcRect.fTop,
srcRect.width(), srcRect.height());
- if (drawMat)
- TilesManager::instance()->shader()->drawLayerQuad(*drawMat, srcRect, *texture, a);
- else
- TilesManager::instance()->shader()->drawQuad(srcRect, *texture, a);
+ // Pull the alpha out of the color so that the shader applies it correctly.
+ // Otherwise we either don't have blending enabled, or the alpha will get
+ // double applied
+ Color colorWithoutAlpha(0xFF000000 | color.rgb());
+ float alpha = color.alpha() / (float) 255;
+ if (drawMat) {
+ TilesManager::instance()->shader()->drawLayerQuad(*drawMat, srcRect, 0,
+ alpha, false, 0, colorWithoutAlpha);
+ } else
+ TilesManager::instance()->shader()->drawQuad(srcRect, 0, alpha, colorWithoutAlpha);
}
-void GLExtras::drawRegion(const SkRegion& region, bool fill,
- bool drawBorder, const TransformationMatrix* drawMat,
- bool useDark)
+void GLExtras::drawRegion(const SkRegion& region, bool fill, bool drawBorder,
+ const TransformationMatrix* drawMat, Color color)
{
if (region.isEmpty())
return;
@@ -105,10 +100,7 @@ void GLExtras::drawRegion(const SkRegion& region, bool fill,
const SkIRect& ir = rgnIter.rect();
SkRect r;
r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom);
- if (useDark)
- drawRing(r, COLOR_HOLO_DARK, drawMat);
- else
- drawRing(r, COLOR_HOLO_LIGHT, drawMat);
+ drawRing(r, color, drawMat);
rgnIter.next();
}
}
@@ -149,10 +141,7 @@ void GLExtras::drawRegion(const SkRegion& region, bool fill,
clip.setRect(line);
}
r.set(line.fLeft, line.fTop, line.fRight, line.fBottom);
- if (useDark)
- drawRing(r, COLOR_HOLO_DARK, drawMat);
- else
- drawRing(r, COLOR_HOLO_LIGHT, drawMat);
+ drawRing(r, color, drawMat);
if (startRect.isEmpty()) {
startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom);
}
@@ -178,7 +167,7 @@ void GLExtras::drawCursorRings(const LayerAndroid* layer)
region.op(rect, SkRegion::kUnion_Op);
}
drawRegion(region, m_ring->m_isPressed, !m_ring->m_isButton,
- layer ? layer->drawTransform() : 0, false);
+ layer ? layer->drawTransform() : 0);
}
void GLExtras::drawFindOnPage(const LayerAndroid* layer)
@@ -211,7 +200,7 @@ void GLExtras::drawFindOnPage(const LayerAndroid* layer)
}
if (rect.intersect(m_viewport.fLeft, m_viewport.fTop,
m_viewport.fRight, m_viewport.fBottom))
- drawRegion(region, i == current, false, drawTransform, true);
+ drawRegion(region, i == current, false, drawTransform, COLOR_HOLO_DARK);
#ifdef DEBUG
else
XLOG("Quick rejecting [%dx%d, %d, %d", rect.fLeft, rect.fTop,
@@ -221,7 +210,7 @@ void GLExtras::drawFindOnPage(const LayerAndroid* layer)
else {
if (matchRange.first <= current && current < matchRange.second) {
MatchInfo& info = matches->at(current);
- drawRegion(info.getLocation(), true, false, drawTransform, true);
+ drawRegion(info.getLocation(), true, false, drawTransform, COLOR_HOLO_DARK);
}
}
}
@@ -234,7 +223,6 @@ void GLExtras::drawGL(const LayerAndroid* layer)
else if (m_drawExtra == m_findOnPage)
drawFindOnPage(layer);
else
- XLOGC("m_drawExtra %p is unknown! (cursor: %p, find: %p",
- m_drawExtra, m_ring, m_findOnPage);
+ m_drawExtra->drawGL(this, layer);
}
}
diff --git a/Source/WebCore/platform/graphics/android/GLExtras.h b/Source/WebCore/platform/graphics/android/GLExtras.h
index 5ccf4cc..51ad8d8 100644
--- a/Source/WebCore/platform/graphics/android/GLExtras.h
+++ b/Source/WebCore/platform/graphics/android/GLExtras.h
@@ -26,13 +26,14 @@
#ifndef GLExtras_h
#define GLExtras_h
+#include "Color.h"
+#include "DrawExtra.h"
#include "SkRect.h"
#include "SkRegion.h"
namespace android {
class FindOnPage;
class CursorRing;
- class DrawExtra;
}
namespace WebCore {
@@ -53,19 +54,17 @@ public:
void setDrawExtra(android::DrawExtra* extra) { m_drawExtra = extra; }
void setViewport(const SkRect & viewport) { m_viewport = viewport; }
-private:
- void drawRing(SkRect& srcRect, int* texture, int r, int g, int b, float a,
- const TransformationMatrix* drawMat);
void drawRegion(const SkRegion& region, bool fill, bool drawBorder,
- const TransformationMatrix* drawMat, bool useDark = false);
+ const TransformationMatrix* drawMat, Color color = COLOR_HOLO_LIGHT);
+
+private:
+ void drawRing(SkRect& srcRect, Color color, const TransformationMatrix* drawMat);
void drawCursorRings(const LayerAndroid* layer);
void drawFindOnPage(const LayerAndroid* layer);
android::FindOnPage* m_findOnPage;
android::CursorRing* m_ring;
android::DrawExtra* m_drawExtra;
- int m_lightRingTexture;
- int m_darkRingTexture;
SkRect m_viewport;
};
diff --git a/Source/WebCore/platform/graphics/android/GLUtils.cpp b/Source/WebCore/platform/graphics/android/GLUtils.cpp
index efd611b..39d8755 100644
--- a/Source/WebCore/platform/graphics/android/GLUtils.cpp
+++ b/Source/WebCore/platform/graphics/android/GLUtils.cpp
@@ -36,12 +36,14 @@
#include <wtf/CurrentTime.h>
#include <wtf/text/CString.h>
-
-#ifdef DEBUG
-
#include <cutils/log.h>
#include <wtf/text/CString.h>
+#undef XLOGC
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "GLUtils", __VA_ARGS__)
+
+#ifdef DEBUG
+
#undef XLOG
#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "GLUtils", __VA_ARGS__)
@@ -425,6 +427,10 @@ bool GLUtils::skipTransferForPureColor(const TileRenderInfo* renderInfo,
bool skipTransfer = false;
BaseTile* tilePtr = renderInfo->baseTile;
+ // TODO: use pure color for partial invals as well
+ if (renderInfo->invalRect)
+ return false;
+
if (tilePtr) {
BaseTileTexture* tileTexture = tilePtr->backTexture();
// Check the bitmap, and make everything ready here.
@@ -450,8 +456,6 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo,
{
if (!renderInfo)
return;
- const int x = renderInfo->invalRect->fLeft;
- const int y = renderInfo->invalRect->fTop;
const SkSize& requiredSize = renderInfo->tileSize;
TextureInfo* textureInfo = renderInfo->textureInfo;
@@ -459,14 +463,14 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo,
return;
if (requiredSize.equals(textureInfo->m_width, textureInfo->m_height))
- GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, x, y, bitmap);
+ GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, bitmap);
else {
if (!requiredSize.equals(bitmap.width(), bitmap.height())) {
XLOG("The bitmap size (%d,%d) does not equal the texture size (%d,%d)",
bitmap.width(), bitmap.height(),
requiredSize.width(), requiredSize.height());
}
- GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, 0, 0, bitmap);
+ GLUtils::updateSharedSurfaceTextureWithBitmap(renderInfo, bitmap);
textureInfo->m_width = bitmap.width();
textureInfo->m_height = bitmap.height();
@@ -474,14 +478,14 @@ void GLUtils::paintTextureWithBitmap(const TileRenderInfo* renderInfo,
}
}
-void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, int x, int y, const SkBitmap& bitmap)
+void GLUtils::updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap)
{
if (!renderInfo
|| !renderInfo->textureInfo
|| !renderInfo->baseTile)
return;
- TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, x, y, bitmap);
+ TilesManager::instance()->transferQueue()->updateQueueWithBitmap(renderInfo, bitmap);
}
void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter)
@@ -515,7 +519,8 @@ void GLUtils::createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GL
glDeleteFramebuffers(1, &fboID);
}
-void GLUtils::updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitmap& bitmap, GLint filter)
+void GLUtils::updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap,
+ const IntRect& inval, GLint filter)
{
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, texture);
@@ -524,13 +529,18 @@ void GLUtils::updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitm
int internalformat = getInternalFormat(config);
int type = getType(config);
bitmap.lockPixels();
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, bitmap.width(), bitmap.height(),
- internalformat, type, bitmap.getPixels());
+ if (inval.isEmpty()) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
+ internalformat, type, bitmap.getPixels());
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), inval.width(), inval.height(),
+ internalformat, type, bitmap.getPixels());
+ }
bitmap.unlockPixels();
if (GLUtils::checkGlError("glTexSubImage2D")) {
XLOG("GL ERROR: glTexSubImage2D parameters are : bitmap.width() %d, bitmap.height() %d,"
- " x %d, y %d, internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
- bitmap.width(), bitmap.height(), x, y, internalformat, type, bitmap.getPixels());
+ " internalformat 0x%x, type 0x%x, bitmap.getPixels() %p",
+ bitmap.width(), bitmap.height(), internalformat, type, bitmap.getPixels());
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
diff --git a/Source/WebCore/platform/graphics/android/GLUtils.h b/Source/WebCore/platform/graphics/android/GLUtils.h
index 3475760..b198d35 100644
--- a/Source/WebCore/platform/graphics/android/GLUtils.h
+++ b/Source/WebCore/platform/graphics/android/GLUtils.h
@@ -74,12 +74,12 @@ public:
static GLuint createBaseTileGLTexture(int width, int height);
static void createTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, GLint filter = GL_LINEAR);
- static void updateTextureWithBitmap(GLuint texture, int x, int y, const SkBitmap& bitmap, GLint filter = GL_LINEAR);
+ static void updateTextureWithBitmap(GLuint texture, const SkBitmap& bitmap, const IntRect&, GLint filter = GL_LINEAR);
static void createEGLImageFromTexture(GLuint texture, EGLImageKHR* image);
static void createTextureFromEGLImage(GLuint texture, EGLImageKHR image, GLint filter = GL_LINEAR);
static void paintTextureWithBitmap(const TileRenderInfo* renderInfo, const SkBitmap& bitmap);
- static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , int x, int y, const SkBitmap& bitmap);
+ static void updateSharedSurfaceTextureWithBitmap(const TileRenderInfo* , const SkBitmap& bitmap);
static void convertToTransformationMatrix(const float* matrix, TransformationMatrix& transformMatrix);
static bool isPureColorBitmap(const SkBitmap& bitmap, Color& pureColor);
diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
index c34aed8..4c049cd 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
@@ -25,6 +25,7 @@
#include "GraphicsLayerClient.h"
#include "LayerAndroid.h"
#include "RefPtr.h"
+#include "ScrollableLayerAndroid.h"
#include "SkBitmapRef.h"
#include "Vector.h"
@@ -122,6 +123,7 @@ public:
void notifyClientAnimationStarted();
LayerAndroid* contentLayer() { return m_contentLayer; }
+ ScrollableLayerAndroid* foregroundLayer() { return m_foregroundLayer; }
static int instancesCount();
diff --git a/Source/WebCore/platform/graphics/android/Layer.cpp b/Source/WebCore/platform/graphics/android/Layer.cpp
index 9280461..f58d648 100644
--- a/Source/WebCore/platform/graphics/android/Layer.cpp
+++ b/Source/WebCore/platform/graphics/android/Layer.cpp
@@ -158,13 +158,13 @@ void Layer::localToAncestor(const Layer* ancestor, SkMatrix* matrix) const {
///////////////////////////////////////////////////////////////////////////////
-void Layer::onDraw(SkCanvas*, SkScalar opacity) {
+void Layer::onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra) {
// SkDebugf("----- no onDraw for %p\n", this);
}
#include "SkString.h"
-void Layer::draw(SkCanvas* canvas, SkScalar opacity) {
+void Layer::draw(SkCanvas* canvas, android::DrawExtra* extra, SkScalar opacity) {
#if 0
SkString str1, str2;
// getMatrix().toDumpString(&str1);
@@ -193,7 +193,7 @@ void Layer::draw(SkCanvas* canvas, SkScalar opacity) {
canvas->concat(tmp);
}
- onDraw(canvas, opacity);
+ onDraw(canvas, opacity, extra);
#ifdef DEBUG_DRAW_LAYER_BOUNDS
{
@@ -213,7 +213,7 @@ void Layer::draw(SkCanvas* canvas, SkScalar opacity) {
if (count > 0) {
canvas->concat(getChildrenMatrix());
for (int i = 0; i < count; i++) {
- getChild(i)->draw(canvas, opacity);
+ getChild(i)->draw(canvas, extra, opacity);
}
}
}
diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h
index 5200a3d..876ca24 100644
--- a/Source/WebCore/platform/graphics/android/Layer.h
+++ b/Source/WebCore/platform/graphics/android/Layer.h
@@ -17,6 +17,7 @@
#ifndef Layer_DEFINED
#define Layer_DEFINED
+#include "DrawExtra.h"
#include "TestExport.h"
#include "SkRefCnt.h"
#include "SkTDArray.h"
@@ -165,17 +166,14 @@ public:
// paint method
virtual bool drawCanvas(SkCanvas*) { return false; }
- void draw(SkCanvas*, SkScalar opacity);
- void draw(SkCanvas* canvas) {
- this->draw(canvas, SK_Scalar1);
- }
+ void draw(SkCanvas*, android::DrawExtra* extra, SkScalar opacity = SK_Scalar1);
void setHasOverflowChildren(bool value) { m_hasOverflowChildren = value; }
virtual bool contentIsScrollable() const { return false; }
protected:
- virtual void onDraw(SkCanvas*, SkScalar opacity);
+ virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra);
bool m_hasOverflowChildren;
diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
index 88e419d..79c02eb 100644
--- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -1022,7 +1022,7 @@ bool LayerAndroid::drawCanvas(SkCanvas* canvas)
layerRect.fTop = 0;
layerRect.fRight = getWidth();
layerRect.fBottom = getHeight();
- onDraw(canvas, m_drawOpacity);
+ onDraw(canvas, m_drawOpacity, 0);
}
// When the layer is dirty, the UI thread should be notified to redraw.
@@ -1133,7 +1133,7 @@ void LayerAndroid::contentDraw(SkCanvas* canvas)
}
}
-void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity)
+void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity, android::DrawExtra* extra)
{
if (m_haveClip) {
SkRect r;
@@ -1163,6 +1163,8 @@ void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity)
ImagesManager::instance()->releaseImage(m_imageCRC);
}
contentDraw(canvas);
+ if (extra)
+ extra->draw(canvas, this);
}
SkPicture* LayerAndroid::recordContext()
diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h
index 578c2ff..d33eea1 100644
--- a/Source/WebCore/platform/graphics/android/LayerAndroid.h
+++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h
@@ -199,6 +199,7 @@ public:
setShouldInheritFromRootTransform(true);
}
+ const IntPoint& scrollOffset() const { return m_offset; }
void setScrollOffset(IntPoint offset) { m_offset = offset; }
void setBackgroundColor(SkColor color);
void setMaskLayer(LayerAndroid*);
@@ -315,7 +316,7 @@ public:
bool isReady();
protected:
- virtual void onDraw(SkCanvas*, SkScalar opacity);
+ virtual void onDraw(SkCanvas*, SkScalar opacity, android::DrawExtra* extra);
IntPoint m_offset;
TransformationMatrix m_drawTransform;
diff --git a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp
index 0c92de4..4b6d2de 100644
--- a/Source/WebCore/platform/graphics/android/RasterRenderer.cpp
+++ b/Source/WebCore/platform/graphics/android/RasterRenderer.cpp
@@ -112,8 +112,14 @@ void RasterRenderer::setupCanvas(const TileRenderInfo& renderInfo, SkCanvas* can
device->unref();
- // ensure the canvas origin is translated to the coordinates of our inval rect
- canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop);
+ // If we have a partially painted bitmap
+ if (renderInfo.invalRect) {
+ SkRect clipRect = SkRect::MakeWH(renderInfo.invalRect->width(),
+ renderInfo.invalRect->height());
+ // ensure the canvas origin is translated to the coordinates of our inval rect
+ canvas->clipRect(clipRect);
+ canvas->translate(-renderInfo.invalRect->fLeft, -renderInfo.invalRect->fTop);
+ }
}
void RasterRenderer::renderingComplete(const TileRenderInfo& renderInfo, SkCanvas* canvas)
diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp
index 56d79a1..e97e1a1 100644
--- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp
+++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp
@@ -162,20 +162,46 @@ bool TransferQueue::checkObsolete(const TileTransferData* data)
}
void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex,
+ BaseTileTexture* frontTex,
GLuint srcTexId, GLenum srcTexTarget,
int index)
{
#if GPU_UPLOAD_WITHOUT_DRAW
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
+ glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId);
+
+ int textureWidth = destTex->getSize().width();
+ int textureHeight = destTex->getSize().height();
+
+ IntRect inval = m_transferQueue[index].tileInfo.m_inval;
+ bool partialInval = !inval.isEmpty();
+
+ if (partialInval && frontTex) {
+ // recopy the previous texture to the new one, as
+ // the partial update will not cover the entire texture
+ glFramebufferTexture2D(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ frontTex->m_ownTextureId,
+ 0);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+ textureWidth, textureHeight);
+ }
+
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
srcTexId,
0);
- glBindTexture(GL_TEXTURE_2D, destTex->m_ownTextureId);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
- destTex->getSize().width(),
- destTex->getSize().height());
+
+ if (!partialInval) {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
+ textureWidth, textureHeight);
+ } else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, inval.x(), inval.y(), 0, 0,
+ inval.width(), inval.height());
+ }
+
#else
// Then set up the FBO and copy the SurfTex content in.
glBindFramebuffer(GL_FRAMEBUFFER, fboID);
@@ -356,8 +382,14 @@ void TransferQueue::updateDirtyBaseTiles()
// Save the needed info, update the Surf Tex, clean up the item in
// the queue. Then either move on to next item or copy the content.
BaseTileTexture* destTexture = 0;
- if (!obsoleteBaseTile)
+ BaseTileTexture* frontTexture = 0;
+ if (!obsoleteBaseTile) {
destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture();
+ // while destTexture is guaranteed to not be null, frontTexture
+ // might be (first transfer)
+ frontTexture = m_transferQueue[index].savedBaseTilePtr->frontTexture();
+ }
+
if (m_transferQueue[index].uploadType == GpuUpload) {
status_t result = m_sharedSurfaceTexture->updateTexImage();
if (result != OK)
@@ -376,14 +408,15 @@ void TransferQueue::updateDirtyBaseTiles()
if (m_transferQueue[index].uploadType == CpuUpload) {
// Here we just need to upload the bitmap content to the GL Texture
- GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, 0, 0,
- *m_transferQueue[index].bitmap);
+ GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId,
+ *m_transferQueue[index].bitmap,
+ m_transferQueue[index].tileInfo.m_inval);
} else {
if (!usedFboForUpload) {
saveGLState();
usedFboForUpload = true;
}
- blitTileFromQueue(m_fboID, destTexture,
+ blitTileFromQueue(m_fboID, destTexture, frontTexture,
m_sharedSurfaceTextureId,
m_sharedSurfaceTexture->getCurrentTextureTarget(),
index);
@@ -420,9 +453,9 @@ void TransferQueue::updateDirtyBaseTiles()
}
void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo,
- int x, int y, const SkBitmap& bitmap)
+ const SkBitmap& bitmap)
{
- if (!tryUpdateQueueWithBitmap(renderInfo, x, y, bitmap)) {
+ if (!tryUpdateQueueWithBitmap(renderInfo, bitmap)) {
// failed placing bitmap in queue, discard tile's texture so it will be
// re-enqueued (and repainted)
BaseTile* tile = renderInfo->baseTile;
@@ -432,7 +465,7 @@ void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo,
}
bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
- int x, int y, const SkBitmap& bitmap)
+ const SkBitmap& bitmap)
{
// This lock need to cover the full update since it is possible that queue
// will be cleaned up in the middle of this update without the lock.
@@ -462,9 +495,10 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
int bpp = 4; // Now we only deal with RGBA8888 format.
int width = TilesManager::instance()->tileWidth();
int height = TilesManager::instance()->tileHeight();
- if (!x && !y && bitmap.width() == width && bitmap.height() == height) {
+ if (bitmap.width() == width && bitmap.height() == height) {
bitmap.lockPixels();
uint8_t* bitmapOrigin = static_cast<uint8_t*>(bitmap.getPixels());
+
if (buffer.stride != bitmap.width())
// Copied line by line since we need to handle the offsets and stride.
for (row = 0 ; row < bitmap.height(); row ++) {
@@ -476,9 +510,6 @@ bool TransferQueue::tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
memcpy(img, bitmapOrigin, bpp * bitmap.width() * bitmap.height());
bitmap.unlockPixels();
- } else {
- // TODO: implement the partial invalidate here!
- XLOG("ERROR: don't expect to get here yet before we support partial inval");
}
ANativeWindow_unlockAndPost(m_ANW.get());
@@ -517,6 +548,15 @@ void TransferQueue::addItemCommon(const TileRenderInfo* renderInfo,
// Now fill the tileInfo.
TextureTileInfo* textureInfo = &(data->tileInfo);
+ IntRect inval(0, 0, 0, 0);
+ if (renderInfo->invalRect) {
+ inval.setX(renderInfo->invalRect->fLeft);
+ inval.setY(renderInfo->invalRect->fTop);
+ inval.setWidth(renderInfo->invalRect->width());
+ inval.setHeight(renderInfo->invalRect->height());
+ }
+ textureInfo->m_inval = inval;
+
textureInfo->m_x = renderInfo->x;
textureInfo->m_y = renderInfo->y;
textureInfo->m_scale = renderInfo->scale;
diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.h b/Source/WebCore/platform/graphics/android/TransferQueue.h
index a18d448..ec3e5e2 100644
--- a/Source/WebCore/platform/graphics/android/TransferQueue.h
+++ b/Source/WebCore/platform/graphics/android/TransferQueue.h
@@ -119,7 +119,7 @@ public:
void initGLResources(int width, int height);
// insert the bitmap into the queue, mark the tile dirty if failing
- void updateQueueWithBitmap(const TileRenderInfo* renderInfo, int x, int y,
+ void updateQueueWithBitmap(const TileRenderInfo* renderInfo,
const SkBitmap& bitmap);
void addItemInTransferQueue(const TileRenderInfo* info,
@@ -151,7 +151,7 @@ public:
private:
// return true if successfully inserted into queue
- bool tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo, int x, int y,
+ bool tryUpdateQueueWithBitmap(const TileRenderInfo* renderInfo,
const SkBitmap& bitmap);
bool getHasGLContext();
void setHasGLContext(bool hasContext);
@@ -172,6 +172,7 @@ private:
void cleanupPendingDiscard();
void blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex,
+ BaseTileTexture* frontTex,
GLuint srcTexId, GLenum srcTexTarget,
int index);
diff --git a/Source/WebCore/platform/graphics/android/android_graphics.cpp b/Source/WebCore/platform/graphics/android/android_graphics.cpp
index 6b8725e..d76d581 100644
--- a/Source/WebCore/platform/graphics/android/android_graphics.cpp
+++ b/Source/WebCore/platform/graphics/android/android_graphics.cpp
@@ -57,7 +57,7 @@ CursorRing::CursorRing(WebViewCore* core)
// The CSS values for the inner and outer widths may be specified as fractions
#define WIDTH_SCALE 0.0625f // 1/16, to offset the scale in CSSStyleSelector
-void CursorRing::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval)
+void CursorRing::drawLegacy(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval)
{
if (!m_lastBounds.isEmpty()) {
*inval = m_lastBounds;
diff --git a/Source/WebCore/platform/graphics/android/android_graphics.h b/Source/WebCore/platform/graphics/android/android_graphics.h
index bd08a6e..68207d7 100644
--- a/Source/WebCore/platform/graphics/android/android_graphics.h
+++ b/Source/WebCore/platform/graphics/android/android_graphics.h
@@ -54,7 +54,7 @@ class CursorRing : public DrawExtra {
public:
CursorRing(WebViewCore* core);
virtual ~CursorRing() {}
- virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
+ virtual void drawLegacy(SkCanvas* , LayerAndroid* , IntRect* );
void setIsButton(const CachedNode* );
bool setup();
WTF::Vector<IntRect>& rings() { return m_rings; }
diff --git a/Source/WebKit/Android.mk b/Source/WebKit/Android.mk
index 4e834fd..ee7f3ce 100644
--- a/Source/WebKit/Android.mk
+++ b/Source/WebKit/Android.mk
@@ -88,6 +88,7 @@ LOCAL_SRC_FILES += \
android/nav/CachedLayer.cpp \
android/nav/CachedNode.cpp \
android/nav/CachedRoot.cpp \
+ android/nav/DrawExtra.cpp \
android/nav/FindCanvas.cpp \
android/nav/SelectText.cpp \
android/nav/WebView.cpp \
diff --git a/Source/WebKit/android/jni/AndroidHitTestResult.cpp b/Source/WebKit/android/jni/AndroidHitTestResult.cpp
index 64408da..fd2fc25 100644
--- a/Source/WebKit/android/jni/AndroidHitTestResult.cpp
+++ b/Source/WebKit/android/jni/AndroidHitTestResult.cpp
@@ -31,9 +31,14 @@
#include "Element.h"
#include "HitTestResult.h"
#include "KURL.h"
+#include "LayerAndroid.h"
#include "PlatformString.h"
+#include "Range.h"
+#include "RenderLayer.h"
+#include "RenderLayerBacking.h"
#include "RenderObject.h"
#include "WebCoreJni.h"
+#include "WebViewCore.h"
#include <cutils/log.h>
#include <JNIHelp.h>
@@ -45,8 +50,6 @@ using namespace WebCore;
static bool gJniInitialized = false;
static struct JavaGlue {
- jmethodID m_rectInit;
-
jmethodID m_hitTestInit;
jfieldID m_hitTestLinkUrl;
jfieldID m_hitTestAnchorText;
@@ -75,9 +78,6 @@ static void InitJni(JNIEnv* env)
jclass hitTestClass = env->FindClass("android/webkit/WebViewCore$WebKitHitTest");
ALOG_ASSERT(hitTestClass, "Could not find android/webkit/WebViewCore$WebKitHitTest");
- gJavaGlue.m_rectInit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
- ALOG_ASSERT(gJavaGlue.m_rectInit, "Could not find init method on Rect");
-
gJavaGlue.m_hitTestInit = env->GetMethodID(hitTestClass, "<init>", "()V");
ALOG_ASSERT(gJavaGlue.m_hitTestInit, "Could not find init method on android/webkit/WebViewCore$WebKitHitTest");
@@ -115,6 +115,13 @@ void setStringField(JNIEnv* env, jobject obj, jfieldID field, const String& str)
env->DeleteLocalRef(jstr);
}
+void setRectArray(JNIEnv* env, jobject obj, jfieldID field, Vector<IntRect> &rects)
+{
+ jobjectArray array = intRectVectorToRectArray(env, rects);
+ env->SetObjectField(obj, field, array);
+ env->DeleteLocalRef(array);
+}
+
// Some helper macros specific to setting hitTest fields
#define _SET(jtype, jfield, value) env->Set ## jtype ## Field(hitTest, gJavaGlue.m_hitTest ## jfield, value)
#define SET_BOOL(jfield, value) _SET(Boolean, jfield, value)
@@ -124,31 +131,17 @@ void setStringField(JNIEnv* env, jobject obj, jfieldID field, const String& str)
jobject AndroidHitTestResult::createJavaObject(JNIEnv* env)
{
InitJni(env);
- jclass rectClass = env->FindClass("android/graphics/Rect");
- ALOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
jclass hitTestClass = env->FindClass("android/webkit/WebViewCore$WebKitHitTest");
ALOG_ASSERT(hitTestClass, "Could not find android/webkit/WebViewCore$WebKitHitTest");
- jobjectArray array = env->NewObjectArray(m_highlightRects.size(), rectClass, 0);
- ALOG_ASSERT(array, "Could not create a Rect array");
-
- for (size_t i = 0; i < m_highlightRects.size(); i++) {
- jobject rect = env->NewObject(rectClass, gJavaGlue.m_rectInit,
- m_highlightRects[i].x(), m_highlightRects[i].y(),
- m_highlightRects[i].maxX(), m_highlightRects[i].maxY());
- if (rect) {
- env->SetObjectArrayElement(array, i, rect);
- env->DeleteLocalRef(rect);
- }
- }
-
- TextDirection titleTextDirection;
jobject hitTest = env->NewObject(hitTestClass, gJavaGlue.m_hitTestInit);
- env->SetObjectField(hitTest, gJavaGlue.m_hitTestTouchRects, array);
+ setRectArray(env, hitTest, gJavaGlue.m_hitTestTouchRects, m_highlightRects);
+
SET_BOOL(Editable, m_hitTestResult.isContentEditable());
SET_STRING(LinkUrl, m_hitTestResult.absoluteLinkURL().string());
SET_STRING(ImageUrl, m_hitTestResult.absoluteImageURL().string());
SET_STRING(AltDisplayString, m_hitTestResult.altDisplayString());
+ TextDirection titleTextDirection;
SET_STRING(Title, m_hitTestResult.title(titleTextDirection));
if (m_hitTestResult.URLElement()) {
Element* urlElement = m_hitTestResult.URLElement();
@@ -159,6 +152,8 @@ jobject AndroidHitTestResult::createJavaObject(JNIEnv* env)
}
}
+ env->DeleteLocalRef(hitTestClass);
+
return hitTest;
}
diff --git a/Source/WebKit/android/jni/WebCoreJni.cpp b/Source/WebKit/android/jni/WebCoreJni.cpp
index 10b3e95..65b6d20 100644
--- a/Source/WebKit/android/jni/WebCoreJni.cpp
+++ b/Source/WebKit/android/jni/WebCoreJni.cpp
@@ -26,7 +26,9 @@
#define LOG_TAG "webcoreglue"
#include "config.h"
+#include "IntRect.h"
#include "WebCoreJni.h"
+#include "wtf/Vector.h"
#include "NotImplemented.h"
#include <JNIUtility.h>
@@ -114,4 +116,25 @@ jstring stdStringToJstring(JNIEnv* env, const std::string& str, bool validOnZero
#endif
+jobjectArray intRectVectorToRectArray(JNIEnv* env, Vector<WebCore::IntRect>& rects)
+{
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ ALOG_ASSERT(rectClass, "Could not find android/graphics/Rect");
+ jmethodID rectInit = env->GetMethodID(rectClass, "<init>", "(IIII)V");
+ ALOG_ASSERT(rectInit, "Could not find init method on Rect");
+ jobjectArray array = env->NewObjectArray(rects.size(), rectClass, 0);
+ ALOG_ASSERT(array, "Could not create a Rect array");
+ for (size_t i = 0; i < rects.size(); i++) {
+ jobject rect = env->NewObject(rectClass, rectInit,
+ rects[i].x(), rects[i].y(),
+ rects[i].maxX(), rects[i].maxY());
+ if (rect) {
+ env->SetObjectArrayElement(array, i, rect);
+ env->DeleteLocalRef(rect);
+ }
+ }
+ env->DeleteLocalRef(rectClass);
+ return array;
+}
+
}
diff --git a/Source/WebKit/android/jni/WebCoreJni.h b/Source/WebKit/android/jni/WebCoreJni.h
index 0f77cc6..7a46f7b 100644
--- a/Source/WebKit/android/jni/WebCoreJni.h
+++ b/Source/WebKit/android/jni/WebCoreJni.h
@@ -27,6 +27,7 @@
#define WebCoreJni_h
#include "ChromiumIncludes.h"
+#include "IntRect.h"
#include "PlatformString.h"
#include <jni.h>
@@ -91,6 +92,8 @@ std::string jstringToStdString(JNIEnv*, jstring);
jstring stdStringToJstring(JNIEnv*, const std::string&, bool validOnZeroLength = false);
#endif
+jobjectArray intRectVectorToRectArray(JNIEnv*, Vector<WebCore::IntRect>&);
+
}
#endif
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 027ab1e..ee6e338 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -105,6 +105,7 @@
#include "RuntimeEnabledFeatures.h"
#include "SchemeRegistry.h"
#include "SelectionController.h"
+#include "SelectText.h"
#include "Settings.h"
#include "SkANP.h"
#include "SkTemplates.h"
@@ -124,6 +125,7 @@
#include "autofill/WebAutofill.h"
#include "htmlediting.h"
#include "markup.h"
+#include "visible_units.h"
#include <JNIHelp.h>
#include <JNIUtility.h>
@@ -410,7 +412,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
m_javaGlue->m_sendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
m_javaGlue->m_sendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "(IIII)V");
m_javaGlue->m_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
- m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIII)V");
+ m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIIII)V");
m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
m_javaGlue->m_restoreScale = GetJMethod(env, clazz, "restoreScale", "(FF)V");
m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V");
@@ -1658,6 +1660,237 @@ static IntRect getAbsoluteBoundingBox(Node* node) {
return rect;
}
+WebCore::Frame* WebViewCore::focusedFrame() const
+{
+ return m_mainFrame->page()->focusController()->focusedOrMainFrame();
+}
+
+VisiblePosition WebViewCore::visiblePositionForContentPoint(int x, int y)
+{
+ return visiblePositionForContentPoint(IntPoint(x, y));
+}
+
+VisiblePosition WebViewCore::visiblePositionForContentPoint(const IntPoint& point)
+{
+ // Hit test of this kind required for this to work inside input fields
+ HitTestRequest request(HitTestRequest::Active
+ | HitTestRequest::MouseMove
+ | HitTestRequest::ReadOnly);
+ HitTestResult result(point);
+ focusedFrame()->document()->renderView()->layer()->hitTest(request, result);
+
+ // Matching the logic in MouseEventWithHitTestResults::targetNode()
+ Node* node = result.innerNode();
+ if (!node)
+ return VisiblePosition();
+ Element* element = node->parentElement();
+ if (!node->inDocument() && element && element->inDocument())
+ node = element;
+
+ return node->renderer()->positionForPoint(result.localPoint());
+}
+
+void WebViewCore::selectWordAt(int x, int y)
+{
+ HitTestResult hoverResult;
+ moveMouse(m_mainFrame, x, y, &hoverResult);
+ if (hoverResult.innerNode()) {
+ Node* node = hoverResult.innerNode();
+ Frame* frame = node->document()->frame();
+ Page* page = m_mainFrame->document()->page();
+ page->focusController()->setFocusedFrame(frame);
+ }
+
+ IntPoint point = convertGlobalContentToFrameContent(IntPoint(x, y));
+
+ // Hit test of this kind required for this to work inside input fields
+ HitTestRequest request(HitTestRequest::Active);
+ HitTestResult result(point);
+
+ focusedFrame()->document()->renderView()->layer()->hitTest(request, result);
+
+ // Matching the logic in MouseEventWithHitTestResults::targetNode()
+ Node* node = result.innerNode();
+ if (!node)
+ return;
+ Element* element = node->parentElement();
+ if (!node->inDocument() && element && element->inDocument())
+ node = element;
+
+ SelectionController* sc = focusedFrame()->selection();
+ if (!sc->contains(point) && (node->isContentEditable() || node->isTextNode()) && !result.isLiveLink()
+ && node->dispatchEvent(Event::create(eventNames().selectstartEvent, true, true))) {
+ VisiblePosition pos(node->renderer()->positionForPoint(result.localPoint()));
+ selectWordAroundPosition(node->document()->frame(), pos);
+ }
+}
+
+void WebViewCore::selectWordAroundPosition(Frame* frame, VisiblePosition pos)
+{
+ VisibleSelection selection(pos);
+ selection.expandUsingGranularity(WordGranularity);
+
+ if (frame->selection()->shouldChangeSelection(selection)) {
+ bool allWhitespaces = true;
+ RefPtr<Range> firstRange = selection.firstRange();
+ String text = firstRange.get() ? firstRange->text() : "";
+ for (size_t i = 0; i < text.length(); ++i) {
+ if (!isSpaceOrNewline(text[i])) {
+ allWhitespaces = false;
+ break;
+ }
+ }
+
+ if (allWhitespaces) {
+ VisibleSelection emptySelection(selection.visibleStart(), selection.visibleStart());
+ frame->selection()->setSelection(emptySelection);
+ }
+ frame->selection()->setSelection(selection);
+ }
+}
+
+int WebViewCore::platformLayerIdFromNode(Node* node, LayerAndroid** outLayer)
+{
+ if (!node || !node->renderer())
+ return -1;
+ RenderLayer* renderLayer = node->renderer()->enclosingLayer();
+ if (!renderLayer || !renderLayer->isComposited())
+ return -1;
+ GraphicsLayer* graphicsLayer = renderLayer->backing()->graphicsLayer();
+ if (!graphicsLayer)
+ return -1;
+ GraphicsLayerAndroid* agl = static_cast<GraphicsLayerAndroid*>(graphicsLayer);
+ LayerAndroid* layer = agl->foregroundLayer();
+ if (!layer)
+ layer = agl->contentLayer();
+ if (!layer)
+ return -1;
+ if (outLayer)
+ *outLayer = layer;
+ return layer->uniqueId();
+}
+
+void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset)
+{
+ while (layer) {
+ const SkPoint& pos = layer->getPosition();
+ offset.move(pos.fX, pos.fY);
+ const IntPoint& scroll = layer->scrollOffset();
+ offset.move(-scroll.x(), -scroll.y());
+ layer = static_cast<LayerAndroid*>(layer->getParent());
+ }
+}
+
+void setCaretInfo(const VisiblePosition& pos, SelectText::HandleId handle,
+ SelectText* target)
+{
+ IntPoint offset;
+ LayerAndroid* layer = 0;
+ IntRect rect = pos.absoluteCaretBounds();
+ int layerId = WebViewCore::platformLayerIdFromNode(pos.deepEquivalent().anchorNode(), &layer);
+ WebViewCore::layerToAbsoluteOffset(layer, offset);
+ rect.move(-offset.x(), -offset.y());
+ target->setCaretRect(handle, rect);
+ target->setCaretLayerId(handle, layerId);
+}
+
+SelectText* WebViewCore::createSelectText(const VisibleSelection& selection)
+{
+ // We need to agressively check to see if this is an empty selection to prevent
+ // accidentally entering text selection mode
+ if (!selection.isRange() || !comparePositions(selection.start(), selection.end()))
+ return 0;
+
+ RefPtr<Range> range = selection.firstRange();
+ Node* startContainer = range->startContainer();
+ Node* endContainer = range->endContainer();
+
+ if (!startContainer || !endContainer)
+ return 0;
+ if (startContainer == endContainer && range->startOffset() == range->endOffset())
+ return 0;
+
+ SelectText* selectTextContainer = new SelectText();
+ IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint());
+
+ Node* stopNode = range->pastLastNode();
+ for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) {
+ RenderObject* r = node->renderer();
+ if (!r || !r->isText() || r->style()->visibility() != VISIBLE)
+ continue;
+ RenderText* renderText = toRenderText(r);
+ int startOffset = node == startContainer ? range->startOffset() : 0;
+ int endOffset = node == endContainer ? range->endOffset() : numeric_limits<int>::max();
+ LayerAndroid* layer = 0;
+ platformLayerIdFromNode(node, &layer);
+ Vector<IntRect> rects;
+ renderText->absoluteRectsForRange(rects, startOffset, endOffset, true);
+ selectTextContainer->addHighlightRegion(layer, rects, frameOffset);
+ }
+
+ IntRect caretRect;
+ int layerId;
+ selectTextContainer->setBaseFirst(selection.isBaseFirst());
+ setCaretInfo(selection.visibleStart(), SelectText::StartHandle, selectTextContainer);
+ setCaretInfo(selection.visibleEnd(), SelectText::EndHandle, selectTextContainer);
+ selectTextContainer->caretRect(SelectText::StartHandle)
+ .move(-frameOffset.x(), -frameOffset.y());
+ selectTextContainer->caretRect(SelectText::EndHandle)
+ .move(-frameOffset.x(), -frameOffset.y());
+
+ selectTextContainer->setText(range->text());
+
+ return selectTextContainer;
+}
+
+IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point)
+{
+ IntPoint frameOffset(-m_scrollOffsetX, -m_scrollOffsetY);
+ frameOffset = focusedFrame()->view()->windowToContents(frameOffset);
+ return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y());
+}
+
+void WebViewCore::selectText(int startX, int startY, int endX, int endY)
+{
+ SelectionController* sc = focusedFrame()->selection();
+ IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY));
+ VisiblePosition startPosition(visiblePositionForContentPoint(startPoint));
+ IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY));
+ VisiblePosition endPosition(visiblePositionForContentPoint(endPoint));
+
+ if (startPosition.isNull() || endPosition.isNull() || startPosition == endPosition)
+ return;
+
+ // Ensure startPosition is before endPosition
+ if (comparePositions(startPosition, endPosition) > 0)
+ swap(startPosition, endPosition);
+
+ if (sc->isContentEditable()) {
+ startPosition = sc->selection().visibleStart().honorEditableBoundaryAtOrAfter(startPosition);
+ endPosition = sc->selection().visibleEnd().honorEditableBoundaryAtOrBefore(endPosition);
+ if (startPosition.isNull() || endPosition.isNull()) {
+ return;
+ }
+ }
+
+ // Ensure startPosition is not at end of block
+ if (startPosition != endPosition && isEndOfBlock(startPosition)) {
+ VisiblePosition nextStartPosition(startPosition.next());
+ if (!nextStartPosition.isNull())
+ startPosition = nextStartPosition;
+ }
+ // Ensure endPosition is not at start of block
+ if (startPosition != endPosition && isStartOfBlock(endPosition)) {
+ VisiblePosition prevEndPosition(endPosition.previous());
+ if (!prevEndPosition.isNull())
+ endPosition = prevEndPosition;
+ }
+
+ VisibleSelection selection(startPosition, endPosition);
+ if (selection.isRange() && sc->shouldChangeSelection(selection))
+ sc->setSelection(selection);
+}
+
// get the highlight rectangles for the touch point (x, y) with the slop
AndroidHitTestResult WebViewCore::hitTestAtPoint(int x, int y, int slop, bool doMoveMouse)
{
@@ -2124,7 +2357,7 @@ void WebViewCore::moveFocus(WebCore::Frame* frame, WebCore::Node* node)
}
// Update mouse position
-void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
+void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode)
{
DBG_NAV_LOGD("frame=%p x=%d y=%d scrollOffset=(%d,%d)", frame,
x, y, m_scrollOffsetX, m_scrollOffsetY);
@@ -2137,7 +2370,7 @@ void WebViewCore::moveMouse(WebCore::Frame* frame, int x, int y)
WebCore::PlatformMouseEvent mouseEvent(m_mousePos, m_mousePos,
WebCore::NoButton, WebCore::MouseEventMoved, 1, false, false, false,
false, WTF::currentTime());
- frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
+ frame->eventHandler()->handleMouseMoveEvent(mouseEvent, hoveredNode);
#if ENABLE(ANDROID_NAVCACHE)
updateCacheOnNodeChange();
#endif
@@ -3693,14 +3926,14 @@ void WebViewCore::updateTextSelection()
if (!javaObject.get())
return;
WebCore::Node* focusNode = currentFocus();
- if (!focusNode)
- return;
int start = 0;
int end = 0;
- getSelectionOffsets(focusNode, start, end);
+ if (focusNode)
+ getSelectionOffsets(focusNode, start, end);
+ SelectText* selectText = createSelectText(focusedFrame()->selection()->selection());
env->CallVoidMethod(javaObject.get(),
m_javaGlue->m_updateTextSelection, reinterpret_cast<int>(focusNode),
- start, end, m_textGeneration);
+ start, end, m_textGeneration, selectText);
checkException(env);
}
@@ -4044,10 +4277,8 @@ Vector<VisibleSelection> WebViewCore::getTextRanges(
// the selected text.
startY--;
endY--;
- VisiblePosition startSelect = visiblePositionForWindowPoint(
- startX - m_scrollOffsetX, startY - m_scrollOffsetY);
- VisiblePosition endSelect = visiblePositionForWindowPoint(
- endX - m_scrollOffsetX, endY - m_scrollOffsetY);
+ VisiblePosition startSelect = visiblePositionForContentPoint(startX, startY);
+ VisiblePosition endSelect = visiblePositionForContentPoint(endX, endY);
Position start = startSelect.deepEquivalent();
Position end = endSelect.deepEquivalent();
Vector<VisibleSelection> ranges;
@@ -4129,43 +4360,6 @@ String WebViewCore::getText(int startX, int startY, int endX, int endY)
return text;
}
-VisiblePosition WebViewCore::visiblePositionForWindowPoint(int x, int y)
-{
- HitTestRequest::HitTestRequestType hitType = HitTestRequest::MouseMove;
- hitType |= HitTestRequest::ReadOnly;
- hitType |= HitTestRequest::Active;
- HitTestRequest request(hitType);
- FrameView* view = m_mainFrame->view();
- IntPoint point(view->windowToContents(
- view->convertFromContainingWindow(IntPoint(x, y))));
-
- // Look for the inner-most frame containing the hit. Its document
- // contains the document with the selected text.
- Frame* frame = m_mainFrame;
- Frame* hitFrame = m_mainFrame;
- Node* node = 0;
- IntPoint localPoint = point;
- do {
- HitTestResult result(localPoint);
- frame = hitFrame;
- frame->document()->renderView()->layer()->hitTest(request, result);
- node = result.innerNode();
- if (!node)
- return VisiblePosition();
-
- if (node->isFrameOwnerElement())
- hitFrame = static_cast<HTMLFrameOwnerElement*>(node)->contentFrame();
- localPoint = result.localPoint();
- } while (hitFrame && hitFrame != frame);
-
- Element* element = node->parentElement();
- if (!node->inDocument() && element && element->inDocument())
- node = element;
-
- RenderObject* renderer = node->renderer();
- return renderer->positionForPoint(localPoint);
-}
-
//----------------------------------------------------------------------
// Native JNI methods
//----------------------------------------------------------------------
@@ -4819,6 +5013,31 @@ static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass,
return text.isEmpty() ? 0 : wtfStringToJstring(env, text);
}
+static void SelectText(JNIEnv* env, jobject obj, jint nativeClass,
+ jint startX, jint startY, jint endX, jint endY)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->selectText(startX, startY, endX, endY);
+}
+
+static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->focusedFrame()->selection()->clear();
+}
+
+static void SelectWordAt(JNIEnv* env, jobject obj, jint nativeClass, jint x, jint y)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->selectWordAt(x, y);
+}
+
+static void SelectAll(JNIEnv* env, jobject obj, jint nativeClass)
+{
+ WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass);
+ viewImpl->focusedFrame()->selection()->selectAll();
+}
+
// ----------------------------------------------------------------------------
/*
@@ -4941,6 +5160,14 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) InsertText },
{ "nativeGetText", "(IIIII)Ljava/lang/String;",
(void*) GetText },
+ { "nativeSelectText", "(IIIII)V",
+ (void*) SelectText },
+ { "nativeClearTextSelection", "(I)V",
+ (void*) ClearSelection },
+ { "nativeSelectWordAt", "(III)V",
+ (void*) SelectWordAt },
+ { "nativeSelectAll", "(I)V",
+ (void*) SelectAll },
};
int registerWebViewCore(JNIEnv* env)
diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h
index 07034b2..9fc55d1 100644
--- a/Source/WebKit/android/jni/WebViewCore.h
+++ b/Source/WebKit/android/jni/WebViewCore.h
@@ -104,6 +104,7 @@ namespace android {
class CachedRoot;
class ListBoxReply;
class AndroidHitTestResult;
+ class SelectText;
class WebCoreReply : public WebCoreRefObject {
public:
@@ -304,7 +305,7 @@ namespace android {
void recordPicture(SkPicture* picture);
void moveFocus(WebCore::Frame* frame, WebCore::Node* node);
- void moveMouse(WebCore::Frame* frame, int x, int y);
+ void moveMouse(WebCore::Frame* frame, int x, int y, HitTestResult* hoveredNode = 0);
void moveMouseIfLatest(int moveGeneration,
WebCore::Frame* frame, int x, int y);
@@ -546,6 +547,7 @@ namespace android {
float scale() const { return m_scale; }
float textWrapScale() const { return m_screenWidth * m_scale / m_textWrapWidth; }
WebCore::Frame* mainFrame() const { return m_mainFrame; }
+ WebCore::Frame* focusedFrame() const;
void updateCursorBounds(const CachedRoot* root,
const CachedFrame* cachedFrame, const CachedNode* cachedNode);
@@ -602,6 +604,14 @@ namespace android {
*/
Vector<WebCore::VisibleSelection> getTextRanges(
int startX, int startY, int endX, int endY);
+ static int platformLayerIdFromNode(Node* node, LayerAndroid** outLayer = 0);
+ void selectText(int startX, int startY, int endX, int endY);
+ void selectWordAt(int x, int y);
+
+ // Converts from the global content coordinates that WebView sends
+ // to frame-local content coordinates using the focused frame
+ IntPoint convertGlobalContentToFrameContent(const IntPoint& point);
+ static void layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& offset);
/**
* Returns a text position at a given coordinate.
@@ -701,6 +711,11 @@ namespace android {
*/
static WebCore::Position getPositionForOffset(Node* node, int offset);
+ VisiblePosition visiblePositionForContentPoint(int x, int y);
+ VisiblePosition visiblePositionForContentPoint(const IntPoint& point);
+ void selectWordAroundPosition(Frame* frame, VisiblePosition pos);
+ SelectText* createSelectText(const VisibleSelection&);
+
// called from constructor, to add this to a global list
static void addInstance(WebViewCore*);
// called from destructor, to remove this from a global list
diff --git a/Source/WebKit/android/nav/DrawExtra.cpp b/Source/WebKit/android/nav/DrawExtra.cpp
new file mode 100644
index 0000000..2f57dc1
--- /dev/null
+++ b/Source/WebKit/android/nav/DrawExtra.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "DrawExtra.h"
+#include "GLExtras.h"
+#include "LayerAndroid.h"
+#include "SkCanvas.h"
+#include "SkRegion.h"
+#include "WebViewCore.h"
+
+RegionLayerDrawExtra::RegionLayerDrawExtra()
+ : m_highlightColor(COLOR_HOLO_LIGHT)
+{}
+
+RegionLayerDrawExtra::~RegionLayerDrawExtra()
+{
+ HighlightRegionMap::iterator end = m_highlightRegions.end();
+ for (HighlightRegionMap::iterator it = m_highlightRegions.begin(); it != end; ++it) {
+ delete it->second;
+ it->second = 0;
+ }
+}
+
+SkRegion* RegionLayerDrawExtra::getHighlightRegionsForLayer(const LayerAndroid* layer)
+{
+ int layerId = layer ? layer->uniqueId() : 0;
+ return m_highlightRegions.get(layerId);
+}
+
+void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects,
+ const IntPoint& additionalOffset)
+{
+ if (rects.isEmpty())
+ return;
+ int layerId = layer ? layer->uniqueId() : 0;
+ SkRegion* region = m_highlightRegions.get(layerId);
+ if (!region) {
+ region = new SkRegion();
+ m_highlightRegions.set(layerId, region);
+ }
+ IntPoint offset = additionalOffset;
+ WebViewCore::layerToAbsoluteOffset(layer, offset);
+ for (size_t i = 0; i < rects.size(); i++) {
+ IntRect r = rects.at(i);
+ r.move(-offset.x(), -offset.y());
+ region->op(r.x(), r.y(), r.maxX(), r.maxY(), SkRegion::kUnion_Op);
+ }
+}
+
+void RegionLayerDrawExtra::draw(SkCanvas* canvas, LayerAndroid* layer)
+{
+ SkRegion* region = getHighlightRegionsForLayer(layer);
+ if (!region || region->isEmpty())
+ return;
+ SkRegion::Iterator rgnIter(*region);
+ SkPaint paint;
+ paint.setColor(m_highlightColor.rgb());
+ while (!rgnIter.done()) {
+ const SkIRect& rect = rgnIter.rect();
+ canvas->drawIRect(rect, paint);
+ rgnIter.next();
+ }
+}
+
+void RegionLayerDrawExtra::drawGL(GLExtras* glExtras, const LayerAndroid* layer)
+{
+ SkRegion* region = getHighlightRegionsForLayer(layer);
+ if (!region || region->isEmpty())
+ return;
+ const TransformationMatrix* transform = layer ? layer->drawTransform() : 0;
+ glExtras->drawRegion(*region, true, false, transform, m_highlightColor);
+}
diff --git a/Source/WebKit/android/nav/DrawExtra.h b/Source/WebKit/android/nav/DrawExtra.h
index 6716a65..83e7dcd 100644
--- a/Source/WebKit/android/nav/DrawExtra.h
+++ b/Source/WebKit/android/nav/DrawExtra.h
@@ -26,11 +26,25 @@
#ifndef DrawExtra_h
#define DrawExtra_h
+#include "config.h"
+
+#include "Color.h"
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "wtf/HashMap.h"
+#include "wtf/Vector.h"
+
+// Color of the ring copied from framework's holo_light
+#define COLOR_HOLO_LIGHT 0x6633B5E5
+// Color of the ring copied from framework's holo_dark
+#define COLOR_HOLO_DARK 0x660099CC
+
class SkCanvas;
+class SkRegion;
namespace WebCore {
- class IntRect;
class LayerAndroid;
+ class GLExtras;
}
using namespace WebCore;
@@ -40,7 +54,28 @@ namespace android {
class DrawExtra {
public:
virtual ~DrawExtra() {}
- virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ) = 0;
+ virtual void drawLegacy(SkCanvas* , LayerAndroid* , IntRect* ) {}
+ virtual void draw(SkCanvas*, LayerAndroid*) {}
+ virtual void drawGL(GLExtras*, const LayerAndroid*) {}
+};
+
+// A helper extra that has a SkRegion per LayerAndroid
+class RegionLayerDrawExtra : public DrawExtra {
+public:
+ RegionLayerDrawExtra();
+ virtual ~RegionLayerDrawExtra();
+
+ void addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects,
+ const IntPoint& additionalOffset = IntPoint());
+ virtual void draw(SkCanvas*, LayerAndroid*);
+ virtual void drawGL(GLExtras*, const LayerAndroid*);
+
+private:
+ SkRegion* getHighlightRegionsForLayer(const LayerAndroid* layer);
+
+ typedef HashMap<int, SkRegion* > HighlightRegionMap;
+ HighlightRegionMap m_highlightRegions;
+ Color m_highlightColor;
};
}
diff --git a/Source/WebKit/android/nav/FindCanvas.cpp b/Source/WebKit/android/nav/FindCanvas.cpp
index 35d31cd..dca9a75 100644
--- a/Source/WebKit/android/nav/FindCanvas.cpp
+++ b/Source/WebKit/android/nav/FindCanvas.cpp
@@ -564,7 +564,7 @@ void FindOnPage::storeCurrentMatchLocation() {
// matches than this, only draw the focused match.
#define MAX_NUMBER_OF_MATCHES_TO_DRAW 101
-void FindOnPage::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) {
+void FindOnPage::drawLegacy(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) {
if (!m_lastBounds.isEmpty()) {
inval->unite(m_lastBounds);
m_lastBounds.setEmpty();
diff --git a/Source/WebKit/android/nav/FindCanvas.h b/Source/WebKit/android/nav/FindCanvas.h
index 939e568..1d81f9a 100644
--- a/Source/WebKit/android/nav/FindCanvas.h
+++ b/Source/WebKit/android/nav/FindCanvas.h
@@ -232,7 +232,7 @@ public:
// This requires the current match to be in a layer. See
// currentMatchIsInLayer().
int currentMatchLayerId() const;
- virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
+ virtual void drawLegacy(SkCanvas* , LayerAndroid* , IntRect* );
void findNext(bool forward);
bool isCurrentLocationValid() { return m_hasCurrentLocation; }
void setMatches(WTF::Vector<MatchInfo>* matches);
diff --git a/Source/WebKit/android/nav/SelectText.cpp b/Source/WebKit/android/nav/SelectText.cpp
index 0f4ff23..22c67bc 100644
--- a/Source/WebKit/android/nav/SelectText.cpp
+++ b/Source/WebKit/android/nav/SelectText.cpp
@@ -25,23 +25,20 @@
#define LOG_TAG "webviewglue"
-#include "CachedPrefix.h"
+#include "config.h"
+
#include "BidiResolver.h"
#include "BidiRunList.h"
-#include "CachedRoot.h"
+#include "GLExtras.h"
#include "LayerAndroid.h"
-#include "ParseCanvas.h"
#include "SelectText.h"
#include "SkBitmap.h"
#include "SkBounder.h"
-#include "SkGradientShader.h"
-#include "SkMatrix.h"
+#include "SkCanvas.h"
#include "SkPicture.h"
-#include "SkPixelXorXfermode.h"
#include "SkPoint.h"
#include "SkRect.h"
#include "SkRegion.h"
-#include "SkUtils.h"
#include "TextRun.h"
#ifdef DEBUG_NAV_UI
@@ -149,1916 +146,15 @@ void ReverseBidi(UChar* chars, int len) {
namespace android {
-#define HYPHEN_MINUS 0x2D // ASCII hyphen
-#define SOLIDUS 0x2F // ASCII slash
-#define REVERSE_SOLIDUS 0x5C // ASCII backslash
-#define HYPHEN 0x2010 // unicode hyphen, first in range of dashes
-#define HORZ_BAR 0x2015 // unicode horizontal bar, last in range of dashes
-#define TOUCH_SLOP 10 // additional distance from character rect when hit
-
-class CommonCheck : public SkBounder {
-public:
- CommonCheck(const SkIRect& area)
- : mArea(area)
- , mLastUni(0)
- {
- mLastGlyph.fGlyphID = static_cast<uint16_t>(-1);
- mLastCandidate.fGlyphID = static_cast<uint16_t>(-1);
- mMatrix.reset();
- reset();
- }
-
- /* called only while the picture is parsed */
- int base() {
- if (mBase == INT_MAX) {
- SkPoint result;
- mMatrix.mapXY(0, mY, &result);
- mBase = SkScalarFloor(result.fY);
- }
- return mBase;
- }
-
- /* called only while the picture is parsed */
- int bottom() {
- if (mBottom == INT_MAX) {
- SkPoint result;
- SkPaint::FontMetrics metrics;
- mPaint.getFontMetrics(&metrics);
- mMatrix.mapXY(0, metrics.fDescent + mY, &result);
- mBottom = SkScalarCeil(result.fY);
- }
- return mBottom;
- }
-
-#if DEBUG_NAV_UI
- // make current (possibily uncomputed) value visible for debugging
- int bottomDebug() const
- {
- return mBottom;
- }
-#endif
-
- bool addNewLine(const SkBounder::GlyphRec& rec)
- {
- SkFixed lineSpacing = SkFixedAbs(mLastGlyph.fLSB.fY - rec.fLSB.fY);
- SkFixed lineHeight = SkIntToFixed(bottom() - top());
- return lineSpacing >= lineHeight + (lineHeight >> 1); // 1.5
- }
-
- bool addSpace(const SkBounder::GlyphRec& rec)
- {
- bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
- if (((mLastUni >= HYPHEN && mLastUni <= HORZ_BAR)
- || mLastUni == HYPHEN_MINUS || mLastUni == SOLIDUS
- || mLastUni == REVERSE_SOLIDUS) && newBaseLine)
- {
- return false;
- }
- return isSpace(rec);
- }
-
- void finishGlyph()
- {
- mLastGlyph = mLastCandidate;
- mLastUni = mLastUniCandidate;
- mLastPaint = mLastPaintCandidate;
- }
-
- const SkIRect& getArea() const {
- return mArea;
- }
-
- /* called only while the picture is parsed */
- SkUnichar getUniChar(const SkBounder::GlyphRec& rec)
- {
- SkUnichar unichar;
- SkPaint::TextEncoding save = mPaint.getTextEncoding();
- mPaint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
- mPaint.glyphsToUnichars(&rec.fGlyphID, 1, &unichar);
- mPaint.setTextEncoding(save);
- return unichar;
- }
-
- bool isSpace(const SkBounder::GlyphRec& rec)
- {
- if (mLastGlyph.fGlyphID == static_cast<uint16_t>(-1))
- return true;
- DBG_NAV_LOGD("mLastGlyph=((%g, %g),(%g, %g), %d)"
- " rec=((%g, %g),(%g, %g), %d) mLastUni=0x%04x '%c'",
- SkFixedToScalar(mLastGlyph.fLSB.fX),
- SkFixedToScalar(mLastGlyph.fLSB.fY),
- SkFixedToScalar(mLastGlyph.fRSB.fX),
- SkFixedToScalar(mLastGlyph.fRSB.fY), mLastGlyph.fGlyphID,
- SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fLSB.fY),
- SkFixedToScalar(rec.fRSB.fX), SkFixedToScalar(rec.fRSB.fY),
- rec.fGlyphID,
- mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
- bool newBaseLine = mLastGlyph.fLSB.fY != rec.fLSB.fY;
- if (newBaseLine)
- return true;
- SkFixed gapOne = mLastGlyph.fLSB.fX - rec.fRSB.fX;
- SkFixed gapTwo = rec.fLSB.fX - mLastGlyph.fRSB.fX;
- if (gapOne < 0 && gapTwo < 0)
- return false; // overlaps
- const SkBounder::GlyphRec& first = mLastGlyph.fLSB.fX < rec.fLSB.fX
- ? mLastGlyph : rec;
- const SkBounder::GlyphRec& second = mLastGlyph.fLSB.fX < rec.fLSB.fX
- ? rec : mLastGlyph;
- uint16_t firstGlyph = first.fGlyphID;
- SkScalar firstWidth = mLastPaint.measureText(&firstGlyph, sizeof(firstGlyph));
- SkFixed ceilWidth = SkIntToFixed(SkScalarCeil(firstWidth));
- SkFixed posNoSpace = first.fLSB.fX + ceilWidth;
- SkFixed ceilSpace = SkIntToFixed(SkFixedCeil(minSpaceWidth(mLastPaint)));
- SkFixed posWithSpace = posNoSpace + ceilSpace;
- SkFixed diffNoSpace = SkFixedAbs(second.fLSB.fX - posNoSpace);
- SkFixed diffWithSpace = SkFixedAbs(second.fLSB.fX - posWithSpace);
- DBG_NAV_LOGD("second=%g width=%g (%g) noSpace=%g (%g) withSpace=%g (%g)"
- " fontSize=%g",
- SkFixedToScalar(second.fLSB.fX),
- firstWidth, SkFixedToScalar(ceilWidth),
- SkFixedToScalar(posNoSpace), SkFixedToScalar(diffNoSpace),
- SkFixedToScalar(posWithSpace), SkFixedToScalar(diffWithSpace),
- mLastPaint.getTextSize());
- return diffWithSpace <= diffNoSpace;
- }
-
- SkFixed minSpaceWidth(SkPaint& paint)
- {
- if (mMinSpaceWidth == SK_FixedMax) {
- SkPaint::TextEncoding save = paint.getTextEncoding();
- paint.setTextEncoding(SkPaint::kUTF8_TextEncoding);
- SkScalar width = paint.measureText(" ", 1);
- mMinSpaceWidth = SkScalarToFixed(width * mMatrix.getScaleX());
- paint.setTextEncoding(save);
- DBG_NAV_LOGV("width=%g matrix sx/sy=(%g, %g) tx/ty=(%g, %g)"
- " mMinSpaceWidth=%g", width,
- mMatrix.getScaleX(), mMatrix.getScaleY(),
- mMatrix.getTranslateX(), mMatrix.getTranslateY(),
- SkFixedToScalar(mMinSpaceWidth));
- }
- return mMinSpaceWidth;
- }
-
- void recordGlyph(const SkBounder::GlyphRec& rec)
- {
- mLastCandidate = rec;
- mLastUniCandidate = getUniChar(rec);
- mLastPaintCandidate = mPaint;
- }
-
- void reset()
- {
- mMinSpaceWidth = SK_FixedMax; // mark as uninitialized
- mBase = mBottom = mTop = INT_MAX; // mark as uninitialized
- }
-
- void set(CommonCheck& check)
- {
- mLastGlyph = check.mLastGlyph;
- mLastUni = check.mLastUni;
- mMatrix = check.mMatrix;
- mLastPaint = check.mLastPaint;
- reset();
- }
-
- void setGlyph(CommonCheck& check)
- {
- mLastGlyph = check.mLastGlyph;
- mLastUni = check.mLastUni;
- mLastPaint = check.mLastPaint;
- }
-
- void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y,
- const void* text)
- {
- mMatrix = matrix;
- mPaint = paint;
- mText = static_cast<const uint16_t*>(text);
- mY = y;
- reset();
- }
-
- /* called only while the picture is parsed */
- int top() {
- if (mTop == INT_MAX) {
- SkPoint result;
- SkPaint::FontMetrics metrics;
- mPaint.getFontMetrics(&metrics);
- mMatrix.mapXY(0, metrics.fAscent + mY, &result);
- mTop = SkScalarFloor(result.fY);
- }
- return mTop;
- }
-
-#if DEBUG_NAV_UI
- // make current (possibily uncomputed) value visible for debugging
- int topDebug() const
- {
- return mTop;
- }
-#endif
-
-protected:
- SkIRect mArea;
- SkBounder::GlyphRec mLastCandidate;
- SkBounder::GlyphRec mLastGlyph;
- SkPaint mLastPaint; // available after picture has been parsed
- SkPaint mLastPaintCandidate; // associated with candidate glyph
- SkUnichar mLastUni;
- SkUnichar mLastUniCandidate;
- SkMatrix mMatrix;
- SkPaint mPaint; // only set up while the picture is parsed
- const uint16_t* mText;
- SkScalar mY;
-private:
- int mBase;
- int mBottom;
- SkFixed mMinSpaceWidth;
- int mTop;
- friend class EdgeCheck;
-};
-
-// generate the limit area for the new selection
-class LineCheck : public CommonCheck {
-public:
- LineCheck(int x, int y, const SkIRect& area)
- : INHERITED(area)
- , mX(x)
- , mY(y)
- , mInBetween(false)
- {
- mLast.setEmpty();
- }
-
- void finish(const SkRegion& selectedRgn)
- {
- if (!mParagraphs.count() && mLast.isEmpty())
- return;
- processLine();
- bool above = false;
- bool below = false;
- bool selected = false;
- SkRegion localRgn(selectedRgn);
- localRgn.translate(-mArea.fLeft, -mArea.fTop, &localRgn);
- DBG_NAV_LOGD("localRgn=(%d,%d,%d,%d)",
- localRgn.getBounds().fLeft, localRgn.getBounds().fTop,
- localRgn.getBounds().fRight, localRgn.getBounds().fBottom);
- for (int index = 0; index < mParagraphs.count(); index++) {
- const SkIRect& rect = mParagraphs[index];
- bool localSelected = localRgn.intersects(rect);
- DBG_NAV_LOGD("[%d] rect=(%d,%d,%d,%d)", index, rect.fLeft, rect.fTop,
- rect.fRight, rect.fBottom);
- if (localSelected) {
- DBG_NAV_LOGD("[%d] localSelected=true", index);
- *mSelected.append() = rect;
- }
- if (rect.fRight <= mX || rect.fLeft >= mX)
- continue;
- if (mY > rect.fBottom) {
- below = true;
- selected |= localSelected;
- DBG_NAV_LOGD("[%d] below=true localSelected=%s", index,
- localSelected ? "true" : "false");
- }
- if (mY < rect.fTop) {
- above = true;
- selected |= localSelected;
- DBG_NAV_LOGD("[%d] above=true localSelected=%s", index,
- localSelected ? "true" : "false");
- }
- }
- DBG_NAV_LOGD("mX=%d mY=%d above=%s below=%s selected=%s",
- mX, mY, above ? "true" : "false", below ? "true" : "false",
- selected ? "true" : "false");
- mInBetween = above && below && selected;
- }
-
- bool inBetween() const
- {
- return mInBetween;
- }
-
- bool inColumn(const SkIRect& test) const
- {
- for (int index = 0; index < mSelected.count(); index++) {
- const SkIRect& rect = mSelected[index];
- if (rect.fRight > test.fLeft && rect.fLeft < test.fRight)
- return true;
- }
- return false;
- }
-
- bool inColumn(int x, int y) const
- {
- for (int index = 0; index < mSelected.count(); index++) {
- const SkIRect& rect = mSelected[index];
- if (rect.contains(x, y))
- return true;
- }
- return false;
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- SkIRect bounds;
- bounds.set(rect.fLeft, top(), rect.fRight, bottom());
- // assume that characters must be consecutive to describe spaces
- // (i.e., don't join rects drawn at different times)
- if (bounds.fTop != mLast.fTop || bounds.fBottom != mLast.fBottom
- || bounds.fLeft > mLast.fRight + minSpaceWidth(mPaint)
- || bounds.fLeft < mLast.fLeft) {
- processLine();
- mLast = bounds;
- } else
- mLast.join(bounds);
- return false;
- }
-
- void processLine()
- {
- // assume line spacing of 1.5
- int lineHeight = bottom() - top();
- mLast.inset(0, -lineHeight >> 1);
- // collect arrays of rectangles making up glyphs below or above this one
- for (int index = 0; index < mParagraphs.count(); index++) {
- SkIRect& rect = mParagraphs[index];
- if (SkIRect::Intersects(rect, mLast)) {
- rect.join(mLast);
- return;
- }
- }
- *mParagraphs.append() = mLast;
- }
-
-protected:
- int mX;
- int mY;
- SkIRect mLast;
- SkTDArray<SkIRect> mParagraphs;
- SkTDArray<SkIRect> mSelected;
- bool mInBetween;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class SelectText::FirstCheck : public CommonCheck {
-public:
- FirstCheck(int x, int y, const SkIRect& area)
- : INHERITED(area)
- , mLineCheck(0)
- , mFocusX(x - area.fLeft)
- , mFocusY(y - area.fTop)
- , mBestInColumn(false)
- , mRecordGlyph(false)
- {
- reset();
- }
-
- const SkIRect& adjustedBounds(int* base)
- {
- *base = mBestBase + mArea.fTop;
- mBestBounds.offset(mArea.fLeft, mArea.fTop);
- DBG_NAV_LOGD("FirstCheck mBestBounds:(%d, %d, %d, %d) mTop=%d mBottom=%d",
- mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight,
- mBestBounds.fBottom, topDebug(), bottomDebug());
- return mBestBounds;
- }
-
- int focusX() const { return mFocusX; }
- int focusY() const { return mFocusY; }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- /* compute distance from rectangle center.
- * centerX = (rect.L + rect.R) / 2
- * multiply centerX and comparison x by 2 to retain better precision
- */
- SkIRect testBounds = {rect.fLeft, top(), rect.fRight, bottom()};
- // dx and dy are the distances from the tested edge
- // The edge distance is paramount if the test point is far away
- int dx = std::max(0, std::max(testBounds.fLeft - mFocusX,
- mFocusX - testBounds.fRight));
- int dy = std::max(0, std::max(testBounds.fTop - mFocusY,
- mFocusY - testBounds.fBottom));
- bool testInColumn = false;
- bool inBetween = false;
- bool inFocus = false;
- if (mLineCheck) {
- testInColumn = mLineCheck->inColumn(testBounds);
- inBetween = mLineCheck->inBetween();
- inFocus = mLineCheck->inColumn(mFocusX, mFocusY);
- }
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) {
- SkUnichar ch = getUniChar(rec);
- DBG_NAV_LOGD("FC dx/y=%d,%d mDx/y=%d,%d test=%d,%d,%d,%d"
- " best=%d,%d,%d,%d bestIn=%s tween=%s testIn=%s focus=%s ch=%c",
- dx, dy, mDx, mDy,
- testBounds.fLeft, testBounds.fTop, testBounds.fRight,
- testBounds.fBottom, mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom,
- mBestInColumn ? "true" : "false", inBetween ? "true" : "false",
- testInColumn ? "true" : "false", inFocus ? "true" : "false",
- ch < 0x7f ? ch : '?');
- }
-#endif
- if ((mBestInColumn || inBetween) && !testInColumn) {
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) DBG_NAV_LOG("FirstCheck reject column");
-#endif
- return false;
- }
- bool ignoreColumn = mBestInColumn == testInColumn || !inFocus;
- if (ignoreColumn && dy > 0 && (mDy < dy
- || (mDy == dy && dx > 0 && mDx <= dx))) {
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) DBG_NAV_LOG("FirstCheck reject edge");
-#endif
- return false;
- }
- // cx and cy are the distances from the tested center
- // The center distance is used when the test point is over the text
- int cx = std::abs(((testBounds.fLeft + testBounds.fRight) >> 1)
- - mFocusX);
- int cy = std::abs(((testBounds.fTop + testBounds.fBottom) >> 1)
- - mFocusY);
- if (ignoreColumn && dy == 0 && mDy == 0) {
- if (mCy < cy) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject cy=%d mCy=%d", cy, mCy);
-#endif
- return false;
- }
- if (mCy == cy) {
- if (dx == 0 && mDx == 0) {
- if (mCx < cx) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject cx=%d mCx=%d", cx, mCx);
-#endif
- return false;
- }
- } else if (dx > 0 && mDx <= dx) {
-#ifdef EXTRA_NOISY_LOGGING
- DBG_NAV_LOGD("FirstCheck reject dx=%d mDx=%d", dx, mDx);
-#endif
- return false;
- }
- }
- }
-#ifdef EXTRA_NOISY_LOGGING
- if (dy < 10) {
- DBG_NAV_LOGD("FirstCheck cx/y=(%d,%d)", cx, cy);
- }
-#endif
- mBestBase = base();
- mBestBounds = testBounds;
- mBestInColumn = testInColumn;
-#ifndef EXTRA_NOISY_LOGGING
- if (dy < 10 && dx < 10)
-#endif
- {
-#if DEBUG_NAV_UI
- SkUnichar ch = getUniChar(rec);
-#endif
- DBG_NAV_LOGD("FirstCheck dx/y=(%d,%d) mFocus=(%d,%d)"
- " mBestBounds={%d,%d,r=%d,b=%d} inColumn=%s ch=%c",
- dx, dy, mFocusX, mFocusY,
- mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom,
- mBestInColumn ? "true" : "false", ch < 0x7f ? ch : '?');
- }
- mCx = cx;
- mCy = cy;
- mDx = dx;
- mDy = dy;
- if (mRecordGlyph)
- recordGlyph(rec);
- return false;
- }
-
- void reset()
- {
- mBestBounds.setEmpty();
- mDx = mDy = mCx = mCy = INT_MAX;
- }
-
- void setLines(const LineCheck* lineCheck) { mLineCheck = lineCheck; }
- void setRecordGlyph() { mRecordGlyph = true; }
-
-protected:
- const LineCheck* mLineCheck;
- int mBestBase;
- SkIRect mBestBounds;
- int mCx;
- int mCy;
- int mDx;
- int mDy;
- int mFocusX;
- int mFocusY;
- bool mBestInColumn;
- bool mRecordGlyph;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class SelectText::EdgeCheck : public SelectText::FirstCheck {
-public:
- EdgeCheck(int x, int y, const SkIRect& area, CommonCheck& last, bool left)
- : INHERITED(x, y, area)
- , mLast(area)
- , mLeft(left)
- {
- mLast.set(last); // CommonCheck::set()
- setGlyph(last);
- }
-
- bool adjacent()
- {
- return !mLast.isSpace(mLastGlyph);
- }
-
- const SkIRect& bestBounds(int* base)
- {
- *base = mBestBase;
- return mBestBounds;
- }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- int dx = mLeft ? mFocusX - rect.fRight : rect.fLeft - mFocusX;
- int dy = ((top() + bottom()) >> 1) - mFocusY;
- dx = abs(dx);
- dy = abs(dy);
- if (mLeft ? mFocusX <= rect.fLeft : mFocusX >= rect.fRight) {
- if (dx <= 10 && dy <= 10) {
- DBG_NAV_LOGD("EdgeCheck fLeft=%d fRight=%d mFocusX=%d dx=%d dy=%d",
- rect.fLeft, rect.fRight, mFocusX, dx, dy);
- }
- return false;
- }
- if (mDy > dy || (mDy == dy && mDx > dx)) {
- if (rec.fLSB == mLastGlyph.fLSB && rec.fRSB == mLastGlyph.fRSB) {
- DBG_NAV_LOGD("dup rec.fLSB.fX=%g rec.fRSB.fX=%g",
- SkFixedToScalar(rec.fLSB.fX), SkFixedToScalar(rec.fRSB.fX));
- return false;
- }
- recordGlyph(rec);
- mDx = dx;
- mDy = dy;
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- if (dx <= 10 && dy <= 10) {
- DBG_NAV_LOGD("EdgeCheck mBestBounds={%d,%d,r=%d,b=%d} dx/y=(%d, %d)",
- mBestBounds.fLeft, mBestBounds.fTop,
- mBestBounds.fRight, mBestBounds.fBottom, dx, dy);
- }
- }
- return false;
- }
-
- void shiftStart(SkIRect bounds)
- {
- DBG_NAV_LOGD("EdgeCheck mFocusX=%d mLeft=%s bounds.fLeft=%d bounds.fRight=%d",
- mFocusX, mLeft ? "true" : "false", bounds.fLeft, bounds.fRight);
- reset();
- mFocusX = mLeft ? bounds.fLeft : bounds.fRight;
- mLast.set(*this); // CommonCheck::set()
- }
-
-protected:
- CommonCheck mLast;
- bool mLeft;
-private:
- typedef SelectText::FirstCheck INHERITED;
-};
-
-class FindFirst : public CommonCheck {
-public:
- FindFirst(const SkIRect& area)
- : INHERITED(area)
- {
- mBestBounds.set(area.width(), area.height(), area.width(), area.height());
- }
-
- const SkIRect& bestBounds(int* base)
- {
- *base = mBestBase;
- return mBestBounds;
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- if (mBestBounds.isEmpty()) {
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- }
- return false;
- }
-
-protected:
- int mBestBase;
- SkIRect mBestBounds;
-private:
- typedef CommonCheck INHERITED;
-};
-
-class FindLast : public FindFirst {
-public:
- FindLast(const SkIRect& area)
- : INHERITED(area)
- {
- mBestBounds.setEmpty();
- }
-
- virtual bool onIRect(const SkIRect& rect)
- {
- mBestBase = base();
- mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
- return false;
- }
-
-private:
- typedef FindFirst INHERITED;
-};
-
-static bool baseLinesAgree(const SkIRect& rectA, int baseA,
- const SkIRect& rectB, int baseB)
-{
- return (rectA.fTop < baseB && rectA.fBottom >= baseB)
- || (rectB.fTop < baseA && rectB.fBottom >= baseA);
-}
-
-class BuilderCheck : public CommonCheck {
-protected:
- enum IntersectionType {
- NO_INTERSECTION, // debugging printf expects this to equal zero
- LAST_INTERSECTION, // debugging printf expects this to equal one
- WAIT_FOR_INTERSECTION
- };
-
- BuilderCheck(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area)
- : INHERITED(area)
- , mCapture(false)
- , mEnd(end)
- , mEndBase(endBase)
- , mStart(start)
- , mStartBase(startBase)
- {
- mEnd.offset(-area.fLeft, -area.fTop);
- mEndBase -= area.fTop;
- mEndExtra.setEmpty();
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mSelectRect.setEmpty();
- mStart.offset(-area.fLeft, -area.fTop);
- mStartBase -= area.fTop;
- mStartExtra.setEmpty();
- DBG_NAV_LOGD(" mStart=(%d,%d,r=%d,b=%d) mStartBase=%d"
- " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d",
- mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase,
- mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase);
- }
-
- int checkFlipRect(const SkIRect& full, int fullBase) {
- mCollectFull = false;
- // is the text to collect between the selection top and bottom?
- if (fullBase < mStart.fTop || fullBase > mEnd.fBottom) {
- if (VERBOSE_LOGGING && !mLast.isEmpty()) DBG_NAV_LOGD("%s 1"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase);
- return mLastIntersects;
- }
- // is the text to the left of the selection start?
- if (baseLinesAgree(mStart, mStartBase, full, fullBase)
- && full.fLeft < mStart.fLeft) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 2"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mStart=(%d,%d,r=%d,b=%d) mStartBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mStart.fLeft, mStart.fTop, mStart.fRight, mStart.fBottom, mStartBase);
- mStartExtra.join(full);
- return mLastIntersects;
- }
- // is the text to the right of the selection end?
- if (baseLinesAgree(mEnd, mEndBase, full, fullBase)
- && full.fRight > mEnd.fRight) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 3"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mEnd=(%d,%d,r=%d,b=%d) mEndBase=%d",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mEnd.fLeft, mEnd.fTop, mEnd.fRight, mEnd.fBottom, mEndBase);
- mEndExtra.join(full);
- return mLastIntersects;
- }
- int spaceGap = SkFixedRound(minSpaceWidth(mPaint) * 3);
- // should text to the left of the start be added to the selection bounds?
- if (!mStartExtra.isEmpty()) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)"
- " mStartExtra=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom);
- if (mStartExtra.fRight + spaceGap >= mStart.fLeft)
- mSelectRect.join(mStartExtra);
- mStartExtra.setEmpty();
- }
- // should text to the right of the end be added to the selection bounds?
- if (!mEndExtra.isEmpty()) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)"
- " mEndExtra=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom);
- if (mEndExtra.fLeft - spaceGap <= mEnd.fRight)
- mSelectRect.join(mEndExtra);
- mEndExtra.setEmpty();
- }
- bool sameBaseLine = baseLinesAgree(mLast, mLastBase, full, fullBase);
- bool adjacent = (full.fLeft - mLast.fRight) < spaceGap;
- // is this the first, or are there more characters on the same line?
- if (mLast.isEmpty() || (sameBaseLine && adjacent)) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("WAIT_FOR_INTERSECTION"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " mSelectRect=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
- mLast.join(full);
- mLastIntersects = SkIRect::Intersects(mLast, mSelectRect);
- return WAIT_FOR_INTERSECTION;
- }
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("%s 4"
- " mLast=(%d,%d,r=%d,b=%d) mLastBase=%d"
- " full=(%d,%d,r=%d,b=%d) fullBase=%d"
- " mSelectRect=(%d,%d,r=%d,b=%d)"
- " mStartExtra=(%d,%d,r=%d,b=%d)"
- " mEndExtra=(%d,%d,r=%d,b=%d)",
- mLastIntersects ? "LAST_INTERSECTION" : "NO_INTERSECTION",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom, mLastBase,
- full.fLeft, full.fTop, full.fRight, full.fBottom, fullBase,
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom,
- mStartExtra.fLeft, mStartExtra.fTop, mStartExtra.fRight, mStartExtra.fBottom,
- mEndExtra.fLeft, mEndExtra.fTop, mEndExtra.fRight, mEndExtra.fBottom);
- // after the caller determines what to do with the last collection,
- // start the collection over with full and fullBase.
- mCollectFull = true;
- return mLastIntersects;
- }
-
- bool resetLast(const SkIRect& full, int fullBase)
- {
- if (mCollectFull) {
- mLast = full;
- mLastBase = fullBase;
- mLastIntersects = SkIRect::Intersects(mLast, mSelectRect);
- } else {
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mLastIntersects = false;
- }
- return mCollectFull;
- }
-
- void setFlippedState()
- {
- mSelectRect = mStart;
- mSelectRect.join(mEnd);
- DBG_NAV_LOGD("mSelectRect=(%d,%d,r=%d,b=%d)",
- mSelectRect.fLeft, mSelectRect.fTop, mSelectRect.fRight, mSelectRect.fBottom);
- mLast.setEmpty();
- mLastBase = INT_MAX;
- mLastIntersects = NO_INTERSECTION;
- }
-
- bool mCapture;
- bool mCollectFull;
- SkIRect mEnd;
- int mEndBase;
- SkIRect mEndExtra;
- bool mFlipped;
- SkIRect mLast;
- int mLastBase;
- int mLastIntersects;
- SkIRect mSelectRect;
- SkIRect mStart;
- SkIRect mStartExtra;
- int mStartBase;
-private:
- typedef CommonCheck INHERITED;
-
-};
-
-class MultilineBuilder : public BuilderCheck {
-public:
- MultilineBuilder(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area, SkRegion* region)
- : INHERITED(start, startBase, end, endBase, area)
- , mSelectRegion(region)
- {
- mFlipped = false;
- }
-
- void addLastToRegion() {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD(" mLast=(%d,%d,r=%d,b=%d)",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
- mSelectRegion->op(mLast, SkRegion::kUnion_Op);
- }
-
- void finish() {
- if (!mFlipped || !mLastIntersects)
- return;
- addLastToRegion();
- }
-
- // return true if capture end was not found after capture begin
- bool flipped() {
- DBG_NAV_LOGD("flipped=%s", mCapture ? "true" : "false");
- if (!mCapture)
- return false;
- mFlipped = true;
- setFlippedState();
- mSelectRegion->setEmpty();
- return true;
- }
-
- virtual bool onIRect(const SkIRect& rect) {
- SkIRect full;
- full.set(rect.fLeft, top(), rect.fRight, bottom());
- int fullBase = base();
- if (mFlipped) {
- int intersectType = checkFlipRect(full, fullBase);
- if (intersectType == LAST_INTERSECTION)
- addLastToRegion();
- if (intersectType != WAIT_FOR_INTERSECTION)
- resetLast(full, fullBase);
- return false;
- }
- if (full == mStart) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mStart full=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom);
- mCapture = true;
- }
- if (mCapture) {
- bool sameLines = baseLinesAgree(mLast, mLastBase, full, fullBase);
- if (sameLines)
- mLast.join(full);
- if (!sameLines || full == mEnd) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("finish mLast=(%d,%d,r=%d,b=%d)",
- mLast.fLeft, mLast.fTop, mLast.fRight, mLast.fBottom);
- addLastToRegion();
- mLast = full;
- mLastBase = fullBase;
- }
- }
- if (full == mEnd) {
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("full == mEnd full=(%d,%d,r=%d,b=%d)",
- full.fLeft, full.fTop, full.fRight, full.fBottom);
- mCapture = false;
- if (full == mStart)
- addLastToRegion();
- }
- return false;
- }
-
-protected:
- SkRegion* mSelectRegion;
-private:
- typedef BuilderCheck INHERITED;
-};
-
-static inline bool compareBounds(const SkIRect* first, const SkIRect* second)
-{
- return first->fTop < second->fTop;
-}
-
-class TextExtractor : public BuilderCheck {
-public:
- TextExtractor(const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, const SkIRect& area, bool flipped)
- : INHERITED(start, startBase, end, endBase, area)
- , mSelectStartIndex(-1)
- , mSkipFirstSpace(true) // don't start with a space
- {
- mFlipped = flipped;
- if (flipped)
- setFlippedState();
- }
-
- void addCharacter(const SkBounder::GlyphRec& rec)
- {
- if (mSelectStartIndex < 0)
- mSelectStartIndex = mSelectText.count();
- if (!mSkipFirstSpace) {
- if (addNewLine(rec)) {
- DBG_NAV_LOG("write new line");
- *mSelectText.append() = '\n';
- *mSelectText.append() = '\n';
- } else if (addSpace(rec)) {
- DBG_NAV_LOG("write space");
- *mSelectText.append() = ' ';
- }
- } else
- mSkipFirstSpace = false;
- recordGlyph(rec);
- finishGlyph();
- if (VERBOSE_LOGGING) DBG_NAV_LOGD("glyphID=%d uni=%d '%c'", rec.fGlyphID,
- mLastUni, mLastUni && mLastUni < 0x7f ? mLastUni : '?');
- if (mLastUni) {
- uint16_t chars[2];
- size_t count = SkUTF16_FromUnichar(mLastUni, chars);
- *mSelectText.append() = chars[0];
- if (count == 2)
- *mSelectText.append() = chars[1];
- }
- }
-
- void addLast()
- {
- *mSelectBounds.append() = mLast;
- *mSelectStart.append() = mSelectStartIndex;
- *mSelectEnd.append() = mSelectText.count();
- }
-
- /* Text characters are collected before it's been determined that the
- characters are part of the selection. The bounds describe valid parts
- of the selection, but the bounds are out of order.
-
- This sorts the characters by sorting the bounds, then copying the
- characters that were captured.
- */
- void finish()
- {
- if (mLastIntersects)
- addLast();
- Vector<SkIRect*> sortedBounds;
- SkTDArray<uint16_t> temp;
- int index;
- DBG_NAV_LOGD("mSelectBounds.count=%d text=%d", mSelectBounds.count(),
- mSelectText.count());
- for (index = 0; index < mSelectBounds.count(); index++)
- sortedBounds.append(&mSelectBounds[index]);
- std::sort(sortedBounds.begin(), sortedBounds.end(), compareBounds);
- int lastEnd = -1;
- for (index = 0; index < mSelectBounds.count(); index++) {
- int order = sortedBounds[index] - &mSelectBounds[0];
- int start = mSelectStart[order];
- int end = mSelectEnd[order];
- DBG_NAV_LOGD("order=%d start=%d end=%d top=%d", order, start, end,
- mSelectBounds[order].fTop);
- int count = temp.count();
- if (count > 0 && temp[count - 1] != '\n' && start != lastEnd) {
- // always separate paragraphs when original text is out of order
- DBG_NAV_LOG("write new line");
- *temp.append() = '\n';
- *temp.append() = '\n';
- }
- temp.append(end - start, &mSelectText[start]);
- lastEnd = end;
- }
- mSelectText.swap(temp);
- }
-
- virtual bool onIRectGlyph(const SkIRect& rect,
- const SkBounder::GlyphRec& rec)
- {
- SkIRect full;
- full.set(rect.fLeft, top(), rect.fRight, bottom());
- int fullBase = base();
- if (mFlipped) {
- int intersectType = checkFlipRect(full, fullBase);
- if (WAIT_FOR_INTERSECTION == intersectType)
- addCharacter(rec); // may not be copied
- else {
- if (LAST_INTERSECTION == intersectType)
- addLast();
- else
- mSkipFirstSpace = true;
- mSelectStartIndex = -1;
- if (resetLast(full, fullBase))
- addCharacter(rec); // may not be copied
- }
- return false;
- }
- if (full == mStart)
- mCapture = true;
- if (mCapture)
- addCharacter(rec);
- else
- mSkipFirstSpace = true;
- if (full == mEnd)
- mCapture = false;
- return false;
- }
-
- WTF::String text() {
- if (mFlipped)
- finish();
- // the text has been copied in visual order. Reverse as needed if
- // result contains right-to-left characters.
- const uint16_t* start = mSelectText.begin();
- const uint16_t* end = mSelectText.end();
- while (start < end) {
- SkUnichar ch = SkUTF16_NextUnichar(&start);
- WTF::Unicode::Direction charDirection = WTF::Unicode::direction(ch);
- if (WTF::Unicode::RightToLeftArabic == charDirection
- || WTF::Unicode::RightToLeft == charDirection) {
- WebCore::ReverseBidi(mSelectText.begin(), mSelectText.count());
- break;
- }
- }
- return WTF::String(mSelectText.begin(), mSelectText.count());
- }
-
-protected:
- SkIRect mEmpty;
- SkTDArray<SkIRect> mSelectBounds;
- SkTDArray<int> mSelectEnd;
- SkTDArray<int> mSelectStart;
- int mSelectStartIndex;
- SkTDArray<uint16_t> mSelectText;
- bool mSkipFirstSpace;
-private:
- typedef BuilderCheck INHERITED;
-};
-
-class TextCanvas : public ParseCanvas {
-public:
-
- TextCanvas(CommonCheck* bounder)
- : mBounder(*bounder) {
- setBounder(bounder);
- SkBitmap bitmap;
- const SkIRect& area = bounder->getArea();
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, area.width(),
- area.height());
- setBitmapDevice(bitmap);
- translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop));
-#ifdef DEBUG_NAV_UI
- const SkIRect& clip = getTotalClip().getBounds();
- const SkMatrix& matrix = getTotalMatrix();
- DBG_NAV_LOGD("bitmap=(%d,%d) clip=(%d,%d,%d,%d) matrix=(%g,%g)",
- bitmap.width(), bitmap.height(), clip.fLeft, clip.fTop,
- clip.fRight, clip.fBottom, matrix.getTranslateX(), matrix.getTranslateY());
-#endif
- }
-
- virtual void drawPaint(const SkPaint& paint) {
- }
-
- virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
- }
-
- virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
- }
-
- virtual void drawPath(const SkPath& path, const SkPaint& paint) {
- }
-
- virtual void commonDrawBitmap(const SkBitmap& bitmap, const SkIRect* rect,
- const SkMatrix& matrix, const SkPaint& paint) {
- }
-
- virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL) {
- }
-
- virtual void drawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) {
- mBounder.setUp(paint, getTotalMatrix(), y, text);
- INHERITED::drawText(text, byteLength, x, y, paint);
- }
-
- virtual void drawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
- mBounder.setUp(paint, getTotalMatrix(), constY, text);
- INHERITED::drawPosTextH(text, byteLength, xpos, constY, paint);
- }
-
- virtual void drawVertices(VertexMode vmode, int vertexCount,
- const SkPoint vertices[], const SkPoint texs[],
- const SkColor colors[], SkXfermode* xmode,
- const uint16_t indices[], int indexCount,
- const SkPaint& paint) {
- }
-
- CommonCheck& mBounder;
-private:
- typedef ParseCanvas INHERITED;
-};
-
-static bool buildSelection(const SkPicture& picture, const SkIRect& area,
- const SkIRect& selStart, int startBase,
- const SkIRect& selEnd, int endBase, SkRegion* region)
-{
- DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)"
- " selEnd=(%d, %d, %d, %d)",
- area.fLeft, area.fTop, area.fRight, area.fBottom,
- selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom,
- selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom);
- MultilineBuilder builder(selStart, startBase, selEnd, endBase, area, region);
- TextCanvas checker(&builder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- bool flipped = builder.flipped();
- if (flipped) {
- TextCanvas checker(&builder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- }
- builder.finish();
- region->translate(area.fLeft, area.fTop);
- return flipped;
-}
-
-static SkIRect findFirst(const SkPicture& picture, int* base)
-{
- SkIRect area;
- area.set(0, 0, picture.width(), picture.height());
- FindFirst finder(area);
- TextCanvas checker(&finder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return finder.bestBounds(base);
-}
-
-static SkIRect findLast(const SkPicture& picture, int* base)
-{
- SkIRect area;
- area.set(0, 0, picture.width(), picture.height());
- FindLast finder(area);
- TextCanvas checker(&finder);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return finder.bestBounds(base);
-}
-
-static WTF::String text(const SkPicture& picture, const SkIRect& area,
- const SkIRect& start, int startBase, const SkIRect& end,
- int endBase, bool flipped)
+SelectText::HandleId SelectText::mapId(HandleId id)
{
- TextExtractor extractor(start, startBase, end, endBase, area, flipped);
- TextCanvas checker(&extractor);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- return extractor.text();
-}
-
-#define CONTROL_NOTCH 16
-// TODO: Now that java is the one actually drawing these, get the real values
-// from the drawable itself
-#define CONTROL_HEIGHT 47
-#define CONTROL_WIDTH 26
-#define CONTROL_SLOP 5
-#define STROKE_WIDTH 1.0f
-#define STROKE_OUTSET 3.5f
-#define STROKE_I_OUTSET 4 // (int) ceil(STROKE_OUTSET)
-#define STROKE_COLOR 0x66000000
-#define OUTER_COLOR 0x33000000
-#define INNER_COLOR 0xe6aae300
-
-SelectText::SelectText()
- : m_controlWidth(CONTROL_WIDTH)
- , m_controlHeight(CONTROL_HEIGHT)
- , m_controlSlop(CONTROL_SLOP)
-{
- m_picture = 0;
- reset();
- SkPaint paint;
- SkRect oval;
-
- SkPath startOuterPath;
- oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET,
- -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 180, 45, true);
- oval.set(-STROKE_OUTSET, -STROKE_OUTSET, STROKE_OUTSET, STROKE_OUTSET);
- startOuterPath.arcTo(oval, 180 + 45, 135, false);
- oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 0, 90, false);
- oval.set(-CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- -CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- startOuterPath.arcTo(oval, 90, 90, false);
- startOuterPath.close();
- SkPath startInnerPath;
- startInnerPath.moveTo(-CONTROL_WIDTH, CONTROL_NOTCH);
- startInnerPath.lineTo(-CONTROL_WIDTH, CONTROL_HEIGHT);
- startInnerPath.lineTo(0, CONTROL_HEIGHT);
- startInnerPath.lineTo(0, 0);
- startInnerPath.close();
- startOuterPath.addPath(startInnerPath, 0, 0);
-
- SkCanvas* canvas = m_startControl.beginRecording(
- CONTROL_WIDTH + STROKE_OUTSET * 2,
- CONTROL_HEIGHT + STROKE_OUTSET * 2);
- paint.setAntiAlias(true);
- paint.setColor(INNER_COLOR);
- paint.setStyle(SkPaint::kFill_Style);
- canvas->drawPath(startInnerPath, paint);
- paint.setColor(OUTER_COLOR);
- canvas->drawPath(startOuterPath, paint);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(STROKE_COLOR);
- paint.setStrokeWidth(STROKE_WIDTH);
- canvas->drawPath(startInnerPath, paint);
- m_startControl.endRecording();
-
- SkPath endOuterPath;
- oval.set(-STROKE_OUTSET, -STROKE_OUTSET, STROKE_OUTSET, STROKE_OUTSET);
- endOuterPath.arcTo(oval, 180, 135, true);
- oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_NOTCH - STROKE_OUTSET,
- CONTROL_WIDTH + STROKE_OUTSET, CONTROL_NOTCH + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 360 - 45, 45, false);
- oval.set(CONTROL_WIDTH - STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- CONTROL_WIDTH + STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 0, 90, false);
- oval.set(-STROKE_OUTSET, CONTROL_HEIGHT - STROKE_OUTSET,
- STROKE_OUTSET, CONTROL_HEIGHT + STROKE_OUTSET);
- endOuterPath.arcTo(oval, 90, 90, false);
- startOuterPath.close();
- SkPath endInnerPath;
- endInnerPath.moveTo(0, 0);
- endInnerPath.lineTo(0, CONTROL_HEIGHT);
- endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_HEIGHT);
- endInnerPath.lineTo(CONTROL_WIDTH, CONTROL_NOTCH);
- endInnerPath.close();
- endOuterPath.addPath(endInnerPath, 0, 0);
-
- canvas = m_endControl.beginRecording(CONTROL_WIDTH + STROKE_OUTSET * 2,
- CONTROL_HEIGHT + STROKE_OUTSET * 2);
- paint.setColor(INNER_COLOR);
- paint.setStyle(SkPaint::kFill_Style);
- canvas->drawPath(endInnerPath, paint);
- paint.setColor(OUTER_COLOR);
- canvas->drawPath(endOuterPath, paint);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(STROKE_COLOR);
- paint.setStrokeWidth(STROKE_WIDTH);
- canvas->drawPath(endInnerPath, paint);
- m_endControl.endRecording();
-}
-
-SelectText::~SelectText()
-{
- SkSafeUnref(m_picture);
-}
-
-void SelectText::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval)
-{
- int drawingLayerId = layer ? layer->uniqueId() : -1;
- if (m_layerId != drawingLayerId)
- return;
- DBG_NAV_LOGD("m_extendSelection=%d m_drawPointer=%d layer [%d]",
- m_extendSelection, m_drawPointer, drawingLayerId);
- if (m_extendSelection)
- drawSelectionRegion(canvas, inval);
- if (m_drawPointer)
- drawSelectionPointer(canvas, inval);
-}
-
-static void addInval(IntRect* inval, const SkCanvas* canvas,
- const SkRect& bounds) {
- const SkMatrix& matrix = canvas->getTotalMatrix();
- SkRect transformed;
- matrix.mapRect(&transformed, bounds);
- SkIRect iTrans;
- transformed.round(&iTrans);
- inval->unite(iTrans);
-}
-
-void SelectText::drawSelectionPointer(SkCanvas* canvas, IntRect* inval)
-{
- SkPath path;
- if (m_extendSelection)
- getSelectionCaret(&path);
- else
- getSelectionArrow(&path);
- SkPixelXorXfermode xorMode(SK_ColorWHITE);
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setColor(SK_ColorBLACK);
- if (m_extendSelection)
- paint.setXfermode(&xorMode);
- else
- paint.setStrokeWidth(SK_Scalar1 * 2);
- int sc = canvas->save();
- canvas->scale(m_inverseScale, m_inverseScale);
- canvas->translate(m_selectX, m_selectY);
- canvas->drawPath(path, paint);
- if (!m_extendSelection) {
- paint.setStyle(SkPaint::kFill_Style);
- paint.setColor(SK_ColorWHITE);
- canvas->drawPath(path, paint);
- }
- SkRect bounds = path.getBounds();
- bounds.inset(-SK_Scalar1 * 2, -SK_Scalar1 * 2); // stroke width
- addInval(inval, canvas, bounds);
- canvas->restoreToCount(sc);
-}
-
-static void addStart(SkRegion* diff, const SkIRect& rect)
-{
- SkIRect bounds;
- bounds.set(rect.fLeft - CONTROL_WIDTH - STROKE_I_OUTSET,
- rect.fBottom - STROKE_I_OUTSET, rect.fLeft + STROKE_I_OUTSET,
- rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET);
- diff->op(bounds, SkRegion::kUnion_Op);
-}
-
-static void addEnd(SkRegion* diff, const SkIRect& rect)
-{
- SkIRect bounds;
- bounds.set(rect.fRight - STROKE_I_OUTSET, rect.fBottom - STROKE_I_OUTSET,
- rect.fRight + CONTROL_WIDTH + STROKE_I_OUTSET,
- rect.fBottom + CONTROL_HEIGHT + STROKE_I_OUTSET);
- diff->op(bounds, SkRegion::kUnion_Op);
-}
-
-void SelectText::getSelectionRegion(const IntRect& vis, SkRegion *region,
- LayerAndroid* root)
-{
- SkIRect ivisBounds = vis;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- region->setEmpty();
- buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, region);
- if (root && m_layerId) {
- Layer* layer = root->findById(m_layerId);
- while (layer) {
- const SkPoint& pos = layer->getPosition();
- region->translate(pos.fX, pos.fY);
- layer = layer->getParent();
- }
- }
-}
-
-void SelectText::drawSelectionRegion(SkCanvas* canvas, IntRect* inval)
-{
- if (!m_picture)
- return;
- SkIRect ivisBounds = m_visibleRect;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)"
- " ivisBounds=(%d,%d,r=%d,b=%d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
- ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
- if (m_lastSelRegion != m_selRegion)
- m_lastSelRegion.set(m_selRegion);
- SkRegion diff(m_lastSelRegion);
- m_selRegion.setEmpty();
- m_flipped = buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, &m_selRegion);
- SkPath path;
- m_selRegion.getBoundaryPath(&path);
- path.setFillType(SkPath::kEvenOdd_FillType);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SkColorSetARGB(0x80, 0x83, 0xCC, 0x39));
- canvas->drawPath(path, paint);
- // experiment to draw touchable controls that resize the selection
- float scale = m_controlHeight / (float)CONTROL_HEIGHT;
- canvas->save();
- canvas->translate(m_selStart.fLeft, m_selStart.fBottom);
- canvas->scale(scale, scale);
- canvas->drawPicture(m_startControl);
- canvas->restore();
- canvas->save();
- canvas->translate(m_selEnd.fRight, m_selEnd.fBottom);
- canvas->scale(scale, scale);
- canvas->drawPicture(m_endControl);
- canvas->restore();
-
-#if DEBUG_TOUCH_HANDLES
- SkRect touchHandleRect;
- paint.setColor(SkColorSetARGB(0x60, 0xFF, 0x00, 0x00));
- touchHandleRect.set(0, m_selStart.fBottom, m_selStart.fLeft, 0);
- touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight;
- touchHandleRect.fLeft = touchHandleRect.fRight - m_controlWidth;
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.inset(-m_controlSlop, -m_controlSlop);
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.set(m_selEnd.fRight, m_selEnd.fBottom, 0, 0);
- touchHandleRect.fBottom = touchHandleRect.fTop + m_controlHeight;
- touchHandleRect.fRight = touchHandleRect.fLeft + m_controlWidth;
- canvas->drawRect(touchHandleRect, paint);
- touchHandleRect.inset(-m_controlSlop, -m_controlSlop);
- canvas->drawRect(touchHandleRect, paint);
-#endif
-
- SkIRect a = diff.getBounds();
- SkIRect b = m_selRegion.getBounds();
- diff.op(m_selRegion, SkRegion::kXOR_Op);
- SkIRect c = diff.getBounds();
- DBG_NAV_LOGD("old=(%d,%d,r=%d,b=%d) new=(%d,%d,r=%d,b=%d) diff=(%d,%d,r=%d,b=%d)",
- a.fLeft, a.fTop, a.fRight, a.fBottom, b.fLeft, b.fTop, b.fRight, b.fBottom,
- c.fLeft, c.fTop, c.fRight, c.fBottom);
- DBG_NAV_LOGD("lastStart=(%d,%d,r=%d,b=%d) m_lastEnd=(%d,%d,r=%d,b=%d)",
- m_lastStart.fLeft, m_lastStart.fTop, m_lastStart.fRight, m_lastStart.fBottom,
- m_lastEnd.fLeft, m_lastEnd.fTop, m_lastEnd.fRight, m_lastEnd.fBottom);
- if (!m_lastDrawnStart.isEmpty())
- addStart(&diff, m_lastDrawnStart);
- if (m_lastStart != m_selStart) {
- m_lastDrawnStart = m_lastStart;
- m_lastStart = m_selStart;
- }
- addStart(&diff, m_selStart);
- if (!m_lastDrawnEnd.isEmpty())
- addEnd(&diff, m_lastDrawnEnd);
- if (m_lastEnd != m_selEnd) {
- m_lastDrawnEnd = m_lastEnd;
- m_lastEnd = m_selEnd;
- }
- addEnd(&diff, m_selEnd);
- SkIRect iBounds = diff.getBounds();
- DBG_NAV_LOGD("diff=(%d,%d,r=%d,b=%d)",
- iBounds.fLeft, iBounds.fTop, iBounds.fRight, iBounds.fBottom);
- SkRect bounds;
- bounds.set(iBounds);
- addInval(inval, canvas, bounds);
-}
-
-void SelectText::extendSelection(const IntRect& vis, int x, int y)
-{
- if (!m_picture)
- return;
- setVisibleRect(vis);
- SkIRect clipRect = m_visibleRect;
- int base;
- DBG_NAV_LOGD("extend x/y=%d,%d m_startOffset=%d,%d", x, y,
- m_startOffset.fX, m_startOffset.fY);
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- if (m_startSelection) {
- if (!clipRect.contains(x, y)
- || !clipRect.contains(m_original.fX, m_original.fY)) {
- clipRect.set(m_original.fX, m_original.fY, x, y);
- clipRect.sort();
- clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
- }
- FirstCheck center(m_original.fX, m_original.fY, clipRect);
- m_selStart = m_selEnd = findClosest(center, *m_picture, &base);
- if (m_selStart.isEmpty())
- return;
- DBG_NAV_LOGD("selStart clip=(%d,%d,%d,%d) m_original=%d,%d"
- " m_selStart=(%d,%d,%d,%d)", clipRect.fLeft, clipRect.fTop,
- clipRect.fRight, clipRect.fBottom, m_original.fX, m_original.fY,
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom);
- m_startBase = m_endBase = base;
- m_startSelection = false;
- m_extendSelection = true;
- m_original.fX = m_original.fY = 0;
- }
- DBG_NAV_LOGD("extend x/y=%d,%d m_original=%d,%d", x, y,
- m_original.fX, m_original.fY);
- x -= m_original.fX;
- y -= m_original.fY;
- if (!clipRect.contains(x, y) || !clipRect.contains(m_selStart)) {
- clipRect.set(m_selStart.fLeft, m_selStart.fTop, x, y);
- clipRect.sort();
- clipRect.inset(-m_visibleRect.width(), -m_visibleRect.height());
- }
- DBG_NAV_LOGD("extend clip=(%d,%d,%d,%d) x/y=%d,%d wordSel=%s outsideWord=%s",
- clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, x, y,
- m_wordSelection ? "true" : "false", m_outsideWord ? "true" : "false");
- FirstCheck extension(x, y, clipRect);
- SkIRect found = findClosest(extension, *m_picture, &base);
- if (m_wordSelection) {
- SkIRect wordBounds = m_wordBounds;
- if (!m_outsideWord)
- wordBounds.inset(-TOUCH_SLOP, -TOUCH_SLOP);
- DBG_NAV_LOGD("x=%d y=%d wordBounds=(%d,%d,r=%d,b=%d)"
- " found=(%d,%d,r=%d,b=%d)", x, y, wordBounds.fLeft, wordBounds.fTop,
- wordBounds.fRight, wordBounds.fBottom, found.fLeft, found.fTop,
- found.fRight, found.fBottom);
- if (wordBounds.contains(x, y)) {
- DBG_NAV_LOG("wordBounds.contains=true");
- m_outsideWord = false;
- return;
- }
- m_outsideWord = true;
- if (found.fBottom <= wordBounds.fTop)
- m_hitTopLeft = true;
- else if (found.fTop >= wordBounds.fBottom)
- m_hitTopLeft = false;
- else
- m_hitTopLeft = (found.fLeft + found.fRight)
- < (wordBounds.fLeft + wordBounds.fRight);
- }
- DBG_NAV_LOGD("x=%d y=%d m_startSelection=%s %s=(%d, %d, %d, %d)"
- " m_extendSelection=%s",
- x, y, m_startSelection ? "true" : "false",
- m_hitTopLeft ? "m_selStart" : "m_selEnd",
- found.fLeft, found.fTop, found.fRight, found.fBottom,
- m_extendSelection ? "true" : "false");
- if (m_hitTopLeft) {
- m_startBase = base;
- m_selStart = found;
- } else {
- m_endBase = base;
- m_selEnd = found;
- }
- swapAsNeeded();
-}
-
-SkIRect SelectText::findClosest(FirstCheck& check, const SkPicture& picture,
- int* base)
-{
- LineCheck lineCheck(check.focusX(), check.focusY(), check.getArea());
- TextCanvas lineChecker(&lineCheck);
- lineChecker.drawPicture(const_cast<SkPicture&>(picture));
- lineCheck.finish(m_selRegion);
- check.setLines(&lineCheck);
- TextCanvas checker(&check);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- check.finishGlyph();
- return check.adjustedBounds(base);
-}
-
-SkIRect SelectText::findEdge(const SkPicture& picture, const SkIRect& area,
- int x, int y, bool left, int* base)
-{
- SkIRect result;
- result.setEmpty();
- FirstCheck center(x, y, area);
- center.setRecordGlyph();
- int closestBase;
- SkIRect closest = findClosest(center, picture, &closestBase);
- SkIRect sloppy = closest;
- sloppy.inset(-TOUCH_SLOP, -TOUCH_SLOP);
- if (!sloppy.contains(x, y)) {
- DBG_NAV_LOGD("sloppy=(%d, %d, %d, %d) area=(%d, %d, %d, %d) x/y=%d,%d",
- sloppy.fLeft, sloppy.fTop, sloppy.fRight, sloppy.fBottom,
- area.fLeft, area.fTop, area.fRight, area.fBottom, x, y);
- return result;
- }
- EdgeCheck edge(x, y, area, center, left);
- do { // detect left or right until there's a gap
- DBG_NAV_LOGD("edge=%p picture=%p area=%d,%d,%d,%d",
- &edge, &picture, area.fLeft, area.fTop, area.fRight, area.fBottom);
- TextCanvas checker(&edge);
- checker.drawPicture(const_cast<SkPicture&>(picture));
- edge.finishGlyph();
- if (!edge.adjacent()) {
- if (result.isEmpty()) {
- *base = closestBase;
- DBG_NAV_LOGD("closest=%d,%d,%d,%d", closest.fLeft,
- closest.fTop, closest.fRight, closest.fBottom);
- return closest;
- }
- DBG_NAV_LOG("adjacent break");
- break;
- }
- int nextBase;
- const SkIRect& next = edge.bestBounds(&nextBase);
- if (next.isEmpty()) {
- DBG_NAV_LOG("empty");
- break;
- }
- if (result == next) {
- DBG_NAV_LOG("result == next");
- break;
- }
- *base = nextBase;
- result = next;
- edge.shiftStart(result);
- } while (true);
- if (!result.isEmpty()) {
- *base += area.fTop;
- result.offset(area.fLeft, area.fTop);
- }
- return result;
-}
-
-SkIRect SelectText::findLeft(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base)
-{
- return findEdge(picture, area, x, y, true, base);
-}
-
-SkIRect SelectText::findRight(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base)
-{
- return findEdge(picture, area, x, y, false, base);
-}
-
-const String SelectText::getSelection()
-{
- if (!m_picture)
- return String();
- SkIRect clipRect;
- clipRect.set(0, 0, m_picture->width(), m_picture->height());
- String result = text(*m_picture, clipRect, m_selStart, m_startBase,
- m_selEnd, m_endBase, m_flipped);
- DBG_NAV_LOGD("clip=(%d,%d,%d,%d)"
- " m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
- clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom,
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
- DBG_NAV_LOGD("text=%s", result.latin1().data()); // uses CString
- return result;
-}
-
-void SelectText::getSelectionArrow(SkPath* path)
-{
- const int arrow[] = {
- 0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
- };
- for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
- path->lineTo(arrow[index], arrow[index + 1]);
- path->close();
-}
-
-void SelectText::getSelectionCaret(SkPath* path)
-{
- SkScalar height = m_selStart.fBottom - m_selStart.fTop;
- SkScalar dist = height / 4;
- path->moveTo(0, -height / 2);
- path->rLineTo(0, height);
- path->rLineTo(-dist, dist);
- path->rMoveTo(0, -0.5f);
- path->rLineTo(dist * 2, 0);
- path->rMoveTo(0, 0.5f);
- path->rLineTo(-dist, -dist);
-}
-
-bool SelectText::hitCorner(int cx, int cy, int x, int y) const
-{
- SkIRect test;
- test.set(cx, cy, cx + m_controlWidth, cy + m_controlHeight);
- test.inset(-m_controlSlop, -m_controlSlop);
- DBG_HANDLE_LOG("checking if %dx%d,%d-%d contains %dx%d",
- cx, cy, m_controlWidth, m_controlHeight, x, y);
- return test.contains(x, y);
-}
-
-bool SelectText::hitStartHandle(int x, int y) const
-{
- int left = m_selStart.fLeft - m_controlWidth;
- return hitCorner(left, m_selStart.fBottom, x, y);
-}
-
-bool SelectText::hitEndHandle(int x, int y) const
-{
- int left = m_selEnd.fRight;
- return hitCorner(left, m_selEnd.fBottom, x, y);
-}
-
-bool SelectText::hitSelection(int x, int y) const
-{
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- if (hitStartHandle(x, y))
- return true;
- if (hitEndHandle(x, y))
- return true;
- return m_selRegion.contains(x, y);
-}
-
-void SelectText::getSelectionHandles(int* handles, LayerAndroid* root)
-{
- handles[0] = m_selStart.fLeft;
- handles[1] = m_selStart.fBottom;
- handles[2] = m_selEnd.fRight;
- handles[3] = m_selEnd.fBottom;
- if (root && m_layerId) {
- Layer* layer = root->findById(m_layerId);
- while (layer) {
- const SkPoint& pos = layer->getPosition();
- handles[0] += pos.fX;
- handles[2] += pos.fX;
- handles[1] += pos.fY;
- handles[3] += pos.fY;
- layer = layer->getParent();
- }
- }
-}
-
-void SelectText::moveSelection(const IntRect& vis, int x, int y)
-{
- if (!m_picture)
- return;
- x -= m_startOffset.fX;
- y -= m_startOffset.fY;
- setVisibleRect(vis);
- SkIRect clipRect = m_visibleRect;
- clipRect.join(m_selStart);
- clipRect.join(m_selEnd);
- FirstCheck center(x, y, clipRect);
- int base;
- SkIRect found = findClosest(center, *m_picture, &base);
- if (m_hitTopLeft || !m_extendSelection) {
- m_startBase = base;
- m_selStart = found;
- }
- if (!m_hitTopLeft || !m_extendSelection) {
- m_endBase = base;
- m_selEnd = found;
- }
- swapAsNeeded();
- DBG_NAV_LOGD("x=%d y=%d extendSelection=%s m_selStart=(%d, %d, %d, %d)"
- " m_selEnd=(%d, %d, %d, %d)", x, y, m_extendSelection ? "true" : "false",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
-}
-
-void SelectText::reset()
-{
- DBG_NAV_LOG("m_extendSelection=false");
- m_selStart.setEmpty();
- m_lastStart.setEmpty();
- m_lastDrawnStart.setEmpty();
- m_selEnd.setEmpty();
- m_lastEnd.setEmpty();
- m_lastDrawnEnd.setEmpty();
- m_extendSelection = false;
- m_startSelection = false;
- SkSafeUnref(m_picture);
- m_picture = 0;
- m_layerId = 0;
-}
-
-IntPoint SelectText::selectableText(const CachedRoot* root)
-{
- int x = 0;
- int y = 0;
- SkPicture* picture = root->pictureAt(&x, &y, &m_layerId);
- if (!picture) {
- DBG_NAV_LOG("picture==0");
- return IntPoint(0, 0);
- }
- int width = picture->width();
- int height = picture->height();
- IntRect vis(0, 0, width, height);
- FirstCheck center(width >> 1, height >> 1, vis);
- int base;
- const SkIRect& closest = findClosest(center, *picture, &base);
- return IntPoint((closest.fLeft + closest.fRight) >> 1,
- (closest.fTop + closest.fBottom) >> 1);
-}
-
-void SelectText::selectAll()
-{
- if (!m_picture)
- return;
- m_selStart = findFirst(*m_picture, &m_startBase);
- m_selEnd = findLast(*m_picture, &m_endBase);
- m_extendSelection = true;
-}
-
-int SelectText::selectionX() const
-{
- return (m_hitTopLeft ? m_selStart.fLeft : m_selEnd.fRight) + m_startOffset.fX;
-}
-
-int SelectText::selectionY() const
-{
- const SkIRect& rect = m_hitTopLeft ? m_selStart : m_selEnd;
- return ((rect.fTop + rect.fBottom) >> 1) + m_startOffset.fY;
-}
-
-void SelectText::setVisibleRect(const IntRect& vis)
-{
- DBG_NAV_LOGD("vis=(%d,%d,w=%d,h=%d) offset=(%d,%d)",
- vis.x(), vis.y(), vis.width(), vis.height(), m_startOffset.fX,
- m_startOffset.fY);
- m_visibleRect = vis;
- m_visibleRect.offset(-m_startOffset.fX, -m_startOffset.fY);
-}
-
-bool SelectText::startSelection(const CachedRoot* root, const IntRect& vis,
- int x, int y)
-{
- m_wordSelection = false;
- m_startOffset.set(x, y);
- DBG_NAV_LOGD("x/y=(%d,%d)", x, y);
- SkSafeUnref(m_picture);
- m_picture = root->pictureAt(&x, &y, &m_layerId);
- DBG_NAV_LOGD("m_picture=%p m_layerId=%d x/y=(%d,%d)", m_picture, m_layerId,
- x, y);
- if (!m_picture) {
- DBG_NAV_LOG("picture==0");
- return false;
- }
- m_picture->ref();
- m_startOffset.fX -= x;
- m_startOffset.fY -= y;
- m_original.fX = x;
- m_original.fY = y;
- setVisibleRect(vis);
- if (m_selStart.isEmpty()) {
- DBG_NAV_LOGD("empty start picture=(%d,%d) x=%d y=%d",
- m_picture->width(), m_picture->height(), x, y);
- m_startSelection = true;
- return true;
- }
- m_hitTopLeft = hitStartHandle(x, y);
- bool hitBottomRight = hitEndHandle(x, y);
- DBG_NAV_LOGD("picture=(%d,%d) left=%d top=%d right=%d bottom=%d x=%d y=%d",
- m_picture->width(), m_picture->height(),left, top, right, bottom, x, y);
- if (m_hitTopLeft) {
- DBG_NAV_LOG("hit top left");
- m_original.fX -= m_selStart.fLeft;
- m_original.fY -= (m_selStart.fTop + m_selStart.fBottom) >> 1;
- } else if (hitBottomRight) {
- DBG_NAV_LOG("hit bottom right");
- m_original.fX -= m_selEnd.fRight;
- m_original.fY -= (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
- }
- return m_hitTopLeft || hitBottomRight;
-}
-
-void SelectText::updateHandleScale(float handleScale)
-{
- m_controlHeight = CONTROL_HEIGHT * handleScale;
- m_controlWidth = CONTROL_WIDTH * handleScale;
- m_controlSlop = CONTROL_SLOP * handleScale;
-}
-
-/* selects the word at (x, y)
-* a word is normally delimited by spaces
-* a string of digits (even with inside spaces) is a word (for phone numbers)
-* FIXME: digit find isn't implemented yet
-* returns true if a word was selected
-*/
-bool SelectText::wordSelection(const CachedRoot* root, const IntRect& vis,
- int x, int y)
-{
- IntRect tapArea = IntRect(x - TOUCH_SLOP, y - TOUCH_SLOP, TOUCH_SLOP * 2,
- TOUCH_SLOP * 2);
- if (!startSelection(root, tapArea, x, y))
- return false;
- extendSelection(tapArea, x, y);
- if (m_selStart.isEmpty())
- return false;
- setDrawPointer(false);
- setVisibleRect(vis);
- SkIRect ivisBounds = m_visibleRect;
- ivisBounds.join(m_selStart);
- ivisBounds.join(m_selEnd);
- DBG_NAV_LOGD("m_selStart=(%d,%d,r=%d,b=%d) m_selEnd=(%d,%d,r=%d,b=%d)"
- " ivisBounds=(%d,%d,r=%d,b=%d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom,
- ivisBounds.fLeft, ivisBounds.fTop, ivisBounds.fRight, ivisBounds.fBottom);
- m_selRegion.setEmpty();
- buildSelection(*m_picture, ivisBounds, m_selStart, m_startBase,
- m_selEnd, m_endBase, &m_selRegion);
- x = m_selStart.fLeft;
- y = (m_selStart.fTop + m_selStart.fBottom) >> 1;
- SkIRect clipRect = m_visibleRect;
- clipRect.fLeft -= m_visibleRect.width() >> 1;
- clipRect.fLeft = std::max(clipRect.fLeft, 0);
- int base;
- SkIRect left = findLeft(*m_picture, clipRect, x, y, &base);
- if (!left.isEmpty()) {
- m_startBase = base;
- m_selStart = left;
- }
- x = m_selEnd.fRight;
- y = (m_selEnd.fTop + m_selEnd.fBottom) >> 1;
- clipRect = m_visibleRect;
- clipRect.fRight += m_visibleRect.width() >> 1;
- SkIRect right = findRight(*m_picture, clipRect, x, y, &base);
- if (!right.isEmpty()) {
- m_endBase = base;
- m_selEnd = right;
- }
- DBG_NAV_LOGD("m_selStart=(%d, %d, %d, %d) m_selEnd=(%d, %d, %d, %d)",
- m_selStart.fLeft, m_selStart.fTop, m_selStart.fRight, m_selStart.fBottom,
- m_selEnd.fLeft, m_selEnd.fTop, m_selEnd.fRight, m_selEnd.fBottom);
- if (!left.isEmpty() || !right.isEmpty()) {
- m_wordBounds = m_selStart;
- m_wordBounds.join(m_selEnd);
- m_extendSelection = m_wordSelection = true;
- m_outsideWord = false;
- return true;
- }
- return false;
-}
-
-void SelectText::swapAsNeeded()
-{
- if (m_selStart.fTop >= (m_selEnd.fTop + m_selEnd.fBottom) >> 1
- || (m_selEnd.fTop < (m_selStart.fTop + m_selStart.fBottom) >> 1
- && m_selStart.fRight > m_selEnd.fLeft))
- {
- SkTSwap(m_startBase, m_endBase);
- SkTSwap(m_selStart, m_selEnd);
- m_hitTopLeft ^= true;
- DBG_NAV_LOGD("m_hitTopLeft=%s", m_hitTopLeft ? "true" : "false");
- }
+ if (id == StartHandle || id == EndHandle)
+ return id;
+ if (isBaseFirst())
+ return (HandleId) (id - 2);
+ if (id == BaseHandle)
+ return EndHandle;
+ return StartHandle;
}
}
diff --git a/Source/WebKit/android/nav/SelectText.h b/Source/WebKit/android/nav/SelectText.h
index b454b8e..904b2b9 100644
--- a/Source/WebKit/android/nav/SelectText.h
+++ b/Source/WebKit/android/nav/SelectText.h
@@ -27,90 +27,38 @@
#define SelectText_h
#include "DrawExtra.h"
-#include "IntPoint.h"
#include "IntRect.h"
#include "PlatformString.h"
-#include "SkPath.h"
-#include "SkPicture.h"
-#include "SkRect.h"
-#include "SkRegion.h"
namespace android {
-class CachedRoot;
-
-class SelectText : public DrawExtra {
-public:
- SelectText();
- virtual ~SelectText();
- virtual void draw(SkCanvas* , LayerAndroid* , IntRect* );
- void extendSelection(const IntRect& vis, int x, int y);
- const String getSelection();
- bool hitSelection(int x, int y) const;
- void moveSelection(const IntRect& vis, int x, int y);
- void reset();
- IntPoint selectableText(const CachedRoot* );
- void selectAll();
- int selectionX() const;
- int selectionY() const;
- void setDrawPointer(bool drawPointer) { m_drawPointer = drawPointer; }
- void setExtendSelection(bool extend) { m_extendSelection = extend; }
- bool startSelection(const CachedRoot* , const IntRect& vis, int x, int y);
- bool wordSelection(const CachedRoot* , const IntRect& vis, int x, int y);
- void getSelectionRegion(const IntRect& vis, SkRegion *region, LayerAndroid* root);
- void updateHandleScale(float handleScale);
- void getSelectionHandles(int* handles, LayerAndroid* root);
+class SelectText : public RegionLayerDrawExtra {
public:
- float m_inverseScale; // inverse scale, x, y used for drawing select path
- int m_selectX;
- int m_selectY;
+ enum HandleId {
+ StartHandle = 0,
+ EndHandle = 1,
+ BaseHandle = 2,
+ ExtentHandle = 3,
+ };
+
+ IntRect& caretRect(HandleId id) { return m_caretRects[mapId(id)]; }
+ void setCaretRect(HandleId id, const IntRect& rect) { m_caretRects[mapId(id)] = rect; }
+ int caretLayerId(HandleId id) { return m_caretLayerId[mapId(id)]; }
+ void setCaretLayerId(HandleId id, int layerId) { m_caretLayerId[mapId(id)] = layerId; }
+
+ bool isBaseFirst() const { return m_baseIsFirst; }
+ void setBaseFirst(bool isFirst) { m_baseIsFirst = isFirst; }
+
+ void setText(const String& text) { m_text = text.threadsafeCopy(); }
+ String& getText() { return m_text; }
+
private:
- int m_controlWidth;
- int m_controlHeight;
- int m_controlSlop;
- class FirstCheck;
- class EdgeCheck;
- void drawSelectionPointer(SkCanvas* , IntRect* );
- void drawSelectionRegion(SkCanvas* , IntRect* );
- SkIRect findClosest(FirstCheck& , const SkPicture& , int* base);
- SkIRect findEdge(const SkPicture& , const SkIRect& area,
- int x, int y, bool left, int* base);
- SkIRect findLeft(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base);
- SkIRect findRight(const SkPicture& picture, const SkIRect& area,
- int x, int y, int* base);
- static void getSelectionArrow(SkPath* );
- void getSelectionCaret(SkPath* );
- bool hitCorner(int cx, int cy, int x, int y) const;
- bool hitStartHandle(int x, int y) const;
- bool hitEndHandle(int x, int y) const;
- void setVisibleRect(const IntRect& );
- void swapAsNeeded();
- SkIPoint m_original; // computed start of extend selection
- SkIPoint m_startOffset; // difference from global to layer
- SkIRect m_selStart;
- SkIRect m_selEnd;
- SkIRect m_lastStart;
- SkIRect m_lastEnd;
- SkIRect m_lastDrawnStart;
- SkIRect m_lastDrawnEnd;
- SkIRect m_wordBounds;
- int m_startBase;
- int m_endBase;
- int m_layerId;
- SkIRect m_visibleRect; // constrains picture computations to visible area
- SkRegion m_lastSelRegion;
- SkRegion m_selRegion; // computed from sel start, end
- SkPicture m_startControl;
- SkPicture m_endControl;
- const SkPicture* m_picture;
- bool m_drawPointer;
- bool m_extendSelection; // false when trackball is moving pointer
- bool m_flipped;
- bool m_hitTopLeft;
- bool m_startSelection;
- bool m_wordSelection;
- bool m_outsideWord;
+ HandleId mapId(HandleId id);
+
+ IntRect m_caretRects[2];
+ int m_caretLayerId[2];
+ bool m_baseIsFirst;
+ String m_text;
};
}
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index 6c49bb7..efdb67f 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -107,6 +107,7 @@ enum FrameCachePermission {
AllowNewer
};
+#define DRAW_EXTRAS_SIZE 3
enum DrawExtras { // keep this in sync with WebView.java
DrawExtrasNone = 0,
DrawExtrasFind = 1,
@@ -139,7 +140,6 @@ struct JavaGlue {
jfieldID m_rectFTop;
jmethodID m_rectFWidth;
jmethodID m_rectFHeight;
- jmethodID m_getTextHandleScale;
AutoJObject object(JNIEnv* env) {
return getRealObject(env, m_obj);
}
@@ -150,6 +150,7 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
m_ring((WebViewCore*) viewImpl)
, m_isHighEndGfx(isHighEndGfx)
{
+ memset(m_extras, 0, DRAW_EXTRAS_SIZE * sizeof(DrawExtra*));
jclass clazz = env->FindClass("android/webkit/WebView");
// m_javaGlue = new JavaGlue;
m_javaGlue.m_obj = env->NewWeakGlobalRef(javaWebView);
@@ -169,7 +170,6 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
m_javaGlue.m_postInvalidateDelayed = GetJMethod(env, clazz,
"viewInvalidateDelayed", "(JIIII)V");
m_javaGlue.m_pageSwapCallback = GetJMethod(env, clazz, "pageSwapCallback", "(Z)V");
- m_javaGlue.m_getTextHandleScale = GetJMethod(env, clazz, "getTextHandleScale", "()F");
env->DeleteLocalRef(clazz);
jclass rectClass = env->FindClass("android/graphics/Rect");
@@ -222,6 +222,45 @@ WebView(JNIEnv* env, jobject javaWebView, int viewImpl, WTF::String drawableDir,
delete m_frameCacheUI;
SkSafeUnref(m_baseLayer);
delete m_glDrawFunctor;
+ for (int i = 0; i < DRAW_EXTRAS_SIZE; i++)
+ delete m_extras[i];
+}
+
+DrawExtra* getDrawExtra(DrawExtras extras)
+{
+ if (extras == DrawExtrasNone)
+ return 0;
+ return m_extras[extras - 1];
+}
+
+DrawExtra* getDrawExtraLegacy(DrawExtras extras)
+{
+ CachedRoot* root = getFrameCache(AllowNewer);
+ if (!root) {
+ DBG_NAV_LOG("!root");
+ if (extras == DrawExtrasCursorRing)
+ resetCursorRing();
+ }
+ DrawExtra* extra = getDrawExtra(extras);
+ if (!extra) {
+ switch (extras) {
+ case DrawExtrasFind:
+ extra = &m_findOnPage;
+ break;
+ case DrawExtrasCursorRing:
+ if (drawCursorPreamble(root) && m_ring.setup()) {
+ if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX)
+ extra = &m_ring;
+ drawCursorPostamble();
+ }
+ break;
+ // Just to prevent compiler warnings
+ case DrawExtrasSelection:
+ case DrawExtrasNone:
+ break;
+ }
+ }
+ return extra;
}
void stopGL()
@@ -236,26 +275,6 @@ WebViewCore* getWebViewCore() const {
return m_viewImpl;
}
-float getTextHandleScale()
-{
- ALOG_ASSERT(m_javaGlue.m_obj, "A java object was not associated with this native WebView!");
- JNIEnv* env = JSC::Bindings::getJNIEnv();
- AutoJObject javaObject = m_javaGlue.object(env);
- if (!javaObject.get())
- return 0;
- float result = env->CallFloatMethod(javaObject.get(), m_javaGlue.m_getTextHandleScale);
- checkException(env);
- return result;
-}
-
-void updateSelectionHandles()
-{
- if (!m_baseLayer)
- return;
- // Adjust for device density & scale
- m_selectText.updateHandleScale(getTextHandleScale());
-}
-
// removes the cursor altogether (e.g., when going to a new page)
void clearCursor()
{
@@ -464,34 +483,7 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
}
}
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- if (extras == DrawExtrasCursorRing)
- resetCursorRing();
- }
- DrawExtra* extra = 0;
- switch (extras) {
- case DrawExtrasFind:
- extra = &m_findOnPage;
- break;
- case DrawExtrasSelection:
- // This will involve a JNI call, but under normal circumstances we will
- // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled
- // in WebView.java will we hit this (so really debug only)
- updateSelectionHandles();
- extra = &m_selectText;
- break;
- case DrawExtrasCursorRing:
- if (drawCursorPreamble(root) && m_ring.setup()) {
- if (m_ring.m_isPressed || m_ringAnimationEnd == UINT_MAX)
- extra = &m_ring;
- drawCursorPostamble();
- }
- break;
- default:
- ;
- }
+ DrawExtra* extra = getDrawExtraLegacy((DrawExtras) extras);
unsigned int pic = m_glWebViewState->currentPictureCounter();
m_glWebViewState->glExtras()->setDrawExtra(extra);
@@ -522,7 +514,7 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect,
return false;
}
-PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
+PictureSet* draw(SkCanvas* canvas, SkColor bgColor, DrawExtras extras, bool split)
{
PictureSet* ret = 0;
if (!m_baseLayer) {
@@ -540,33 +532,10 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
if (content->draw(canvas))
ret = split ? new PictureSet(*content) : 0;
- CachedRoot* root = getFrameCache(AllowNewer);
- if (!root) {
- DBG_NAV_LOG("!root");
- if (extras == DrawExtrasCursorRing)
- resetCursorRing();
- }
- DrawExtra* extra = 0;
- switch (extras) {
- case DrawExtrasFind:
- extra = &m_findOnPage;
- break;
- case DrawExtrasSelection:
- // This will involve a JNI call, but under normal circumstances we will
- // not hit this anyway. Only if USE_JAVA_TEXT_SELECTION is disabled
- // in WebView.java will we hit this (so really debug only)
- updateSelectionHandles();
- extra = &m_selectText;
- break;
- case DrawExtrasCursorRing:
- if (drawCursorPreamble(root) && m_ring.setup()) {
- extra = &m_ring;
- drawCursorPostamble();
- }
- break;
- default:
- ;
- }
+ DrawExtra* extra = getDrawExtraLegacy(extras);
+ if (extra)
+ extra->draw(canvas, 0);
+
#if USE(ACCELERATED_COMPOSITING)
LayerAndroid* compositeLayer = compositeRoot();
if (compositeLayer) {
@@ -579,11 +548,11 @@ PictureSet* draw(SkCanvas* canvas, SkColor bgColor, int extras, bool split)
SkAutoCanvasRestore restore(canvas, true);
m_baseLayer->setMatrix(canvas->getTotalMatrix());
canvas->resetMatrix();
- m_baseLayer->draw(canvas);
+ m_baseLayer->draw(canvas, extra);
}
if (extra) {
IntRect dummy; // inval area, unused for now
- extra->draw(canvas, compositeLayer, &dummy);
+ extra->drawLegacy(canvas, compositeLayer, &dummy);
}
#endif
return ret;
@@ -1144,85 +1113,11 @@ void setHeightCanMeasure(bool measure)
String getSelection()
{
- return m_selectText.getSelection();
-}
-
-void moveSelection(int x, int y)
-{
- m_selectText.moveSelection(getVisibleRect(), x, y);
-}
-
-IntPoint selectableText()
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return IntPoint(0, 0);
- return m_selectText.selectableText(root);
-}
-
-void selectAll()
-{
- m_selectText.selectAll();
-}
-
-int selectionX()
-{
- return m_selectText.selectionX();
-}
-
-int selectionY()
-{
- return m_selectText.selectionY();
-}
-
-void resetSelection()
-{
- m_selectText.reset();
-}
-
-bool startSelection(int x, int y)
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return false;
- updateSelectionHandles();
- return m_selectText.startSelection(root, getVisibleRect(), x, y);
-}
-
-bool wordSelection(int x, int y)
-{
- const CachedRoot* root = getFrameCache(DontAllowNewer);
- if (!root)
- return false;
- updateSelectionHandles();
- return m_selectText.wordSelection(root, getVisibleRect(), x, y);
-}
-
-bool extendSelection(int x, int y)
-{
- m_selectText.extendSelection(getVisibleRect(), x, y);
- return true;
-}
-
-bool hitSelection(int x, int y)
-{
- updateSelectionHandles();
- return m_selectText.hitSelection(x, y);
-}
-
-void setExtendSelection()
-{
- m_selectText.setExtendSelection(true);
-}
-
-void setSelectionPointer(bool set, float scale, int x, int y)
-{
- m_selectText.setDrawPointer(set);
- if (!set)
- return;
- m_selectText.m_inverseScale = scale;
- m_selectText.m_selectX = x;
- m_selectText.m_selectY = y;
+ SelectText* select = static_cast<SelectText*>(
+ getDrawExtra(WebView::DrawExtrasSelection));
+ if (select)
+ return select->getText();
+ return String();
}
void sendMoveFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr)
@@ -1460,16 +1355,6 @@ void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndic
root->setRootLayer(compositeRoot());
}
-void getTextSelectionRegion(SkRegion *region)
-{
- m_selectText.getSelectionRegion(getVisibleRect(), region, compositeRoot());
-}
-
-void getTextSelectionHandles(int* handles)
-{
- m_selectText.getSelectionHandles(handles, compositeRoot());
-}
-
void replaceBaseContent(PictureSet* set)
{
if (!m_baseLayer)
@@ -1515,6 +1400,38 @@ FindOnPage& findOnPage() {
return m_findOnPage;
}
+void setDrawExtra(DrawExtra *extra, DrawExtras type)
+{
+ if (type == DrawExtrasNone)
+ return;
+ DrawExtra* old = m_extras[type - 1];
+ m_extras[type - 1] = extra;
+ if (old != extra) {
+ delete old;
+ }
+}
+
+void setTextSelection(SelectText *selection) {
+ setDrawExtra(selection, DrawExtrasSelection);
+}
+
+int getHandleLayerId(SelectText::HandleId handleId, SkIRect& cursorRect) {
+ SelectText* selectText = static_cast<SelectText*>(getDrawExtra(DrawExtrasSelection));
+ if (!selectText)
+ return -1;
+ int layerId = selectText->caretLayerId(handleId);
+ const IntRect& r = selectText->caretRect(handleId);
+ cursorRect.set(r.x(), r.y(), r.maxX(), r.maxY());
+ if (layerId != -1) {
+ LayerAndroid* root = compositeRoot();
+ LayerAndroid* layer = root ? root->findById(layerId) : 0;
+ IntPoint offset;
+ WebViewCore::layerToAbsoluteOffset(layer, offset);
+ cursorRect.offset(offset.x(), offset.y());
+ }
+ return layerId;
+}
+
bool m_isDrawingPaused;
private: // local state for WebView
// private to getFrameCache(); other functions operate in a different thread
@@ -1526,9 +1443,9 @@ private: // local state for WebView
bool m_heightCanMeasure;
int m_lastDx;
SkMSec m_lastDxTime;
- SelectText m_selectText;
FindOnPage m_findOnPage;
CursorRing m_ring;
+ DrawExtra* m_extras[DRAW_EXTRAS_SIZE];
BaseLayerAndroid* m_baseLayer;
Functor* m_glDrawFunctor;
#if USE(ACCELERATED_COMPOSITING)
@@ -1852,7 +1769,8 @@ static jint nativeDraw(JNIEnv *env, jobject obj, jobject canv,
WebView* webView = GET_NATIVE_VIEW(env, obj);
SkRect visibleRect = jrectf_to_rect(env, visible);
webView->setVisibleRect(visibleRect);
- PictureSet* pictureSet = webView->draw(canvas, color, extras, split);
+ PictureSet* pictureSet = webView->draw(canvas, color,
+ static_cast<WebView::DrawExtras>(extras), split);
return reinterpret_cast<jint>(pictureSet);
}
@@ -1920,24 +1838,6 @@ static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint nativeView, jint l
registerPageSwapCallback);
}
-static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jint view,
- jobject region)
-{
- if (!region)
- return;
- SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region);
- ((WebView*)view)->getTextSelectionRegion(nregion);
-}
-
-static void nativeGetSelectionHandles(JNIEnv *env, jobject obj, jint view,
- jintArray arr)
-{
- int handles[4];
- ((WebView*)view)->getTextSelectionHandles(handles);
- env->SetIntArrayRegion(arr, 0, 4, handles);
- checkException(env);
-}
-
static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
{
return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
@@ -2449,51 +2349,6 @@ static int nativeMoveGeneration(JNIEnv *env, jobject obj)
return view->moveGeneration();
}
-static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- GET_NATIVE_VIEW(env, obj)->moveSelection(x, y);
-}
-
-static void nativeResetSelection(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->resetSelection();
-}
-
-static jobject nativeSelectableText(JNIEnv* env, jobject obj)
-{
- IntPoint pos = GET_NATIVE_VIEW(env, obj)->selectableText();
- jclass pointClass = env->FindClass("android/graphics/Point");
- jmethodID init = env->GetMethodID(pointClass, "<init>", "(II)V");
- jobject point = env->NewObject(pointClass, init, pos.x(), pos.y());
- env->DeleteLocalRef(pointClass);
- return point;
-}
-
-static void nativeSelectAll(JNIEnv* env, jobject obj)
-{
- GET_NATIVE_VIEW(env, obj)->selectAll();
-}
-
-static void nativeSetExtendSelection(JNIEnv *env, jobject obj)
-{
- GET_NATIVE_VIEW(env, obj)->setExtendSelection();
-}
-
-static jboolean nativeStartSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- return GET_NATIVE_VIEW(env, obj)->startSelection(x, y);
-}
-
-static jboolean nativeWordSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- return GET_NATIVE_VIEW(env, obj)->wordSelection(x, y);
-}
-
-static void nativeExtendSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- GET_NATIVE_VIEW(env, obj)->extendSelection(x, y);
-}
-
static jobject nativeGetSelection(JNIEnv *env, jobject obj)
{
WebView* view = GET_NATIVE_VIEW(env, obj);
@@ -2502,27 +2357,6 @@ static jobject nativeGetSelection(JNIEnv *env, jobject obj)
return wtfStringToJstring(env, selection);
}
-static jboolean nativeHitSelection(JNIEnv *env, jobject obj, int x, int y)
-{
- return GET_NATIVE_VIEW(env, obj)->hitSelection(x, y);
-}
-
-static jint nativeSelectionX(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->selectionX();
-}
-
-static jint nativeSelectionY(JNIEnv *env, jobject obj)
-{
- return GET_NATIVE_VIEW(env, obj)->selectionY();
-}
-
-static void nativeSetSelectionPointer(JNIEnv *env, jobject obj, jint nativeView,
- jboolean set, jfloat scale, jint x, jint y)
-{
- ((WebView*)nativeView)->setSelectionPointer(set, scale, x, y);
-}
-
static void nativeRegisterPageSwapCallback(JNIEnv *env, jobject obj, jint nativeView)
{
((WebView*)nativeView)->registerPageSwapCallback();
@@ -2675,7 +2509,7 @@ static void nativeDumpDisplayTree(JNIEnv* env, jobject jwebview, jstring jurl)
SkDumpCanvas canvas(&dumper);
// this will playback the picture into the canvas, which will
// spew its contents to the dumper
- view->draw(&canvas, 0, 0, false);
+ view->draw(&canvas, 0, WebView::DrawExtrasNone, false);
// we're done with the file now
fwrite("\n", 1, 1, file);
fclose(file);
@@ -2767,6 +2601,32 @@ static bool nativeDisableNavcache(JNIEnv *env, jobject obj)
#endif
}
+static void nativeSetTextSelection(JNIEnv *env, jobject obj, jint nativeView,
+ jint selectionPtr)
+{
+ SelectText* selection = reinterpret_cast<SelectText*>(selectionPtr);
+ reinterpret_cast<WebView*>(nativeView)->setTextSelection(selection);
+}
+
+static jint nativeGetHandleLayerId(JNIEnv *env, jobject obj, jint nativeView,
+ jint handleIndex, jobject cursorRect)
+{
+ WebView* webview = reinterpret_cast<WebView*>(nativeView);
+ SkIRect nativeRect;
+ int layerId = webview->getHandleLayerId((SelectText::HandleId) handleIndex, nativeRect);
+ if (cursorRect)
+ GraphicsJNI::irect_to_jrect(nativeRect, env, cursorRect);
+ return layerId;
+}
+
+static jboolean nativeIsBaseFirst(JNIEnv *env, jobject obj, jint nativeView)
+{
+ WebView* webview = reinterpret_cast<WebView*>(nativeView);
+ SelectText* select = static_cast<SelectText*>(
+ webview->getDrawExtra(WebView::DrawExtrasSelection));
+ return select ? select->isBaseFirst() : false;
+}
+
/*
* JNI registration
*/
@@ -2817,8 +2677,6 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeDumpDisplayTree },
{ "nativeEvaluateLayersAnimations", "(I)Z",
(void*) nativeEvaluateLayersAnimations },
- { "nativeExtendSelection", "(II)V",
- (void*) nativeExtendSelection },
{ "nativeFindAll", "(Ljava/lang/String;Ljava/lang/String;Z)I",
(void*) nativeFindAll },
{ "nativeFindNext", "(Z)V",
@@ -2875,8 +2733,6 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeHasFocusNode },
{ "nativeHideCursor", "()V",
(void*) nativeHideCursor },
- { "nativeHitSelection", "(II)Z",
- (void*) nativeHitSelection },
{ "nativeImageURI", "(II)Ljava/lang/String;",
(void*) nativeImageURI },
{ "nativeLayerBounds", "(I)Landroid/graphics/Rect;",
@@ -2889,26 +2745,12 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeMoveCursorToNextTextInput },
{ "nativeMoveGeneration", "()I",
(void*) nativeMoveGeneration },
- { "nativeMoveSelection", "(II)V",
- (void*) nativeMoveSelection },
{ "nativePointInNavCache", "(III)Z",
(void*) nativePointInNavCache },
- { "nativeResetSelection", "()V",
- (void*) nativeResetSelection },
- { "nativeSelectableText", "()Landroid/graphics/Point;",
- (void*) nativeSelectableText },
- { "nativeSelectAll", "()V",
- (void*) nativeSelectAll },
{ "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
(void*) nativeSelectBestAt },
{ "nativeSelectAt", "(II)V",
(void*) nativeSelectAt },
- { "nativeSelectionX", "()I",
- (void*) nativeSelectionX },
- { "nativeSelectionY", "()I",
- (void*) nativeSelectionY },
- { "nativeSetExtendSelection", "()V",
- (void*) nativeSetExtendSelection },
{ "nativeSetFindIsEmpty", "()V",
(void*) nativeSetFindIsEmpty },
{ "nativeSetFindIsUp", "(Z)V",
@@ -2917,10 +2759,6 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeSetHeightCanMeasure },
{ "nativeSetBaseLayer", "(IILandroid/graphics/Region;ZZZ)V",
(void*) nativeSetBaseLayer },
- { "nativeGetTextSelectionRegion", "(ILandroid/graphics/Region;)V",
- (void*) nativeGetTextSelectionRegion },
- { "nativeGetSelectionHandles", "(I[I)V",
- (void*) nativeGetSelectionHandles },
{ "nativeGetBaseLayer", "()I",
(void*) nativeGetBaseLayer },
{ "nativeReplaceBaseContent", "(I)V",
@@ -2929,8 +2767,6 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeCopyBaseContentToPicture },
{ "nativeHasContent", "()Z",
(void*) nativeHasContent },
- { "nativeSetSelectionPointer", "(IZFII)V",
- (void*) nativeSetSelectionPointer },
{ "nativeShowCursorTimed", "()V",
(void*) nativeShowCursorTimed },
{ "nativeRegisterPageSwapCallback", "(I)V",
@@ -2951,8 +2787,6 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeTileProfilingGetInt },
{ "nativeTileProfilingGetFloat", "(IILjava/lang/String;)F",
(void*) nativeTileProfilingGetFloat },
- { "nativeStartSelection", "(II)Z",
- (void*) nativeStartSelection },
{ "nativeStopGL", "()V",
(void*) nativeStopGL },
{ "nativeSubtractLayers", "(Landroid/graphics/Rect;)Landroid/graphics/Rect;",
@@ -2961,8 +2795,6 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeTextGeneration },
{ "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
(void*) nativeUpdateCachedTextfield },
- { "nativeWordSelection", "(II)Z",
- (void*) nativeWordSelection },
{ "nativeGetBlockLeftEdge", "(IIF)I",
(void*) nativeGetBlockLeftEdge },
{ "nativeScrollableLayer", "(IILandroid/graphics/Rect;Landroid/graphics/Rect;)I",
@@ -2987,6 +2819,12 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeDisableNavcache },
{ "nativeFocusCandidateIsEditableText", "(I)Z",
(void*) nativeFocusCandidateIsEditableText },
+ { "nativeSetTextSelection", "(II)V",
+ (void*) nativeSetTextSelection },
+ { "nativeGetHandleLayerId", "(IILandroid/graphics/Rect;)I",
+ (void*) nativeGetHandleLayerId },
+ { "nativeIsBaseFirst", "(I)Z",
+ (void*) nativeIsBaseFirst },
};
int registerWebView(JNIEnv* env)