diff options
Diffstat (limited to 'Source')
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", |