summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authortedchoc@chromium.org <tedchoc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-20 18:45:00 +0000
committertedchoc@chromium.org <tedchoc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-06-20 18:45:00 +0000
commitca6b8608f99aff601b7899d89aa1b748f855fc83 (patch)
treeda2bef2339fec03787f08536ee703724f62056e0 /content
parent4529c84eac99324912c3ad0418b20e56d2782c77 (diff)
downloadchromium_src-ca6b8608f99aff601b7899d89aa1b748f855fc83.zip
chromium_src-ca6b8608f99aff601b7899d89aa1b748f855fc83.tar.gz
chromium_src-ca6b8608f99aff601b7899d89aa1b748f855fc83.tar.bz2
Upstream WebSettings and ZoomManager for ContentShell.
WebSettings has dependencies on ZoomManager, so it is easier to bring them up together. BUG= TEST= Review URL: https://chromiumcodereview.appspot.com/10573020 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@143214 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r--content/app/android/content_jni_registrar.cc2
-rw-r--r--content/browser/android/content_view_impl.h6
-rw-r--r--content/browser/android/web_settings.cc314
-rw-r--r--content/browser/android/web_settings.h55
-rw-r--r--content/content_browser.gypi2
-rw-r--r--content/content_jni.gypi2
-rw-r--r--content/public/android/java/org/chromium/content/browser/ContentView.java284
-rw-r--r--content/public/android/java/org/chromium/content/browser/WebSettings.java678
-rw-r--r--content/public/android/java/org/chromium/content/browser/ZoomManager.java211
9 files changed, 1524 insertions, 30 deletions
diff --git a/content/app/android/content_jni_registrar.cc b/content/app/android/content_jni_registrar.cc
index 61f2192..3ac6dc2 100644
--- a/content/app/android/content_jni_registrar.cc
+++ b/content/app/android/content_jni_registrar.cc
@@ -16,6 +16,7 @@
#include "content/browser/android/download_controller.h"
#include "content/browser/android/sandboxed_process_launcher.h"
#include "content/browser/android/touch_point.h"
+#include "content/browser/android/web_settings.h"
#include "content/common/android/command_line.h"
#include "content/common/android/surface_callback.h"
#include "content/common/android/trace_event_binding.h"
@@ -37,6 +38,7 @@ base::android::RegistrationMethod kContentRegisteredMethods[] = {
{ "TouchPoint", content::RegisterTouchPoint },
{ "TraceEvent", RegisterTraceEvent },
{ "UserAgent", content::RegisterUserAgent },
+ { "WebSettings", WebSettings::RegisterWebSettings },
};
bool RegisterJni(JNIEnv* env) {
diff --git a/content/browser/android/content_view_impl.h b/content/browser/android/content_view_impl.h
index 5550434..3b890d1 100644
--- a/content/browser/android/content_view_impl.h
+++ b/content/browser/android/content_view_impl.h
@@ -24,6 +24,12 @@ class ContentViewImpl : public ContentView,
WebContents* web_contents);
virtual void Destroy(JNIEnv* env, jobject obj);
+ // --------------------------------------------------------------------------
+ // Methods called from native code
+ // --------------------------------------------------------------------------
+
+ WebContents* web_contents() const { return web_contents_; }
+
private:
// NotificationObserver implementation.
virtual void Observe(int type,
diff --git a/content/browser/android/web_settings.cc b/content/browser/android/web_settings.cc
new file mode 100644
index 0000000..71a09a46
--- /dev/null
+++ b/content/browser/android/web_settings.cc
@@ -0,0 +1,314 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/web_settings.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "content/browser/android/content_view_impl.h"
+#include "content/browser/renderer_host/render_view_host_delegate.h"
+#include "content/browser/renderer_host/render_view_host_impl.h"
+#include "content/public/browser/web_contents.h"
+#include "webkit/glue/user_agent.h"
+#include "webkit/glue/webkit_glue.h"
+#include "webkit/glue/webpreferences.h"
+
+// TODO(tedchoc): Remove once the JNI generator has been updated to allow
+// namespace specification.
+namespace content {
+#include "jni/web_settings_jni.h"
+}
+
+using base::android::CheckException;
+using base::android::ConvertJavaStringToUTF16;
+using base::android::ConvertUTF16ToJavaString;
+using base::android::ConvertUTF8ToJavaString;
+using base::android::GetClass;
+using base::android::GetFieldID;
+using base::android::GetMethodIDFromClassName;
+using base::android::ScopedJavaLocalRef;
+using webkit_glue::WebPreferences;
+
+namespace content {
+
+struct WebSettings::FieldIds {
+ // Note on speed. One may think that an approach that reads field values via
+ // JNI is ineffective and should not be used. Please keep in mind that in the
+ // legacy WebView the whole Sync method took <1ms on Xoom, and no one is
+ // expected to modify settings in performance-critical code.
+ FieldIds() { }
+
+ FieldIds(JNIEnv* env) {
+ const char* kStringClassName = "Ljava/lang/String;";
+
+ // FIXME: we should be using a new GetFieldIDFromClassName() with caching.
+ ScopedJavaLocalRef<jclass> clazz(
+ GetClass(env, "org/chromium/content/browser/WebSettings"));
+ standard_fond_family =
+ GetFieldID(env, clazz, "mStandardFontFamily", kStringClassName);
+ fixed_font_family =
+ GetFieldID(env, clazz, "mFixedFontFamily", kStringClassName);
+ sans_serif_font_family =
+ GetFieldID(env, clazz, "mSansSerifFontFamily", kStringClassName);
+ serif_font_family =
+ GetFieldID(env, clazz, "mSerifFontFamily", kStringClassName);
+ cursive_font_family =
+ GetFieldID(env, clazz, "mCursiveFontFamily", kStringClassName);
+ fantasy_font_family =
+ GetFieldID(env, clazz, "mFantasyFontFamily", kStringClassName);
+ default_text_encoding =
+ GetFieldID(env, clazz, "mDefaultTextEncoding", kStringClassName);
+ user_agent =
+ GetFieldID(env, clazz, "mUserAgent", kStringClassName);
+ minimum_font_size = GetFieldID(env, clazz, "mMinimumFontSize", "I");
+ minimum_logical_font_size =
+ GetFieldID(env, clazz, "mMinimumLogicalFontSize", "I");
+ default_font_size = GetFieldID(env, clazz, "mDefaultFontSize", "I");
+ default_fixed_font_size =
+ GetFieldID(env, clazz, "mDefaultFixedFontSize", "I");
+ load_images_automatically =
+ GetFieldID(env, clazz, "mLoadsImagesAutomatically", "Z");
+ java_script_enabled =
+ GetFieldID(env, clazz, "mJavaScriptEnabled", "Z");
+ java_script_can_open_windows_automatically =
+ GetFieldID(env, clazz, "mJavaScriptCanOpenWindowsAutomatically", "Z");
+ }
+
+ // Field ids
+ jfieldID standard_fond_family;
+ jfieldID fixed_font_family;
+ jfieldID sans_serif_font_family;
+ jfieldID serif_font_family;
+ jfieldID cursive_font_family;
+ jfieldID fantasy_font_family;
+ jfieldID default_text_encoding;
+ jfieldID user_agent;
+ jfieldID minimum_font_size;
+ jfieldID minimum_logical_font_size;
+ jfieldID default_font_size;
+ jfieldID default_fixed_font_size;
+ jfieldID load_images_automatically;
+ jfieldID java_script_enabled;
+ jfieldID java_script_can_open_windows_automatically;
+};
+
+WebSettings::WebSettings(JNIEnv* env,
+ jobject obj,
+ content::WebContents* contents,
+ bool is_master_mode)
+ : content::WebContentsObserver(contents),
+ is_master_mode_(is_master_mode) {
+ web_settings_.Reset(env, obj);
+}
+
+WebSettings::~WebSettings() {
+}
+
+// static
+bool WebSettings::RegisterWebSettings(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+void WebSettings::Destroy(JNIEnv* env, jobject obj) {
+ delete this;
+}
+
+void WebSettings::SyncFromNativeImpl() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ CHECK(env);
+ if (!field_ids_.get()) {
+ field_ids_.reset(new FieldIds(env));
+ }
+
+ jobject obj = web_settings_.obj();
+ content::RenderViewHost* render_view_host =
+ web_contents()->GetRenderViewHost();
+ WebPreferences prefs = render_view_host->GetDelegate()->GetWebkitPrefs();
+
+ ScopedJavaLocalRef<jstring> str =
+ ConvertUTF16ToJavaString(env,
+ prefs.standard_font_family_map[WebPreferences::kCommonScript]);
+ env->SetObjectField(obj, field_ids_->standard_fond_family, str.obj());
+ CheckException(env);
+
+ str.Reset(ConvertUTF16ToJavaString(env,
+ prefs.fixed_font_family_map[WebPreferences::kCommonScript]));
+ env->SetObjectField(obj, field_ids_->fixed_font_family, str.obj());
+ CheckException(env);
+
+ str.Reset(ConvertUTF16ToJavaString(env,
+ prefs.sans_serif_font_family_map[WebPreferences::kCommonScript]));
+ env->SetObjectField(obj, field_ids_->sans_serif_font_family, str.obj());
+ CheckException(env);
+
+ str.Reset(ConvertUTF16ToJavaString(env,
+ prefs.serif_font_family_map[WebPreferences::kCommonScript]));
+ env->SetObjectField(obj, field_ids_->serif_font_family, str.obj());
+ CheckException(env);
+
+ str.Reset(ConvertUTF16ToJavaString(env,
+ prefs.cursive_font_family_map[WebPreferences::kCommonScript]));
+ env->SetObjectField(obj, field_ids_->cursive_font_family, str.obj());
+ CheckException(env);
+
+ str.Reset(ConvertUTF16ToJavaString(env,
+ prefs.fantasy_font_family_map[WebPreferences::kCommonScript]));
+ env->SetObjectField(obj, field_ids_->fantasy_font_family, str.obj());
+ CheckException(env);
+
+ str.Reset(ConvertUTF8ToJavaString(env, prefs.default_encoding));
+ env->SetObjectField(obj, field_ids_->default_text_encoding, str.obj());
+ CheckException(env);
+
+ str.Reset(ConvertUTF8ToJavaString(env, webkit_glue::GetUserAgent(GURL(""))));
+ env->SetObjectField(obj, field_ids_->user_agent, str.obj());
+ CheckException(env);
+
+ env->SetIntField(obj, field_ids_->minimum_font_size,
+ prefs.minimum_font_size);
+ CheckException(env);
+
+ env->SetIntField(
+ obj,
+ field_ids_->minimum_logical_font_size, prefs.minimum_logical_font_size);
+ CheckException(env);
+
+ env->SetIntField(obj, field_ids_->default_font_size,
+ prefs.default_font_size);
+ CheckException(env);
+
+ env->SetIntField(
+ obj, field_ids_->default_fixed_font_size, prefs.default_fixed_font_size);
+ CheckException(env);
+
+ env->SetBooleanField(
+ obj,
+ field_ids_->load_images_automatically, prefs.loads_images_automatically);
+ CheckException(env);
+
+ env->SetBooleanField(
+ obj, field_ids_->java_script_enabled, prefs.javascript_enabled);
+ CheckException(env);
+
+ env->SetBooleanField(
+ obj,
+ field_ids_->java_script_can_open_windows_automatically,
+ prefs.javascript_can_open_windows_automatically);
+ CheckException(env);
+
+ Java_WebSettings_setPluginsDisabled(env, obj, !prefs.plugins_enabled);
+ CheckException(env);
+}
+
+void WebSettings::SyncToNativeImpl() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ CHECK(env);
+ if (!field_ids_.get()) {
+ field_ids_.reset(new FieldIds(env));
+ }
+
+ jobject obj = web_settings_.obj();
+ content::RenderViewHost* render_view_host =
+ web_contents()->GetRenderViewHost();
+ WebPreferences prefs = render_view_host->GetDelegate()->GetWebkitPrefs();
+
+ ScopedJavaLocalRef<jstring> str(
+ env, static_cast<jstring>(
+ env->GetObjectField(obj, field_ids_->standard_fond_family)));
+ prefs.standard_font_family_map[WebPreferences::kCommonScript] =
+ ConvertJavaStringToUTF16(str);
+
+ str.Reset(
+ env, static_cast<jstring>(
+ env->GetObjectField(obj, field_ids_->fixed_font_family)));
+ prefs.fixed_font_family_map[WebPreferences::kCommonScript] =
+ ConvertJavaStringToUTF16(str);
+
+ str.Reset(
+ env, static_cast<jstring>(
+ env->GetObjectField(obj, field_ids_->sans_serif_font_family)));
+ prefs.sans_serif_font_family_map[WebPreferences::kCommonScript] =
+ ConvertJavaStringToUTF16(str);
+
+ str.Reset(
+ env, static_cast<jstring>(
+ env->GetObjectField(obj, field_ids_->serif_font_family)));
+ prefs.serif_font_family_map[WebPreferences::kCommonScript] =
+ ConvertJavaStringToUTF16(str);
+
+ str.Reset(
+ env, static_cast<jstring>(
+ env->GetObjectField(obj, field_ids_->cursive_font_family)));
+ prefs.cursive_font_family_map[WebPreferences::kCommonScript] =
+ ConvertJavaStringToUTF16(str);
+
+ str.Reset(
+ env, static_cast<jstring>(
+ env->GetObjectField(obj, field_ids_->fantasy_font_family)));
+ prefs.fantasy_font_family_map[WebPreferences::kCommonScript] =
+ ConvertJavaStringToUTF16(str);
+
+ str.Reset(
+ env, static_cast<jstring>(
+ env->GetObjectField(obj, field_ids_->default_text_encoding)));
+ prefs.default_encoding = ConvertJavaStringToUTF8(str);
+
+ prefs.minimum_font_size =
+ env->GetIntField(obj, field_ids_->minimum_font_size);
+
+ prefs.minimum_logical_font_size =
+ env->GetIntField(obj, field_ids_->minimum_logical_font_size);
+
+ prefs.default_font_size =
+ env->GetIntField(obj, field_ids_->default_font_size);
+
+ prefs.default_fixed_font_size =
+ env->GetIntField(obj, field_ids_->default_fixed_font_size);
+
+ prefs.loads_images_automatically =
+ env->GetBooleanField(obj, field_ids_->load_images_automatically);
+
+ prefs.javascript_enabled =
+ env->GetBooleanField(obj, field_ids_->java_script_enabled);
+
+ prefs.javascript_can_open_windows_automatically = env->GetBooleanField(
+ obj, field_ids_->java_script_can_open_windows_automatically);
+
+ prefs.plugins_enabled = !Java_WebSettings_getPluginsDisabled(env, obj);
+
+ render_view_host->UpdateWebkitPreferences(prefs);
+}
+
+void WebSettings::SyncFromNative(JNIEnv* env, jobject obj) {
+ SyncFromNativeImpl();
+}
+
+void WebSettings::SyncToNative(JNIEnv* env, jobject obj) {
+ SyncToNativeImpl();
+}
+
+void WebSettings::RenderViewCreated(content::RenderViewHost*) {
+ if (is_master_mode_) {
+ SyncToNativeImpl();
+ }
+}
+
+static jint Init(
+ JNIEnv* env, jobject obj, jint nativeContentView,
+ jboolean is_master_mode) {
+ content::WebContents* web_contents =
+ reinterpret_cast<content::ContentViewImpl*>(nativeContentView)
+ ->web_contents();
+ WebSettings* web_settings =
+ new WebSettings(env, obj, web_contents, is_master_mode);
+ return reinterpret_cast<jint>(web_settings);
+}
+
+static jstring GetDefaultUserAgent(JNIEnv* env, jclass clazz) {
+ // "Version/4.0" had been hardcoded in the legacy WebView.
+ std::string ua = webkit_glue::BuildUserAgentFromProduct("Version/4.0");
+ return base::android::ConvertUTF8ToJavaString(env, ua).Release();
+}
+
+} // namespace content
diff --git a/content/browser/android/web_settings.h b/content/browser/android/web_settings.h
new file mode 100644
index 0000000..de8a3d7
--- /dev/null
+++ b/content/browser/android/web_settings.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_WEB_SETTINGS_H_
+#define CONTENT_BROWSER_ANDROID_WEB_SETTINGS_H_
+#pragma once
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+
+class WebSettings : public WebContentsObserver {
+ public:
+ WebSettings(JNIEnv* env, jobject obj,
+ WebContents* contents,
+ bool is_master_mode);
+ virtual ~WebSettings();
+
+ static bool RegisterWebSettings(JNIEnv* env);
+
+ void Destroy(JNIEnv* env, jobject obj);
+
+ // Synchronizes the Java settings from native settings.
+ void SyncFromNative(JNIEnv* env, jobject obj);
+ // Synchronizes the native settings from Java settings.
+ void SyncToNative(JNIEnv* env, jobject obj);
+
+ private:
+ struct FieldIds;
+
+ void SyncFromNativeImpl();
+ void SyncToNativeImpl();
+
+ // WebContentsObserver overrides:
+ virtual void RenderViewCreated(RenderViewHost*) OVERRIDE;
+
+ // Determines whether a sync to native should be triggered when a new render
+ // view is created.
+ bool is_master_mode_;
+
+ // Java field references for accessing the values in the Java object.
+ scoped_ptr<FieldIds> field_ids_;
+
+ // The Java counterpart to this class.
+ base::android::ScopedJavaGlobalRef<jobject> web_settings_;
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_ANDROID_WEB_SETTINGS_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index d7adcf3..e5489bd 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -205,6 +205,8 @@
'browser/android/sandboxed_process_launcher.h',
'browser/android/touch_point.cc',
'browser/android/touch_point.h',
+ 'browser/android/web_settings.cc',
+ 'browser/android/web_settings.h',
'browser/appcache/appcache_dispatcher_host.cc',
'browser/appcache/appcache_dispatcher_host.h',
'browser/appcache/appcache_frontend_proxy.cc',
diff --git a/content/content_jni.gypi b/content/content_jni.gypi
index 21acb5a..9b0054c 100644
--- a/content/content_jni.gypi
+++ b/content/content_jni.gypi
@@ -22,6 +22,7 @@
'public/android/java/org/chromium/content/browser/LocationProvider.java',
'public/android/java/org/chromium/content/browser/SandboxedProcessLauncher.java',
'public/android/java/org/chromium/content/browser/TouchPoint.java',
+ 'public/android/java/org/chromium/content/browser/WebSettings.java',
'public/android/java/org/chromium/content/common/CommandLine.java',
'public/android/java/org/chromium/content/common/SurfaceCallback.java',
'public/android/java/org/chromium/content/common/TraceEvent.java',
@@ -40,6 +41,7 @@
'<(SHARED_INTERMEDIATE_DIR)/content/jni/location_provider_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/sandboxed_process_launcher_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/touch_point_jni.h',
+ '<(SHARED_INTERMEDIATE_DIR)/content/jni/web_settings_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/command_line_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/surface_callback_jni.h',
'<(SHARED_INTERMEDIATE_DIR)/content/jni/trace_event_jni.h',
diff --git a/content/public/android/java/org/chromium/content/browser/ContentView.java b/content/public/android/java/org/chromium/content/browser/ContentView.java
index 98e6a3a..aa2fc11 100644
--- a/content/public/android/java/org/chromium/content/browser/ContentView.java
+++ b/content/public/android/java/org/chromium/content/browser/ContentView.java
@@ -7,11 +7,12 @@ package org.chromium.content.browser;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.View;
import android.webkit.DownloadListener;
import android.widget.FrameLayout;
import org.chromium.base.WeakContext;
-import org.chromium.content.browser.AndroidBrowserProcess;
+import org.chromium.content.common.TraceEvent;
public class ContentView extends FrameLayout {
private static final String TAG = "ContentView";
@@ -33,15 +34,33 @@ public class ContentView extends FrameLayout {
public static final int MAX_RENDERERS_SINGLE_PROCESS =
AndroidBrowserProcess.MAX_RENDERERS_SINGLE_PROCESS;
+ // Used to avoid enabling zooming in / out in WebView zoom controls
+ // if resulting zooming will produce little visible difference.
+ private static float WEBVIEW_ZOOM_CONTROLS_EPSILON = 0.007f;
+
// content_view_client.cc depends on ContentView.java holding a ref to the current client
// instance since the native side only holds a weak pointer to the client. We chose this
// solution over the managed object owning the C++ object's memory since it's a lot simpler
// in terms of clean up.
private ContentViewClient mContentViewClient;
+ private WebSettings mWebSettings;
+
// Native pointer to C++ ContentView object which will be set by nativeInit()
private int mNativeContentView = 0;
+ private ZoomManager mZoomManager;
+
+ // Cached page scale factor from native
+ private float mNativePageScaleFactor = 1.0f;
+ private float mNativeMinimumScale = 1.0f;
+ private float mNativeMaximumScale = 1.0f;
+
+ // TODO(klobag): this is to avoid a bug in GestureDetector. With multi-touch,
+ // mAlwaysInTapRegion is not reset. So when the last finger is up, onSingleTapUp()
+ // will be mistakenly fired.
+ private boolean mIgnoreSingleTap;
+
// The legacy webview DownloadListener.
private DownloadListener mDownloadListener;
// ContentViewDownloadDelegate adds support for authenticated downloads
@@ -49,33 +68,6 @@ public class ContentView extends FrameLayout {
// over DownloadListener.
private ContentViewDownloadDelegate mDownloadDelegate;
- public void setContentViewClient(ContentViewClient client) {
- if (client == null) {
- throw new IllegalArgumentException("The client can't be null.");
- }
- mContentViewClient = client;
- if (mNativeContentView != 0) {
-
- // TODO(jrg): upstream this chain. nativeSetClient(),
- // ContentView::SetClient(), add a content_view_client_,
- // add web_contents_, pass web_contents into native ContentView ctor, ...
- /* nativeSetClient(mNativeContentView, mContentViewClient); */
- }
- }
-
- ContentViewClient getContentViewClient() {
- if (mContentViewClient == null) {
- // We use the Null Object pattern to avoid having to perform a null check in this class.
- // We create it lazily because most of the time a client will be set almost immediately
- // after ChromeView is created.
- mContentViewClient = new ContentViewClient();
- // We don't set the native ContentViewClient pointer here on purpose. The native
- // implementation doesn't mind a null delegate and using one is better than passing a
- // Null Object, since we cut down on the number of JNI calls.
- }
- return mContentViewClient;
- }
-
/**
* Enable multi-process ContentView. This should be called by the application before
* constructing any ContentView instances. If enabled, ContentView will run renderers in
@@ -133,10 +125,32 @@ public class ContentView extends FrameLayout {
// TODO(jrg): incomplete; upstream the rest of this method.
private void initialize(Context context, int nativeWebContents, int personality) {
mNativeContentView = nativeInit(nativeWebContents);
+
+ mPersonality = personality;
+ mWebSettings = new WebSettings(this, mNativeContentView);
+
+ initGestureDetectors(context);
+
Log.i(TAG, "mNativeContentView=0x"+ Integer.toHexString(mNativeContentView));
}
/**
+ * @return Whether the configured personality of this ContentView is {@link #PERSONALITY_VIEW}.
+ */
+ boolean isPersonalityView() {
+ switch (mPersonality) {
+ case PERSONALITY_VIEW:
+ return true;
+ case PERSONALITY_CHROME:
+ return false;
+ default:
+ Log.e(TAG, "Unknown ContentView personality: " + mPersonality);
+ return false;
+ }
+ }
+
+
+ /**
* Destroy the internal state of the WebView. This method may only be called
* after the WebView has been removed from the view system. No other methods
* may be called on this WebView after this method has been called.
@@ -147,18 +161,62 @@ public class ContentView extends FrameLayout {
nativeDestroy(mNativeContentView);
mNativeContentView = 0;
}
+ if (mWebSettings != null) {
+ mWebSettings.destroy();
+ mWebSettings = null;
+ }
+ }
+
+ /**
+ * Returns true initially, false after destroy() has been called.
+ * It is illegal to call any other public method after destroy().
+ */
+ public boolean isAlive() {
+ return mNativeContentView != 0;
+ }
+
+ public void setContentViewClient(ContentViewClient client) {
+ if (client == null) {
+ throw new IllegalArgumentException("The client can't be null.");
+ }
+ mContentViewClient = client;
+ if (mNativeContentView != 0) {
+
+ // TODO(jrg): upstream this chain. nativeSetClient(),
+ // ContentView::SetClient(), add a content_view_client_,
+ // add web_contents_, pass web_contents into native ContentView ctor, ...
+ /* nativeSetClient(mNativeContentView, mContentViewClient); */
+ }
}
+ ContentViewClient getContentViewClient() {
+ if (mContentViewClient == null) {
+ // We use the Null Object pattern to avoid having to perform a null check in this class.
+ // We create it lazily because most of the time a client will be set almost immediately
+ // after ContentView is created.
+ mContentViewClient = new ContentViewClient();
+ // We don't set the native ContentViewClient pointer here on purpose. The native
+ // implementation doesn't mind a null delegate and using one is better than passing a
+ // Null Object, since we cut down on the number of JNI calls.
+ }
+ return mContentViewClient;
+ }
/**
- * Load url without fixing up the url string. Calls from Chrome should be not
- * be using this, but should use Tab.loadUrl instead.
+ * Load url without fixing up the url string. Consumers of ContentView are responsible for
+ * ensuring the URL passed in is properly formatted (i.e. the scheme has been added if left
+ * off during user input).
+ *
* @param url The url to load.
*/
public void loadUrlWithoutUrlSanitization(String url) {
// TODO(tedchoc): Implement.
}
+ void setAllUserAgentOverridesInHistory() {
+ // TODO(tedchoc): Pass user agent override down to native.
+ }
+
/**
* Get the URL of the current page.
*
@@ -207,6 +265,79 @@ public class ContentView extends FrameLayout {
}
/**
+ * Start pinch zoom. You must call {@link #pinchEnd} to stop.
+ */
+ void pinchBegin(long timeMs, int x, int y) {
+ if (mNativeContentView != 0) {
+ // TODO(tedchoc): Pass pinch begin to native.
+ }
+ }
+
+ /**
+ * Stop pinch zoom.
+ */
+ void pinchEnd(long timeMs) {
+ if (mNativeContentView != 0) {
+ // TODO(tedchoc): Pass pinch end to native.
+ }
+ }
+
+ void setIgnoreSingleTap(boolean value) {
+ mIgnoreSingleTap = value;
+ }
+
+ /**
+ * Modify the ContentView magnification level. The effect of calling this
+ * method is exactly as after "pinch zoom".
+ *
+ * @param timeMs The event time in milliseconds.
+ * @param delta The ratio of the new magnification level over the current
+ * magnification level.
+ * @param anchorX The magnification anchor (X) in the current view
+ * coordinate.
+ * @param anchorY The magnification anchor (Y) in the current view
+ * coordinate.
+ */
+ void pinchBy(long timeMs, int anchorX, int anchorY, float delta) {
+ if (mNativeContentView != 0) {
+ // TODO(tedchoc): Pass pinch by to native.
+ }
+ }
+
+ /**
+ * Return the WebSettings object used to control the settings for this
+ * WebView.
+ *
+ * Note that when ContentView is used in the PERSONALITY_CHROME role,
+ * WebSettings can only be used for retrieving settings values. For
+ * modifications, ChromeNativePreferences is to be used.
+ * @return A WebSettings object that can be used to control this WebView's
+ * settings.
+ */
+ public WebSettings getSettings() {
+ return mWebSettings;
+ }
+
+ private void initGestureDetectors(final Context context) {
+ try {
+ TraceEvent.begin();
+ // TODO(tedchoc): Upstream the rest of the initialization.
+ mZoomManager = new ZoomManager(context, this);
+ mZoomManager.updateMultiTouchSupport();
+ } finally {
+ TraceEvent.end();
+ }
+ }
+
+ void updateMultiTouchZoomSupport() {
+ mZoomManager.updateMultiTouchSupport();
+ }
+
+ public boolean isMultiTouchZoomSupported() {
+ return mZoomManager.isMultiTouchZoomSupported();
+ }
+
+ /**
* Register the listener to be used when content can not be handled by the
* rendering engine, and should be downloaded instead. This will replace the
* current listener.
@@ -242,6 +373,99 @@ public class ContentView extends FrameLayout {
}
/**
+ * Checks whether the WebView can be zoomed in.
+ *
+ * @return True if the WebView can be zoomed in.
+ */
+ // This method uses the term 'zoom' for legacy reasons, but relates
+ // to what chrome calls the 'page scale factor'.
+ public boolean canZoomIn() {
+ return mNativeMaximumScale - mNativePageScaleFactor > WEBVIEW_ZOOM_CONTROLS_EPSILON;
+ }
+
+ /**
+ * Checks whether the WebView can be zoomed out.
+ *
+ * @return True if the WebView can be zoomed out.
+ */
+ // This method uses the term 'zoom' for legacy reasons, but relates
+ // to what chrome calls the 'page scale factor'.
+ public boolean canZoomOut() {
+ return mNativePageScaleFactor - mNativeMinimumScale > WEBVIEW_ZOOM_CONTROLS_EPSILON;
+ }
+
+ /**
+ * Zooms in the WebView by 25% (or less if that would result in zooming in
+ * more than possible).
+ *
+ * @return True if there was a zoom change, false otherwise.
+ */
+ // This method uses the term 'zoom' for legacy reasons, but relates
+ // to what chrome calls the 'page scale factor'.
+ public boolean zoomIn() {
+ if (!canZoomIn()) {
+ return false;
+ }
+
+ if (mNativeContentView == 0) {
+ return false;
+ }
+
+ long timeMs = System.currentTimeMillis();
+ int x = getWidth() / 2;
+ int y = getHeight() / 2;
+ float delta = 1.25f;
+
+ pinchBegin(timeMs, x, y);
+ pinchBy(timeMs, x, y, delta);
+ pinchEnd(timeMs);
+
+ return true;
+ }
+
+ /**
+ * Zooms out the WebView by 20% (or less if that would result in zooming out
+ * more than possible).
+ *
+ * @return True if there was a zoom change, false otherwise.
+ */
+ // This method uses the term 'zoom' for legacy reasons, but relates
+ // to what chrome calls the 'page scale factor'.
+ public boolean zoomOut() {
+ if (!canZoomOut()) {
+ return false;
+ }
+
+ if (mNativeContentView == 0) {
+ return false;
+ }
+
+ long timeMs = System.currentTimeMillis();
+ int x = getWidth() / 2;
+ int y = getHeight() / 2;
+ float delta = 0.8f;
+
+ pinchBegin(timeMs, x, y);
+ pinchBy(timeMs, x, y, delta);
+ pinchEnd(timeMs);
+
+ return true;
+ }
+
+ // Invokes the graphical zoom picker widget for this ContentView.
+ public void invokeZoomPicker() {
+ if (mWebSettings.supportZoom()) {
+ mZoomManager.invokeZoomPicker();
+ }
+ }
+
+ // Unlike legacy WebView getZoomControls which returns external zoom controls,
+ // this method returns built-in zoom controls. This method is used in tests.
+ public View getZoomControlsForTest() {
+ return mZoomManager.getZoomControlsViewForTest();
+ }
+
+ /**
* Initialize the ContentView native side.
* Should be called with a valid native WebContents.
* If nativeInitProcess is never called, the first time this method is called, nativeInitProcess
diff --git a/content/public/android/java/org/chromium/content/browser/WebSettings.java b/content/public/android/java/org/chromium/content/browser/WebSettings.java
new file mode 100644
index 0000000..7650a15
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/WebSettings.java
@@ -0,0 +1,678 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import android.os.Handler;
+import android.os.Message;
+import android.webkit.WebSettings.PluginState;
+import android.webkit.WebView;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.ThreadUtils;
+
+/**
+ * Manages settings state for a ContentView. A WebSettings instance is obtained
+ * from ContentView.getSettings(). If ContentView is used in the
+ * ContentView.PERSONALITY_VIEW role, all settings are read / write. If ContentView
+ * is in the ContentView.PERSONALITY_CHROME role, setting can only be read.
+ */
+public class WebSettings {
+ private static final String TAG = "WebSettings";
+
+ // This class must be created on the UI thread. Afterwards, it can be
+ // used from any thread. Internally, the class uses a message queue
+ // to call native code on the UI thread only.
+
+ private int mNativeWebSettings = 0;
+
+ private ContentView mContentView;
+
+ // When ContentView is used in PERSONALITY_CHROME mode, settings can't
+ // be modified through the WebSettings instance.
+ private boolean mCanModifySettings;
+
+ // A flag to avoid sending superfluous synchronization messages.
+ private boolean mIsSyncMessagePending = false;
+ // Custom handler that queues messages to call native code on the UI thread.
+ private final EventHandler mEventHandler;
+
+ private static final int MINIMUM_FONT_SIZE = 1;
+ private static final int MAXIMUM_FONT_SIZE = 72;
+
+ // Private settings so we don't have to go into native code to
+ // retrieve the values. After setXXX, sendSyncMessage() needs to be called.
+ //
+ // TODO(mnaganov): populate with the complete set of legacy WebView settings.
+
+ private String mStandardFontFamily = "sans-serif";
+ private String mFixedFontFamily = "monospace";
+ private String mSansSerifFontFamily = "sans-serif";
+ private String mSerifFontFamily = "serif";
+ private String mCursiveFontFamily = "cursive";
+ private String mFantasyFontFamily = "fantasy";
+ // FIXME: Should be obtained from Android. Problem: it is hidden.
+ private String mDefaultTextEncoding = "Latin-1";
+ private String mUserAgent;
+ private int mMinimumFontSize = 8;
+ private int mMinimumLogicalFontSize = 8;
+ private int mDefaultFontSize = 16;
+ private int mDefaultFixedFontSize = 13;
+ private boolean mLoadsImagesAutomatically = true;
+ private boolean mJavaScriptEnabled = false;
+ private boolean mJavaScriptCanOpenWindowsAutomatically = false;
+ private PluginState mPluginState = PluginState.OFF;
+
+ // Not accessed by the native side.
+ private String mDefaultUserAgent = "";
+ private boolean mSupportZoom = true;
+ private boolean mBuiltInZoomControls = false;
+ private boolean mDisplayZoomControls = true;
+
+ // Class to handle messages to be processed on the UI thread.
+ private class EventHandler {
+ // Message id for syncing
+ private static final int SYNC = 0;
+ // Message id for updating user agent in the view
+ private static final int UPDATE_UA = 1;
+ // Message id for updating multi-touch zoom state in the view
+ private static final int UPDATE_MULTI_TOUCH = 2;
+ // Actual UI thread handler
+ private Handler mHandler;
+
+ EventHandler() {
+ mHandler = mContentView.isPersonalityView() ?
+ new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SYNC:
+ synchronized (WebSettings.this) {
+ nativeSyncToNative(mNativeWebSettings);
+ mIsSyncMessagePending = false;
+ }
+ break;
+ case UPDATE_UA:
+ synchronized (mContentView) {
+ mContentView.setAllUserAgentOverridesInHistory();
+ }
+ break;
+ case UPDATE_MULTI_TOUCH:
+ synchronized (mContentView) {
+ mContentView.updateMultiTouchZoomSupport();
+ }
+ break;
+ }
+ }
+ } :
+ new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case SYNC:
+ synchronized (WebSettings.this) {
+ nativeSyncFromNative(mNativeWebSettings);
+ mIsSyncMessagePending = false;
+ }
+ break;
+ }
+ }
+ };
+ }
+
+ private synchronized void sendSyncMessage() {
+ mHandler.sendMessage(Message.obtain(null, SYNC));
+ }
+
+ private synchronized void sendUpdateUaMessage() {
+ mHandler.sendMessage(Message.obtain(null, UPDATE_UA));
+ }
+
+ private synchronized void sendUpdateMultiTouchMessage() {
+ mHandler.sendMessage(Message.obtain(null, UPDATE_MULTI_TOUCH));
+ }
+ }
+
+ /**
+ * Package constructor to prevent clients from creating a new settings
+ * instance. Must be called on the UI thread.
+ */
+ WebSettings(ContentView contentView, int nativeContentView) {
+ ThreadUtils.assertOnUiThread();
+ mContentView = contentView;
+ mCanModifySettings = mContentView.isPersonalityView();
+ mNativeWebSettings = nativeInit(nativeContentView, mCanModifySettings);
+ assert mNativeWebSettings != 0;
+
+ mEventHandler = new EventHandler();
+ if (mCanModifySettings) {
+ // PERSONALITY_VIEW
+ mDefaultUserAgent = nativeGetDefaultUserAgent();
+ mUserAgent = mDefaultUserAgent;
+ nativeSyncToNative(mNativeWebSettings);
+ } else {
+ // PERSONALITY_CHROME
+ // Chrome has zooming enabled by default. These settings are not
+ // set by the native code.
+ mBuiltInZoomControls = true;
+ mDisplayZoomControls = false;
+ nativeSyncFromNative(mNativeWebSettings);
+ }
+ }
+
+ /**
+ * Destroys the native side of the WebSettings. This WebSettings object
+ * cannot be used after this method has been called. Should only be called
+ * when related ContentView is destroyed.
+ */
+ void destroy() {
+ nativeDestroy(mNativeWebSettings);
+ mNativeWebSettings = 0;
+ }
+
+ /**
+ * Set the WebView's user-agent string. If the string "ua" is null or empty,
+ * it will use the system default user-agent string.
+ */
+ public synchronized void setUserAgentString(String ua) {
+ assert mCanModifySettings;
+ final String oldUserAgent = mUserAgent;
+ if (ua == null || ua.length() == 0) {
+ mUserAgent = mDefaultUserAgent;
+ } else {
+ mUserAgent = ua;
+ }
+ if (!oldUserAgent.equals(mUserAgent)) {
+ mEventHandler.sendUpdateUaMessage();
+ }
+ }
+
+ /**
+ * Gets the WebView's user-agent string.
+ */
+ public synchronized String getUserAgentString() {
+ // TODO(mnaganov): Doesn't reflect changes made by ChromeNativePreferences.
+ return mUserAgent;
+ }
+
+ /**
+ * Sets whether the WebView should support zooming using its on-screen zoom
+ * controls and gestures. The particular zoom mechanisms that should be used
+ * can be set with {@link #setBuiltInZoomControls}. This setting does not
+ * affect zooming performed using the {@link WebView#zoomIn()} and
+ * {@link WebView#zoomOut()} methods. The default is true.
+ *
+ * @param support whether the WebView should support zoom
+ */
+ public void setSupportZoom(boolean support) {
+ mSupportZoom = support;
+ mEventHandler.sendUpdateMultiTouchMessage();
+ }
+
+ /**
+ * Gets whether the WebView supports zoom.
+ *
+ * @return true if the WebView supports zoom
+ * @see #setSupportZoom
+ */
+ public boolean supportZoom() {
+ return mSupportZoom;
+ }
+
+ /**
+ * Sets whether the WebView should use its built-in zoom mechanisms. The
+ * built-in zoom mechanisms comprise on-screen zoom controls, which are
+ * displayed over the WebView's content, and the use of a pinch gesture to
+ * control zooming. Whether or not these on-screen controls are displayed
+ * can be set with {@link #setDisplayZoomControls}. The default is false,
+ * due to compatibility reasons.
+ * <p>
+ * The built-in mechanisms are the only currently supported zoom
+ * mechanisms, so it is recommended that this setting is always enabled.
+ * In other words, there is no point of calling this method other than
+ * with the 'true' parameter.
+ *
+ * @param enabled whether the WebView should use its built-in zoom mechanisms
+ */
+ public void setBuiltInZoomControls(boolean enabled) {
+ mBuiltInZoomControls = enabled;
+ mEventHandler.sendUpdateMultiTouchMessage();
+ }
+
+ /**
+ * Gets whether the zoom mechanisms built into WebView are being used.
+ *
+ * @return true if the zoom mechanisms built into WebView are being used
+ * @see #setBuiltInZoomControls
+ */
+ public boolean getBuiltInZoomControls() {
+ return mBuiltInZoomControls;
+ }
+
+ /**
+ * Sets whether the WebView should display on-screen zoom controls when
+ * using the built-in zoom mechanisms. See {@link #setBuiltInZoomControls}.
+ * The default is true.
+ *
+ * @param enabled whether the WebView should display on-screen zoom controls
+ */
+ public void setDisplayZoomControls(boolean enabled) {
+ mDisplayZoomControls = enabled;
+ mEventHandler.sendUpdateMultiTouchMessage();
+ }
+
+ /**
+ * Gets whether the WebView displays on-screen zoom controls when using
+ * the built-in zoom mechanisms.
+ *
+ * @return true if the WebView displays on-screen zoom controls when using
+ * the built-in zoom mechanisms
+ * @see #setDisplayZoomControls
+ */
+ public boolean getDisplayZoomControls() {
+ return mDisplayZoomControls;
+ }
+
+ boolean supportsMultiTouchZoom() {
+ return mSupportZoom && mBuiltInZoomControls;
+ }
+
+ boolean shouldDisplayZoomControls() {
+ return supportsMultiTouchZoom() && mDisplayZoomControls;
+ }
+
+ /**
+ * Set the standard font family name.
+ * @param font A font family name.
+ */
+ public synchronized void setStandardFontFamily(String font) {
+ assert mCanModifySettings;
+ if (!mStandardFontFamily.equals(font)) {
+ mStandardFontFamily = font;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the standard font family name. The default is "sans-serif".
+ * @return The standard font family name as a string.
+ */
+ public synchronized String getStandardFontFamily() {
+ return mStandardFontFamily;
+ }
+
+ /**
+ * Set the fixed font family name.
+ * @param font A font family name.
+ */
+ public synchronized void setFixedFontFamily(String font) {
+ assert mCanModifySettings;
+ if (!mFixedFontFamily.equals(font)) {
+ mFixedFontFamily = font;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the fixed font family name. The default is "monospace".
+ * @return The fixed font family name as a string.
+ */
+ public synchronized String getFixedFontFamily() {
+ return mFixedFontFamily;
+ }
+
+ /**
+ * Set the sans-serif font family name.
+ * @param font A font family name.
+ */
+ public synchronized void setSansSerifFontFamily(String font) {
+ assert mCanModifySettings;
+ if (!mSansSerifFontFamily.equals(font)) {
+ mSansSerifFontFamily = font;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the sans-serif font family name.
+ * @return The sans-serif font family name as a string.
+ */
+ public synchronized String getSansSerifFontFamily() {
+ return mSansSerifFontFamily;
+ }
+
+ /**
+ * Set the serif font family name. The default is "sans-serif".
+ * @param font A font family name.
+ */
+ public synchronized void setSerifFontFamily(String font) {
+ assert mCanModifySettings;
+ if (!mSerifFontFamily.equals(font)) {
+ mSerifFontFamily = font;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the serif font family name. The default is "serif".
+ * @return The serif font family name as a string.
+ */
+ public synchronized String getSerifFontFamily() {
+ return mSerifFontFamily;
+ }
+
+ /**
+ * Set the cursive font family name.
+ * @param font A font family name.
+ */
+ public synchronized void setCursiveFontFamily(String font) {
+ assert mCanModifySettings;
+ if (!mCursiveFontFamily.equals(font)) {
+ mCursiveFontFamily = font;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the cursive font family name. The default is "cursive".
+ * @return The cursive font family name as a string.
+ */
+ public synchronized String getCursiveFontFamily() {
+ return mCursiveFontFamily;
+ }
+
+ /**
+ * Set the fantasy font family name.
+ * @param font A font family name.
+ */
+ public synchronized void setFantasyFontFamily(String font) {
+ assert mCanModifySettings;
+ if (!mFantasyFontFamily.equals(font)) {
+ mFantasyFontFamily = font;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the fantasy font family name. The default is "fantasy".
+ * @return The fantasy font family name as a string.
+ */
+ public synchronized String getFantasyFontFamily() {
+ return mFantasyFontFamily;
+ }
+
+ /**
+ * Set the minimum font size.
+ * @param size A non-negative integer between 1 and 72.
+ * Any number outside the specified range will be pinned.
+ */
+ public synchronized void setMinimumFontSize(int size) {
+ assert mCanModifySettings;
+ size = clipFontSize(size);
+ if (mMinimumFontSize != size) {
+ mMinimumFontSize = size;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the minimum font size. The default is 8.
+ * @return A non-negative integer between 1 and 72.
+ */
+ public synchronized int getMinimumFontSize() {
+ return mMinimumFontSize;
+ }
+
+ /**
+ * Set the minimum logical font size.
+ * @param size A non-negative integer between 1 and 72.
+ * Any number outside the specified range will be pinned.
+ */
+ public synchronized void setMinimumLogicalFontSize(int size) {
+ assert mCanModifySettings;
+ size = clipFontSize(size);
+ if (mMinimumLogicalFontSize != size) {
+ mMinimumLogicalFontSize = size;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the minimum logical font size. The default is 8.
+ * @return A non-negative integer between 1 and 72.
+ */
+ public synchronized int getMinimumLogicalFontSize() {
+ return mMinimumLogicalFontSize;
+ }
+
+ /**
+ * Set the default font size.
+ * @param size A non-negative integer between 1 and 72.
+ * Any number outside the specified range will be pinned.
+ */
+ public synchronized void setDefaultFontSize(int size) {
+ assert mCanModifySettings;
+ size = clipFontSize(size);
+ if (mDefaultFontSize != size) {
+ mDefaultFontSize = size;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the default font size. The default is 16.
+ * @return A non-negative integer between 1 and 72.
+ */
+ public synchronized int getDefaultFontSize() {
+ return mDefaultFontSize;
+ }
+
+ /**
+ * Set the default fixed font size.
+ * @param size A non-negative integer between 1 and 72.
+ * Any number outside the specified range will be pinned.
+ */
+ public synchronized void setDefaultFixedFontSize(int size) {
+ assert mCanModifySettings;
+ size = clipFontSize(size);
+ if (mDefaultFixedFontSize != size) {
+ mDefaultFixedFontSize = size;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the default fixed font size. The default is 16.
+ * @return A non-negative integer between 1 and 72.
+ */
+ public synchronized int getDefaultFixedFontSize() {
+ return mDefaultFixedFontSize;
+ }
+
+ /**
+ * Tell the WebView to enable JavaScript execution.
+ *
+ * @param flag True if the WebView should execute JavaScript.
+ */
+ public synchronized void setJavaScriptEnabled(boolean flag) {
+ assert mCanModifySettings;
+ if (mJavaScriptEnabled != flag) {
+ mJavaScriptEnabled = flag;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Tell the WebView to load image resources automatically.
+ * @param flag True if the WebView should load images automatically.
+ */
+ public synchronized void setLoadsImagesAutomatically(boolean flag) {
+ assert mCanModifySettings;
+ if (mLoadsImagesAutomatically != flag) {
+ mLoadsImagesAutomatically = flag;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Return true if the WebView will load image resources automatically.
+ * The default is true.
+ * @return True if the WebView loads images automatically.
+ */
+ public synchronized boolean getLoadsImagesAutomatically() {
+ return mLoadsImagesAutomatically;
+ }
+
+ /**
+ * Return true if JavaScript is enabled. <b>Note: The default is false.</b>
+ *
+ * @return True if JavaScript is enabled.
+ */
+ public synchronized boolean getJavaScriptEnabled() {
+ return mJavaScriptEnabled;
+ }
+
+ /**
+ * Tell the WebView to enable plugins.
+ * @param flag True if the WebView should load plugins.
+ * @deprecated This method has been deprecated in favor of
+ * {@link #setPluginState}
+ */
+ @Deprecated
+ public synchronized void setPluginsEnabled(boolean flag) {
+ assert mCanModifySettings;
+ setPluginState(flag ? PluginState.ON : PluginState.OFF);
+ }
+
+ /**
+ * Tell the WebView to enable, disable, or have plugins on demand. On
+ * demand mode means that if a plugin exists that can handle the embedded
+ * content, a placeholder icon will be shown instead of the plugin. When
+ * the placeholder is clicked, the plugin will be enabled.
+ * @param state One of the PluginState values.
+ */
+ public synchronized void setPluginState(PluginState state) {
+ assert mCanModifySettings;
+ if (mPluginState != state) {
+ mPluginState = state;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Return true if plugins are enabled.
+ * @return True if plugins are enabled.
+ * @deprecated This method has been replaced by {@link #getPluginState}
+ */
+ @Deprecated
+ public synchronized boolean getPluginsEnabled() {
+ return mPluginState == PluginState.ON;
+ }
+
+ /**
+ * Return true if plugins are disabled.
+ * @return True if plugins are disabled.
+ * @hide
+ */
+ @CalledByNative
+ private synchronized boolean getPluginsDisabled() {
+ return mPluginState == PluginState.OFF;
+ }
+
+ /**
+ * Sets if plugins are disabled.
+ * @return True if plugins are disabled.
+ * @hide
+ */
+ @CalledByNative
+ private synchronized void setPluginsDisabled(boolean disabled) {
+ mPluginState = disabled ? PluginState.OFF : PluginState.ON;
+ }
+
+ /**
+ * Return the current plugin state.
+ * @return A value corresponding to the enum PluginState.
+ */
+ public synchronized PluginState getPluginState() {
+ return mPluginState;
+ }
+
+
+ /**
+ * Tell javascript to open windows automatically. This applies to the
+ * javascript function window.open().
+ * @param flag True if javascript can open windows automatically.
+ */
+ public synchronized void setJavaScriptCanOpenWindowsAutomatically(boolean flag) {
+ assert mCanModifySettings;
+ if (mJavaScriptCanOpenWindowsAutomatically != flag) {
+ mJavaScriptCanOpenWindowsAutomatically = flag;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Return true if javascript can open windows automatically. The default
+ * is false.
+ * @return True if javascript can open windows automatically during
+ * window.open().
+ */
+ public synchronized boolean getJavaScriptCanOpenWindowsAutomatically() {
+ return mJavaScriptCanOpenWindowsAutomatically;
+ }
+
+ /**
+ * Set the default text encoding name to use when decoding html pages.
+ * @param encoding The text encoding name.
+ */
+ public synchronized void setDefaultTextEncodingName(String encoding) {
+ assert mCanModifySettings;
+ if (!mDefaultTextEncoding.equals(encoding)) {
+ mDefaultTextEncoding = encoding;
+ sendSyncMessage();
+ }
+ }
+
+ /**
+ * Get the default text encoding name. The default is "Latin-1".
+ * @return The default text encoding name as a string.
+ */
+ public synchronized String getDefaultTextEncodingName() {
+ return mDefaultTextEncoding;
+ }
+
+ private int clipFontSize(int size) {
+ if (size < MINIMUM_FONT_SIZE) {
+ return MINIMUM_FONT_SIZE;
+ } else if (size > MAXIMUM_FONT_SIZE) {
+ return MAXIMUM_FONT_SIZE;
+ }
+ return size;
+ }
+
+ // Send a synchronization message to handle syncing the native settings.
+ // When the ContentView is in the PERSONALITY_VIEW role, called from setter
+ // methods. When the ContentView is in the PERSONALITY_CHROME role, called
+ // from ContentView on Chrome preferences updates.
+ synchronized void sendSyncMessage() {
+ // Only post if a sync is not pending
+ if (!mIsSyncMessagePending) {
+ mIsSyncMessagePending = true;
+ mEventHandler.sendSyncMessage();
+ }
+ }
+
+ // Initialize the WebSettings native side.
+ private native int nativeInit(int contentViewPtr, boolean isMasterMode);
+
+ private native void nativeDestroy(int nativeWebSettings);
+
+ private static native String nativeGetDefaultUserAgent();
+
+ // Synchronize Java settings from native settings.
+ private native void nativeSyncFromNative(int nativeWebSettings);
+
+ // Synchronize native settings from Java settings.
+ private native void nativeSyncToNative(int nativeWebSettings);
+}
diff --git a/content/public/android/java/org/chromium/content/browser/ZoomManager.java b/content/public/android/java/org/chromium/content/browser/ZoomManager.java
new file mode 100644
index 0000000..8e7ae08
--- /dev/null
+++ b/content/public/android/java/org/chromium/content/browser/ZoomManager.java
@@ -0,0 +1,211 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content.browser;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ZoomButtonsController;
+
+/**
+ * The ZoomManager is responsible for maintaining the ContentView's current zoom
+ * level state. It is also responsible for managing the on-screen zoom controls.
+ */
+class ZoomManager {
+ private static final String TAG = "ContentViewZoom";
+
+ private ContentView mContentView;
+ private ZoomButtonsController mZoomButtonsController;
+
+ private class ScaleGestureListener implements ScaleGestureDetector.OnScaleGestureListener {
+ // Completely silence scaling events. Used in WebView when zoom support
+ // is turned off.
+ private boolean mPermanentlyIgnoreDetectorEvents = false;
+ // Bypass events through the detector to maintain its state. Used when
+ // renderes already handles the touch event.
+ private boolean mTemporarilyIgnoreDetectorEvents = false;
+
+ // Whether any pinch zoom event has been sent to native.
+ private boolean mPinchEventSent;
+
+ boolean getPermanentlyIgnoreDetectorEvents() {
+ return mPermanentlyIgnoreDetectorEvents;
+ }
+
+ void setPermanentlyIgnoreDetectorEvents(boolean value) {
+ // Note that returning false from onScaleBegin / onScale makes the
+ // gesture detector not to emit further scaling notifications
+ // related to this gesture. Thus, if detector events are enabled in
+ // the middle of the gesture, we don't need to do anything.
+ mPermanentlyIgnoreDetectorEvents = value;
+ }
+
+ void setTemporarilyIgnoreDetectorEvents(boolean value) {
+ mTemporarilyIgnoreDetectorEvents = value;
+ }
+
+ @Override
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ if (ignoreDetectorEvents()) return false;
+ mPinchEventSent = false;
+ mContentView.setIgnoreSingleTap(true);
+ return true;
+ }
+
+ @Override
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ if (!mPinchEventSent || !mContentView.isAlive()) return;
+ mContentView.pinchEnd(detector.getEventTime());
+ mPinchEventSent = false;
+ }
+
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ if (ignoreDetectorEvents()) return false;
+ // It is possible that pinchBegin() was never called when we reach here.
+ // This happens when webkit handles the 2nd touch down event. That causes
+ // ContentView to ignore the onScaleBegin() call. And if webkit does not
+ // handle the touch move events afterwards, we will face a situation
+ // that pinchBy() is called without any pinchBegin().
+ // To solve this problem, we call pinchBegin() here if it is never called.
+ if (!mPinchEventSent) {
+ mContentView.pinchBegin(detector.getEventTime(),
+ (int) detector.getFocusX(), (int) detector.getFocusY());
+ mPinchEventSent = true;
+ }
+ mContentView.pinchBy(
+ detector.getEventTime(), (int) detector.getFocusX(), (int) detector.getFocusY(),
+ detector.getScaleFactor());
+ return true;
+ }
+
+ private boolean ignoreDetectorEvents() {
+ return mPermanentlyIgnoreDetectorEvents ||
+ mTemporarilyIgnoreDetectorEvents ||
+ !mContentView.isAlive();
+ }
+ }
+
+ private ScaleGestureDetector mMultiTouchDetector;
+ private ScaleGestureListener mMultiTouchListener;
+
+ ZoomManager(final Context context, ContentView contentView) {
+ mContentView = contentView;
+ mMultiTouchListener = new ScaleGestureListener();
+ mMultiTouchDetector = new ScaleGestureDetector(context, mMultiTouchListener);
+ }
+
+ void invokeZoomPicker() {
+ ZoomButtonsController zoomControls = getZoomControls();
+ if (zoomControls != null && !zoomControls.isVisible()) {
+ zoomControls.setVisible(true);
+ }
+ }
+
+ boolean isMultiTouchZoomSupported() {
+ return !mMultiTouchListener.getPermanentlyIgnoreDetectorEvents();
+ }
+
+ boolean isScaleGestureDetectionInProgress() {
+ return isMultiTouchZoomSupported()
+ && mMultiTouchDetector.isInProgress();
+ }
+
+ // Passes the touch event to ScaleGestureDetector so that its internal
+ // state won't go wrong, but instructs the listener to ignore the result
+ // of processing, if any.
+ void passTouchEventThrough(MotionEvent event) {
+ mMultiTouchListener.setTemporarilyIgnoreDetectorEvents(true);
+ try {
+ mMultiTouchDetector.onTouchEvent(event);
+ } catch (Exception e) {
+ Log.e(TAG, "ScaleGestureDetector got into a bad state!", e);
+ assert(false);
+ }
+ }
+
+ // Passes the touch event to ScaleGestureDetector so that its internal state
+ // won't go wrong. ScaleGestureDetector needs two pointers in a MotionEvent
+ // to recognize a zoom gesture.
+ boolean processTouchEvent(MotionEvent event) {
+ // TODO: Need to deal with multi-touch transition
+ mMultiTouchListener.setTemporarilyIgnoreDetectorEvents(false);
+ try {
+ return mMultiTouchDetector.onTouchEvent(event);
+ } catch (Exception e) {
+ Log.e(TAG, "ScaleGestureDetector got into a bad state!", e);
+ assert(false);
+ }
+ return false;
+ }
+
+ void updateMultiTouchSupport() {
+ mMultiTouchListener.setPermanentlyIgnoreDetectorEvents(
+ !mContentView.getSettings().supportsMultiTouchZoom());
+ }
+
+ private ZoomButtonsController getZoomControls() {
+ if (mZoomButtonsController == null &&
+ mContentView.getSettings().shouldDisplayZoomControls()) {
+ mZoomButtonsController = new ZoomButtonsController(mContentView);
+ mZoomButtonsController.setOnZoomListener(new ZoomListener());
+ // ZoomButtonsController positions the buttons at the bottom, but in
+ // the middle. Change their layout parameters so they appear on the
+ // right.
+ View controls = mZoomButtonsController.getZoomControls();
+ ViewGroup.LayoutParams params = controls.getLayoutParams();
+ if (params instanceof FrameLayout.LayoutParams) {
+ ((FrameLayout.LayoutParams) params).gravity = Gravity.RIGHT;
+ }
+ }
+ return mZoomButtonsController;
+ }
+
+ // This method is used in tests. It doesn't modify the state of zoom controls.
+ View getZoomControlsViewForTest() {
+ return mZoomButtonsController != null ? mZoomButtonsController.getZoomControls() : null;
+ }
+
+ void updateZoomControls() {
+ if (mZoomButtonsController == null) return;
+ boolean canZoomIn = mContentView.canZoomIn();
+ boolean canZoomOut = mContentView.canZoomOut();
+ if (!canZoomIn && !canZoomOut) {
+ // Hide the zoom in and out buttons if the page cannot zoom
+ mZoomButtonsController.getZoomControls().setVisibility(View.GONE);
+ } else {
+ // Set each one individually, as a page may be able to zoom in or out
+ mZoomButtonsController.setZoomInEnabled(canZoomIn);
+ mZoomButtonsController.setZoomOutEnabled(canZoomOut);
+ }
+ }
+
+ private class ZoomListener implements ZoomButtonsController.OnZoomListener {
+ @Override
+ public void onVisibilityChanged(boolean visible) {
+ if (visible) {
+ // Bring back the hidden zoom controls.
+ mZoomButtonsController.getZoomControls().setVisibility(View.VISIBLE);
+ updateZoomControls();
+ }
+ }
+
+ @Override
+ public void onZoom(boolean zoomIn) {
+ if (zoomIn) {
+ mContentView.zoomIn();
+ } else {
+ mContentView.zoomOut();
+ }
+ // ContentView will call updateZoomControls after its current page scale
+ // is got updated from the native code.
+ }
+ }
+}