diff options
Diffstat (limited to 'Source/WebKit/android/jni')
-rw-r--r-- | Source/WebKit/android/jni/GeolocationServiceBridge.cpp | 242 | ||||
-rw-r--r-- | Source/WebKit/android/jni/GeolocationServiceBridge.h | 75 | ||||
-rwxr-xr-x | Source/WebKit/android/jni/MockGeolocation.cpp | 68 | ||||
-rw-r--r-- | Source/WebKit/android/jni/PicturePile.cpp | 225 | ||||
-rw-r--r-- | Source/WebKit/android/jni/PicturePile.h | 38 | ||||
-rw-r--r-- | Source/WebKit/android/jni/ViewStateSerializer.cpp | 65 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebCoreFrameBridge.cpp | 25 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebCoreFrameBridge.h | 2 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebFrameView.cpp | 1 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebHistory.cpp | 65 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebSettings.cpp | 6 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebStorage.cpp | 10 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.cpp | 376 | ||||
-rw-r--r-- | Source/WebKit/android/jni/WebViewCore.h | 39 |
14 files changed, 873 insertions, 364 deletions
diff --git a/Source/WebKit/android/jni/GeolocationServiceBridge.cpp b/Source/WebKit/android/jni/GeolocationServiceBridge.cpp new file mode 100644 index 0000000..056c788 --- /dev/null +++ b/Source/WebKit/android/jni/GeolocationServiceBridge.cpp @@ -0,0 +1,242 @@ +/* + * 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 "GeolocationServiceBridge.h" + +#include "WebViewCore.h" + +#include <GeolocationError.h> +#include <GeolocationPosition.h> +#include <JNIHelp.h> + +using JSC::Bindings::getJNIEnv; +using WebCore::GeolocationError; +using WebCore::GeolocationPosition; + +namespace android { + +static const char* javaGeolocationServiceClassName = "android/webkit/GeolocationService"; +enum javaGeolocationServiceClassMethods { + GeolocationServiceMethodInit = 0, + GeolocationServiceMethodStart, + GeolocationServiceMethodStop, + GeolocationServiceMethodSetEnableGps, + GeolocationServiceMethodCount, +}; +static jmethodID javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodCount]; + +static const JNINativeMethod javaGeolocationServiceClassNativeMethods[] = { + { "nativeNewLocationAvailable", "(JLandroid/location/Location;)V", + (void*) GeolocationServiceBridge::newLocationAvailable }, + { "nativeNewErrorAvailable", "(JLjava/lang/String;)V", + (void*) GeolocationServiceBridge::newErrorAvailable } +}; + +static const char *javaLocationClassName = "android/location/Location"; +enum javaLocationClassMethods { + LocationMethodGetLatitude = 0, + LocationMethodGetLongitude, + LocationMethodHasAltitude, + LocationMethodGetAltitude, + LocationMethodHasAccuracy, + LocationMethodGetAccuracy, + LocationMethodHasBearing, + LocationMethodGetBearing, + LocationMethodHasSpeed, + LocationMethodGetSpeed, + LocationMethodGetTime, + LocationMethodCount, +}; +static jmethodID javaLocationClassMethodIDs[LocationMethodCount]; + +GeolocationServiceBridge::GeolocationServiceBridge(Listener* listener, WebViewCore* webViewCore) + : m_listener(listener) + , m_javaGeolocationServiceObject(0) +{ + ASSERT(m_listener); + startJavaImplementation(webViewCore); +} + +GeolocationServiceBridge::~GeolocationServiceBridge() +{ + stop(); + stopJavaImplementation(); +} + +bool GeolocationServiceBridge::start() +{ + if (!m_javaGeolocationServiceObject) + return false; + return getJNIEnv()->CallBooleanMethod(m_javaGeolocationServiceObject, + javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStart]); +} + +void GeolocationServiceBridge::stop() +{ + if (!m_javaGeolocationServiceObject) + return; + getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject, + javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStop]); +} + +void GeolocationServiceBridge::setEnableGps(bool enable) +{ + if (!m_javaGeolocationServiceObject) + return; + getJNIEnv()->CallVoidMethod(m_javaGeolocationServiceObject, + javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodSetEnableGps], + enable); +} + +void GeolocationServiceBridge::newLocationAvailable(JNIEnv* env, jclass, jlong nativeObject, jobject location) +{ + ASSERT(nativeObject); + ASSERT(location); + GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject); + object->m_listener->newPositionAvailable(toGeolocationPosition(env, location)); +} + +void GeolocationServiceBridge::newErrorAvailable(JNIEnv* env, jclass, jlong nativeObject, jstring message) +{ + GeolocationServiceBridge* object = reinterpret_cast<GeolocationServiceBridge*>(nativeObject); + RefPtr<GeolocationError> error = GeolocationError::create(GeolocationError::PositionUnavailable, jstringToWtfString(env, message)); + object->m_listener->newErrorAvailable(error.release()); +} + +PassRefPtr<GeolocationPosition> GeolocationServiceBridge::toGeolocationPosition(JNIEnv *env, const jobject &location) +{ + // Altitude is optional and may not be supplied. + bool hasAltitude = + env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasAltitude]); + double Altitude = + hasAltitude ? + env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetAltitude]) : + 0.0; + // Accuracy is required, but is not supplied by the emulator. + double Accuracy = + env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasAccuracy]) ? + env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetAccuracy]) : + 0.0; + // heading is optional and may not be supplied. + bool hasHeading = + env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasBearing]); + double heading = + hasHeading ? + env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetBearing]) : + 0.0; + // speed is optional and may not be supplied. + bool hasSpeed = + env->CallBooleanMethod(location, javaLocationClassMethodIDs[LocationMethodHasSpeed]); + double speed = + hasSpeed ? + env->CallFloatMethod(location, javaLocationClassMethodIDs[LocationMethodGetSpeed]) : + 0.0; + + return GeolocationPosition::create( + env->CallLongMethod(location, javaLocationClassMethodIDs[LocationMethodGetTime]) / 1000.0, + env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLatitude]), + env->CallDoubleMethod(location, javaLocationClassMethodIDs[LocationMethodGetLongitude]), + Accuracy, + hasAltitude, Altitude, + false, 0.0, // AltitudeAccuracy not provided. + hasHeading, heading, + hasSpeed, speed); +} + +void GeolocationServiceBridge::startJavaImplementation(WebViewCore* webViewCore) +{ + JNIEnv* env = getJNIEnv(); + + // Get the Java GeolocationService class. + jclass javaGeolocationServiceClass = env->FindClass(javaGeolocationServiceClassName); + ASSERT(javaGeolocationServiceClass); + + // Set up the methods we wish to call on the Java GeolocationService class. + javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodInit] = + env->GetMethodID(javaGeolocationServiceClass, "<init>", "(Landroid/content/Context;J)V"); + javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStart] = + env->GetMethodID(javaGeolocationServiceClass, "start", "()Z"); + javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodStop] = + env->GetMethodID(javaGeolocationServiceClass, "stop", "()V"); + javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodSetEnableGps] = + env->GetMethodID(javaGeolocationServiceClass, "setEnableGps", "(Z)V"); + + // Create the Java GeolocationService object. + jobject context = webViewCore->getContext(); + if (!context) + return; + jlong nativeObject = reinterpret_cast<jlong>(this); + jobject object = env->NewObject(javaGeolocationServiceClass, + javaGeolocationServiceClassMethodIDs[GeolocationServiceMethodInit], + context, + nativeObject); + + m_javaGeolocationServiceObject = getJNIEnv()->NewGlobalRef(object); + ASSERT(m_javaGeolocationServiceObject); + + // Register to handle calls to native methods of the Java GeolocationService + // object. We register once only. + static int registered = jniRegisterNativeMethods(env, + javaGeolocationServiceClassName, + javaGeolocationServiceClassNativeMethods, + NELEM(javaGeolocationServiceClassNativeMethods)); + ASSERT(registered == JNI_OK); + + // Set up the methods we wish to call on the Java Location class. + jclass javaLocationClass = env->FindClass(javaLocationClassName); + ASSERT(javaLocationClass); + javaLocationClassMethodIDs[LocationMethodGetLatitude] = + env->GetMethodID(javaLocationClass, "getLatitude", "()D"); + javaLocationClassMethodIDs[LocationMethodGetLongitude] = + env->GetMethodID(javaLocationClass, "getLongitude", "()D"); + javaLocationClassMethodIDs[LocationMethodHasAltitude] = + env->GetMethodID(javaLocationClass, "hasAltitude", "()Z"); + javaLocationClassMethodIDs[LocationMethodGetAltitude] = + env->GetMethodID(javaLocationClass, "getAltitude", "()D"); + javaLocationClassMethodIDs[LocationMethodHasAccuracy] = + env->GetMethodID(javaLocationClass, "hasAccuracy", "()Z"); + javaLocationClassMethodIDs[LocationMethodGetAccuracy] = + env->GetMethodID(javaLocationClass, "getAccuracy", "()F"); + javaLocationClassMethodIDs[LocationMethodHasBearing] = + env->GetMethodID(javaLocationClass, "hasBearing", "()Z"); + javaLocationClassMethodIDs[LocationMethodGetBearing] = + env->GetMethodID(javaLocationClass, "getBearing", "()F"); + javaLocationClassMethodIDs[LocationMethodHasSpeed] = + env->GetMethodID(javaLocationClass, "hasSpeed", "()Z"); + javaLocationClassMethodIDs[LocationMethodGetSpeed] = + env->GetMethodID(javaLocationClass, "getSpeed", "()F"); + javaLocationClassMethodIDs[LocationMethodGetTime] = + env->GetMethodID(javaLocationClass, "getTime", "()J"); +} + +void GeolocationServiceBridge::stopJavaImplementation() +{ + if (!m_javaGeolocationServiceObject) + return; + getJNIEnv()->DeleteGlobalRef(m_javaGeolocationServiceObject); +} + +} // namespace android diff --git a/Source/WebKit/android/jni/GeolocationServiceBridge.h b/Source/WebKit/android/jni/GeolocationServiceBridge.h new file mode 100644 index 0000000..826ba71 --- /dev/null +++ b/Source/WebKit/android/jni/GeolocationServiceBridge.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#ifndef GeolocationServiceBridge_h +#define GeolocationServiceBridge_h + +#include <JNIUtility.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { +class GeolocationError; +class GeolocationPosition; +} + +namespace android { + +class WebViewCore; + +// GeolocationServiceBridge is the bridge to the Java implementation. It manages +// the lifetime of the Java object. It is an implementation detail of +// GeolocationClientAndroid. +class GeolocationServiceBridge { +public: + class Listener { + public: + virtual ~Listener() {} + virtual void newPositionAvailable(PassRefPtr<WebCore::GeolocationPosition>) = 0; + virtual void newErrorAvailable(PassRefPtr<WebCore::GeolocationError>) = 0; + }; + + GeolocationServiceBridge(Listener*, WebViewCore*); + ~GeolocationServiceBridge(); + + bool start(); + void stop(); + void setEnableGps(bool enable); + + // Static wrapper functions to hide JNI nastiness. + static void newLocationAvailable(JNIEnv *env, jclass, jlong nativeObject, jobject location); + static void newErrorAvailable(JNIEnv *env, jclass, jlong nativeObject, jstring message); + static PassRefPtr<WebCore::GeolocationPosition> toGeolocationPosition(JNIEnv *env, const jobject &location); + +private: + void startJavaImplementation(WebViewCore*); + void stopJavaImplementation(); + + Listener* m_listener; + jobject m_javaGeolocationServiceObject; +}; + +} // namespace android + +#endif // GeolocationServiceBridge_h diff --git a/Source/WebKit/android/jni/MockGeolocation.cpp b/Source/WebKit/android/jni/MockGeolocation.cpp index 250953f..d588010 100755 --- a/Source/WebKit/android/jni/MockGeolocation.cpp +++ b/Source/WebKit/android/jni/MockGeolocation.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, The Android Open Source Project + * 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 @@ -23,19 +23,17 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// The functions in this file are used to configure the mock GeolocationService +// The functions in this file are used to configure the mock Geolocation client // for the LayoutTests. #include "config.h" -#include "Coordinates.h" -#include "GeolocationServiceMock.h" -#include "Geoposition.h" -#include "JavaSharedClient.h" -#include "PositionError.h" -#include "WebCoreJni.h" -#include <JNIHelp.h> -#include <JNIUtility.h> +#include "WebViewCore.h" + +#include <GeolocationError.h> +#include <GeolocationPosition.h> +#include "JNIHelp.h" +#include "ScopedLocalRef.h" #include <wtf/CurrentTime.h> using namespace WebCore; @@ -44,30 +42,46 @@ namespace android { static const char* javaMockGeolocationClass = "android/webkit/MockGeolocation"; -static void setPosition(JNIEnv* env, jobject, double latitude, double longitude, double accuracy) +WebViewCore* getWebViewCore(JNIEnv* env, jobject webViewCore) +{ + ScopedLocalRef<jclass> webViewCoreClass(env, env->FindClass("android/webkit/WebViewCore")); + jfieldID nativeClassField = env->GetFieldID(webViewCoreClass.get(), "mNativeClass", "I"); + return reinterpret_cast<WebViewCore*>(env->GetIntField(webViewCore, nativeClassField)); +} + +static void setUseMock(JNIEnv* env, jobject, jobject webViewCore) +{ + getWebViewCore(env, webViewCore)->geolocationManager()->setUseMock(); +} + +static void setPosition(JNIEnv* env, jobject, jobject webViewCore, double latitude, double longitude, double accuracy) +{ + getWebViewCore(env, webViewCore)->geolocationManager()->setMockPosition(GeolocationPosition::create(WTF::currentTime(), + latitude, + longitude, + accuracy, + false, 0.0, // altitude, + false, 0.0, // altitudeAccuracy, + false, 0.0, // heading + false, 0.0)); // speed +} + +static void setError(JNIEnv* env, jobject, jobject webViewCore, int code, jstring message) { - RefPtr<Coordinates> coordinates = Coordinates::create(latitude, - longitude, - false, 0.0, // altitude, - accuracy, - false, 0.0, // altitudeAccuracy, - false, 0.0, // heading - false, 0.0); // speed - RefPtr<Geoposition> position = Geoposition::create(coordinates.release(), WTF::currentTimeMS()); - GeolocationServiceMock::setPosition(position.release()); + GeolocationError::ErrorCode codeEnum = static_cast<GeolocationError::ErrorCode>(code); + getWebViewCore(env, webViewCore)->geolocationManager()->setMockError(GeolocationError::create(codeEnum, jstringToWtfString(env, message))); } -static void setError(JNIEnv* env, jobject, int code, jstring message) +static void setPermission(JNIEnv* env, jobject, jobject webViewCore, bool allow) { - PositionError::ErrorCode codeEnum = static_cast<PositionError::ErrorCode>(code); - String messageString = jstringToWtfString(env, message); - RefPtr<PositionError> error = PositionError::create(codeEnum, messageString); - GeolocationServiceMock::setError(error.release()); + getWebViewCore(env, webViewCore)->geolocationManager()->setMockPermission(allow); } static JNINativeMethod gMockGeolocationMethods[] = { - { "nativeSetPosition", "(DDD)V", (void*) setPosition }, - { "nativeSetError", "(ILjava/lang/String;)V", (void*) setError } + { "nativeSetUseMock", "(Landroid/webkit/WebViewCore;)V", (void*) setUseMock }, + { "nativeSetPosition", "(Landroid/webkit/WebViewCore;DDD)V", (void*) setPosition }, + { "nativeSetError", "(Landroid/webkit/WebViewCore;ILjava/lang/String;)V", (void*) setError }, + { "nativeSetPermission", "(Landroid/webkit/WebViewCore;Z)V", (void*) setPermission }, }; int registerMockGeolocation(JNIEnv* env) diff --git a/Source/WebKit/android/jni/PicturePile.cpp b/Source/WebKit/android/jni/PicturePile.cpp index ccdfa59..f995e92 100644 --- a/Source/WebKit/android/jni/PicturePile.cpp +++ b/Source/WebKit/android/jni/PicturePile.cpp @@ -35,11 +35,16 @@ #include "PlatformGraphicsContextSkia.h" #include "SkCanvas.h" #include "SkNWayCanvas.h" -#include "SkPicture.h" #include "SkPixelRef.h" #include "SkRect.h" #include "SkRegion.h" +#if USE_RECORDING_CONTEXT +#include "PlatformGraphicsContextRecording.h" +#else +#include "SkPicture.h" +#endif + #define ENABLE_PRERENDERED_INVALS true #define MAX_OVERLAP_COUNT 2 #define MAX_OVERLAP_AREA .7 @@ -50,11 +55,18 @@ static SkIRect toSkIRect(const IntRect& rect) { return SkIRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height()); } -static IntRect extractClipBounds(SkCanvas* canvas, const IntSize& size) { - SkRect clip; - canvas->getClipBounds(&clip); - clip.intersect(0, 0, size.width(), size.height()); - return enclosingIntRect(clip); +PictureContainer::PictureContainer(const PictureContainer& other) + : picture(other.picture) + , area(other.area) + , dirty(other.dirty) + , prerendered(other.prerendered) +{ + SkSafeRef(picture); +} + +PictureContainer::~PictureContainer() +{ + SkSafeUnref(picture); } PicturePile::PicturePile(const PicturePile& other) @@ -64,15 +76,6 @@ PicturePile::PicturePile(const PicturePile& other) { } -PicturePile::PicturePile(SkPicture* picture) -{ - m_size = IntSize(picture->width(), picture->height()); - PictureContainer pc(IntRect(0, 0, m_size.width(), m_size.height())); - pc.picture = picture; - pc.dirty = false; - m_pile.append(pc); -} - void PicturePile::draw(SkCanvas* canvas) { /* Loop down recursively, subtracting the previous clip from the SkRegion, @@ -81,10 +84,10 @@ void PicturePile::draw(SkCanvas* canvas) * the rect bounds of the SkRegion for the clip, so this still can't be * used for translucent surfaces */ - TRACE_METHOD(); - IntRect clipBounds = extractClipBounds(canvas, m_size); - SkRegion clipRegion(toSkIRect(clipBounds)); - drawWithClipRecursive(canvas, clipRegion, m_pile.size() - 1); + if (canvas->quickReject(SkRect::MakeWH(m_size.width(), m_size.height()), + SkCanvas::kBW_EdgeType)) + return; + drawWithClipRecursive(canvas, m_pile.size() - 1); } void PicturePile::clearPrerenders() @@ -93,25 +96,23 @@ void PicturePile::clearPrerenders() m_pile[i].prerendered.clear(); } -void PicturePile::drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, - int index) +void PicturePile::drawWithClipRecursive(SkCanvas* canvas, int index) { // TODO: Add some debug visualizations of this - if (index < 0 || clipRegion.isEmpty()) + if (index < 0) return; PictureContainer& pc = m_pile[index]; - IntRect intersection = clipRegion.getBounds(); - intersection.intersect(pc.area); - if (pc.picture && !intersection.isEmpty()) { - clipRegion.op(intersection, SkRegion::kDifference_Op); - drawWithClipRecursive(canvas, clipRegion, index - 1); - int saved = canvas->save(); - canvas->clipRect(intersection); - canvas->translate(pc.area.x(), pc.area.y()); - canvas->drawPicture(*pc.picture); + if (pc.picture && !canvas->quickReject(pc.area, SkCanvas::kBW_EdgeType)) { + int saved = canvas->save(SkCanvas::kClip_SaveFlag); + if (canvas->clipRect(pc.area, SkRegion::kDifference_Op)) + drawWithClipRecursive(canvas, index - 1); + canvas->restoreToCount(saved); + saved = canvas->save(SkCanvas::kClip_SaveFlag); + if (canvas->clipRect(pc.area)) + drawPicture(canvas, pc); canvas->restoreToCount(saved); } else - drawWithClipRecursive(canvas, clipRegion, index - 1); + drawWithClipRecursive(canvas, index - 1); } // Used by WebViewCore @@ -140,14 +141,30 @@ void PicturePile::setSize(const IntSize& size) { if (m_size == size) return; + IntSize oldSize = m_size; m_size = size; - // TODO: See above about just adding invals for new content - m_pile.clear(); - m_webkitInvals.clear(); - if (!size.isEmpty()) { - IntRect area(0, 0, size.width(), size.height()); - m_webkitInvals.append(area); - m_pile.append(area); + if (size.width() <= oldSize.width() && size.height() <= oldSize.height()) { + // We are shrinking - huzzah, nothing to do! + // TODO: Loop through and throw out Pictures that are now clipped out + } else if (oldSize.width() == size.width()) { + // Only changing vertically + IntRect rect(0, std::min(oldSize.height(), size.height()), + size.width(), std::abs(oldSize.height() - size.height())); + invalidate(rect); + } else if (oldSize.height() == size.height()) { + // Only changing horizontally + IntRect rect(std::min(oldSize.width(), size.width()), 0, + std::abs(oldSize.width() - size.width()), size.height()); + invalidate(rect); + } else { + // Both width & height changed, full inval :( + m_pile.clear(); + m_webkitInvals.clear(); + if (!size.isEmpty()) { + IntRect area(0, 0, size.width(), size.height()); + m_webkitInvals.append(area); + m_pile.append(area); + } } } @@ -163,43 +180,8 @@ void PicturePile::updatePicturesIfNeeded(PicturePainter* painter) void PicturePile::updatePicture(PicturePainter* painter, PictureContainer& pc) { - /* The ref counting here is a bit unusual. What happens is begin/end recording - * will ref/unref the recording canvas. However, 'canvas' might be pointing - * at an SkNWayCanvas instead of the recording canvas, which needs to be - * unref'd. Thus what we do is ref the recording canvas so that we can - * always unref whatever canvas we have at the end. - */ TRACE_METHOD(); - SkPicture* picture = new SkPicture(); - SkCanvas* canvas = picture->beginRecording(pc.area.width(), pc.area.height(), - SkPicture::kUsePathBoundsForClip_RecordingFlag); - SkSafeRef(canvas); - canvas->translate(-pc.area.x(), -pc.area.y()); - IntRect drawArea = pc.area; - if (pc.prerendered.get()) { - SkCanvas* prerender = painter->createPrerenderCanvas(pc.prerendered.get()); - if (!prerender) { - ALOGV("Failed to create prerendered for " INT_RECT_FORMAT, - INT_RECT_ARGS(pc.prerendered->area)); - pc.prerendered.clear(); - } else { - drawArea.unite(pc.prerendered->area); - SkNWayCanvas* nwayCanvas = new SkNWayCanvas(drawArea.width(), drawArea.height()); - nwayCanvas->translate(-drawArea.x(), -drawArea.y()); - nwayCanvas->addCanvas(canvas); - nwayCanvas->addCanvas(prerender); - SkSafeUnref(canvas); - SkSafeUnref(prerender); - canvas = nwayCanvas; - } - } - WebCore::PlatformGraphicsContextSkia pgc(canvas); - WebCore::GraphicsContext gc(&pgc); - ALOGV("painting picture: " INT_RECT_FORMAT, INT_RECT_ARGS(drawArea)); - painter->paintContents(&gc, drawArea); - SkSafeUnref(canvas); - picture->endRecording(); - + Picture* picture = recordPicture(painter, pc); SkSafeUnref(pc.picture); pc.picture = picture; pc.dirty = false; @@ -298,4 +280,97 @@ PrerenderedInval* PicturePile::prerenderedInvalForArea(const IntRect& area) return 0; } +bool PicturePile::hasText() const +{ + for (size_t i = 0; i < m_pile.size(); i++) { + if (m_pile[i].hasText) + return true; + } + return false; +} + +bool PicturePile::isEmpty() const +{ + for (size_t i = 0; i < m_pile.size(); i++) { + if (m_pile[i].picture) + return false; + } + return true; +} + +#if USE_RECORDING_CONTEXT +void PicturePile::drawPicture(SkCanvas* canvas, PictureContainer& pc) +{ + TRACE_METHOD(); + pc.picture->draw(canvas); +} + +Picture* PicturePile::recordPicture(PicturePainter* painter, PictureContainer& pc) +{ + pc.prerendered.clear(); // TODO: Support? Not needed? + + Recording* picture = new Recording(); + WebCore::PlatformGraphicsContextRecording pgc(picture); + WebCore::GraphicsContext gc(&pgc); + painter->paintContents(&gc, pc.area); + pc.hasText = pgc.hasText(); + if (pgc.isEmpty()) { + SkSafeUnref(picture); + picture = 0; + } + + return picture; +} +#else +void PicturePile::drawPicture(SkCanvas* canvas, PictureContainer& pc) +{ + canvas->translate(pc.area.x(), pc.area.y()); + pc.picture->draw(canvas); +} + +Picture* PicturePile::recordPicture(PicturePainter* painter, PictureContainer& pc) +{ + /* The ref counting here is a bit unusual. What happens is begin/end recording + * will ref/unref the recording canvas. However, 'canvas' might be pointing + * at an SkNWayCanvas instead of the recording canvas, which needs to be + * unref'd. Thus what we do is ref the recording canvas so that we can + * always unref whatever canvas we have at the end. + */ + SkPicture* picture = new SkPicture(); + SkCanvas* canvas = picture->beginRecording(pc.area.width(), pc.area.height(), + SkPicture::kUsePathBoundsForClip_RecordingFlag); + SkSafeRef(canvas); + canvas->translate(-pc.area.x(), -pc.area.y()); + IntRect drawArea = pc.area; + if (pc.prerendered.get()) { + SkCanvas* prerender = painter->createPrerenderCanvas(pc.prerendered.get()); + if (!prerender) { + ALOGV("Failed to create prerendered for " INT_RECT_FORMAT, + INT_RECT_ARGS(pc.prerendered->area)); + pc.prerendered.clear(); + } else { + drawArea.unite(pc.prerendered->area); + SkNWayCanvas* nwayCanvas = new SkNWayCanvas(drawArea.width(), drawArea.height()); + nwayCanvas->translate(-drawArea.x(), -drawArea.y()); + nwayCanvas->addCanvas(canvas); + nwayCanvas->addCanvas(prerender); + SkSafeUnref(canvas); + SkSafeUnref(prerender); + canvas = nwayCanvas; + } + } + WebCore::PlatformGraphicsContextSkia pgc(canvas); + WebCore::GraphicsContext gc(&pgc); + ALOGV("painting picture: " INT_RECT_FORMAT, INT_RECT_ARGS(drawArea)); + painter->paintContents(&gc, drawArea); + + // TODO: consider paint-time checking for these with SkPicture painting? + pc.hasText = true; + + SkSafeUnref(canvas); + picture->endRecording(); + return picture; +} +#endif + } // namespace WebCore diff --git a/Source/WebKit/android/jni/PicturePile.h b/Source/WebKit/android/jni/PicturePile.h index b28a792..1f99054 100644 --- a/Source/WebKit/android/jni/PicturePile.h +++ b/Source/WebKit/android/jni/PicturePile.h @@ -38,7 +38,17 @@ #include <wtf/ThreadSafeRefCounted.h> #include <wtf/Vector.h> +#define USE_RECORDING_CONTEXT true +#if USE_RECORDING_CONTEXT +namespace WebCore { +class Recording; +} +typedef WebCore::Recording Picture; +#else class SkPicture; +typedef SkPicture Picture; +#endif + class SkCanvas; namespace WebCore { @@ -57,37 +67,27 @@ public: class PictureContainer { public: - SkPicture* picture; + Picture* picture; IntRect area; bool dirty; RefPtr<PrerenderedInval> prerendered; + bool hasText; PictureContainer(const IntRect& area) : picture(0) , area(area) , dirty(true) + , hasText(false) {} - PictureContainer(const PictureContainer& other) - : picture(other.picture) - , area(other.area) - , dirty(other.dirty) - , prerendered(other.prerendered) - { - SkSafeRef(picture); - } - - ~PictureContainer() - { - SkSafeUnref(picture); - } + PictureContainer(const PictureContainer& other); + ~PictureContainer(); }; class PicturePile { public: PicturePile() {} PicturePile(const PicturePile& other); - PicturePile(SkPicture* picture); const IntSize& size() { return m_size; } @@ -104,11 +104,17 @@ public: SkRegion& dirtyRegion() { return m_dirtyRegion; } PrerenderedInval* prerenderedInvalForArea(const IntRect& area); + // UI-side methods used to check content, after construction/updates are complete + bool hasText() const; + bool isEmpty() const; + private: void applyWebkitInvals(); void updatePicture(PicturePainter* painter, PictureContainer& container); + Picture* recordPicture(PicturePainter* painter, PictureContainer& container); void appendToPile(const IntRect& inval, const IntRect& originalInval = IntRect()); - void drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, int index); + void drawWithClipRecursive(SkCanvas* canvas, int index); + void drawPicture(SkCanvas* canvas, PictureContainer& pc); IntSize m_size; Vector<PictureContainer> m_pile; diff --git a/Source/WebKit/android/jni/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp index 02ddca6..8963837 100644 --- a/Source/WebKit/android/jni/ViewStateSerializer.cpp +++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp @@ -30,6 +30,7 @@ #include "BaseLayerAndroid.h" #include "CreateJavaOutputStreamAdaptor.h" +#include "DumpLayer.h" #include "FixedPositioning.h" #include "ImagesManager.h" #include "IFrameContentLayerAndroid.h" @@ -56,6 +57,68 @@ enum LayerTypes { LTFixedLayerAndroid = 3 }; +#define ID "mID" +#define LEFT "layout:mLeft" +#define TOP "layout:mTop" +#define WIDTH "layout:getWidth()" +#define HEIGHT "layout:getHeight()" + +class HierarchyLayerDumper : public LayerDumper { +public: + HierarchyLayerDumper(SkWStream* stream, int level) + : LayerDumper(level) + , m_stream(stream) + {} + + virtual void beginLayer(const char* className, const LayerAndroid* layerPtr) { + LayerDumper::beginLayer(className, layerPtr); + for (int i = 0; i < m_indentLevel; i++) { + m_stream->writeText(" "); + } + m_stream->writeText(className); + m_stream->writeText("@"); + m_stream->writeHexAsText(layerPtr->uniqueId()); + m_stream->writeText(" "); + + writeHexVal(ID, (int) layerPtr); + writeIntVal(LEFT, layerPtr->getPosition().fX); + writeIntVal(TOP, layerPtr->getPosition().fY); + writeIntVal(WIDTH, layerPtr->getWidth()); + writeIntVal(HEIGHT, layerPtr->getHeight()); + } + + virtual void beginChildren(int childCount) { + m_stream->writeText("\n"); + LayerDumper::beginChildren(childCount); + } + +protected: + virtual void writeEntry(const char* label, const char* value) { + m_stream->writeText(label); + m_stream->writeText("="); + int len = strlen(value); + m_stream->writeDecAsText(len); + m_stream->writeText(","); + m_stream->writeText(value); + m_stream->writeText(" "); + } + +private: + SkWStream* m_stream; +}; + +static void nativeDumpLayerHierarchy(JNIEnv* env, jobject, jint jbaseLayer, jint level, + jobject jstream, jbyteArray jstorage) +{ + SkWStream *stream = CreateJavaOutputStreamAdaptor(env, jstream, jstorage); + BaseLayerAndroid* baseLayer = reinterpret_cast<BaseLayerAndroid*>(jbaseLayer); + SkSafeRef(baseLayer); + HierarchyLayerDumper dumper(stream, level); + baseLayer->dumpLayers(&dumper); + SkSafeUnref(baseLayer); + delete stream; +} + static bool nativeSerializeViewState(JNIEnv* env, jobject, jint jbaseLayer, jobject jstream, jbyteArray jstorage) { @@ -478,6 +541,8 @@ LayerAndroid* deserializeLayer(int version, SkStream* stream) * JNI registration */ static JNINativeMethod gSerializerMethods[] = { + { "nativeDumpLayerHierarchy", "(IILjava/io/OutputStream;[B)V", + (void*) nativeDumpLayerHierarchy }, { "nativeSerializeViewState", "(ILjava/io/OutputStream;[B)Z", (void*) nativeSerializeViewState }, { "nativeDeserializeViewState", "(ILjava/io/InputStream;[B)I", diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp index 4ce3d8e..61ffd29 100644 --- a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -50,6 +50,7 @@ #include "FrameLoadRequest.h" #include "FrameTree.h" #include "FrameView.h" +#include "GeolocationClientAndroid.h" #include "GraphicsContext.h" #include "HistoryItem.h" #include "HTMLCollection.h" @@ -88,7 +89,6 @@ #include "WebFrameView.h" #include "WebUrlLoaderClient.h" #include "WebViewCore.h" -#include "android_graphics.h" #include "jni.h" #include "wds/DebugServer.h" @@ -273,7 +273,7 @@ WebFrame::WebFrame(JNIEnv* env, jobject obj, jobject historyList, WebCore::Page* mJavaFrame->mReportSslCertError = env->GetMethodID(clazz, "reportSslCertError", "(II[BLjava/lang/String;)V"); mJavaFrame->mRequestClientCert = env->GetMethodID(clazz, "requestClientCert", "(ILjava/lang/String;)V"); mJavaFrame->mDownloadStart = env->GetMethodID(clazz, "downloadStart", - "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V"); + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;J)V"); mJavaFrame->mDidReceiveData = env->GetMethodID(clazz, "didReceiveData", "([BI)V"); mJavaFrame->mDidFinishLoading = env->GetMethodID(clazz, "didFinishLoading", "()V"); mJavaFrame->mSetCertificate = env->GetMethodID(clazz, "setCertificate", "([B)V"); @@ -497,15 +497,9 @@ WebFrame::loadStarted(WebCore::Frame* frame) if (favicon) env->DeleteLocalRef(favicon); - // Inform the client that the main frame has started a new load. - if (isMainFrame && mPage) { - Chrome* chrome = mPage->chrome(); - if (chrome) { - ChromeClientAndroid* client = static_cast<ChromeClientAndroid*>(chrome->client()); - if (client) - client->onMainFrameLoadStarted(); - } - } + // The main frame has started a new load. + if (isMainFrame && mPage) + WebViewCore::getWebViewCore(mPage->mainFrame()->view())->geolocationManager()->resetRealClientTemporaryPermissionStates(); } void @@ -842,7 +836,7 @@ WebFrame::requestClientCert(WebUrlLoaderClient* client, const std::string& hostA } void -WebFrame::downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, long long contentLength) +WebFrame::downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, const std::string& referer, long long contentLength) { JNIEnv* env = getJNIEnv(); AutoJObject javaFrame = mJavaFrame->frame(env); @@ -852,13 +846,15 @@ WebFrame::downloadStart(const std::string& url, const std::string& userAgent, co jstring jUserAgent = stdStringToJstring(env, userAgent, true); jstring jContentDisposition = stdStringToJstring(env, contentDisposition, true); jstring jMimetype = stdStringToJstring(env, mimetype, true); + jstring jReferer = stdStringToJstring(env, referer, true); - env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDownloadStart, jUrl, jUserAgent, jContentDisposition, jMimetype, contentLength); + env->CallVoidMethod(javaFrame.get(), mJavaFrame->mDownloadStart, jUrl, jUserAgent, jContentDisposition, jMimetype, jReferer, contentLength); env->DeleteLocalRef(jUrl); env->DeleteLocalRef(jUserAgent); env->DeleteLocalRef(jContentDisposition); env->DeleteLocalRef(jMimetype); + env->DeleteLocalRef(jReferer); checkException(env); } @@ -1099,6 +1095,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss EditorClientAndroid* editorC = new EditorClientAndroid; DeviceMotionClientAndroid* deviceMotionC = new DeviceMotionClientAndroid; DeviceOrientationClientAndroid* deviceOrientationC = new DeviceOrientationClientAndroid; + GeolocationClientAndroid* geolocationC = new GeolocationClientAndroid; WebCore::Page::PageClients pageClients; pageClients.chromeClient = chromeC; @@ -1108,6 +1105,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss pageClients.inspectorClient = new InspectorClientAndroid; pageClients.deviceMotionClient = deviceMotionC; pageClients.deviceOrientationClient = deviceOrientationC; + pageClients.geolocationClient = geolocationC; WebCore::Page* page = new WebCore::Page(pageClients); editorC->setPage(page); @@ -1150,6 +1148,7 @@ static void CreateFrame(JNIEnv* env, jobject obj, jobject javaview, jobject jAss frame->page()->focusController()->setFocused(true); deviceMotionC->setWebViewCore(webViewCore); deviceOrientationC->setWebViewCore(webViewCore); + geolocationC->setWebViewCore(webViewCore); // Allow local access to file:/// and substitute data WebCore::SecurityOrigin::setLocalLoadPolicy( diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.h b/Source/WebKit/android/jni/WebCoreFrameBridge.h index 30c1d83..56b095b 100644 --- a/Source/WebKit/android/jni/WebCoreFrameBridge.h +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.h @@ -116,7 +116,7 @@ class WebFrame : public WebCoreRefObject { void didReceiveAuthenticationChallenge(WebUrlLoaderClient*, const std::string& host, const std::string& realm, bool useCachedCredentials, bool suppressDialog); void reportSslCertError(WebUrlLoaderClient* client, int cert_error, const std::string& cert, const std::string& url); void requestClientCert(WebUrlLoaderClient* client, const std::string& hostAndPort); - void downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, long long contentLength); + void downloadStart(const std::string& url, const std::string& userAgent, const std::string& contentDisposition, const std::string& mimetype, const std::string& referer, long long contentLength); void didReceiveData(const char* data, int size); void didFinishLoading(); void setCertificate(const std::string& cert); diff --git a/Source/WebKit/android/jni/WebFrameView.cpp b/Source/WebKit/android/jni/WebFrameView.cpp index 10e31dc..ed332aa 100644 --- a/Source/WebKit/android/jni/WebFrameView.cpp +++ b/Source/WebKit/android/jni/WebFrameView.cpp @@ -28,7 +28,6 @@ #include <config.h> #include "WebFrameView.h" -#include "android_graphics.h" #include "GraphicsContext.h" #include "Frame.h" #include "FrameTree.h" diff --git a/Source/WebKit/android/jni/WebHistory.cpp b/Source/WebKit/android/jni/WebHistory.cpp index 6b71d0f..c06244b 100644 --- a/Source/WebKit/android/jni/WebHistory.cpp +++ b/Source/WebKit/android/jni/WebHistory.cpp @@ -60,19 +60,19 @@ static void writeItem(WTF::Vector<char>& vector, WebCore::HistoryItem* item); static void writeChildrenRecursive(WTF::Vector<char>& vector, WebCore::HistoryItem* parent); static bool readItemRecursive(WebCore::HistoryItem* child, const char** pData, int length); -// Field ids for WebHistoryItems -struct WebHistoryItemFields { +// Field ids for WebHistoryClassicItems +struct WebHistoryItemClassicFields { jmethodID mInit; -} gWebHistoryItem; +} gWebHistoryItemClassic; -struct WebBackForwardListFields { +struct WebBackForwardListClassicFields { jmethodID mAddHistoryItem; jmethodID mRemoveHistoryItem; jmethodID mSetCurrentIndex; -} gWebBackForwardList; +} gWebBackForwardListClassic; //-------------------------------------------------------------------------- -// WebBackForwardList native methods. +// WebBackForwardListClassic native methods. //-------------------------------------------------------------------------- static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame) @@ -398,9 +398,9 @@ void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) WebHistoryItem* bridge = new WebHistoryItem(item); bridge->setActive(); item->setBridge(bridge); - // Allocate a blank WebHistoryItem - jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); - jobject newItem = env->NewObject(clazz, gWebHistoryItem.mInit, + // Allocate a blank WebHistoryItemClassic + jclass clazz = env->FindClass("android/webkit/WebHistoryItemClassic"); + jobject newItem = env->NewObject(clazz, gWebHistoryItemClassic.mInit, reinterpret_cast<int>(bridge)); env->DeleteLocalRef(clazz); @@ -409,7 +409,7 @@ void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) bridge->updateHistoryItem(item); // Add it to the list. - env->CallVoidMethod(list.get(), gWebBackForwardList.mAddHistoryItem, newItem); + env->CallVoidMethod(list.get(), gWebBackForwardListClassic.mAddHistoryItem, newItem); // Delete our local reference. env->DeleteLocalRef(newItem); @@ -418,13 +418,13 @@ void WebHistory::AddItem(const AutoJObject& list, WebCore::HistoryItem* item) void WebHistory::RemoveItem(const AutoJObject& list, int index) { if (list.get()) - list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mRemoveHistoryItem, index); + list.env()->CallVoidMethod(list.get(), gWebBackForwardListClassic.mRemoveHistoryItem, index); } void WebHistory::UpdateHistoryIndex(const AutoJObject& list, int newIndex) { if (list.get()) - list.env()->CallVoidMethod(list.get(), gWebBackForwardList.mSetCurrentIndex, newIndex); + list.env()->CallVoidMethod(list.get(), gWebBackForwardListClassic.mSetCurrentIndex, newIndex); } static void writeString(WTF::Vector<char>& vector, const WTF::String& str) @@ -948,14 +948,14 @@ static void unitTest() //--------------------------------------------------------- // JNI registration //--------------------------------------------------------- -static JNINativeMethod gWebBackForwardListMethods[] = { +static JNINativeMethod gWebBackForwardListClassicMethods[] = { { "nativeClose", "(I)V", (void*) WebHistoryClose }, { "restoreIndex", "(II)V", (void*) WebHistoryRestoreIndex } }; -static JNINativeMethod gWebHistoryItemMethods[] = { +static JNINativeMethod gWebHistoryItemClassicMethods[] = { { "inflate", "(I[B)I", (void*) WebHistoryInflate }, { "nativeRef", "(I)V", @@ -981,31 +981,30 @@ int registerWebHistory(JNIEnv* env) #ifdef UNIT_TEST unitTest(); #endif - // Find WebHistoryItem, its constructor, and the update method. - jclass clazz = env->FindClass("android/webkit/WebHistoryItem"); - ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem"); - gWebHistoryItem.mInit = env->GetMethodID(clazz, "<init>", "(I)V"); - ALOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor"); - + // Find WebHistoryItemClassic, its constructor, and the update method. + jclass clazz = env->FindClass("android/webkit/WebHistoryItemClassic"); + ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItemClassic"); + gWebHistoryItemClassic.mInit = env->GetMethodID(clazz, "<init>", "(I)V"); + ALOG_ASSERT(gWebHistoryItemClassic.mInit, "Could not find WebHistoryItemClassic constructor"); env->DeleteLocalRef(clazz); - // Find the WebBackForwardList object and method. - clazz = env->FindClass("android/webkit/WebBackForwardList"); - ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardList"); - gWebBackForwardList.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem", + // Find the WebBackForwardListClassic object and method. + clazz = env->FindClass("android/webkit/WebBackForwardListClassic"); + ALOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardListClassic"); + gWebBackForwardListClassic.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem", "(Landroid/webkit/WebHistoryItem;)V"); - ALOG_ASSERT(gWebBackForwardList.mAddHistoryItem, "Could not find method addHistoryItem"); - gWebBackForwardList.mRemoveHistoryItem = env->GetMethodID(clazz, "removeHistoryItem", + ALOG_ASSERT(gWebBackForwardListClassic.mAddHistoryItem, "Could not find method addHistoryItem"); + gWebBackForwardListClassic.mRemoveHistoryItem = env->GetMethodID(clazz, "removeHistoryItem", "(I)V"); - ALOG_ASSERT(gWebBackForwardList.mRemoveHistoryItem, "Could not find method removeHistoryItem"); - gWebBackForwardList.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V"); - ALOG_ASSERT(gWebBackForwardList.mSetCurrentIndex, "Could not find method setCurrentIndex"); + ALOG_ASSERT(gWebBackForwardListClassic.mRemoveHistoryItem, "Could not find method removeHistoryItem"); + gWebBackForwardListClassic.mSetCurrentIndex = env->GetMethodID(clazz, "setCurrentIndex", "(I)V"); + ALOG_ASSERT(gWebBackForwardListClassic.mSetCurrentIndex, "Could not find method setCurrentIndex"); env->DeleteLocalRef(clazz); - int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardList", - gWebBackForwardListMethods, NELEM(gWebBackForwardListMethods)); - return (result < 0) ? result : jniRegisterNativeMethods(env, "android/webkit/WebHistoryItem", - gWebHistoryItemMethods, NELEM(gWebHistoryItemMethods)); + int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardListClassic", + gWebBackForwardListClassicMethods, NELEM(gWebBackForwardListClassicMethods)); + return (result < 0) ? result : jniRegisterNativeMethods(env, "android/webkit/WebHistoryItemClassic", + gWebHistoryItemClassicMethods, NELEM(gWebHistoryItemClassicMethods)); } } /* namespace android */ diff --git a/Source/WebKit/android/jni/WebSettings.cpp b/Source/WebKit/android/jni/WebSettings.cpp index 467da3d..1bd3e36 100644 --- a/Source/WebKit/android/jni/WebSettings.cpp +++ b/Source/WebKit/android/jni/WebSettings.cpp @@ -151,6 +151,7 @@ struct FieldIds { #endif mOverrideCacheMode = env->GetFieldID(clazz, "mOverrideCacheMode", "I"); mPasswordEchoEnabled = env->GetFieldID(clazz, "mPasswordEchoEnabled", "Z"); + mMediaPlaybackRequiresUserGesture = env->GetFieldID(clazz, "mMediaPlaybackRequiresUserGesture", "Z"); ALOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm"); ALOG_ASSERT(mTextSize, "Could not find field mTextSize"); @@ -195,6 +196,7 @@ struct FieldIds { ALOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree"); ALOG_ASSERT(mPageCacheCapacity, "Could not find field mPageCacheCapacity"); ALOG_ASSERT(mPasswordEchoEnabled, "Could not find field mPasswordEchoEnabled"); + ALOG_ASSERT(mMediaPlaybackRequiresUserGesture, "Could not find field mMediaPlaybackRequiresUserGesture"); jclass enumClass = env->FindClass("java/lang/Enum"); ALOG_ASSERT(enumClass, "Could not find Enum class!"); @@ -281,6 +283,7 @@ struct FieldIds { #endif jfieldID mOverrideCacheMode; jfieldID mPasswordEchoEnabled; + jfieldID mMediaPlaybackRequiresUserGesture; }; static struct FieldIds* gFieldIds; @@ -616,6 +619,9 @@ public: bool echoPassword = env->GetBooleanField(obj, gFieldIds->mPasswordEchoEnabled); s->setPasswordEchoEnabled(echoPassword); + + flag = env->GetBooleanField(obj, gFieldIds->mMediaPlaybackRequiresUserGesture); + s->setMediaPlaybackRequiresUserGesture(flag); } }; diff --git a/Source/WebKit/android/jni/WebStorage.cpp b/Source/WebKit/android/jni/WebStorage.cpp index 66a3517..0cfe414 100644 --- a/Source/WebKit/android/jni/WebStorage.cpp +++ b/Source/WebKit/android/jni/WebStorage.cpp @@ -130,14 +130,10 @@ static void DeleteOrigin(JNIEnv* env, jobject obj, jstring origin) static void DeleteAllData(JNIEnv* env, jobject obj) { + // delete WebSQL database WebCore::DatabaseTracker::tracker().deleteAllDatabases(); - - Vector<WebCore::KURL> manifestUrls; - if (!WebCore::cacheStorage().manifestURLs(&manifestUrls)) - return; - int size = manifestUrls.size(); - for (int i = 0; i < size; ++i) - WebCore::cacheStorage().deleteCacheGroup(manifestUrls[i]); + // delete AppCache + WebCore::cacheStorage().deleteAllEntries(); // FIXME: this is a workaround for eliminating any DOM Storage data (both // session and local storage) as there is no functionality inside WebKit at the diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index f17e573..aa38222 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -30,6 +30,7 @@ #include "AccessibilityObject.h" #include "AndroidHitTestResult.h" +#include "ApplicationCacheStorage.h" #include "Attribute.h" #include "content/address_detector.h" #include "Chrome.h" @@ -62,7 +63,6 @@ #include "Geolocation.h" #include "GraphicsContext.h" #include "GraphicsJNI.h" -#include "GraphicsOperationCollection.h" #include "HTMLAnchorElement.h" #include "HTMLAreaElement.h" #include "HTMLElement.h" @@ -131,10 +131,10 @@ #include "WebCoreJni.h" #include "WebFrameView.h" #include "WindowsKeyboardCodes.h" -#include "android_graphics.h" #include "autofill/WebAutofill.h" #include "htmlediting.h" #include "markup.h" +#include "unicode/uloc.h" #include "visible_units.h" #include <JNIHelp.h> @@ -367,8 +367,6 @@ struct WebViewCore::JavaGlue { jmethodID m_showRect; jmethodID m_centerFitRect; jmethodID m_setScrollbarModes; - jmethodID m_setInstallableWebApp; - jmethodID m_enterFullscreenForVideoLayer; jmethodID m_exitFullscreenVideo; jmethodID m_setWebTextViewAutoFillable; jmethodID m_selectAt; @@ -401,7 +399,7 @@ struct WebViewCore::TextFieldInitDataGlue { jfieldID m_maxLength; jfieldID m_contentBounds; jfieldID m_nodeLayerId; - jfieldID m_contentRect; + jfieldID m_clientRect; }; /* @@ -423,7 +421,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_mainFrame(mainframe) , m_popupReply(0) , m_blockTextfieldUpdates(false) - , m_focusBoundsChanged(false) , m_skipContentDraw(false) , m_textGeneration(0) , m_maxXScroll(320/4) @@ -436,7 +433,6 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_textWrapWidth(320) , m_scale(1.0f) , m_groupForVisitedLinks(0) - , m_isPaused(false) , m_cacheMode(0) , m_fullscreenVideoMode(false) , m_matchCount(0) @@ -446,6 +442,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m , m_screenOnCounter(0) , m_currentNodeDomNavigationAxis(0) , m_deviceMotionAndOrientationManager(this) + , m_geolocationManager(this) #if ENABLE(TOUCH_EVENTS) , m_forwardingTouchEvents(false) #endif @@ -471,7 +468,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_updateViewport = GetJMethod(env, clazz, "updateViewport", "()V"); 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_updateTextfield = GetJMethod(env, clazz, "updateTextfield", "(ILjava/lang/String;I)V"); m_javaGlue->m_updateTextSelection = GetJMethod(env, clazz, "updateTextSelection", "(IIIII)V"); m_javaGlue->m_updateTextSizeAndScroll = GetJMethod(env, clazz, "updateTextSizeAndScroll", "(IIIII)V"); m_javaGlue->m_clearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V"); @@ -479,7 +476,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_needTouchEvents = GetJMethod(env, clazz, "needTouchEvents", "(Z)V"); m_javaGlue->m_requestKeyboard = GetJMethod(env, clazz, "requestKeyboard", "(Z)V"); m_javaGlue->m_exceededDatabaseQuota = GetJMethod(env, clazz, "exceededDatabaseQuota", "(Ljava/lang/String;Ljava/lang/String;JJ)V"); - m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(J)V"); + m_javaGlue->m_reachedMaxAppCacheSize = GetJMethod(env, clazz, "reachedMaxAppCacheSize", "(JJ)V"); m_javaGlue->m_populateVisitedLinks = GetJMethod(env, clazz, "populateVisitedLinks", "()V"); m_javaGlue->m_geolocationPermissionsShowPrompt = GetJMethod(env, clazz, "geolocationPermissionsShowPrompt", "(Ljava/lang/String;)V"); m_javaGlue->m_geolocationPermissionsHidePrompt = GetJMethod(env, clazz, "geolocationPermissionsHidePrompt", "()V"); @@ -499,9 +496,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_javaGlue->m_showRect = GetJMethod(env, clazz, "showRect", "(IIIIIIFFFF)V"); m_javaGlue->m_centerFitRect = GetJMethod(env, clazz, "centerFitRect", "(IIII)V"); m_javaGlue->m_setScrollbarModes = GetJMethod(env, clazz, "setScrollbarModes", "(II)V"); - m_javaGlue->m_setInstallableWebApp = GetJMethod(env, clazz, "setInstallableWebApp", "()V"); #if ENABLE(VIDEO) - m_javaGlue->m_enterFullscreenForVideoLayer = GetJMethod(env, clazz, "enterFullscreenForVideoLayer", "(ILjava/lang/String;)V"); m_javaGlue->m_exitFullscreenVideo = GetJMethod(env, clazz, "exitFullscreenVideo", "()V"); #endif m_javaGlue->m_setWebTextViewAutoFillable = GetJMethod(env, clazz, "setWebTextViewAutoFillable", "(ILjava/lang/String;)V"); @@ -526,7 +521,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m m_textFieldInitDataGlue->m_maxLength = env->GetFieldID(tfidClazz, "mMaxLength", "I"); m_textFieldInitDataGlue->m_contentBounds = env->GetFieldID(tfidClazz, "mContentBounds", "Landroid/graphics/Rect;"); m_textFieldInitDataGlue->m_nodeLayerId = env->GetFieldID(tfidClazz, "mNodeLayerId", "I"); - m_textFieldInitDataGlue->m_contentRect = env->GetFieldID(tfidClazz, "mContentRect", "Landroid/graphics/Rect;"); + m_textFieldInitDataGlue->m_clientRect = env->GetFieldID(tfidClazz, "mClientRect", "Landroid/graphics/Rect;"); m_textFieldInitDataGlue->m_constructor = GetJMethod(env, tfidClazz, "<init>", "()V"); env->DeleteLocalRef(tfidClazz); @@ -728,13 +723,6 @@ void WebViewCore::clearContent() updateLocale(); } -bool WebViewCore::focusBoundsChanged() -{ - bool result = m_focusBoundsChanged; - m_focusBoundsChanged = false; - return result; -} - void WebViewCore::paintContents(WebCore::GraphicsContext* gc, WebCore::IntRect& dirty) { WebCore::FrameView* view = m_mainFrame->view(); @@ -1507,6 +1495,7 @@ bool WebViewCore::selectWordAroundPosition(Frame* frame, VisiblePosition pos) VisibleSelection selection(pos); selection.expandUsingGranularity(WordGranularity); SelectionController* selectionController = frame->selection(); + selection = VisibleSelection(selection.start(), selection.end()); bool wordSelected = false; if (selectionController->shouldChangeSelection(selection)) { @@ -1566,7 +1555,8 @@ void WebViewCore::layerToAbsoluteOffset(const LayerAndroid* layer, IntPoint& off void WebViewCore::setSelectionCaretInfo(SelectText* selectTextContainer, const WebCore::Position& pos, const IntPoint& frameOffset, - SelectText::HandleId handleId, int caretRectOffset, EAffinity affinity) + SelectText::HandleId handleId, SelectText::HandleType handleType, + int caretRectOffset, EAffinity affinity) { Node* node = pos.anchorNode(); LayerAndroid* layer = 0; @@ -1584,8 +1574,9 @@ void WebViewCore::setSelectionCaretInfo(SelectText* selectTextContainer, caretRect.setX(absoluteOffset.x() - offset.x() + caretRectOffset); caretRect.setY(absoluteOffset.y() - offset.y()); selectTextContainer->setCaretRect(handleId, caretRect); + selectTextContainer->setHandleType(handleId, handleType); selectTextContainer->setTextRect(handleId, - positionToTextRect(pos, affinity, offset)); + positionToTextRect(pos, affinity, offset, caretRect)); } bool WebViewCore::isLtr(const Position& position) @@ -1601,14 +1592,28 @@ bool WebViewCore::isLtr(const Position& position) return isLtr; } +static Node* findInputParent(Node* node) +{ + Node* testNode = node; + while (testNode) { + RenderObject* renderer = testNode->renderer(); + if (renderer + && (renderer->isTextArea() || renderer->isTextControl())) { + return testNode; + } + testNode = testNode->parentOrHostNode(); + } + return node; +} + SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) { bool isCaret = selection.isCaret(); + Position base = selection.base(); + Position extent = selection.extent(); if (selection.isNone() || (!selection.isContentEditable() && isCaret) - || !selection.start().anchorNode() - || !selection.start().anchorNode()->renderer() - || !selection.end().anchorNode() - || !selection.end().anchorNode()->renderer()) + || !base.anchorNode() || !base.anchorNode()->renderer() + || !extent.anchorNode() || !extent.anchorNode()->renderer()) return 0; RefPtr<Range> range = selection.firstRange(); @@ -1624,20 +1629,39 @@ SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) IntPoint frameOffset = convertGlobalContentToFrameContent(IntPoint()); SelectText* selectTextContainer = new SelectText(); if (isCaret) { - setSelectionCaretInfo(selectTextContainer, selection.start(), frameOffset, - SelectText::LeftHandle, 0, selection.affinity()); - setSelectionCaretInfo(selectTextContainer, selection.start(), frameOffset, - SelectText::RightHandle, 0, selection.affinity()); + setSelectionCaretInfo(selectTextContainer, base, frameOffset, + SelectText::BaseHandle, SelectText::CenterHandle, 0, + selection.affinity()); + setSelectionCaretInfo(selectTextContainer, base, frameOffset, + SelectText::ExtentHandle, SelectText::CenterHandle, 0, + selection.affinity()); } else { - bool ltr = isLtr(selection.start()); - Position left = ltr ? selection.start() : selection.end(); - Position right = ltr ? selection.end() : selection.start(); - int leftOffset = isLtr(left) ? 0 : -1; - int rightOffset = isLtr(right) ? 0 : -1; - setSelectionCaretInfo(selectTextContainer, left, frameOffset, - SelectText::LeftHandle, leftOffset, selection.affinity()); - setSelectionCaretInfo(selectTextContainer, right, frameOffset, - SelectText::RightHandle, rightOffset, selection.affinity()); + bool isBaseLtr = isLtr(base); + bool isBaseStart = comparePositions(base, extent) <= 0; + int baseOffset = isBaseLtr ? 0 : -1; + SelectText::HandleType baseHandleType = (isBaseLtr == isBaseStart) + ? SelectText::LeftHandle : SelectText::RightHandle; + EAffinity affinity = selection.affinity(); + setSelectionCaretInfo(selectTextContainer, base, frameOffset, + SelectText::BaseHandle, baseHandleType, baseOffset, affinity); + bool isExtentLtr = isLtr(extent); + int extentOffset = isExtentLtr ? 0 : -1; + SelectText::HandleType extentHandleType = (isExtentLtr == isBaseStart) + ? SelectText::RightHandle : SelectText::LeftHandle; + setSelectionCaretInfo(selectTextContainer, extent, frameOffset, + SelectText::ExtentHandle, extentHandleType, extentOffset, affinity); + IntRect clipRect; + if (selection.isContentEditable()) { + Node* editable = findInputParent(base.anchorNode()); + RenderObject* render = editable->renderer(); + if (render && render->isBox() && !render->isBody()) { + RenderBox* renderBox = toRenderBox(render); + clipRect = renderBox->clientBoxRect(); + FloatPoint pos = renderBox->localToAbsolute(clipRect.location()); + clipRect.setX(pos.x()); + clipRect.setY(pos.y()); + } + } Node* stopNode = range->pastLastNode(); for (Node* node = range->firstNode(); node != stopNode; node = node->traverseNextNode()) { @@ -1651,7 +1675,8 @@ SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) int layerId = platformLayerIdFromNode(node, &layer); Vector<IntRect> rects; renderText->absoluteRectsForRange(rects, startOffset, endOffset, true); - selectTextContainer->addHighlightRegion(layer, rects, frameOffset); + selectTextContainer->addHighlightRegion(layer, rects, frameOffset, + clipRect); } } selectTextContainer->setText(range->text()); @@ -1659,9 +1684,9 @@ SelectText* WebViewCore::createSelectText(const VisibleSelection& selection) } IntRect WebViewCore::positionToTextRect(const Position& position, - EAffinity affinity, const WebCore::IntPoint& offset) + EAffinity affinity, const WebCore::IntPoint& offset, const IntRect& caretRect) { - IntRect textRect; + IntRect textRect = caretRect; InlineBox* inlineBox; int offsetIndex; position.getInlineBoxAndOffset(affinity, inlineBox, offsetIndex); @@ -1697,25 +1722,25 @@ IntPoint WebViewCore::convertGlobalContentToFrameContent(const IntPoint& point, return IntPoint(point.x() + frameOffset.x(), point.y() + frameOffset.y()); } -Position WebViewCore::trimSelectionPosition(const Position &start, const Position& stop) +VisiblePosition WebViewCore::trimSelectionPosition(const VisiblePosition &start, + const VisiblePosition& stop) { int direction = comparePositions(start, stop); if (direction == 0) return start; bool forward = direction < 0; - EAffinity affinity = forward ? DOWNSTREAM : UPSTREAM; bool move; - Position pos = start; + VisiblePosition pos = start; bool movedTooFar = false; do { move = true; - Node* node = pos.anchorNode(); + Node* node = pos.deepEquivalent().anchorNode(); if (node && node->isTextNode() && node->renderer()) { RenderText *textRenderer = toRenderText(node->renderer()); move = !textRenderer->textLength(); } if (move) { - Position nextPos = forward ? pos.next() : pos.previous(); + VisiblePosition nextPos = forward ? pos.next() : pos.previous(); movedTooFar = nextPos.isNull() || pos == nextPos || ((comparePositions(nextPos, stop) < 0) != forward); pos = nextPos; @@ -1726,47 +1751,65 @@ Position WebViewCore::trimSelectionPosition(const Position &start, const Positio return pos; } -void WebViewCore::selectText(int startX, int startY, int endX, int endY) +void WebViewCore::selectText(SelectText::HandleId handleId, int x, int y) { SelectionController* sc = focusedFrame()->selection(); - IntPoint startPoint = convertGlobalContentToFrameContent(IntPoint(startX, startY)); - VisiblePosition startPosition(visiblePositionForContentPoint(startPoint)); - IntPoint endPoint = convertGlobalContentToFrameContent(IntPoint(endX, endY)); - VisiblePosition endPosition(visiblePositionForContentPoint(endPoint)); + VisibleSelection selection = sc->selection(); + Position base = selection.base(); + Position extent = selection.extent(); + IntPoint dragPoint = convertGlobalContentToFrameContent(IntPoint(x, y)); + VisiblePosition dragPosition(visiblePositionForContentPoint(dragPoint)); - if (startPosition.isNull() || endPosition.isNull()) + if (base.isNull() || extent.isNull() || dragPosition.isNull()) return; + bool draggingBase = (handleId == SelectText::BaseHandle); + if (draggingBase) + base = dragPosition.deepEquivalent(); + else + extent = dragPosition.deepEquivalent(); - // Ensure startPosition is before endPosition - if (comparePositions(startPosition, endPosition) > 0) - swap(startPosition, endPosition); + bool baseIsStart = (comparePositions(base, extent) <= 0); + Position& start = baseIsStart ? base : extent; + Position& end = baseIsStart ? extent : base; + VisiblePosition startPosition(start, selection.affinity()); + VisiblePosition endPosition(end, selection.affinity()); + bool draggingStart = (baseIsStart == draggingBase); - if (sc->isContentEditable()) { - startPosition = sc->selection().visibleStart().honorEditableBoundaryAtOrAfter(startPosition); - endPosition = sc->selection().visibleEnd().honorEditableBoundaryAtOrBefore(endPosition); - if (startPosition.isNull() || endPosition.isNull()) { + if (draggingStart) { + if (selection.isRange()) { + startPosition = trimSelectionPosition(startPosition, endPosition); + if ((startPosition != endPosition) && isEndOfBlock(startPosition)) { + // Ensure startPosition is not at end of block + VisiblePosition nextStartPosition(startPosition.next()); + if (nextStartPosition.isNotNull()) + startPosition = nextStartPosition; + } + } + startPosition = endPosition.honorEditableBoundaryAtOrAfter(startPosition); + if (startPosition.isNull()) return; + start = startPosition.deepEquivalent(); + if (selection.isCaret()) + end = start; + } else { + if (selection.isRange()) { + endPosition = trimSelectionPosition(endPosition, startPosition); + if ((start != end) && isStartOfBlock(endPosition)) { + // Ensure endPosition is not at start of block + VisiblePosition prevEndPosition(endPosition.previous()); + if (!prevEndPosition.isNull()) + endPosition = prevEndPosition; + } } + endPosition = startPosition.honorEditableBoundaryAtOrAfter(endPosition); + if (endPosition.isNull()) + return; + end = endPosition.deepEquivalent(); + if (selection.isCaret()) + start = end; } - // 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; - } - - Position start = startPosition.deepEquivalent(); - Position end = endPosition.deepEquivalent(); - start = trimSelectionPosition(start, end); - end = trimSelectionPosition(end, start); - VisibleSelection selection(start, end); + selection = VisibleSelection(base, extent); // Only allow changes between caret positions or to text selection. bool selectChangeAllowed = (!selection.isCaret() || sc->isCaret()); if (selectChangeAllowed && sc->shouldChangeSelection(selection)) @@ -2944,33 +2987,31 @@ void WebViewCore::passToJs(int generation, const WTF::String& current, WTF::String test = getInputText(focus); if (test != current) { // If the text changed during the key event, update the UI text field. - updateTextfield(focus, false, test); + updateTextfield(focus, test); } // Now that the selection has settled down, send it. updateTextSelection(); } -WebCore::IntRect WebViewCore::scrollFocusedTextInput(float xPercent, int y) +void WebViewCore::scrollFocusedTextInput(float xPercent, int y) { WebCore::Node* focus = currentFocus(); if (!focus) { clearTextEntry(); - return WebCore::IntRect(); + return; } WebCore::RenderTextControl* renderText = toRenderTextControl(focus); if (!renderText) { clearTextEntry(); - return WebCore::IntRect(); + return; } - int x = (int) (xPercent * (renderText->scrollWidth() - - renderText->clientWidth())); + int x = (int)round(xPercent * (renderText->scrollWidth() - + renderText->contentWidth())); renderText->setScrollLeft(x); renderText->setScrollTop(y); focus->document()->frame()->selection()->recomputeCaretRect(); - LayerAndroid* layer = 0; - platformLayerIdFromNode(focus, &layer); - return absoluteContentRect(focus, layer); + updateTextSelection(); } void WebViewCore::setFocusControllerActive(bool active) @@ -3364,10 +3405,10 @@ bool WebViewCore::isAutoCompleteEnabled(Node* node) return isEnabled; } -WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node, +WebCore::IntRect WebViewCore::absoluteClientRect(WebCore::Node* node, LayerAndroid* layer) { - IntRect contentRect; + IntRect clientRect; if (node) { RenderObject* render = node->renderer(); if (render && render->isBox() && !render->isBody()) { @@ -3376,11 +3417,15 @@ WebCore::IntRect WebViewCore::absoluteContentRect(WebCore::Node* node, WebViewCore::layerToAbsoluteOffset(layer, offset); RenderBox* renderBox = toRenderBox(render); - contentRect = renderBox->absoluteContentBox(); - contentRect.move(-offset.x(), -offset.y()); + clientRect = renderBox->clientBoxRect(); + IntRect contentBox = renderBox->contentBoxRect(); + clientRect.setX(contentBox.x()); + clientRect.setWidth(contentBox.width()); + FloatPoint absPos = renderBox->localToAbsolute(FloatPoint()); + clientRect.move(absPos.x() - offset.x(), absPos.y() - offset.y()); } } - return contentRect; + return clientRect; } jobject WebViewCore::createTextFieldInitData(Node* node) @@ -3417,7 +3462,7 @@ jobject WebViewCore::createTextFieldInitData(Node* node) env->SetIntField(initData, classDef->m_maxLength, getMaxLength(node)); LayerAndroid* layer = 0; int layerId = platformLayerIdFromNode(node, &layer); - IntRect bounds = absoluteContentRect(node, layer); + IntRect bounds = absoluteClientRect(node, layer); ScopedLocalRef<jobject> jbounds(env, intRectToRect(env, bounds)); env->SetObjectField(initData, classDef->m_contentBounds, jbounds.get()); env->SetIntField(initData, classDef->m_nodeLayerId, layerId); @@ -3429,7 +3474,7 @@ jobject WebViewCore::createTextFieldInitData(Node* node) contentRect.move(-rtc->scrollLeft(), -rtc->scrollTop()); } ScopedLocalRef<jobject> jcontentRect(env, intRectToRect(env, contentRect)); - env->SetObjectField(initData, classDef->m_contentRect, jcontentRect.get()); + env->SetObjectField(initData, classDef->m_clientRect, jcontentRect.get()); return initData; } @@ -3611,6 +3656,19 @@ bool WebViewCore::exceededDatabaseQuota(const WTF::String& url, const WTF::Strin #endif } +/* + * TODO Note that this logic still needs to be cleaned up. Normally the + * information provided in this callback is used to resize the appcache. + * so we need to provide the current database size. However, webkit provides no + * way to reach this information. It can be calculated by fetching all the + * origins and their usage, however this is too expensize (requires one inner + * join operation for each origin). Rather, we simply return the maximum cache size, + * which should be equivalent to the current cache size. This is generally safe. + * However, setting the maximum database size to less than the current database size + * may cause a problem. In this case, ApplicationCacheStorage ("the owner of database") + * uses the updated value, while database internally ignores it and uses the current size + * as quota. This means the value we returned here won't reflect the actual database size. + */ bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) { #if ENABLE(OFFLINE_WEB_APPLICATIONS) @@ -3618,7 +3676,7 @@ bool WebViewCore::reachedMaxAppCacheSize(const unsigned long long spaceNeeded) AutoJObject javaObject = m_javaGlue->object(env); if (!javaObject.get()) return false; - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded); + env->CallVoidMethod(javaObject.get(), m_javaGlue->m_reachedMaxAppCacheSize, spaceNeeded, WebCore::cacheStorage().maximumSize()); checkException(env); return true; #endif @@ -3848,8 +3906,7 @@ void WebViewCore::updateTextSizeAndScroll(WebCore::Node* node) checkException(env); } -void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, - const WTF::String& text) +void WebViewCore::updateTextfield(WebCore::Node* ptr, const WTF::String& text) { JNIEnv* env = JSC::Bindings::getJNIEnv(); AutoJObject javaObject = m_javaGlue->object(env); @@ -3857,15 +3914,9 @@ void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword, return; if (m_blockTextfieldUpdates) return; - if (changeToPassword) { - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, - (int) ptr, true, 0, m_textGeneration); - checkException(env); - return; - } jstring string = wtfStringToJstring(env, text); env->CallVoidMethod(javaObject.get(), m_javaGlue->m_updateTextfield, - (int) ptr, false, string, m_textGeneration); + (int) ptr, string, m_textGeneration); env->DeleteLocalRef(string); checkException(env); } @@ -4059,27 +4110,11 @@ void WebViewCore::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode checkException(env); } -void WebViewCore::notifyWebAppCanBeInstalled() -{ - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_setInstallableWebApp); - checkException(env); -} - #if ENABLE(VIDEO) -void WebViewCore::enterFullscreenForVideoLayer(int layerId, const WTF::String& url) +void WebViewCore::enterFullscreenForVideoLayer() { - JNIEnv* env = JSC::Bindings::getJNIEnv(); - AutoJObject javaObject = m_javaGlue->object(env); - if (!javaObject.get()) - return; - jstring jUrlStr = wtfStringToJstring(env, url); - env->CallVoidMethod(javaObject.get(), m_javaGlue->m_enterFullscreenForVideoLayer, layerId, jUrlStr); + // Just need to update the video mode, to avoid multiple exit full screen. m_fullscreenVideoMode = true; - checkException(env); } void WebViewCore::exitFullscreenVideo() @@ -4373,6 +4408,44 @@ void WebViewCore::getLocale(String& language, String& region) region = String(propRegn, 2); } +// generate bcp47 identifier for the supplied language/region +static void toLanguageTag(char* output, size_t outSize, const String& language, + const String& region) { + if (output == NULL || outSize <= 0) + return; + String locale = language; + locale.append('_'); + locale.append(region); + char canonicalChars[ULOC_FULLNAME_CAPACITY]; + UErrorCode uErr = U_ZERO_ERROR; + uloc_canonicalize(locale.ascii().data(), canonicalChars, + ULOC_FULLNAME_CAPACITY, &uErr); + if (U_SUCCESS(uErr)) { + char likelyChars[ULOC_FULLNAME_CAPACITY]; + uErr = U_ZERO_ERROR; + uloc_addLikelySubtags(canonicalChars, likelyChars, + ULOC_FULLNAME_CAPACITY, &uErr); + if (U_SUCCESS(uErr)) { + uErr = U_ZERO_ERROR; + uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr); + if (U_SUCCESS(uErr)) { + return; + } else { + ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars, + u_errorName(uErr)); + } + } else { + ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s", canonicalChars, + u_errorName(uErr)); + } + } else { + ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale.ascii().data(), + u_errorName(uErr)); + } + // unable to build a proper language identifier + output[0] = '\0'; +} + void WebViewCore::updateLocale() { static String prevLang; @@ -4387,6 +4460,9 @@ void WebViewCore::updateLocale() prevRegn = region; GlyphPageTreeNode::resetRoots(); fontCache()->invalidate(); + char langTag[ULOC_FULLNAME_CAPACITY]; + toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, language, region); + FontPlatformData::setDefaultLanguage(langTag); } } @@ -4505,12 +4581,10 @@ static void PassToJs(JNIEnv* env, jobject obj, jint nativeClass, } static void ScrollFocusedTextInput(JNIEnv* env, jobject obj, jint nativeClass, - jfloat xPercent, jint y, jobject contentBounds) + jfloat xPercent, jint y) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - IntRect bounds = viewImpl->scrollFocusedTextInput(xPercent, y); - if (contentBounds) - GraphicsJNI::irect_to_jrect(bounds, env, contentBounds); + viewImpl->scrollFocusedTextInput(xPercent, y); } static void SetFocusControllerActive(JNIEnv* env, jobject obj, jint nativeClass, @@ -4765,10 +4839,7 @@ static void GeolocationPermissionsProvide(JNIEnv* env, jobject obj, jint nativeClass, jstring origin, jboolean allow, jboolean remember) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - Frame* frame = viewImpl->mainFrame(); - - ChromeClientAndroid* chromeClient = static_cast<ChromeClientAndroid*>(frame->page()->chrome()->client()); - chromeClient->provideGeolocationPermissions(jstringToWtfString(env, origin), allow, remember); + viewImpl->geolocationManager()->provideRealClientPermissionState(jstringToWtfString(env, origin), allow, remember); } static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, @@ -4777,20 +4848,6 @@ static void RegisterURLSchemeAsLocal(JNIEnv* env, jobject obj, jint nativeClass, WebCore::SchemeRegistry::registerURLSchemeAsLocal(jstringToWtfString(env, scheme)); } -static bool FocusBoundsChanged(JNIEnv* env, jobject obj, jint nativeClass) -{ - return reinterpret_cast<WebViewCore*>(nativeClass)->focusBoundsChanged(); -} - -static void SetIsPaused(JNIEnv* env, jobject obj, jint nativeClass, - jboolean isPaused) -{ - // tell the webcore thread to stop thinking while we do other work - // (selection and scrolling). This has nothing to do with the lifecycle - // pause and resume. - reinterpret_cast<WebViewCore*>(nativeClass)->setIsPaused(isPaused); -} - static void Pause(JNIEnv* env, jobject obj, jint nativeClass) { // This is called for the foreground tab when the browser is put to the @@ -4798,50 +4855,36 @@ static void Pause(JNIEnv* env, jobject obj, jint nativeClass) // browser). The browser can only be killed by the system when it is in the // background, so saving the Geolocation permission state now ensures that // is maintained when the browser is killed. - WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - ChromeClient* chromeClient = viewImpl->mainFrame()->page()->chrome()->client(); - ChromeClientAndroid* chromeClientAndroid = static_cast<ChromeClientAndroid*>(chromeClient); - chromeClientAndroid->storeGeolocationPermissions(); + GeolocationPermissions::maybeStorePermanentPermissions(); + WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); Frame* mainFrame = viewImpl->mainFrame(); - for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { - Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); - if (geolocation) - geolocation->suspend(); - } if (mainFrame) mainFrame->settings()->setMinDOMTimerInterval(BACKGROUND_TIMER_INTERVAL); viewImpl->deviceMotionAndOrientationManager()->maybeSuspendClients(); + viewImpl->geolocationManager()->suspendRealClient(); ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kPause_ANPLifecycleAction; viewImpl->sendPluginEvent(event); - - viewImpl->setIsPaused(true); } static void Resume(JNIEnv* env, jobject obj, jint nativeClass) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); Frame* mainFrame = viewImpl->mainFrame(); - for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext()) { - Geolocation* geolocation = frame->domWindow()->navigator()->optionalGeolocation(); - if (geolocation) - geolocation->resume(); - } if (mainFrame) mainFrame->settings()->setMinDOMTimerInterval(FOREGROUND_TIMER_INTERVAL); viewImpl->deviceMotionAndOrientationManager()->maybeResumeClients(); + viewImpl->geolocationManager()->resumeRealClient(); ANPEvent event; SkANP::InitEvent(&event, kLifecycle_ANPEventType); event.data.lifecycle.action = kResume_ANPLifecycleAction; viewImpl->sendPluginEvent(event); - - viewImpl->setIsPaused(false); } static void FreeMemory(JNIEnv* env, jobject obj, jint nativeClass) @@ -4959,10 +5002,10 @@ static jobject GetText(JNIEnv* env, jobject obj, jint nativeClass, } static void SelectText(JNIEnv* env, jobject obj, jint nativeClass, - jint startX, jint startY, jint endX, jint endY) + jint handleId, jint x, jint y) { WebViewCore* viewImpl = reinterpret_cast<WebViewCore*>(nativeClass); - viewImpl->selectText(startX, startY, endX, endY); + viewImpl->selectText(static_cast<SelectText::HandleId>(handleId), x, y); } static void ClearSelection(JNIEnv* env, jobject obj, jint nativeClass) @@ -5006,8 +5049,6 @@ static int FindNext(JNIEnv* env, jobject obj, jint nativeClass, static JNINativeMethod gJavaWebViewCoreMethods[] = { { "nativeClearContent", "(I)V", (void*) ClearContent }, - { "nativeFocusBoundsChanged", "(I)Z", - (void*) FocusBoundsChanged } , { "nativeKey", "(IIIIZZZZ)Z", (void*) Key }, { "nativeContentInvalidateAll", "(I)V", @@ -5034,7 +5075,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) MoveMouse }, { "passToJs", "(IILjava/lang/String;IIZZZZ)V", (void*) PassToJs }, - { "nativeScrollFocusedTextInput", "(IFILandroid/graphics/Rect;)V", + { "nativeScrollFocusedTextInput", "(IFI)V", (void*) ScrollFocusedTextInput }, { "nativeSetFocusControllerActive", "(IZ)V", (void*) SetFocusControllerActive }, @@ -5072,7 +5113,6 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) SetNewStorageLimit }, { "nativeGeolocationPermissionsProvide", "(ILjava/lang/String;ZZ)V", (void*) GeolocationPermissionsProvide }, - { "nativeSetIsPaused", "(IZ)V", (void*) SetIsPaused }, { "nativePause", "(I)V", (void*) Pause }, { "nativeResume", "(I)V", (void*) Resume }, { "nativeFreeMemory", "(I)V", (void*) FreeMemory }, @@ -5100,7 +5140,7 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = { (void*) InsertText }, { "nativeGetText", "(IIIII)Ljava/lang/String;", (void*) GetText }, - { "nativeSelectText", "(IIIII)V", + { "nativeSelectText", "(IIII)V", (void*) SelectText }, { "nativeClearTextSelection", "(I)V", (void*) ClearSelection }, diff --git a/Source/WebKit/android/jni/WebViewCore.h b/Source/WebKit/android/jni/WebViewCore.h index 5264f7f..4e223b3 100644 --- a/Source/WebKit/android/jni/WebViewCore.h +++ b/Source/WebKit/android/jni/WebViewCore.h @@ -30,6 +30,7 @@ #include "DOMSelection.h" #include "FileChooser.h" #include "FocusDirection.h" +#include "GeolocationManager.h" #include "HitTestResult.h" #include "PicturePile.h" #include "PlatformGraphicsContext.h" @@ -201,13 +202,9 @@ namespace android { /** * Tell the java side to update the focused textfield * @param pointer Pointer to the node for the input field. - * @param changeToPassword If true, we are changing the textfield to - * a password field, and ignore the WTF::String - * @param text If changeToPassword is false, this is the new text that - * should go into the textfield. + * @param text This is the new text that should go into the textfield. */ - void updateTextfield(WebCore::Node* pointer, - bool changeToPassword, const WTF::String& text); + void updateTextfield(WebCore::Node* pointer, const WTF::String& text); /** * Tell the java side to update the current selection in the focused @@ -396,7 +393,7 @@ namespace android { /** * Scroll the focused textfield to (x, y) in document space */ - WebCore::IntRect scrollFocusedTextInput(float x, int y); + void scrollFocusedTextInput(float x, int y); /** * Set the FocusController's active and focused states, so that * the caret will draw (true) or not. @@ -508,8 +505,6 @@ namespace android { // reset the picture set to empty void clearContent(); - bool focusBoundsChanged(); - // record content in a new BaseLayerAndroid, copying the layer tree as well WebCore::BaseLayerAndroid* recordContent(SkIPoint* ); @@ -526,8 +521,6 @@ namespace android { WebCore::Frame* mainFrame() const { return m_mainFrame; } WebCore::Frame* focusedFrame() const; - void notifyWebAppCanBeInstalled(); - void deleteText(int startX, int startY, int endX, int endY); WTF::String getText(int startX, int startY, int endX, int endY); void insertText(const WTF::String &text); @@ -539,19 +532,18 @@ namespace android { void updateMatchCount() const; #if ENABLE(VIDEO) - void enterFullscreenForVideoLayer(int layerId, const WTF::String& url); + void enterFullscreenForVideoLayer(); void exitFullscreenVideo(); #endif void setWebTextViewAutoFillable(int queryId, const string16& previewSummary); DeviceMotionAndOrientationManager* deviceMotionAndOrientationManager() { return &m_deviceMotionAndOrientationManager; } + GeolocationManager* geolocationManager() { return &m_geolocationManager; } void listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount, bool multiple, const int selected[], size_t selectedCountOrSelection); - bool isPaused() const { return m_isPaused; } - void setIsPaused(bool isPaused) { m_isPaused = isPaused; } bool drawIsPaused() const; // The actual content (without title bar) size in doc coordinate int screenWidth() const { return m_screenWidth; } @@ -580,7 +572,7 @@ namespace android { int startX, int startY, int endX, int endY); static int platformLayerIdFromNode(WebCore::Node* node, WebCore::LayerAndroid** outLayer = 0); - void selectText(int startX, int startY, int endX, int endY); + void selectText(SelectText::HandleId handleId, int x, int y); bool selectWordAt(int x, int y); // Converts from the global content coordinates that WebView sends @@ -728,18 +720,20 @@ namespace android { void setSelectionCaretInfo(SelectText* selectTextContainer, const WebCore::Position& position, const WebCore::IntPoint& frameOffset, - SelectText::HandleId handleId, int offset, - EAffinity affinity); + SelectText::HandleId handleId, SelectText::HandleType handleType, + int offset, EAffinity affinity); static int getMaxLength(WebCore::Node* node); static WTF::String getFieldName(WebCore::Node* node); static bool isAutoCompleteEnabled(WebCore::Node* node); - WebCore::IntRect absoluteContentRect(WebCore::Node* node, + WebCore::IntRect absoluteClientRect(WebCore::Node* node, WebCore::LayerAndroid* layer); static WebCore::IntRect positionToTextRect(const WebCore::Position& position, - WebCore::EAffinity affinity, const WebCore::IntPoint& offset); + WebCore::EAffinity affinity, const WebCore::IntPoint& offset, + const WebCore::IntRect& caretRect); static bool isLtr(const WebCore::Position& position); - static WebCore::Position trimSelectionPosition( - const WebCore::Position& start, const WebCore::Position& stop); + static WebCore::VisiblePosition trimSelectionPosition( + const WebCore::VisiblePosition& start, + const WebCore::VisiblePosition& stop); // called from constructor, to add this to a global list static void addInstance(WebViewCore*); @@ -759,7 +753,6 @@ namespace android { // Used in passToJS to avoid updating the UI text field until after the // key event has been processed. bool m_blockTextfieldUpdates; - bool m_focusBoundsChanged; bool m_skipContentDraw; // Passed in with key events to know when they were generated. Store it // with the cache so that we can ignore stale text changes. @@ -782,7 +775,6 @@ namespace android { int m_textWrapWidth; float m_scale; WebCore::PageGroup* m_groupForVisitedLinks; - bool m_isPaused; int m_cacheMode; bool m_fullscreenVideoMode; @@ -801,6 +793,7 @@ namespace android { int m_screenOnCounter; WebCore::Node* m_currentNodeDomNavigationAxis; DeviceMotionAndOrientationManager m_deviceMotionAndOrientationManager; + GeolocationManager m_geolocationManager; #if ENABLE(TOUCH_EVENTS) bool m_forwardingTouchEvents; |