summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/WebCore/bridge/jni/JavaMethodJobject.cpp2
-rw-r--r--Source/WebCore/bridge/jni/jsc/JavaFieldJSC.cpp6
-rw-r--r--Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp15
-rw-r--r--Source/WebCore/bridge/jni/v8/JavaFieldJobjectV8.cpp13
-rw-r--r--Source/WebCore/platform/graphics/android/FontAndroid.cpp1
-rw-r--r--Source/WebCore/platform/graphics/android/GLWebViewState.cpp2
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp7
-rw-r--r--Source/WebCore/platform/graphics/android/ShaderProgram.cpp36
-rw-r--r--Source/WebCore/platform/graphics/android/ShaderProgram.h6
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCache.cpp12
-rw-r--r--Source/WebKit/android/WebCoreSupport/WebCache.h5
-rw-r--r--Source/WebKit/android/jni/PictureSet.cpp376
-rw-r--r--Source/WebKit/android/jni/PictureSet.h69
-rw-r--r--Source/WebKit/android/jni/WebViewCore.cpp32
-rw-r--r--Source/WebKit/android/nav/SelectText.cpp10
-rw-r--r--Source/WebKit/android/nav/SelectText.h1
-rw-r--r--Source/WebKit/android/nav/WebView.cpp16
17 files changed, 552 insertions, 57 deletions
diff --git a/Source/WebCore/bridge/jni/JavaMethodJobject.cpp b/Source/WebCore/bridge/jni/JavaMethodJobject.cpp
index 73cae54..01a0b5b 100644
--- a/Source/WebCore/bridge/jni/JavaMethodJobject.cpp
+++ b/Source/WebCore/bridge/jni/JavaMethodJobject.cpp
@@ -45,7 +45,7 @@ JavaMethodJobject::JavaMethodJobject(JNIEnv* env, jobject aMethod)
// Get return type name
jstring returnTypeName = 0;
if (jobject returnType = callJNIMethod<jobject>(aMethod, "getReturnType", "()Ljava/lang/Class;")) {
- returnTypeName = static_cast<jstring>(callJNIMethod<jobject>(returnType, "getName", "()Ljava/lang/String;"));
+ returnTypeName = static_cast<jstring>(callJNIMethod<jobject>(returnType, "getName", "()Ljava/lang/String;"));
if (!returnTypeName)
returnTypeName = env->NewStringUTF("<Unknown>");
env->DeleteLocalRef(returnType);
diff --git a/Source/WebCore/bridge/jni/jsc/JavaFieldJSC.cpp b/Source/WebCore/bridge/jni/jsc/JavaFieldJSC.cpp
index b7c664e..ee18f66 100644
--- a/Source/WebCore/bridge/jni/jsc/JavaFieldJSC.cpp
+++ b/Source/WebCore/bridge/jni/jsc/JavaFieldJSC.cpp
@@ -44,19 +44,23 @@ JavaField::JavaField(JNIEnv* env, jobject aField)
{
// Get field type name
jstring fieldTypeName = 0;
- if (jobject fieldType = callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;"))
+ jclass fieldType = static_cast<jclass>(callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;"));
+ if (fieldType)
fieldTypeName = static_cast<jstring>(callJNIMethod<jobject>(fieldType, "getName", "()Ljava/lang/String;"));
if (!fieldTypeName)
fieldTypeName = env->NewStringUTF("<Unknown>");
m_typeClassName = JavaString(env, fieldTypeName);
m_type = javaTypeFromClassName(m_typeClassName.utf8());
+ env->DeleteLocalRef(fieldType);
+ env->DeleteLocalRef(fieldTypeName);
// Get field name
jstring fieldName = static_cast<jstring>(callJNIMethod<jobject>(aField, "getName", "()Ljava/lang/String;"));
if (!fieldName)
fieldName = env->NewStringUTF("<Unknown>");
m_name = JavaString(env, fieldName);
+ env->DeleteLocalRef(fieldName);
m_field = new JobjectWrapper(aField);
}
diff --git a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp
index 0d1a9f2..a731fe1 100644
--- a/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp
+++ b/Source/WebCore/bridge/jni/v8/JNIUtilityPrivate.cpp
@@ -107,7 +107,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
}
env->SetByteArrayRegion(static_cast<jbyteArray>(javaArray), i, 1, &bVal);
}
- } else if (!strcmp(javaClassName.data(), "[C")) {
+ } else if (!strcmp(javaClassName.data(), "[C")) {
// array of chars
javaArray = env->NewCharArray(length);
// Now iterate over each element and add to the array.
@@ -123,7 +123,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
}
env->SetCharArrayRegion(static_cast<jcharArray>(javaArray), i, 1, &cVal);
}
- } else if (!strcmp(javaClassName.data(), "[D")) {
+ } else if (!strcmp(javaClassName.data(), "[D")) {
// array of doubles
javaArray = env->NewDoubleArray(length);
// Now iterate over each element and add to the array.
@@ -135,7 +135,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
env->SetDoubleArrayRegion(static_cast<jdoubleArray>(javaArray), i, 1, &dVal);
}
}
- } else if (!strcmp(javaClassName.data(), "[F")) {
+ } else if (!strcmp(javaClassName.data(), "[F")) {
// array of floats
javaArray = env->NewFloatArray(length);
// Now iterate over each element and add to the array.
@@ -147,7 +147,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
env->SetFloatArrayRegion(static_cast<jfloatArray>(javaArray), i, 1, &fVal);
}
}
- } else if (!strcmp(javaClassName.data(), "[I")) {
+ } else if (!strcmp(javaClassName.data(), "[I")) {
// array of ints
javaArray = env->NewIntArray(length);
// Now iterate over each element and add to the array.
@@ -162,7 +162,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
}
env->SetIntArrayRegion(static_cast<jintArray>(javaArray), i, 1, &iVal);
}
- } else if (!strcmp(javaClassName.data(), "[J")) {
+ } else if (!strcmp(javaClassName.data(), "[J")) {
// array of longs
javaArray = env->NewLongArray(length);
// Now iterate over each element and add to the array.
@@ -177,7 +177,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
}
env->SetLongArrayRegion(static_cast<jlongArray>(javaArray), i, 1, &jVal);
}
- } else if (!strcmp(javaClassName.data(), "[S")) {
+ } else if (!strcmp(javaClassName.data(), "[S")) {
// array of shorts
javaArray = env->NewShortArray(length);
// Now iterate over each element and add to the array.
@@ -192,7 +192,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
}
env->SetShortArrayRegion(static_cast<jshortArray>(javaArray), i, 1, &sVal);
}
- } else if (!strcmp(javaClassName.data(), "[Z")) {
+ } else if (!strcmp(javaClassName.data(), "[Z")) {
// array of booleans
javaArray = env->NewBooleanArray(length);
// Now iterate over each element and add to the array.
@@ -210,6 +210,7 @@ JavaValue convertNPVariantToJavaValue(NPVariant value, const String& javaClass)
}
result.m_objectValue = adoptRef(new JavaInstanceJobject(javaArray));
+ env->DeleteLocalRef(javaArray);
}
break;
#endif // PLATFORM(ANDROID)
diff --git a/Source/WebCore/bridge/jni/v8/JavaFieldJobjectV8.cpp b/Source/WebCore/bridge/jni/v8/JavaFieldJobjectV8.cpp
index 0fe5837..fb23cf5 100644
--- a/Source/WebCore/bridge/jni/v8/JavaFieldJobjectV8.cpp
+++ b/Source/WebCore/bridge/jni/v8/JavaFieldJobjectV8.cpp
@@ -33,14 +33,23 @@ using namespace JSC::Bindings;
JavaFieldJobject::JavaFieldJobject(JNIEnv* env, jobject aField)
{
// Get field type
- jobject fieldType = callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;");
- jstring fieldTypeName = static_cast<jstring>(callJNIMethod<jobject>(fieldType, "getName", "()Ljava/lang/String;"));
+ jstring fieldTypeName = 0;
+ jclass fieldType = static_cast<jclass>(callJNIMethod<jobject>(aField, "getType", "()Ljava/lang/Class;"));
+ if (fieldType)
+ fieldTypeName = static_cast<jstring>(callJNIMethod<jobject>(fieldType, "getName", "()Ljava/lang/String;"));
+ if (!fieldTypeName)
+ fieldTypeName = env->NewStringUTF("<Unknown>");
m_typeClassName = JavaString(env, fieldTypeName);
m_type = javaTypeFromClassName(m_typeClassName.utf8());
+ env->DeleteLocalRef(fieldType);
+ env->DeleteLocalRef(fieldTypeName);
// Get field name
jstring fieldName = static_cast<jstring>(callJNIMethod<jobject>(aField, "getName", "()Ljava/lang/String;"));
+ if (!fieldName)
+ fieldName = env->NewStringUTF("<Unknown>");
m_name = JavaString(env, fieldName);
+ env->DeleteLocalRef(fieldName);
m_field = new JobjectWrapper(aField);
}
diff --git a/Source/WebCore/platform/graphics/android/FontAndroid.cpp b/Source/WebCore/platform/graphics/android/FontAndroid.cpp
index 31589e3..674938b 100644
--- a/Source/WebCore/platform/graphics/android/FontAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/FontAndroid.cpp
@@ -99,6 +99,7 @@ static bool setupForText(SkPaint* paint, GraphicsContext* gc,
SkLayerDrawLooper::LayerInfo info;
info.fPaintBits = SkLayerDrawLooper::kEntirePaint_Bits;
info.fColorMode = SkXfermode::kSrc_Mode;
+ info.fFlagsMask = SkPaint::kAllFlags;
// The paint is only valid until the looper receives another call to
// addLayer(). Therefore, we must cache certain state for later use.
diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
index e07c86f..bc07925 100644
--- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
+++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
@@ -473,7 +473,7 @@ double GLWebViewState::setupDrawing(IntRect& viewRect, SkRect& visibleRect,
glUseProgram(shader->program());
glUniform1i(shader->textureSampler(), 0);
shader->setViewRect(viewRect);
- shader->setViewport(visibleRect);
+ shader->setViewport(visibleRect, scale);
shader->setWebViewRect(webViewRect);
shader->setTitleBarHeight(titleBarHeight);
shader->setScreenClip(screenClip);
diff --git a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
index aa30035..40d25e4 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
@@ -693,6 +693,13 @@ bool GraphicsLayerAndroid::addAnimation(const KeyframeValueList& valueList,
const String& keyframesName,
double beginTime)
{
+ // For now, let webkit deals with the animations -- the current UI-side
+ // animation code has some annoying bugs, and we improved communication
+ // between webkit and UI enough that performance-wise it's not so much
+ // a problem to let webkit do everything.
+ // TODO: re-enable UI-side animations
+ return false;
+
if (!anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2)
return false;
diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
index bf5f760..536d228 100644
--- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
+++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp
@@ -235,6 +235,8 @@ void ShaderProgram::init()
glBufferData(GL_ARRAY_BUFFER, 2 * 4 * sizeof(GLfloat), coord, GL_STATIC_DRAW);
GLUtils::checkGlError("init");
+
+ memset(m_webViewMatrix, 0, sizeof(m_webViewMatrix));
}
void ShaderProgram::resetBlending()
@@ -262,13 +264,14 @@ void ShaderProgram::setBlendingState(bool enableBlending)
// Drawing
/////////////////////////////////////////////////////////////////////////////////////////
-void ShaderProgram::setViewport(SkRect& viewport)
+void ShaderProgram::setViewport(SkRect& viewport, float scale)
{
TransformationMatrix ortho;
GLUtils::setOrthographicMatrix(ortho, viewport.fLeft, viewport.fTop,
viewport.fRight, viewport.fBottom, -1000, 1000);
m_projectionMatrix = ortho;
m_viewport = viewport;
+ m_currentScale = scale;
}
void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrixHandle)
@@ -277,8 +280,29 @@ void ShaderProgram::setProjectionMatrix(SkRect& geometry, GLint projectionMatrix
translate.translate3d(geometry.fLeft, geometry.fTop, 0.0);
TransformationMatrix scale;
scale.scale3d(geometry.width(), geometry.height(), 1.0);
-
- TransformationMatrix total = m_projectionMatrix * translate * scale;
+ // Translate float* to TransformationMatrix
+ TransformationMatrix webViewTransformMatrix(
+ m_webViewMatrix[0], m_webViewMatrix[1], m_webViewMatrix[2], m_webViewMatrix[3],
+ m_webViewMatrix[4], m_webViewMatrix[5], m_webViewMatrix[6], m_webViewMatrix[7],
+ m_webViewMatrix[8], m_webViewMatrix[9], m_webViewMatrix[10], m_webViewMatrix[11],
+ m_webViewMatrix[12], m_webViewMatrix[13], m_webViewMatrix[14], m_webViewMatrix[15] );
+
+
+ TransformationMatrix reposition;
+ // After the webViewTranform, we need to reposition the rect to match our viewport.
+ reposition.translate3d(-m_webViewRect.x(), -m_webViewRect.y() - m_titleBarHeight, 0);
+ reposition.translate3d(m_viewport.fLeft * m_currentScale, m_viewport.fTop * m_currentScale, 0);
+
+ // Basically, the webViewTransformMatrix should apply on the screen resolution.
+ // So we start by doing the scale and translate to get each tile into screen coordinates.
+ // After applying the webViewTransformMatrix, b/c the way it currently set up
+ // for scroll and titlebar, we need to offset both of them.
+ // Finally, map everything back to (-1, 1) by using the m_projectionMatrix.
+ // TODO: Given that webViewTransformMatrix contains most of the tranformation
+ // information, we should be able to get rid of some parameter we got from
+ // Java side and simplify our code.
+ TransformationMatrix total =
+ m_projectionMatrix * reposition * webViewTransformMatrix * translate * scale;
GLfloat projectionMatrix[16];
GLUtils::toGLMatrix(projectionMatrix, total);
@@ -573,6 +597,12 @@ void ShaderProgram::drawVideoLayerQuad(const TransformationMatrix& drawMatrix,
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
+void ShaderProgram::setWebViewMatrix(float* matrix)
+{
+ if (matrix)
+ memcpy(m_webViewMatrix, matrix, sizeof(m_webViewMatrix));
+}
+
} // namespace WebCore
#endif // USE(ACCELERATED_COMPOSITING)
diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h
index d8447bf..f31eb91 100644
--- a/Source/WebCore/platform/graphics/android/ShaderProgram.h
+++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h
@@ -39,7 +39,7 @@ public:
int program() { return m_program; }
// Drawing
- void setViewport(SkRect& viewport);
+ void setViewport(SkRect& viewport, float scale);
float zValue(const TransformationMatrix& drawMatrix, float w, float h);
// For drawQuad and drawLayerQuad, they can handle 3 cases for now:
@@ -88,6 +88,7 @@ public:
contrast = MAX_CONTRAST;
m_contrast = contrast;
}
+ void setWebViewMatrix(float* matrix);
private:
GLuint loadShader(GLenum shaderType, const char* pSource);
@@ -149,6 +150,9 @@ private:
// attribs
GLint m_hPosition;
GLint m_hVideoPosition;
+
+ float m_webViewMatrix[16];
+ float m_currentScale;
};
} // namespace WebCore
diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.cpp b/Source/WebKit/android/WebCoreSupport/WebCache.cpp
index a15bf7f..3c49430 100644
--- a/Source/WebKit/android/WebCoreSupport/WebCache.cpp
+++ b/Source/WebKit/android/WebCoreSupport/WebCache.cpp
@@ -134,6 +134,18 @@ void WebCache::clear()
thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::clearImpl));
}
+void WebCache::closeIdleConnections()
+{
+ base::Thread* thread = WebUrlLoaderClient::ioThread();
+ if (thread)
+ thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this, &WebCache::closeIdleImpl));
+}
+
+void WebCache::closeIdleImpl()
+{
+ m_cache->CloseIdleConnections();
+}
+
void WebCache::clearImpl()
{
if (m_isClearInProgress)
diff --git a/Source/WebKit/android/WebCoreSupport/WebCache.h b/Source/WebKit/android/WebCoreSupport/WebCache.h
index 7149fcc..c3b623d 100644
--- a/Source/WebKit/android/WebCoreSupport/WebCache.h
+++ b/Source/WebKit/android/WebCoreSupport/WebCache.h
@@ -47,6 +47,8 @@ public:
net::HostResolver* hostResolver() { return m_hostResolver.get(); }
net::HttpCache* cache() { return m_cache.get(); }
net::ProxyConfigServiceAndroid* proxy() { return m_proxyConfigService; }
+ void closeIdleConnections();
+
private:
WebCache(bool isPrivateBrowsing);
@@ -56,6 +58,9 @@ private:
void doomAllEntries(int);
void onClearDone(int);
+ // For closeIdleConnections
+ void closeIdleImpl();
+
// For getEntry()
void getEntryImpl();
void openEntry(int);
diff --git a/Source/WebKit/android/jni/PictureSet.cpp b/Source/WebKit/android/jni/PictureSet.cpp
index bf61c3e..3c62205 100644
--- a/Source/WebKit/android/jni/PictureSet.cpp
+++ b/Source/WebKit/android/jni/PictureSet.cpp
@@ -43,14 +43,18 @@
#define MAX_ADDITIONAL_AREA 0.65
#define MAX_ADDITIONAL_PICTURES 32
-#include <wtf/CurrentTime.h>
+#define BUCKET_SIZE 256
-//#define DEBUG
-#ifdef DEBUG
+#include <wtf/CurrentTime.h>
#include <cutils/log.h>
#include <wtf/text/CString.h>
+#undef XLOGC
+#define XLOGC(...) android_printLog(ANDROID_LOG_DEBUG, "PictureSet", __VA_ARGS__)
+
+#ifdef DEBUG
+
#undef XLOG
#define XLOG(...) android_printLog(ANDROID_LOG_DEBUG, "PictureSet", __VA_ARGS__)
@@ -91,6 +95,8 @@ PictureSet::PictureSet(SkPicture* picture)
mWidth = picture->width();
mHeight = picture->height();
mBaseArea = mWidth * mHeight;
+#ifdef FAST_PICTURESET
+#else
Pictures pictureAndBounds;
pictureAndBounds.mPicture = picture;
SkSafeRef(pictureAndBounds.mPicture);
@@ -101,6 +107,7 @@ PictureSet::PictureSet(SkPicture* picture)
pictureAndBounds.mElapsed = 0;
pictureAndBounds.mWroteElapsed = false;
mPictures.append(pictureAndBounds);
+#endif // FAST_PICTURESET
}
PictureSet::~PictureSet()
@@ -108,6 +115,8 @@ PictureSet::~PictureSet()
clear();
}
+#ifdef FAST_PICTURESET
+#else
void PictureSet::add(const Pictures* temp)
{
Pictures pictureAndBounds = *temp;
@@ -115,6 +124,232 @@ void PictureSet::add(const Pictures* temp)
pictureAndBounds.mWroteElapsed = false;
mPictures.append(pictureAndBounds);
}
+#endif // FAST_PICTURESET
+
+void PictureSet::add(const SkRegion& area, SkPicture* picture,
+ uint32_t elapsed, bool split)
+{
+ if (area.isRect()) {
+#ifdef FAST_PICTURESET
+ splitAdd(area.getBounds());
+#else
+ add(area, picture, elapsed, split, false);
+#endif // FAST_PICTURESET
+ } else {
+ SkRegion::Iterator cliperator(area);
+ while (!cliperator.done()) {
+ SkIRect ir = cliperator.rect();
+#ifdef FAST_PICTURESET
+ splitAdd(ir);
+#else
+ SkRegion newArea;
+ newArea.setRect(ir);
+ add(newArea, picture, elapsed, split, false);
+#endif // FAST_PICTURESET
+ cliperator.next();
+ }
+ }
+}
+
+#ifdef FAST_PICTURESET
+
+Bucket* PictureSet::getBucket(int x, int y)
+{
+ BucketPosition position(x+1, y+1);
+ if (!mBuckets.contains(position)) {
+ Bucket* bucket = new Bucket();
+ mBuckets.add(position, bucket);
+ }
+ return mBuckets.get(position);
+}
+
+void PictureSet::displayBucket(Bucket* bucket)
+{
+ BucketPicture* first = bucket->begin();
+ BucketPicture* last = bucket->end();
+ for (BucketPicture* current = first; current != last; current++) {
+ XLOGC("- in %x, bucketPicture %d,%d,%d,%d - %dx%d, picture: %x, base: %x",
+ bucket,
+ current->mArea.fLeft,
+ current->mArea.fTop,
+ current->mArea.fRight,
+ current->mArea.fBottom,
+ current->mArea.width(),
+ current->mArea.height(),
+ current->mPicture,
+ current->mBase);
+ }
+}
+
+void PictureSet::displayBuckets()
+{
+ XLOGC("\n\n****** DISPLAY BUCKETS ON PictureSet %x ******", this);
+ for (BucketMap::iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
+ XLOGC("\n*** Bucket %x for %d, %d", iter->second, iter->first.first, iter->first.second);
+ displayBucket(iter->second);
+ }
+ XLOGC("\n****** END OF DISPLAY BUCKETS ******\n\n");
+}
+
+// When we receive an inval in a Bucket, we try to see if we intersect with
+// existing invals/pictures in the Bucket.
+void PictureSet::addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect)
+{
+ bool resetBase = false;
+
+ SkIRect totalArea = rect;
+ BucketPicture* first = bucket->begin();
+ BucketPicture* last = bucket->end();
+
+ // If the inval covers a large area of the base inval, let's repaint the
+ // entire bucket.
+ if (rect.width() * rect.height() > MAX_ADDITIONAL_AREA * BUCKET_SIZE * BUCKET_SIZE)
+ resetBase = true;
+
+ // let's gather all the BucketPicture intersecting with the new invalidated
+ // area, collect their area and remove their picture
+ for (BucketPicture* current = first; current != last; current++) {
+ bool remove = resetBase;
+ bool intersect = false;
+
+ if (!remove)
+ intersect = SkIRect::Intersects(current->mArea, rect);
+ // If the current picture is not a base, and we intersect, remove it
+ if (!remove && !current->mBase && intersect)
+ remove = true;
+ // If the current picture is a base, check if the new inval completely
+ // contains the base, and if so remove it.
+ if (!remove && current->mBase && rect.contains(current->mArea))
+ remove = true;
+ // If the current picture is a base and it intersects,
+ // also check that it fully covers the bucket -- otherwise,
+ // let's aggregate it with the new inval.
+ if (!remove && current->mBase && intersect
+ && (current->mArea.width() < BUCKET_SIZE || current->mArea.height() < BUCKET_SIZE)) {
+ remove = true;
+ }
+
+ if (remove) {
+ totalArea.join(current->mArea);
+ current->mBase = false;
+ current->mArea.setEmpty();
+ SkSafeUnref(current->mPicture);
+ current->mPicture = 0;
+ }
+ }
+
+ // Now, let's add the new BucketPicture to the list, with the correct
+ // area that needs to be repainted
+ SkRegion region;
+ SkIRect area = totalArea;
+ area.offset(dx, dy);
+ BucketPicture picture = { 0, totalArea, area, false };
+
+ bucket->append(picture);
+
+ first = bucket->begin();
+ last = bucket->end();
+
+ // let's do a pass to collapse out empty areas
+ BucketPicture* writer = first;
+ for (BucketPicture* current = first; current != last; current++) {
+ if (current && current->mArea.isEmpty())
+ continue;
+ *writer++ = *current;
+ }
+
+ bucket->shrink(writer - first);
+
+ // let's recompute the bases
+ first = bucket->begin();
+ last = bucket->end();
+ SkRegion drawn;
+ drawn.setEmpty();
+ for (BucketPicture* current = first; current != last; current++) {
+ if (drawn.contains(current->mArea) == false) {
+ current->mBase = true;
+ }
+ drawn.op(current->mArea, SkRegion::kUnion_Op);
+ }
+}
+
+void PictureSet::gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect)
+{
+ int maxSize = BUCKET_SIZE;
+
+ int x = rect.fLeft;
+ int y = rect.fTop;
+ int firstTileX = rect.fLeft / maxSize;
+ int firstTileY = rect.fTop / maxSize;
+ int lastTileX = rect.fRight / maxSize;
+ int lastTileY = rect.fBottom / maxSize;
+
+ for (int i = firstTileX; i <= lastTileX; i++) {
+ for (int j = firstTileY; j <= lastTileY; j++) {
+ Bucket* bucket = getBucket(i, j);
+ XLOG("gather bucket %x for %d, %d", bucket, i+1, j+1);
+ list.append(bucket);
+ }
+ }
+}
+
+// When we receive a new inval rect, we first find the Buckets that intersect
+// with it; then we split the original inval into a serie of invals (one for
+// each Bucket we intersect with). We then send that inval to the Bucket.
+void PictureSet::splitAdd(const SkIRect& rect)
+{
+ XLOG("\n--- splitAdd for rect %d, %d, %d, %d (%d x %d)",
+ rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+ rect.width(), rect.height());
+
+ int maxSize = BUCKET_SIZE;
+
+ // TODO: reuse gatherBucketsForArea() (change Bucket to be a class)
+ int x = rect.fLeft;
+ int y = rect.fTop;
+ int firstTileX = rect.fLeft / maxSize;
+ int firstTileY = rect.fTop / maxSize;
+ int lastTileX = rect.fRight / maxSize;
+ int lastTileY = rect.fBottom / maxSize;
+
+ XLOG("--- firstTile(%d, %d) lastTile(%d, %d)",
+ firstTileX, firstTileY,
+ lastTileX, lastTileY);
+
+ for (int i = firstTileX; i <= lastTileX; i++) {
+ for (int j = firstTileY; j <= lastTileY; j++) {
+ Bucket* bucket = getBucket(i, j);
+ SkIRect newRect;
+ int deltaX = i * maxSize;
+ int deltaY = j * maxSize;
+ int left, top, right, bottom;
+ if (i == firstTileX)
+ left = rect.fLeft;
+ else
+ left = 0;
+ if (j == firstTileY)
+ top = rect.fTop;
+ else
+ top = 0;
+ if (i == lastTileX)
+ right = rect.fRight % maxSize;
+ else
+ right = maxSize;
+ if (j == lastTileY)
+ bottom = rect.fBottom % maxSize;
+ else
+ bottom = maxSize;
+
+ newRect.set(left, top, right, bottom);
+ addToBucket(bucket, deltaX, deltaY, newRect);
+ mUpdatedBuckets.append(bucket);
+ }
+ }
+
+ XLOG("--- splitAdd DONE\n");
+}
+
+#endif // FAST_PICTURESET
// This function is used to maintain the list of Pictures.
// Pictures contain an SkPicture covering a specific area; some
@@ -139,6 +374,8 @@ void PictureSet::add(const Pictures* temp)
// needing a full repaint
// - we limit the number of pictures to 32 -- above that, we do the same
// things (deleting additional pictures + full repaint of base pictures)
+#ifdef FAST_PICTURESET
+#else
void PictureSet::add(const SkRegion& area, SkPicture* picture,
uint32_t elapsed, bool split, bool empty)
{
@@ -195,7 +432,6 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture,
working->mArea.setEmpty();
SkSafeUnref(working->mPicture);
working->mPicture = 0;
-
}
}
@@ -205,6 +441,10 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture,
collect.setRect(totalArea);
Pictures pictureAndBounds = {collect, 0, collect.getBounds(),
elapsed, split, false, false, empty};
+
+ if (mPictures.size() == 0)
+ checkForNewBases = true;
+
mPictures.append(pictureAndBounds);
mAdditionalArea += totalArea.width() * totalArea.height();
last = mPictures.end();
@@ -293,6 +533,7 @@ void PictureSet::add(const SkRegion& area, SkPicture* picture,
}
}
}
+#endif // FAST_PICTURESET
void PictureSet::checkDimensions(int width, int height, SkRegion* inval)
{
@@ -315,17 +556,72 @@ void PictureSet::checkDimensions(int width, int height, SkRegion* inval)
void PictureSet::clear()
{
DBG_SET_LOG("");
+#ifdef FAST_PICTURESET
+ for (BucketMap::iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
+ Bucket* bucket = iter->second;
+ BucketPicture* first = bucket->begin();
+ BucketPicture* last = bucket->end();
+ for (BucketPicture* current = first; current != last; current++) {
+ SkSafeUnref(current->mPicture);
+ current->mPicture = 0;
+ }
+ bucket->clear();
+ }
+ mBuckets.clear();
+#else
Pictures* last = mPictures.end();
for (Pictures* working = mPictures.begin(); working != last; working++) {
working->mArea.setEmpty();
SkSafeUnref(working->mPicture);
}
mPictures.clear();
+#endif // FAST_PICTURESET
mWidth = mHeight = 0;
}
bool PictureSet::draw(SkCanvas* canvas)
{
+#ifdef FAST_PICTURESET
+ XLOG("PictureSet %x draw on canvas %x", this, canvas);
+ SkRect bounds;
+ if (canvas->getClipBounds(&bounds) == false)
+ return false;
+ SkIRect irect;
+ bounds.roundOut(&irect);
+
+ WTF::Vector<Bucket*> list;
+ gatherBucketsForArea(list, irect);
+
+ XLOG("PictureSet draw on canvas %x, we have %d buckets", canvas, list.size());
+ for (unsigned int i = 0; i < list.size(); i++) {
+ Bucket* bucket = list[i];
+ XLOG("We paint using bucket %x with %d pictures", bucket, bucket->size());
+ for (unsigned int j = 0; j < bucket->size(); j++) {
+ BucketPicture& picture = bucket->at(j);
+ if (!picture.mPicture)
+ continue;
+ int saved = canvas->save();
+ SkRect pathBounds;
+ pathBounds.set(picture.mRealArea);
+ XLOG("[%d/%d] draw on canvas with clip %d, %d, %d, %d - %d x %d",
+ j, bucket->size(),
+ picture.mRealArea.fLeft,
+ picture.mRealArea.fTop,
+ picture.mRealArea.fRight,
+ picture.mRealArea.fBottom,
+ picture.mRealArea.width(),
+ picture.mRealArea.height());
+ canvas->clipRect(pathBounds);
+ canvas->translate(pathBounds.fLeft, pathBounds.fTop);
+ canvas->save();
+ canvas->drawPicture(*picture.mPicture);
+ canvas->restoreToCount(saved);
+ }
+ }
+ return false;
+
+#else
+
validate(__FUNCTION__);
Pictures* first = mPictures.begin();
Pictures* last = mPictures.end();
@@ -410,6 +706,7 @@ bool PictureSet::draw(SkCanvas* canvas)
}
// dump(__FUNCTION__);
return maxElapsed >= MAX_DRAW_TIME;
+#endif // FAST_PICTURESET
}
void PictureSet::dump(const char* label) const
@@ -548,17 +845,68 @@ bool PictureSet::emptyPicture(SkPicture* picture) const
bool PictureSet::isEmpty() const
{
+#ifdef FAST_PICTURESET
+ // For now, just assume the pictureset is *not* empty
+ // if the hashmap contains something
+ for (BucketMap::const_iterator iter = mBuckets.begin(); iter != mBuckets.end(); ++iter) {
+ if (iter->second->size() > 0)
+ return false;
+ }
+ return true;
+#else
const Pictures* last = mPictures.end();
for (const Pictures* working = mPictures.begin(); working != last; working++) {
if (!working->mEmpty)
return false;
}
return true;
+#endif // FAST_PICTURESET
}
+void PictureSet::set(const PictureSet& src)
+{
+ DBG_SET_LOGD("start %p src=%p", this, &src);
+ clear();
+ mWidth = src.mWidth;
+ mHeight = src.mHeight;
+#ifdef FAST_PICTURESET
+ XLOG("\n--- set picture ---");
+ for (BucketMap::const_iterator iter = src.mBuckets.begin();
+ iter != src.mBuckets.end(); ++iter) {
+ Bucket* sourceBucket = iter->second;
+ Bucket* targetBucket = getBucket(iter->first.first-1, iter->first.second-1);
+ BucketPicture* first = sourceBucket->begin();
+ BucketPicture* last = sourceBucket->end();
+ XLOG("set from bucket %x (%d, %d), %d pictures", sourceBucket,
+ iter->first.first, iter->first.second, sourceBucket->size());
+ for (BucketPicture* current = first; current != last; current++) {
+ XLOG("set picture %x from bucket %x in bucket %x (%d, %d)",
+ current->mPicture, sourceBucket, targetBucket,
+ iter->first.first, iter->first.second);
+ SkSafeRef(current->mPicture);
+ BucketPicture picture = { current->mPicture, current->mArea,
+ current->mRealArea, current->mBase };
+ targetBucket->append(picture);
+ }
+ }
+ XLOG("--- DONE set picture ---\n");
+#else
+ const Pictures* last = src.mPictures.end();
+ for (const Pictures* working = src.mPictures.begin(); working != last; working++)
+ add(working);
+ // dump(__FUNCTION__);
+ validate(__FUNCTION__);
+ DBG_SET_LOG("end");
+#endif // FAST_PICTURESET
+}
+
+#ifdef FAST_PICTURESET
+#else
+
bool PictureSet::reuseSubdivided(const SkRegion& inval)
{
validate(__FUNCTION__);
+
if (inval.isComplex())
return false;
Pictures* working, * last = mPictures.end();
@@ -589,20 +937,6 @@ bool PictureSet::reuseSubdivided(const SkRegion& inval)
return true;
}
-void PictureSet::set(const PictureSet& src)
-{
- DBG_SET_LOGD("start %p src=%p", this, &src);
- clear();
- mWidth = src.mWidth;
- mHeight = src.mHeight;
- const Pictures* last = src.mPictures.end();
- for (const Pictures* working = src.mPictures.begin(); working != last; working++)
- add(working);
- // dump(__FUNCTION__);
- validate(__FUNCTION__);
- DBG_SET_LOG("end");
-}
-
void PictureSet::setDrawTimes(const PictureSet& src)
{
validate(__FUNCTION__);
@@ -719,8 +1053,13 @@ void PictureSet::split(PictureSet* out) const
out->dump("split-out");
}
+#endif // FAST_PICTURESET
+
bool PictureSet::validate(const char* funct) const
{
+#ifdef FAST_PICTURESET
+ return true;
+#else
bool valid = true;
#if PICTURE_SET_VALIDATE
SkRegion all;
@@ -778,6 +1117,7 @@ bool PictureSet::validate(const char* funct) const
;
#endif
return valid;
+#endif // FAST_PICTURESET
}
} /* namespace android */
diff --git a/Source/WebKit/android/jni/PictureSet.h b/Source/WebKit/android/jni/PictureSet.h
index 647d177..1ca4580 100644
--- a/Source/WebKit/android/jni/PictureSet.h
+++ b/Source/WebKit/android/jni/PictureSet.h
@@ -43,6 +43,9 @@
#include "jni.h"
#include "SkRegion.h"
#include <wtf/Vector.h>
+#include <wtf/HashMap.h>
+
+#define FAST_PICTURESET // use a hierarchy of pictures
class SkCanvas;
class SkPicture;
@@ -50,32 +53,39 @@ class SkIRect;
namespace android {
+#ifdef FAST_PICTURESET
+ struct BucketPicture {
+ SkPicture* mPicture;
+ SkIRect mArea;
+ SkIRect mRealArea;
+ bool mBase;
+ };
+
+ typedef std::pair<int, int> BucketPosition;
+ typedef WTF::Vector<BucketPicture> Bucket;
+ typedef WTF::HashMap<BucketPosition , Bucket* > BucketMap;
+#endif
+
class PictureSet {
public:
PictureSet();
PictureSet(const PictureSet& src) { set(src); }
PictureSet(SkPicture* picture);
virtual ~PictureSet();
+
+#ifdef FAST_PICTURESET
+ void displayBucket(Bucket* bucket);
+ void displayBuckets();
+ WTF::Vector<Bucket*>* bucketsToUpdate() { return &mUpdatedBuckets; }
+ Bucket* getBucket(int x, int y);
+ void addToBucket(Bucket* bucket, int dx, int dy, SkIRect& rect);
+ void gatherBucketsForArea(WTF::Vector<Bucket*>& list, const SkIRect& rect);
+ void splitAdd(const SkIRect& rect);
+#endif
+
void add(const SkRegion& area, SkPicture* picture,
- uint32_t elapsed, bool split)
- {
- if (area.isRect()) {
- add(area, picture, elapsed, split, false);
- } else {
- SkRegion::Iterator cliperator(area);
- while (!cliperator.done()) {
- SkIRect ir = cliperator.rect();
- SkRegion newArea;
- newArea.setRect(ir);
- add(newArea, picture, elapsed, split, false);
- cliperator.next();
- }
- }
- }
- void add(const SkRegion& area, SkPicture* picture,
- uint32_t elapsed, bool split, bool empty);
- const SkIRect& bounds(size_t i) const {
- return mPictures[i].mArea.getBounds(); }
+ uint32_t elapsed, bool split);
+
// Update mWidth/mHeight, and adds any additional inval region
void checkDimensions(int width, int height, SkRegion* inval);
void clear();
@@ -83,18 +93,30 @@ namespace android {
static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic);
int height() const { return mHeight; }
bool isEmpty() const; // returns true if empty or only trivial content
- bool reuseSubdivided(const SkRegion& );
void set(const PictureSet& );
- void setDrawTimes(const PictureSet& );
+
+#ifdef FAST_PICTURESET
+#else
+ void add(const SkRegion& area, SkPicture* picture,
+ uint32_t elapsed, bool split, bool empty);
+ const SkIRect& bounds(size_t i) const {
+ return mPictures[i].mArea.getBounds(); }
+ bool reuseSubdivided(const SkRegion& );
void setPicture(size_t i, SkPicture* p);
+ void setDrawTimes(const PictureSet& );
size_t size() const { return mPictures.size(); }
void split(PictureSet* result) const;
bool upToDate(size_t i) const { return mPictures[i].mPicture != NULL; }
+#endif
int width() const { return mWidth; }
void dump(const char* label) const;
bool validate(const char* label) const;
private:
bool emptyPicture(SkPicture* ) const; // true if no text, images, paths
+#ifdef FAST_PICTURESET
+ BucketMap mBuckets;
+ WTF::Vector<Bucket*> mUpdatedBuckets;
+#else
struct Pictures {
SkRegion mArea;
SkPicture* mPicture;
@@ -105,10 +127,11 @@ namespace android {
bool mBase : 8; // true if nothing is drawn underneath this
bool mEmpty : 8; // true if the picture only draws white
};
- float mBaseArea;
- float mAdditionalArea;
void add(const Pictures* temp);
WTF::Vector<Pictures> mPictures;
+#endif
+ float mBaseArea;
+ float mAdditionalArea;
int mHeight;
int mWidth;
};
diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp
index 5bc7f48..9b5a6fa 100644
--- a/Source/WebKit/android/jni/WebViewCore.cpp
+++ b/Source/WebKit/android/jni/WebViewCore.cpp
@@ -113,6 +113,7 @@
#include "SkUtils.h"
#include "Text.h"
#include "TypingCommand.h"
+#include "WebCache.h"
#include "WebCoreFrameBridge.h"
#include "WebFrameView.h"
#include "WindowsKeyboardCodes.h"
@@ -888,6 +889,22 @@ SkPicture* WebViewCore::rebuildPicture(const SkIRect& inval)
void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
{
WebCore::FrameView* view = m_mainFrame->view();
+
+#ifdef FAST_PICTURESET
+ WTF::Vector<Bucket*>* buckets = pictureSet->bucketsToUpdate();
+
+ for (unsigned int i = 0; i < buckets->size(); i++) {
+ Bucket* bucket = (*buckets)[i];
+ for (unsigned int j = 0; j < bucket->size(); j++) {
+ BucketPicture& bucketPicture = (*bucket)[j];
+ const SkIRect& inval = bucketPicture.mRealArea;
+ SkPicture* picture = rebuildPicture(inval);
+ SkSafeUnref(bucketPicture.mPicture);
+ bucketPicture.mPicture = picture;
+ }
+ }
+ buckets->clear();
+#else
size_t size = pictureSet->size();
for (size_t index = 0; index < size; index++) {
if (pictureSet->upToDate(index))
@@ -897,7 +914,9 @@ void WebViewCore::rebuildPictureSet(PictureSet* pictureSet)
inval.fLeft, inval.fTop, inval.width(), inval.height());
pictureSet->setPicture(index, rebuildPicture(inval));
}
+
pictureSet->validate(__FUNCTION__);
+#endif
}
BaseLayerAndroid* WebViewCore::createBaseLayer()
@@ -973,11 +992,14 @@ BaseLayerAndroid* WebViewCore::recordContent(SkRegion* region, SkIPoint* point)
void WebViewCore::splitContent(PictureSet* content)
{
+#ifdef FAST_PICTURESET
+#else
bool layoutSucceeded = layoutIfNeededRecursive(m_mainFrame);
LOG_ASSERT(layoutSucceeded, "Can never be called recursively");
content->split(&m_content);
rebuildPictureSet(&m_content);
content->set(m_content);
+#endif // FAST_PICTURESET
}
void WebViewCore::scrollTo(int x, int y, bool animate)
@@ -4595,6 +4617,14 @@ static void AutoFillForm(JNIEnv* env, jobject obj, jint queryId)
#endif
}
+static void CloseIdleConnections(JNIEnv* env, jobject obj)
+{
+#if USE(CHROME_NETWORK_STACK)
+ WebCache::get(true)->closeIdleConnections();
+ WebCache::get(false)->closeIdleConnections();
+#endif
+}
+
static void ScrollRenderLayer(JNIEnv* env, jobject obj, jint layer, jobject jRect)
{
SkRect rect;
@@ -4714,6 +4744,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
(void*) AutoFillForm },
{ "nativeScrollLayer", "(ILandroid/graphics/Rect;)V",
(void*) ScrollRenderLayer },
+ { "nativeCloseIdleConnections", "()V",
+ (void*) CloseIdleConnections },
};
int registerWebViewCore(JNIEnv* env)
diff --git a/Source/WebKit/android/nav/SelectText.cpp b/Source/WebKit/android/nav/SelectText.cpp
index c56c53c..7d18d5d 100644
--- a/Source/WebKit/android/nav/SelectText.cpp
+++ b/Source/WebKit/android/nav/SelectText.cpp
@@ -1475,6 +1475,16 @@ static void addEnd(SkRegion* diff, const SkIRect& rect)
diff->op(bounds, SkRegion::kUnion_Op);
}
+void SelectText::getSelectionRegion(const IntRect& vis, SkRegion *region)
+{
+ 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);
+}
+
void SelectText::drawSelectionRegion(SkCanvas* canvas, IntRect* inval)
{
if (!m_picture)
diff --git a/Source/WebKit/android/nav/SelectText.h b/Source/WebKit/android/nav/SelectText.h
index de577ac..272cfd1 100644
--- a/Source/WebKit/android/nav/SelectText.h
+++ b/Source/WebKit/android/nav/SelectText.h
@@ -57,6 +57,7 @@ public:
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);
public:
float m_inverseScale; // inverse scale, x, y used for drawing select path
int m_selectX;
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index 945a785..8835f70 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -1482,6 +1482,11 @@ void setBaseLayer(BaseLayerAndroid* layer, SkRegion& inval, bool showVisualIndic
root->setRootLayer(compositeRoot());
}
+void getTextSelectionRegion(SkRegion *region)
+{
+ m_selectText.getSelectionRegion(getVisibleRect(), region);
+}
+
void replaceBaseContent(PictureSet* set)
{
if (!m_baseLayer)
@@ -1576,6 +1581,7 @@ class GLDrawFunctor : Functor {
WebCore::IntRect clip(info->clipLeft, info->clipTop,
info->clipRight - info->clipLeft,
info->clipBottom - info->clipTop);
+ TilesManager::instance()->shader()->setWebViewMatrix(info->transform);
bool retVal = (*wvInstance.*funcPtr)(localViewRect, &inval, webViewRect, titlebarHeight, clip, scale, extras);
if (retVal) {
@@ -1910,6 +1916,14 @@ static void nativeSetBaseLayer(JNIEnv *env, jobject obj, jint layer, jobject inv
registerPageSwapCallback);
}
+static void nativeGetTextSelectionRegion(JNIEnv *env, jobject obj, jobject region)
+{
+ if (!region)
+ return;
+ SkRegion* nregion = GraphicsJNI::getNativeRegion(env, region);
+ GET_NATIVE_VIEW(env, obj)->getTextSelectionRegion(nregion);
+}
+
static BaseLayerAndroid* nativeGetBaseLayer(JNIEnv *env, jobject obj)
{
return GET_NATIVE_VIEW(env, obj)->getBaseLayer();
@@ -2794,6 +2808,8 @@ static JNINativeMethod gJavaWebViewMethods[] = {
(void*) nativeSetHeightCanMeasure },
{ "nativeSetBaseLayer", "(ILandroid/graphics/Region;ZZZ)V",
(void*) nativeSetBaseLayer },
+ { "nativeGetTextSelectionRegion", "(Landroid/graphics/Region;)V",
+ (void*) nativeGetTextSelectionRegion },
{ "nativeGetBaseLayer", "()I",
(void*) nativeGetBaseLayer },
{ "nativeReplaceBaseContent", "(I)V",